diff --git a/CargoHub/AppDbContext.cs b/CargoHub/AppDbContext.cs index 6282168..9996ad8 100644 --- a/CargoHub/AppDbContext.cs +++ b/CargoHub/AppDbContext.cs @@ -90,17 +90,17 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .HasForeignKey(oi => oi.ItemUid); // De koppeling is via ItemUid - modelBuilder.Entity() - .HasMany(i => i.Locations) - .WithMany(l => l.Inventories); - // .UsingEntity(j => j.ToTable("StudentCourses")); - modelBuilder.Entity().Navigation(c => c.Warehouses).AutoInclude(true); - modelBuilder.Entity().Navigation(c => c.Locations).AutoInclude(true); - modelBuilder.Entity().Navigation(c => c.Transfers).AutoInclude(true); - modelBuilder.Entity().Navigation(c => c.Suppliers).AutoInclude(true); - modelBuilder.Entity().Navigation(c => c.Items).AutoInclude(true); - modelBuilder.Entity().Navigation(c => c.Shipments).AutoInclude(true); - modelBuilder.Entity().Navigation(c => c.Orders).AutoInclude(true); + // modelBuilder.Entity() + // .HasMany(i => i.Locations) + // .WithMany(l => l.Inventories); + // // .UsingEntity(j => j.ToTable("StudentCourses")); + // modelBuilder.Entity().Navigation(c => c.Warehouses).AutoInclude(true); + // modelBuilder.Entity().Navigation(c => c.Locations).AutoInclude(true); + // modelBuilder.Entity().Navigation(c => c.Transfers).AutoInclude(true); + // modelBuilder.Entity().Navigation(c => c.Suppliers).AutoInclude(true); + // modelBuilder.Entity().Navigation(c => c.Items).AutoInclude(true); + // modelBuilder.Entity().Navigation(c => c.Shipments).AutoInclude(true); + // modelBuilder.Entity().Navigation(c => c.Orders).AutoInclude(true); diff --git a/CargoHub/CargoHub.csproj b/CargoHub/CargoHub.csproj index b8ec674..7892e11 100644 --- a/CargoHub/CargoHub.csproj +++ b/CargoHub/CargoHub.csproj @@ -7,6 +7,8 @@ + + diff --git a/CargoHub/Controllers/ClassificationsControlller.cs b/CargoHub/Controllers/ClassificationsControlller.cs index a1083c0..c2f6385 100644 --- a/CargoHub/Controllers/ClassificationsControlller.cs +++ b/CargoHub/Controllers/ClassificationsControlller.cs @@ -1,61 +1,61 @@ -using CargoHub.Models; -using CargoHub.Services; -using CargoHub.Utilities; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore.Metadata.Internal; +// using CargoHub.Models; +// using CargoHub.Services; +// using CargoHub.Utilities; +// using Microsoft.AspNetCore.Mvc; +// using Microsoft.EntityFrameworkCore.Metadata.Internal; -namespace CargoHub.Controllers -{ - [Route("api/v2/[Controller]")] - public class ClassificationController(ClassificationService service, ErrorHandler handler) : BaseController(service, handler) - { - [HttpPut("Order")] - public async Task AssignClassificationToOrder([FromQuery] int OrderId, [FromQuery] int ClassificationId) - { - var SuccessfullyAssigned = await service.AssignClassificationToEntity(OrderId, ClassificationId); - return SuccessfullyAssigned ? Ok() : BadRequest(); - } +// namespace CargoHub.Controllers +// { +// [Route("api/v2/[Controller]")] +// public class ClassificationController(ClassificationService service, ErrorHandler handler) : BaseController(service, handler) +// { +// [HttpPut("Order")] +// public async Task AssignClassificationToOrder([FromQuery] int OrderId, [FromQuery] int ClassificationId) +// { +// var SuccessfullyAssigned = await service.AssignClassificationToEntity(OrderId, ClassificationId); +// return SuccessfullyAssigned ? Ok() : BadRequest(); +// } - [HttpPut("Shipment")] - public async Task AssignClassificationToShipment([FromQuery] int ShipmentId, [FromQuery] int ClassificationId) - { - var SuccessfullyAssigned = await service.AssignClassificationToEntity(ShipmentId, ClassificationId); - return SuccessfullyAssigned ? Ok() : BadRequest(); - } +// [HttpPut("Shipment")] +// public async Task AssignClassificationToShipment([FromQuery] int ShipmentId, [FromQuery] int ClassificationId) +// { +// var SuccessfullyAssigned = await service.AssignClassificationToEntity(ShipmentId, ClassificationId); +// return SuccessfullyAssigned ? Ok() : BadRequest(); +// } - [HttpPut("Warehouse")] - public async Task AssignClassificationToWarehouse([FromQuery] int WarehouseId, [FromQuery] int ClassificationId) - { - var SuccessfullyAssigned = await service.AssignClassificationToEntity(WarehouseId, ClassificationId); - return SuccessfullyAssigned ? Ok() : BadRequest(); - } - [HttpPut("Location")] - public async Task AssignClassificationToLocation([FromQuery] int LocationId, [FromBody] int ClassificationId) - { +// [HttpPut("Warehouse")] +// public async Task AssignClassificationToWarehouse([FromQuery] int WarehouseId, [FromQuery] int ClassificationId) +// { +// var SuccessfullyAssigned = await service.AssignClassificationToEntity(WarehouseId, ClassificationId); +// return SuccessfullyAssigned ? Ok() : BadRequest(); +// } +// [HttpPut("Location")] +// public async Task AssignClassificationToLocation([FromQuery] int LocationId, [FromBody] int ClassificationId) +// { - var SuccessfullyAssigned = await service.AssignClassificationToEntity(LocationId, ClassificationId); - return SuccessfullyAssigned ? Ok() : BadRequest(); - } - [HttpPut("Transfer")] - public async Task AssignClassificationToTransfer([FromQuery] int LocationId, [FromQuery] int ClassificationId) - { +// var SuccessfullyAssigned = await service.AssignClassificationToEntity(LocationId, ClassificationId); +// return SuccessfullyAssigned ? Ok() : BadRequest(); +// } +// [HttpPut("Transfer")] +// public async Task AssignClassificationToTransfer([FromQuery] int LocationId, [FromQuery] int ClassificationId) +// { - var SuccessfullyAssigned = await service.AssignClassificationToEntity(LocationId, ClassificationId); - return SuccessfullyAssigned ? Ok() : BadRequest(); - } - [HttpPut("Supplier")] - public async Task AssignClassificationToSupplier([FromQuery] int SupplierId, [FromQuery] int ClassificationId) - { +// var SuccessfullyAssigned = await service.AssignClassificationToEntity(LocationId, ClassificationId); +// return SuccessfullyAssigned ? Ok() : BadRequest(); +// } +// [HttpPut("Supplier")] +// public async Task AssignClassificationToSupplier([FromQuery] int SupplierId, [FromQuery] int ClassificationId) +// { - var SuccessfullyAssigned = await service.AssignClassificationToEntity(SupplierId, ClassificationId); - return SuccessfullyAssigned ? Ok() : BadRequest(); - } - [HttpPut("Item")] - public async Task AssignClassificationToItem([FromQuery] int ItemId, [FromQuery] int ClassificationId) - { +// var SuccessfullyAssigned = await service.AssignClassificationToEntity(SupplierId, ClassificationId); +// return SuccessfullyAssigned ? Ok() : BadRequest(); +// } +// [HttpPut("Item")] +// public async Task AssignClassificationToItem([FromQuery] int ItemId, [FromQuery] int ClassificationId) +// { - var SuccessfullyAssigned = await service.AssignClassificationToEntity(ItemId, ClassificationId); - return SuccessfullyAssigned ? Ok() : BadRequest(); - } - } -} \ No newline at end of file +// var SuccessfullyAssigned = await service.AssignClassificationToEntity(ItemId, ClassificationId); +// return SuccessfullyAssigned ? Ok() : BadRequest(); +// } +// } +// } \ No newline at end of file diff --git a/CargoHub/Controllers/MigrationsController.cs b/CargoHub/Controllers/MigrationsController.cs index 0270924..e222d36 100644 --- a/CargoHub/Controllers/MigrationsController.cs +++ b/CargoHub/Controllers/MigrationsController.cs @@ -1,5 +1,8 @@ using Microsoft.AspNetCore.Mvc; using CargoHub.Services; +using CsvHelper; +using System.Globalization; +using Microsoft.AspNetCore.Components.Web; namespace CargoHub.Controllers { @@ -16,9 +19,18 @@ public MigrationsController(MigrationsService Migrate) [HttpPost()] public async Task Migrate([FromQuery] string FolderName) { - var files = MigrationService.ReadDataFolder(FolderName); - return Ok($"Files transfered:\n${files}"); + // Get the absolute path using a known directory (e.g., Logs) + var logFilePath = Path.Combine(Directory.GetCurrentDirectory(), "Logs", MigrationService.ReadDataFolder(FolderName)); + + if (string.IsNullOrEmpty(logFilePath) || !System.IO.File.Exists(logFilePath)) + { + return NotFound("File not found"); + } + byte[] fileBytes = await System.IO.File.ReadAllBytesAsync(logFilePath); + + return File(fileBytes, "application/octet-stream", Path.GetFileName(logFilePath)); } + } } \ No newline at end of file diff --git a/CargoHub/Controllers/MonthlyReportController.cs b/CargoHub/Controllers/MonthlyReportController.cs index af6507e..818018c 100644 --- a/CargoHub/Controllers/MonthlyReportController.cs +++ b/CargoHub/Controllers/MonthlyReportController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using System.IO; +using System.Text; using System.Threading.Tasks; using CargoHub.Services; @@ -24,21 +25,20 @@ public async Task GenerateMonthlyReport(int year, int month) return BadRequest(new { message = "Invalid year or month. Please provide valid values." }); } - // Generate the report and get the file path - string filePath = await _reportService.GenerateMonthlyReport(year, month); + // Generate the report and get the CSV content + string csvContent = await _reportService.GenerateMonthlyCsvReport(year, month); - // Serve the file if it exists - if (System.IO.File.Exists(filePath)) + if (!string.IsNullOrEmpty(csvContent)) { - byte[] fileBytes = await System.IO.File.ReadAllBytesAsync(filePath); - string fileName = Path.GetFileName(filePath); + byte[] csvBytes = Encoding.UTF8.GetBytes(csvContent); + string fileName = $"MonthlyReport_{year}_{month:D2}.csv"; - return Ok(); + return File(csvBytes, "text/csv", fileName); } else { - return NotFound(new { message = "Report not found." }); + return NotFound(new { message = "No data available for the specified month and year." }); } } } -} +} \ No newline at end of file diff --git a/CargoHub/Controllers/OrdersController.cs b/CargoHub/Controllers/OrdersController.cs index c821383..a40f339 100644 --- a/CargoHub/Controllers/OrdersController.cs +++ b/CargoHub/Controllers/OrdersController.cs @@ -38,6 +38,21 @@ public async Task> GetOrder(int id) return Ok(order); } + // GET /orders/{orderId}/items + [HttpGet("{orderId}/items")] + public async Task GetOrderItems(int orderId) + { + try + { + var items = await _orderService.GetOrderItems(orderId); + return Ok(items); + } + catch (Exception ex) + { + return NotFound(new { message = ex.Message }); + } + } + [HttpGet("client/{clientId}")] public async Task>> GetOrdersForClient(int clientId) { @@ -88,46 +103,75 @@ public async Task>> GetOrderForStatus(string status) } [HttpPost] - public async Task> CreateOrder([FromBody] OrderWithItemsDTO orderDto) - { - if (orderDto == null) - { - return BadRequest("Ordergegevens zijn verplicht."); - } +[HttpPost] +public async Task> CreateOrder([FromBody] OrderWithItemsDTO orderDto) +{ + if (orderDto == null) + { + return BadRequest("Ordergegevens zijn verplicht."); + } - try - { - var order = new Order - { - SourceId = orderDto.SourceId, - OrderDate = orderDto.OrderDate, - RequestDate = orderDto.RequestDate, - Reference = orderDto.Reference, - ExtrReference = orderDto.ReferenceExtra, - OrderStatus = orderDto.OrderStatus, - Notes = orderDto.Notes, - ShippingNotes = orderDto.ShippingNotes, - PickingNotes = orderDto.PickingNotes, - WarehouseId = orderDto.WarehouseId ?? null, - ShipTo = orderDto.ShipTo ?? null, - BillTo = orderDto.BillTo ?? null, - ShipmentId = orderDto.ShipmentId ?? null, - TotalAmount = orderDto.TotalAmount, - TotalDiscount = orderDto.TotalDiscount, - TotalTax = orderDto.TotalTax, - TotalSurcharge = orderDto.TotalSurcharge, - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - - var createdOrder = await _orderService.CreateOrder(order, orderDto.Items); - return CreatedAtAction(nameof(GetOrder), new { id = createdOrder.Id }, createdOrder); - } - catch (Exception ex) - { - return StatusCode(500, $"Interne serverfout: {ex.Message}"); - } - } + try + { + var order = new Order + { + SourceId = orderDto.SourceId, + OrderDate = orderDto.OrderDate, + RequestDate = orderDto.RequestDate, + Reference = orderDto.Reference, + ExtrReference = orderDto.ReferenceExtra, + OrderStatus = orderDto.OrderStatus, + Notes = orderDto.Notes, + ShippingNotes = orderDto.ShippingNotes, + PickingNotes = orderDto.PickingNotes, + WarehouseId = orderDto.WarehouseId ?? null, + ShipTo = orderDto.ShipTo ?? null, + BillTo = orderDto.BillTo ?? null, + ShipmentId = orderDto.ShipmentId ?? null, + TotalAmount = orderDto.TotalAmount, + TotalDiscount = orderDto.TotalDiscount, + TotalTax = orderDto.TotalTax, + TotalSurcharge = orderDto.TotalSurcharge, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + + // Maak de order aan via de service + var createdOrder = await _orderService.CreateOrder(order, orderDto.Items); + + // Map de gemaakte order naar een DTO + var createdOrderDto = new OrderWithItemsDTO + { + Id = createdOrder.Id, + SourceId = createdOrder.SourceId, + OrderDate = createdOrder.OrderDate, + RequestDate = createdOrder.RequestDate, + Reference = createdOrder.Reference, + ReferenceExtra = createdOrder.ExtrReference, + OrderStatus = createdOrder.OrderStatus, + Notes = createdOrder.Notes, + ShippingNotes = createdOrder.ShippingNotes, + PickingNotes = createdOrder.PickingNotes, + WarehouseId = createdOrder.WarehouseId, + ShipTo = createdOrder.ShipTo, + BillTo = createdOrder.BillTo, + ShipmentId = createdOrder.ShipmentId, + TotalAmount = createdOrder.TotalAmount, + TotalDiscount = createdOrder.TotalDiscount, + TotalTax = createdOrder.TotalTax, + TotalSurcharge = createdOrder.TotalSurcharge, + CreatedAt = createdOrder.CreatedAt, + UpdatedAt = createdOrder.UpdatedAt, + Items = orderDto.Items // Aangezien deze al correct zijn aangeleverd + }; + + return CreatedAtAction(nameof(GetOrder), new { id = createdOrder.Id }, createdOrderDto); + } + catch (Exception ex) + { + return StatusCode(500, $"Interne serverfout: {ex.Message}"); + } +} [HttpPut("{id}/items")] public async Task UpdateItemsInOrder(int id, [FromBody] List orderItems) diff --git a/CargoHub/Controllers/Paklijst.cs b/CargoHub/Controllers/Paklijst.cs new file mode 100644 index 0000000..e69de29 diff --git a/CargoHub/Controllers/ShipmentsController.cs b/CargoHub/Controllers/ShipmentsController.cs index 042d221..aa935a5 100644 --- a/CargoHub/Controllers/ShipmentsController.cs +++ b/CargoHub/Controllers/ShipmentsController.cs @@ -148,6 +148,20 @@ public async Task UpdateShipmentFields(int shipmentId, [FromBody] } } + [HttpGet("{shipmentId}/items")] + public async Task>> GetItemsByShipmentId(int shipmentId) + { + var items = await _shipmentService.GetItemsByShipmentId(shipmentId); + + if (items == null) + { + return NotFound($"Shipment met ID {shipmentId} niet gevonden of bevat geen items."); + } + + return Ok(items); + } + + [HttpDelete("{id}")] public async Task DeleteShipment(int id) { diff --git a/CargoHub/LogTransferData.csv b/CargoHub/LogTransferData.csv new file mode 100644 index 0000000..dd1d92b --- /dev/null +++ b/CargoHub/LogTransferData.csv @@ -0,0 +1,13 @@ +File,DateOfTransfer,RowsChanged,TransferTime,Error +../data\clients.json,18-01-25,9820,00:00:02, +../data\inventories.json,18-01-25,11720,00:00:04, +../data\items.json,18-01-25,11720,00:00:08, +../data\item_groups.json,18-01-25,100,00:00:08, +../data\item_lines.json,18-01-25,97,00:00:08, +../data\item_types.json,18-01-25,100,00:00:08, +../data\locations.json,18-01-25,34533,00:00:13, +../data\orders.json,18-01-25,0,00:00:14,Error: The entity type 'JsonOrder' was not found. Ensure that the entity type has been added to the model. +../data\shipments.json,18-01-25,0,00:00:14,Error: The entity type 'JsonShipment' was not found. Ensure that the entity type has been added to the model. +../data\suppliers.json,18-01-25,497,00:00:14, +../data\transfers.json,18-01-25,119240,00:00:39, +../data\warehouses.json,18-01-25,58,00:00:39, diff --git a/CargoHub/Models/Inventory.cs b/CargoHub/Models/Inventory.cs index 528fec3..b1628a1 100644 --- a/CargoHub/Models/Inventory.cs +++ b/CargoHub/Models/Inventory.cs @@ -37,4 +37,4 @@ public class Inventory : BaseModel [JsonPropertyName("total_available")] public required int TotalAvailable { get; set; } } -} +} \ No newline at end of file diff --git a/CargoHub/Models/Location.cs b/CargoHub/Models/Location.cs index db8a314..4292fd3 100644 --- a/CargoHub/Models/Location.cs +++ b/CargoHub/Models/Location.cs @@ -1,16 +1,24 @@ +using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; namespace CargoHub.Models { public class Location : BaseModel, IContainsClassification { + + [Required] [JsonPropertyName("warehouse_id")] public int? WarehouseId { get; set; } [JsonIgnore] - public Warehouse? Warehouse { get; set; } + + public Warehouse? Warehouse { get; set; } // Navigation property with correct capitalization + + [JsonPropertyName("code")] + public string? Code { get; set; } // Nullable based on provided JSON [JsonIgnore] public ICollection Inventories { get; } = []; - public required string Code { get; set; } public required string Name { get; set; } + [JsonIgnore] + public List Classifications { get; set; } = []; } -} +} \ No newline at end of file diff --git a/CargoHub/Models/Order.cs b/CargoHub/Models/Order.cs index c94288f..e6c12cb 100644 --- a/CargoHub/Models/Order.cs +++ b/CargoHub/Models/Order.cs @@ -4,7 +4,7 @@ namespace CargoHub.Models { - public class Order : BaseModel, IContainsClassification + public class Order : IContainsClassification { public int? SourceId { get; set; } public DateTime? OrderDate { get; set; } @@ -31,11 +31,20 @@ public class Order : BaseModel, IContainsClassification public double? TotalDiscount { get; set; } public double? TotalTax { get; set; } public double? TotalSurcharge { get; set; } + public bool IsDeleted { get; set; } = false; + // Avoid serializing the OrderItems navigation property public List? OrderItems { get; set; } = new List(); public List Classifications { get; set; } = []; + [JsonPropertyOrder(-1)] + [JsonPropertyName("id")] + public int Id { get; set; } + [JsonPropertyName("created_at")] + public DateTime CreatedAt { get; set; } + [JsonPropertyName("updated_at")] + public DateTime UpdatedAt { get; set; } } diff --git a/CargoHub/Models/Shipment.cs b/CargoHub/Models/Shipment.cs index f98a2f3..ffdf5ea 100644 --- a/CargoHub/Models/Shipment.cs +++ b/CargoHub/Models/Shipment.cs @@ -4,7 +4,7 @@ namespace CargoHub.Models { - public class Shipment : BaseModel, IContainsClassification + public class Shipment : IContainsClassification { public int? SourceId { get; set; } public DateTime? Orderdate { get; set; } @@ -23,6 +23,16 @@ public class Shipment : BaseModel, IContainsClassification public List? orders { get; set; } [JsonIgnore] public List Classifications { get; set; } = []; + [JsonPropertyOrder(-1)] + [JsonPropertyName("id")] + public int Id { get; set; } + [JsonPropertyName("created_at")] + public DateTime CreatedAt { get; set; } + [JsonPropertyName("updated_at")] + public DateTime UpdatedAt { get; set; } + + + } public class ShipmentDTO { diff --git a/CargoHub/Models/Supplier.cs b/CargoHub/Models/Supplier.cs index 1f25e85..fcf4c5f 100644 --- a/CargoHub/Models/Supplier.cs +++ b/CargoHub/Models/Supplier.cs @@ -4,19 +4,37 @@ namespace CargoHub.Models { public class Supplier : BaseModel, IContainsClassification { - public required string Code {get; set;} - public required string Name {get; set;} - public required string Address {get; set;} + [JsonPropertyName("code")] + + public required string? Code { get; set; } + [JsonPropertyName("name")] + + public required string? Name { get; set; } + [JsonPropertyName("address")] + + public required string? Address { get; set; } [JsonPropertyName("address_extra")] - public required string AddressExtra { get; set; } - public required string City { get; set; } + public required string? AddressExtra { get; set; } + [JsonPropertyName("city")] + public required string? City { get; set; } [JsonPropertyName("zip_code")] - public required string ZipCode {get; set;} - public required string Province {get; set;} - public required string Country {get; set;} + public required string? ZipCode { get; set; } + [JsonPropertyName("province")] + + public required string? Province { get; set; } + [JsonPropertyName("country")] + + public required string? Country { get; set; } + [JsonPropertyName("contact_name")] - public required string ContactName {get; set;} - public required string Phonenumber {get; set;} - public required string Reference {get; set;} + public required string? ContactName { get; set; } + [JsonPropertyName("phonenumber")] + + public required string? Phonenumber { get; set; } + [JsonPropertyName("reference")] + + public required string? Reference { get; set; } + [JsonIgnore] + public List Classifications { get; set; } = []; } -} +} \ No newline at end of file diff --git a/CargoHub/Models/TransferData.cs b/CargoHub/Models/TransferData.cs new file mode 100644 index 0000000..2453d6f --- /dev/null +++ b/CargoHub/Models/TransferData.cs @@ -0,0 +1,24 @@ +namespace CargoHub.Models +{ + + public class TransferData + { + public string File { get; set; } + public string DateOfTransfer { get; set; } + public int RowsChanged { get; set; } + public string TransferTime { get; set; } + public string Error { get; set; } + + public TransferData(string file, string dateOfTransfer, int rows, string transferTime, string error) + { + File = file; + DateOfTransfer = dateOfTransfer; + RowsChanged = rows; + TransferTime = transferTime; + Error = error; + } + + + } +} + diff --git a/CargoHub/Models/Warehouse.cs b/CargoHub/Models/Warehouse.cs index 9bcf376..8b40856 100644 --- a/CargoHub/Models/Warehouse.cs +++ b/CargoHub/Models/Warehouse.cs @@ -46,5 +46,7 @@ public class Warehouse : BaseModel, IContainsClassification [JsonIgnore] public ICollection Locations { get; } = []; + [JsonIgnore] + public List Classifications { get; set; } = []; } -} +} \ No newline at end of file diff --git a/CargoHub/Program.cs b/CargoHub/Program.cs index f9cb444..7a3b9a8 100644 --- a/CargoHub/Program.cs +++ b/CargoHub/Program.cs @@ -24,8 +24,11 @@ public static void Main(string[] args) builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); - builder.Services.AddScoped(); + // builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.AddScoped(); diff --git a/CargoHub/Rest/Inventories.rest b/CargoHub/Rest/Inventories.rest new file mode 100644 index 0000000..4799426 --- /dev/null +++ b/CargoHub/Rest/Inventories.rest @@ -0,0 +1,19 @@ +POST http://localhost:3000/api/v2/Inventories HTTP/1.1 +Content-Type: application/json + +{ + "id": 0, + "created_at": "2025-01-05T13:14:19.103Z", + "updated_at": "2025-01-05T13:14:19.103Z", + "item_id": "P000002", + "description": "string", + "item_reference": "string", + "locations": [ + 0 + ], + "total_on_hand": 0, + "total_expected": 0, + "total_ordered": 0, + "total_allocated": 0, + "total_available": 0 +} \ No newline at end of file diff --git a/CargoHub/Rest/Migrate.rest b/CargoHub/Rest/Migrate.rest index 80fc781..6f19310 100644 --- a/CargoHub/Rest/Migrate.rest +++ b/CargoHub/Rest/Migrate.rest @@ -1,3 +1,4 @@ -@baseUrl = http://localhost:3000/api/v1/Migrations +@baseUrl = http://localhost:3000/api/v2/Migrations POST {{baseUrl}}?FolderName=data + diff --git a/CargoHub/Rest/Orders.rest b/CargoHub/Rest/Orders.rest index 981f659..e217eec 100644 --- a/CargoHub/Rest/Orders.rest +++ b/CargoHub/Rest/Orders.rest @@ -1,4 +1,4 @@ -POST http://localhost:3000/api/v1/orders +POST http://localhost:3000/api/v2/orders Content-Type: application/json ApiKey: Admin { @@ -24,12 +24,12 @@ Content-Type: application/json ApiKey: Admin "Items": [ { - "ItemId": "ITEM001", - "Amount": 3 + "Item_Id": "P000001", + "Amount": 1 }, { - "ItemId": "ITEM002", - "Amount": 3 + "Item_Id": "P000002", + "Amount": 1 } ] diff --git a/CargoHub/Services/ClassificationService.cs b/CargoHub/Services/ClassificationService.cs index fccebb0..20e85ac 100644 --- a/CargoHub/Services/ClassificationService.cs +++ b/CargoHub/Services/ClassificationService.cs @@ -1,41 +1,41 @@ -using CargoHub.Models; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -namespace CargoHub.Services -{ - public class ClassificationService : BaseStorageService - { - private readonly AppDbContext _context; +// using CargoHub.Models; +// using Microsoft.AspNetCore.Mvc; +// using Microsoft.EntityFrameworkCore; +// namespace CargoHub.Services +// { +// public class ClassificationService : BaseStorageService +// { +// private readonly AppDbContext _context; - public ClassificationService(AppDbContext context) : base(context) - { - _context = context; - } - public async Task AssignClassificationToEntity(int Id, int ClassificationId) where T : BaseModel, IContainsClassification - { - T? Entity = await _context.FindAsync(Id); - Classification? FoundClassification = await _context.Classifications.FindAsync(ClassificationId); - if (Entity == null || FoundClassification == null) - { - return false; - } - if (Entity.Classifications.Contains(FoundClassification)) - { - return false; - } - try - { - Entity.Classifications.Add(FoundClassification); - // appDbContext.Set().Add(Entity); - int rowsChanged = await appDbContext.SaveChangesAsync(); - return rowsChanged > 0; - } - catch (Exception ex) - { - Console.WriteLine($"An error has occured while adding classification to order with Id {Id}: {ex.Message}"); - return false; - } +// public ClassificationService(AppDbContext context) : base(context) +// { +// _context = context; +// } +// public async Task AssignClassificationToEntity(int Id, int ClassificationId) where T : BaseModel, IContainsClassification +// { +// T? Entity = await _context.FindAsync(Id); +// Classification? FoundClassification = await _context.Classifications.FindAsync(ClassificationId); +// if (Entity == null || FoundClassification == null) +// { +// return false; +// } +// if (Entity.Classifications.Contains(FoundClassification)) +// { +// return false; +// } +// try +// { +// Entity.Classifications.Add(FoundClassification); +// // appDbContext.Set().Add(Entity); +// int rowsChanged = await appDbContext.SaveChangesAsync(); +// return rowsChanged > 0; +// } +// catch (Exception ex) +// { +// Console.WriteLine($"An error has occured while adding classification to order with Id {Id}: {ex.Message}"); +// return false; +// } - } - } -} \ No newline at end of file +// } +// } +// } \ No newline at end of file diff --git a/CargoHub/Services/DropBoxService.cs b/CargoHub/Services/DropBoxService.cs new file mode 100644 index 0000000..cc747af --- /dev/null +++ b/CargoHub/Services/DropBoxService.cs @@ -0,0 +1,36 @@ +using Dropbox.Api; +using System; +using System.IO; +using System.Threading.Tasks; +namespace CargoHub.Services +{ + public class DropboxService + { + private static string accessToken = "sl.u.AFeGs_kE86tDJ0b7FURQg5esf17ka1INNPmfZwrmnNVQV64deAlquYstsHsG4nn2BYXRIgKbVxAzWzvFJZwN46x-QnBBpbE2FEkUZvATn5rlog793TWd0DAVblupxyTfRTUVyvNPaxlCiOXChVc-J4Iq8BPGW3NoDJWUP57i1uicUEcjU6kGoqjtWiHGBW3dUicN6sTS4rKw8mGxxfam3Ely1XU1FHpR4V5AiUjBNERT0MK32JoWEiZnFblif5JjjCTLBoOYl_E1bnbsKajI57NQZcVbMtL-5Rfm9eMgq1VuN0P9oIVqOMwgLg-GMhpwuh_lItiDXPER4LJ_1YrwFwHGn2V2ia4_eq5TvkDTePrt7M1o3XF1GGFQDVYTVFAa1gNCD71T1JePqSMt-o2W6j2aF25g0g9YRaw16SI4aN49fpzU4o7adXaoYaj-z8dTRl0ZK6TVevmN933TlFKjBsw2IsqZMURv2fD-1eTCx12qKn0fYf7yzxdfUUGYZP7KyuHOu45ILWp0WrLIQuZ3cIckJU7GrKipl1uJRaeORJhSzXKv2kz7r35BPUgXPx_XjdJ25QgfeQGE0OdHIxwJRAKuQUgDL9nFmJOUALWloLWcfMnI3Y4xM4YaHoMK7pqgN0YkL0O8jkZXDmrq6RS1uNZTue8UXfIrnAQ2fpRxEP6Ur1uUaDnAuySTSeyY1mFDHhdwuJb_jXDIZY4xDkHNEeSAAsWyfSLVzoyVb4M4oY8bmcC87psK4eKqJdevzi0pjdWcUaD0e98GEOqdwIRWfrWFT-GQtabOm7nIuuWXgHIdJB5xd4-IFD8QkGeRRySsDE_PuKUV0DCQhHSuAkVSypx1c3JLaPWm1Ju8NC51FMSoZQkN8hSluAmJUSgKZBoa5UtMTENj413du2Uw7pfK7uGfO7bjUh1CwjUZf9735G9lCfxlDLddyewrEzrx2JXnqOJUwTKefIaV14p5QJ59z3w9xy1ySepTi5vibly4vkT38uIxdE7A22-N5emCtBVCSLDIdKTFDYCeMyUC-7vBZB4BWpRwF5fc5-VWF9zocmAAWR09BjASP_Dqy4EV9bAzp_3utBySgTybIKOMKY0mbEQPj-PZZlTKxfYi-ZSo48juR3AACG3AVuQcn-mgfMn7gJs8nM2tK6V44L_J334KuYYDQz5Yj6EAQkfV6AI7wLcu4twpv9hkNfUJLCrLKHzclDFTi7uXHZ9wXRwtHCg3dLVbb9SPUU0KN_5xycNBzQSOGVtV6IOpUdxf5isJjwnArl6HGnXZGc1clSlgTaTvHbthuoKFLiyJ5T2k-cooz4WODo4Bv2F06PrKeZE5jJcGuDwJO9lQoIEUHLSEB1JhIQx5Xo0ud3tBu6L4awG8quuMlNyfAN7h7W7kYTE70Di4ciUVV-fr0YA_qt7h9tP_Z72yrM1j-sJYg7OnsGvHKR8aiQ"; // Replace with your generated token + + public static async Task UploadFileToDropbox(string localFilePath, string dropboxFilePath) + { + using (var dbx = new DropboxClient(accessToken)) + { + using (var fileStream = File.Open(localFilePath, FileMode.Open)) + { + var updated = await dbx.Files.UploadAsync( + dropboxFilePath, // Path to the file in Dropbox (including the file name) + Dropbox.Api.Files.WriteMode.Overwrite.Instance, + body: fileStream); + + Console.WriteLine("File uploaded: " + updated.PathDisplay); + } + } + } + + public static async Task GetSharedLink(string dropboxFilePath) + { + using (var dbx = new DropboxClient(accessToken)) + { + var sharedLink = await dbx.Files.GetTemporaryLinkAsync(dropboxFilePath); + return sharedLink.Link; // Returns a temporary URL to download the file + } + } + } +} diff --git a/CargoHub/Services/Migrations.cs b/CargoHub/Services/Migrations.cs index c7b3828..d09fcd3 100644 --- a/CargoHub/Services/Migrations.cs +++ b/CargoHub/Services/Migrations.cs @@ -1,97 +1,75 @@ using CargoHub.Models; using System.Text.Json; +using System.Globalization; +using System.Diagnostics; +using CsvHelper; +using Microsoft.EntityFrameworkCore; +using System.Reflection; namespace CargoHub.Services { public class MigrationsService { - AppDbContext _context; + AppDbContext Context; + Stopwatch Stopwatch; + JsonSerializerOptions options; + List LogData; public MigrationsService(AppDbContext context) { - _context = context; + Context = context; + Stopwatch = new Stopwatch(); + options = new JsonSerializerOptions(); + options.Converters.Add(new CustomDateTimeConverter()); + LogData = []; + } - public List ReadDataFolder(string Folder) + public string ReadDataFolder(string Folder) { string path = $"../{Folder}"; var files = Directory.GetFiles(path); List fileNames = new(); + foreach (var file in files) { - if (file.Contains("clients")) - { - TransferData(file); - } - else if (file.Contains("item_groups")) - { - TransferData(file); - } - else if (file.Contains("inventories")) - { - TransferData(file); - } - else if (file.Contains("item_lines")) - { - TransferData(file); - } - else if (file.Contains("item_types")) - { - TransferData(file); - } - else if (file.Contains("items")) - { - TransferData(file); - } - else if (file.Contains("warehouses")) - { - TransferData(file); - } + // search for the type of the file using the dictionary of type mapping + var fileName = Path.GetFileName(file).ToLower(); + var matchedType = TypeMapping.fileTypeMap.FirstOrDefault(m => fileName.Contains(m.Key)).Value; - else if (file.Contains("locations")) - { - TransferData(file); - } - else if (file.Contains("suppliers")) - { - TransferData(file); - } - else if (file.Contains("transfers")) + if (matchedType != null) { - TransferData(file); - - } - - // else if (file.Contains("shipments")) - // { - // TransferData(file); + // make the method + var methodInfo = typeof(MigrationsService) + .GetMethod(nameof(MigrationsService.TransferData)); - // } - // else if (file.Contains("orders")) - // { - // TransferData(file); + var GenericMethodInfo = methodInfo.MakeGenericMethod(matchedType); - // } + // Invoke the method + GenericMethodInfo.Invoke(this, [file]); + } else { Console.WriteLine($"The file {file} is not included in the transfer files."); } - fileNames.Add(file); } + string LogFilesName = "LogTransferData.csv"; - - return fileNames; + MakeLogFile($"LogTransferData.csv"); + return $"../{LogFilesName}"; } - private void TransferData(string DataFile) where T : BaseModel - { - var options = new JsonSerializerOptions(); - options.Converters.Add(new CustomDateTimeConverter()); - int RowsChanged = 0; + public void TransferData(string DataFile) where T : BaseModel + { + Stopwatch.Start(); + int RowsChanged = 0; + List ErrorMessage = new(); try { + // Disable foreign key constraints + Context.Database.ExecuteSqlRaw("PRAGMA foreign_keys = OFF;"); List? Models = JsonSerializer.Deserialize>(File.ReadAllText(DataFile), options); if (Models != null && Models.Count > 0) @@ -100,56 +78,78 @@ private void TransferData(string DataFile) where T : BaseModel { Models.ForEach(m => m.Id += 1); } - // if the models are of type shipments, Convert the JSONshipments to shipments objects - if (typeof(T) == typeof(JsonShipment)) - { - var JsonShipments = Models.Cast().ToList(); - List Shipments = []; - foreach (JsonShipment JShipment in JsonShipments) - { - Shipments.Add(JShipment.ConvertToShipment()); - - } - _context.Shipments.AddRange(Shipments); - RowsChanged = _context.SaveChanges(); - return; - } - - if (typeof(T) == typeof(JsonOrder)) - { - var JsonOrders = Models.Cast().ToList(); - List Orders = []; - foreach (JsonOrder order in JsonOrders) - { - Orders.Add(order.ConvertToOrder()); - } - _context.Orders.AddRange(Orders); - RowsChanged = _context.SaveChanges(); - Console.WriteLine($"Rows inserted: {RowsChanged}"); - } - _context.AddRange(Models); - RowsChanged = _context.SaveChanges(); - Console.WriteLine($"Rows inserted: {RowsChanged}"); + Context.AddRange(Models); + RowsChanged = Context.SaveChanges(); } } catch (JsonException ex) { - Console.WriteLine($"Error deserializing: {ex.Message}"); + ErrorMessage.Add($"Error deserializing: {ex.Message}"); } catch (Exception ex) { - Console.WriteLine($"Error: {ex.Message}"); + string Error = $"Error: {ex.Message}"; if (ex.InnerException != null) { - Console.WriteLine($"Inner Exception: {ex.InnerException.Message}"); + Error += $" Inner Exception: {ex.InnerException.Message}"; } + ErrorMessage.Add(Error); } + finally + { + // Re-enable foreign key constraints + Context.Database.ExecuteSqlRaw("PRAGMA foreign_keys = ON;"); + + Stopwatch.Stop(); + TimeSpan TransferTime = Stopwatch.Elapsed; + LogTransfer(DataFile, RowsChanged, TransferTime, ErrorMessage); + } + } + + + + private void LogTransfer(string File, int RowsChanged, TimeSpan TransferTime, List Error) + { + string FormattedTime = TransferTime.ToString(@"hh\:mm\:ss"); + string CombinedErrors = String.Join("|", Error); + string DateOfTransfer = DateTime.Now.ToString(@"dd-MM-yy"); + TransferData Data = new TransferData(File, DateOfTransfer, RowsChanged, FormattedTime, CombinedErrors); + LogData.Add(Data); } - private void LogTransfer(bool Success, string File, int RowsChanged = 0) + private void MakeLogFile(string OutputFile) { - throw new NotImplementedException(); + try + { + var logDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Logs"); + + // Ensure the Logs directory exists + if (!Directory.Exists(logDirectory)) + { + Directory.CreateDirectory(logDirectory); + } + + // Combine the file path with the Logs folder + string filePath = Path.Combine(logDirectory, OutputFile); + + using var writer = new StreamWriter(filePath); + using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); + csv.WriteRecords(LogData); + } + catch (Exception ex) + { + Console.WriteLine($"Error creating log file: {ex.Message}"); + } } } + + } + + + + + + + diff --git a/CargoHub/Services/MontlyReportService.cs b/CargoHub/Services/MontlyReportService.cs index 50b207e..eea8a69 100644 --- a/CargoHub/Services/MontlyReportService.cs +++ b/CargoHub/Services/MontlyReportService.cs @@ -1,25 +1,22 @@ using CargoHub.Models; using Microsoft.EntityFrameworkCore; -using Swashbuckle.AspNetCore.SwaggerUI; using System; using System.Linq; +using System.Text; using System.Threading.Tasks; -using Xunit.Sdk; namespace CargoHub.Services { public class ReportService { private readonly AppDbContext _context; - private readonly PdfReportService _pdfReportService; - public ReportService(AppDbContext context, PdfReportService pdfReportService) + public ReportService(AppDbContext context) { _context = context; - _pdfReportService = pdfReportService; } - public async Task GenerateMonthlyReport(int year, int month) + public async Task GenerateMonthlyCsvReport(int year, int month) { // Orders created in the specified month var orders = await _context.Orders @@ -32,21 +29,26 @@ public async Task GenerateMonthlyReport(int year, int month) .Where(s => s.CreatedAt.Year == year && s.CreatedAt.Month == month) .ToListAsync(); - var CalculateAverageOrderProcessingTime = orders - .Where(o => o.OrderDate.HasValue && o.OrderDate > o.CreatedAt) - .Select(o => (o.OrderDate.Value - o.CreatedAt).TotalDays) - .DefaultIfEmpty(0) - .Average(); + if (!orders.Any() && !shipments.Any()) + { + return null; + } - var CalculateAverageShipmentTransitProcessingTime = shipments - .Where(s => s.ShipmentDate > s.CreatedAt) - .Select(s => (s.ShipmentDate - s.CreatedAt).TotalDays) - .DefaultIfEmpty(0) - .Average(); + // Analyze data for the report + var CalculateAverageOrderProcessingTime = orders + .Where(o => o.OrderDate.HasValue && o.OrderDate > o.CreatedAt) + .Select(o => (o.OrderDate.Value - o.CreatedAt).TotalDays) + .DefaultIfEmpty(0) + .Average(); + + var CalculateAverageShipmentTransitProcessingTime = shipments + .Where(s => s.ShipmentDate > s.CreatedAt) + .Select(s => (s.ShipmentDate - s.CreatedAt).TotalDays) + .DefaultIfEmpty(0) + .Average(); var totalItems = orders.Sum(o => o.OrderItems.Count()); - - + var topWarehouse = orders .GroupBy(o => o.WarehouseId) .OrderByDescending(g => g.Count()) @@ -57,30 +59,28 @@ public async Task GenerateMonthlyReport(int year, int month) }) .FirstOrDefault(); - + // Create CSV content + var csvBuilder = new StringBuilder(); - if (!orders.Any() && !shipments.Any()) - { - throw new InvalidOperationException("No data available for the specified month and year."); - } + // Gebruik puntkomma als scheidingsteken voor betere compatibiliteit + csvBuilder.AppendLine("Jaar;Maand;Totaal Bestellingen;Totale Waarde (€);Gem. Orderverwerkingstijd (dagen);Totaal Zendingen;Gem. Transittijd (dagen);Totaal Items;Top Magazijn ID;Top Magazijn Bestellingen"); - // Analyze data for the report - var report = new MonthlyReportDTO - { - Year = year, - Month = month, - TotalOrders = orders.Count, - TotalOrderAmount = orders.Sum(o => o.TotalAmount), - AverageOrderProcessingTime = CalculateAverageOrderProcessingTime, - TotalShipments = shipments.Count, - AverageShipmentTransitProcessingTime = CalculateAverageShipmentTransitProcessingTime, - TotalItems = totalItems, - TopWarehouseId = topWarehouse?.WarehouseId ?? 0, - TopWarehouseOrderCount = topWarehouse?.OrderCount ?? 0 - }; + // Voeg data toe met nette formatting + csvBuilder.AppendLine( + $"{year};" + + $"{month};" + + $"{orders.Count};" + + $"{orders.Sum(o => o.TotalAmount):0.00};" + // 2 decimalen voor geldwaarde + $"{CalculateAverageOrderProcessingTime:0.0};" + // 1 decimaal voor gemiddelden + $"{shipments.Count};" + + $"{CalculateAverageShipmentTransitProcessingTime:0.0};" + + $"{totalItems};" + + $"{(topWarehouse?.WarehouseId.HasValue == true ? topWarehouse.WarehouseId.ToString() : "N/A")};" + + $"{(topWarehouse?.OrderCount ?? 0)}" + ); + + return csvBuilder.ToString(); - // Generate the PDF and return the file path - return _pdfReportService.GenerateMonthlyReport(report); } } } diff --git a/CargoHub/Services/OrderServices.cs b/CargoHub/Services/OrderServices.cs index 6b3e522..89d4539 100644 --- a/CargoHub/Services/OrderServices.cs +++ b/CargoHub/Services/OrderServices.cs @@ -11,7 +11,6 @@ public class OrderService { private readonly AppDbContext _context; - // Constructor om de database context te injecteren public OrderService(AppDbContext context) { _context = context; @@ -39,6 +38,29 @@ public async Task> GetAllOrdersWithItems() return orders.Select(order => MapOrderToDTO(order)).ToList(); } + // Haal alleen de items van een specifieke order op + public async Task> GetOrderItems(int orderId) + { + // Haal de order op inclusief de items + var order = await _context.Orders + .Include(o => o.OrderItems) + .ThenInclude(oi => oi.Item) + .FirstOrDefaultAsync(o => o.Id == orderId); + + if (order == null) + { + throw new Exception($"Order met ID {orderId} niet gevonden."); + } + + // Map de order-items naar ItemDTO's + return order.OrderItems.Select(oi => new ItemDTO + { + ItemId = oi.Item.Uid, + Amount = oi.Amount + }).ToList(); + } + + // Haal alle orders op voor een specifieke klant @@ -50,6 +72,7 @@ public async Task> GetOrdersCLient(int clientId) .ToListAsync(); } + public async Task> GetOrdersLinkedWithWarehouseId(int Warehouseid) { return await _context.Orders @@ -73,74 +96,72 @@ public async Task> GetOrdersStatus(string status) - // Maak een nieuwe order aan en voeg items toe public async Task CreateOrder(Order order, List itemDTOs) { try { - // Voeg de nieuwe order toe en sla op om het ID te genereren - _context.Orders.Add(order); - await _context.SaveChangesAsync(); - - // Voeg items toe aan de order + // Valideer alle items vooraf foreach (var itemDto in itemDTOs) { - // Controleer of het item bestaat var item = await _context.Items.FirstOrDefaultAsync(i => i.Uid == itemDto.ItemId); if (item == null) - { throw new Exception($"Item met Uid {itemDto.ItemId} bestaat niet."); - } - // Controleer of het item in de voorraad aanwezig is - var itemInventory = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == itemDto.ItemId); - if (itemInventory == null) - { + if (itemDto.Amount < item.PackOrderQuantity) + throw new Exception($"Hoeveelheid voor item {itemDto.ItemId} moet minimaal {item.PackOrderQuantity} zijn."); + + if (itemDto.Amount % item.UnitOrderQuantity != 0) + throw new Exception($"Hoeveelheid voor item {itemDto.ItemId} moet een veelvoud zijn van {item.UnitOrderQuantity}."); + + var inventory = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == itemDto.ItemId); + if (inventory == null) throw new Exception($"Geen inventaris gevonden voor item met Uid {itemDto.ItemId}."); - } - // Controleer of er voldoende voorraad beschikbaar is - if (itemInventory.TotalAvailable < itemDto.Amount) - { - throw new Exception($"Niet genoeg voorraad voor item met Uid {itemDto.ItemId}. Beschikbaar: {itemInventory.TotalAvailable}, gevraagd: {itemDto.Amount}"); - } + if (inventory.TotalAvailable < itemDto.Amount) + throw new Exception($"Niet genoeg voorraad voor item met Uid {itemDto.ItemId}. Beschikbaar: {inventory.TotalAvailable}, gevraagd: {itemDto.Amount}"); } - // Alle items zijn geldig, voeg nu de order-items toe + // Voeg de order toe + _context.Orders.Add(order); + await _context.SaveChangesAsync(); // Save om een ID voor de order te genereren + + // Verwerk items na validatie foreach (var itemDto in itemDTOs) { - var itemInventory = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == itemDto.ItemId); + var inventory = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == itemDto.ItemId); - // Verminder de beschikbare voorraad - itemInventory.TotalAvailable -= itemDto.Amount; + // Update voorraad + inventory.TotalAvailable -= itemDto.Amount; + inventory.TotalAllocated += itemDto.Amount; + _context.Inventory.Update(inventory); - // Maak een nieuw OrderItem aan + // Voeg het orderitem toe var orderItem = new OrderItem { - OrderId = order.Id, // Order-ID is nu beschikbaar + OrderId = order.Id, ItemUid = itemDto.ItemId, Amount = itemDto.Amount }; - - // Voeg het item toe aan de context _context.OrderItems.Add(orderItem); } - // Sla de order-items en voorraadwijzigingen op in de database + // Sla de wijzigingen op in één keer await _context.SaveChangesAsync(); - return order; } catch (Exception ex) { - // Log de fout en gooi hem opnieuw voor verder gebruik - Console.WriteLine($"Fout bij het aanmaken van een order: {ex.Message}"); + // Log de fout en geef deze door + Console.WriteLine($"Fout bij het aanmaken van de order: {ex.Message}"); throw; } } + + + // Update een bestaande order en de gekoppelde items public async Task UpdateOrder(int orderId, OrderWithItemsDTO updatedOrderDto) { @@ -168,85 +189,134 @@ public async Task UpdateOrder(int orderId, OrderWithItemsDTO updatedOrde } // Update alleen de items van een bestaande order - public async Task UpdateItemsInOrder(int orderId, List orderItems) +public async Task UpdateItemsInOrder(int orderId, List orderItems) +{ + foreach (var item in orderItems) + { + if (!await ItemExist(item.ItemId)) { - // Controleer of elk opgegeven item bestaat - foreach (var item in orderItems) + return $"Item met ID {item.ItemId} is niet gevonden."; + } + } + + var updateOrder = await _context.Orders + .Include(o => o.OrderItems) + .FirstOrDefaultAsync(o => o.Id == orderId); + + if (updateOrder == null) + { + return $"Order met ID {orderId} is niet gevonden."; + } + + foreach (var currentItem in updateOrder.OrderItems.ToList()) + { + var matchingItem = orderItems.FirstOrDefault(i => i.ItemId == currentItem.ItemUid); + + if (matchingItem != null) + { + var inventoryItem = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == currentItem.ItemUid); + if (inventoryItem != null) { - if (!await ItemExist(item.ItemId)) // Controleer of het item bestaat in de database + int adjustment = matchingItem.Amount - currentItem.Amount; + + if (adjustment > 0 && inventoryItem.TotalAvailable < adjustment) { - return $"Item met ID {item.ItemId} is niet gevonden."; + return $"Niet genoeg voorraad voor item met ID {currentItem.ItemUid}. Beschikbaar: {inventoryItem.TotalAvailable}, nodig: {adjustment}"; } - } - // Haal de bestaande order inclusief de gekoppelde items op - var updateOrder = await _context.Orders - .Include(o => o.OrderItems) - .FirstOrDefaultAsync(o => o.Id == orderId); + var item = await _context.Items.FirstOrDefaultAsync(i => i.Uid == currentItem.ItemUid); + if (item != null) + { + if (matchingItem.Amount % item.UnitOrderQuantity != 0) + { + throw new Exception($"Hoeveelheid voor item {matchingItem.ItemId} moet een veelvoud zijn van {item.UnitOrderQuantity}."); + } + + if (matchingItem.Amount < item.PackOrderQuantity) + { + throw new Exception($"Hoeveelheid voor item {matchingItem.ItemId} moet minimaal {item.PackOrderQuantity} zijn."); + } + } + + inventoryItem.TotalAllocated += adjustment; + inventoryItem.TotalAvailable -= adjustment; - if (updateOrder == null) + // Prevent negative inventory values + inventoryItem.TotalAllocated = Math.Max(0, inventoryItem.TotalAllocated); + inventoryItem.TotalAvailable = Math.Max(0, inventoryItem.TotalAvailable); + + _context.Inventory.Update(inventoryItem); + } + + currentItem.Amount = matchingItem.Amount; + } + else + { + var inventoryItem = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == currentItem.ItemUid); + if (inventoryItem != null) { - return $"Order met ID {orderId} is niet gevonden."; + inventoryItem.TotalAllocated -= currentItem.Amount; + inventoryItem.TotalAvailable += currentItem.Amount; + + inventoryItem.TotalAllocated = Math.Max(0, inventoryItem.TotalAllocated); + inventoryItem.TotalAvailable = Math.Max(0, inventoryItem.TotalAvailable); } + _context.OrderItems.Remove(currentItem); + } + } - // Update bestaande items of verwijder ze indien ze niet meer in de order voorkomen - foreach (var currentItem in updateOrder.OrderItems.ToList()) // Doorloop alle huidige items in de order + foreach (var newItem in orderItems) + { + var existingItem = updateOrder.OrderItems.FirstOrDefault(i => i.ItemUid == newItem.ItemId); + if (existingItem == null) + { + var inventoryItem = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == newItem.ItemId); + if (inventoryItem != null) { - var matchingItem = orderItems.FirstOrDefault(i => i.ItemId == currentItem.ItemUid); // Zoek het overeenkomende item in de nieuwe lijst - if (matchingItem != null) + var item = await _context.Items.FirstOrDefaultAsync(i => i.Uid == newItem.ItemId); + + if (item != null) { - // Update voorraad voor het item als het nog bestaat - var inventoryItem = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == currentItem.ItemUid); - if (inventoryItem != null) + if (newItem.Amount % item.UnitOrderQuantity != 0) { - inventoryItem.TotalAllocated += matchingItem.Amount - currentItem.Amount; // Pas de allocatie aan op basis van de hoeveelheidwijziging + throw new Exception($"Hoeveelheid voor item {newItem.ItemId} moet een veelvoud zijn van {item.UnitOrderQuantity}."); } - currentItem.Amount = matchingItem.Amount; // Update de hoeveelheid van het item in de order - } - else - { - // Verwijder het item als het niet meer nodig is - var inventoryItem = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == currentItem.ItemUid); - if (inventoryItem != null) + + if (newItem.Amount < item.PackOrderQuantity) { - inventoryItem.TotalAllocated -= currentItem.Amount; // Verminder de allocatie in de voorraad + throw new Exception($"Hoeveelheid voor item {newItem.ItemId} moet minimaal {item.PackOrderQuantity} zijn."); } - _context.OrderItems.Remove(currentItem); // Verwijder het item uit de order } - } - // Voeg nieuwe items toe aan de order - foreach (var newItem in orderItems) - { - var existingItem = updateOrder.OrderItems.FirstOrDefault(i => i.ItemUid == newItem.ItemId); // Controleer of het item al in de order zit - if (existingItem == null) // Als het item nog niet bestaat + if (inventoryItem.TotalAvailable < newItem.Amount) { - var inventoryItem = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == newItem.ItemId); // Haal het item op uit de voorraad - if (inventoryItem != null) - { - // Controleer of er voldoende voorraad beschikbaar is - if (inventoryItem.TotalAvailable < newItem.Amount) - { - return $"Niet genoeg voorraad voor item met ID {newItem.ItemId}. Beschikbaar: {inventoryItem.TotalAvailable}, gevraagd: {newItem.Amount}"; - } - - // Maak een nieuw orderitem aan en voeg het toe - var orderItem = new OrderItem - { - ItemUid = newItem.ItemId, - Amount = newItem.Amount, - OrderId = orderId - }; - - _context.OrderItems.Add(orderItem); // Voeg het nieuwe item toe aan de order - inventoryItem.TotalAllocated += newItem.Amount; // Verhoog de allocatie in de voorraad - } + return $"Niet genoeg voorraad voor item met ID {newItem.ItemId}. Beschikbaar: {inventoryItem.TotalAvailable}, gevraagd: {newItem.Amount}"; } - } - await _context.SaveChangesAsync(); // Sla alle wijzigingen op in de database - return $"Order met ID {orderId} is succesvol bijgewerkt."; // Retourneer een succesbericht + var orderItem = new OrderItem + { + ItemUid = newItem.ItemId, + Amount = newItem.Amount, + OrderId = orderId + }; + + _context.OrderItems.Add(orderItem); + inventoryItem.TotalAllocated += newItem.Amount; + inventoryItem.TotalAvailable -= newItem.Amount; + + inventoryItem.TotalAllocated = Math.Max(0, inventoryItem.TotalAllocated); + inventoryItem.TotalAvailable = Math.Max(0, inventoryItem.TotalAvailable); + } } + } + + await _context.SaveChangesAsync(); + return $"Order met ID {orderId} is succesvol bijgewerkt."; +} + + + + // Controleer of een item bestaat @@ -258,27 +328,47 @@ public async Task ItemExist(string itemId) // Verwijder een order en herstel de voorraad van de items public async Task DeleteOrder(int orderId) { + // Haal de order inclusief de gekoppelde items op var order = await _context.Orders .Include(o => o.OrderItems) - .ThenInclude(o => o.Item) + .ThenInclude(oi => oi.Item) .FirstOrDefaultAsync(o => o.Id == orderId); - if (order == null) return false; + if (order == null) + { + return false; // Order niet gevonden + } + // Pas de voorraad aan voor elk item in de order foreach (var orderItem in order.OrderItems) { - var item = orderItem.Item; - if (item != null) + var inventoryItem = await _context.Inventory.FirstOrDefaultAsync(i => i.ItemId == orderItem.ItemUid); + if (inventoryItem != null) { - item.UnitOrderQuantity += orderItem.Amount; + // Herstel de allocatie en beschikbare voorraad + inventoryItem.TotalAllocated -= orderItem.Amount; + inventoryItem.TotalAvailable += orderItem.Amount; + + // Optioneel: Validatie om negatieve waarden te voorkomen + if (inventoryItem.TotalAllocated < 0) + { + inventoryItem.TotalAllocated = 0; + } + + // Update de voorraad in de context + _context.Inventory.Update(inventoryItem); } } + // Verwijder de order _context.Orders.Remove(order); + + // Sla de wijzigingen op in de database await _context.SaveChangesAsync(); - return true; + return true; // Succesvol verwijderd } + // Map een database-order naar een DTO inclusief de items private OrderWithItemsDTO MapOrderToDTO(Order order) { diff --git a/CargoHub/Services/ShipmentService.cs b/CargoHub/Services/ShipmentService.cs index d555fde..bcddc6f 100644 --- a/CargoHub/Services/ShipmentService.cs +++ b/CargoHub/Services/ShipmentService.cs @@ -59,6 +59,32 @@ public async Task> GetAllShipmentsWithorderdetailsItems() return result; } + + public async Task> GetItemsByShipmentId(int shipmentId) + { + var shipment = await _context.Shipments + .Include(s => s.orders) + .ThenInclude(o => o.OrderItems) + .ThenInclude(oi => oi.Item) + .FirstOrDefaultAsync(s => s.Id == shipmentId); + + if (shipment == null) + { + return null; + } + + // Verzamel alle items uit de gekoppelde orders + return shipment.orders + .SelectMany(o => o.OrderItems) + .Select(oi => new ItemDTO + { + ItemId = oi.Item.Uid, + Amount = oi.Amount + }) + .ToList(); + } + + // Haal een specifieke zending op met gekoppelde orders en items public async Task GetShipmentByIdWithOrderDetails(int shipmentId) { @@ -218,6 +244,7 @@ public async Task UpdateShipmentFields(int shipmentId, ShipmentDTO updat return $"Shipment met ID {shipmentId} is niet gevonden."; } + // Update naar transit: wijzig ShipmentDate en de status van gekoppelde orders if (!string.IsNullOrEmpty(updatedShipmentDto.ShipmentStatus) && updatedShipmentDto.ShipmentStatus.Equals("transit", StringComparison.OrdinalIgnoreCase) && !existingShipment.ShipmentStatus.Equals("transit", StringComparison.OrdinalIgnoreCase)) @@ -230,13 +257,20 @@ public async Task UpdateShipmentFields(int shipmentId, ShipmentDTO updat } } + // Update naar delivered: wijzig Orderdate en de status van gekoppelde orders naar delivered if (!string.IsNullOrEmpty(updatedShipmentDto.ShipmentStatus) && updatedShipmentDto.ShipmentStatus.Equals("delivered", StringComparison.OrdinalIgnoreCase) && !existingShipment.ShipmentStatus.Equals("delivered", StringComparison.OrdinalIgnoreCase)) { existingShipment.Orderdate = DateTime.UtcNow; + + foreach (var order in existingShipment.orders) + { + order.OrderStatus = "delivered"; + } } + // Verhinder statuswijziging naar pending vanuit transit of delivered if (!string.IsNullOrEmpty(updatedShipmentDto.ShipmentStatus) && updatedShipmentDto.ShipmentStatus.Equals("pending", StringComparison.OrdinalIgnoreCase) && (existingShipment.ShipmentStatus.Equals("transit", StringComparison.OrdinalIgnoreCase) || @@ -245,6 +279,7 @@ public async Task UpdateShipmentFields(int shipmentId, ShipmentDTO updat throw new InvalidOperationException("Kan de status van de Shipment niet wijzigen naar pending vanaf transit of delivered."); } + // Update overige velden van de shipment existingShipment.ShipmentType = updatedShipmentDto.ShipmentType; existingShipment.ShipmentStatus = updatedShipmentDto.ShipmentStatus; existingShipment.Notes = updatedShipmentDto.Notes; @@ -262,6 +297,7 @@ public async Task UpdateShipmentFields(int shipmentId, ShipmentDTO updat return $"Shipment met ID {shipmentId} is succesvol bijgewerkt."; } + // Koppel orders aan een zending public async Task AssignOrdersToShipment(int shipmentId, List orderIds) { diff --git a/CargoHub/rest/Monthly.rest b/CargoHub/rest/Monthly.rest index b387ac4..cece37c 100644 --- a/CargoHub/rest/Monthly.rest +++ b/CargoHub/rest/Monthly.rest @@ -1,4 +1,4 @@ ### Generate Monthly Report -GET http://localhost:3000/api/v1/reports/monthly-report?year=2024&month=12 +GET http://localhost:3000/api/v1/reports/monthly-report?year=2023&month=10 Content-Type: application/json ApiKey: Admin diff --git a/Reference/CargoHub/data/warehouses.json b/Reference/CargoHub/data/warehouses.json index cc5edf6..4a89678 100644 --- a/Reference/CargoHub/data/warehouses.json +++ b/Reference/CargoHub/data/warehouses.json @@ -1 +1,988 @@ -[{"id": 1, "code": "YQZZNL56", "name": "Heemskerk cargo hub", "address": "Karlijndreef 281", "zip": "4002 AS", "city": "Heemskerk", "province": "Friesland", "country": "NL", "contact": {"name": "Fem Keijzer", "phone": "(078) 0013363", "email": "blamore@example.net"}, "created_at": "1983-04-13 04:59:55", "updated_at": "2007-02-08 20:11:00"}, {"id": 2, "code": "GIOMNL90", "name": "Petten longterm hub", "address": "Owenweg 731", "zip": "4615 RB", "city": "Petten", "province": "Noord-Holland", "country": "NL", "contact": {"name": "Maud Adryaens", "phone": "+31836 752702", "email": "nickteunissen@example.com"}, "created_at": "2008-02-22 19:55:39", "updated_at": "2009-08-28 23:15:50"}, {"id": 3, "code": "VCKINLLK", "name": "Naaldwijk distribution hub", "address": "Izesteeg 807", "zip": "1636 KI", "city": "Naaldwijk", "province": "Utrecht", "country": "NL", "contact": {"name": "Frederique van Wallaert", "phone": "(009) 4870289", "email": "jelle66@example.net"}, "created_at": "2001-05-11 10:43:52", "updated_at": "2017-12-19 14:32:38"}, {"id": 4, "code": "IPJMNLSY", "name": "Bosch en Duin storage location", "address": "Fabianweg 71", "zip": "5701 IA", "city": "Bosch en Duin", "province": "Flevoland", "country": "NL", "contact": {"name": "Oscar Hemma van Allemani\u00eb-Hoes", "phone": "058 2995479", "email": "suze00@example.org"}, "created_at": "2007-10-19 09:43:20", "updated_at": "2019-11-02 07:30:52"}, {"id": 5, "code": "QAQMNLCL", "name": "Hoogeveen distribution facility", "address": "Noaboulevard 7", "zip": "1735XO", "city": "Hoogeveen", "province": "Zuid-Holland", "country": "NL", "contact": {"name": "Sjoerd Sterkman", "phone": "0943-736616", "email": "imkehermans@example.org"}, "created_at": "2017-11-03 19:21:26", "updated_at": "2023-05-30 16:45:10"}, {"id": 6, "code": "JBDTNLFX", "name": "Loosdrecht longterm center", "address": "Yasminebaan 422", "zip": "8254 IY", "city": "Loosdrecht", "province": "Overijssel", "country": "NL", "contact": {"name": "Joey die Pelser", "phone": "(0930)-760273", "email": "welberts@example.com"}, "created_at": "2018-02-11 22:45:46", "updated_at": "2022-09-19 14:08:52"}, {"id": 7, "code": "ZSLSNL4C", "name": "Obdam distribution facility", "address": "Larshof 775", "zip": "1693NI", "city": "Obdam", "province": "Noord-Brabant", "country": "NL", "contact": {"name": "Michael Ramaker", "phone": "(097) 5523868", "email": "jacepsjulian@example.com"}, "created_at": "1996-07-31 05:51:38", "updated_at": "2017-11-16 02:39:09"}, {"id": 8, "code": "BQHMNLPJ", "name": "Idaerd distribution hub", "address": "Ceylinsteeg 95", "zip": "4742MW", "city": "Idaerd", "province": "Zuid-Holland", "country": "NL", "contact": {"name": "Matthijs Verbeeck", "phone": "+3137-5511465", "email": "jspreeuw@example.org"}, "created_at": "1994-10-07 19:48:40", "updated_at": "2002-01-17 11:16:57"}, {"id": 9, "code": "QRVXNLIF", "name": "Walsoorden air and road location", "address": "Lizalaan 22", "zip": "1950 YO", "city": "Walsoorden", "province": "Noord-Holland", "country": "NL", "contact": {"name": "Sofia Kisman-Gellemeyer", "phone": "+3118-4888384", "email": "jelle43@example.org"}, "created_at": "1998-07-25 20:29:56", "updated_at": "2024-03-17 03:08:13"}, {"id": 10, "code": "HXVLNLIJ", "name": "Wolvega distribution center", "address": "Juleshof 12", "zip": "9646AO", "city": "Wolvega", "province": "Gelderland", "country": "NL", "contact": {"name": "Demi van Cuijck", "phone": "+31(0)64 8859265", "email": "amelie56@example.com"}, "created_at": "1992-10-02 11:55:52", "updated_at": "2019-06-17 00:14:43"}, {"id": 11, "code": "FFCVNLU9", "name": "Stokkum distribution facility", "address": "Ibrahimsingel 6", "zip": "1791LM", "city": "Stokkum", "province": "Flevoland", "country": "NL", "contact": {"name": "Jamie van Bruchem", "phone": "+31(0)563-472814", "email": "lizzvan-duvenvoirde@example.org"}, "created_at": "2001-01-26 13:25:16", "updated_at": "2012-10-14 14:49:08"}, {"id": 12, "code": "QNPUNLGN", "name": "Deelen distribution location", "address": "Izebaan 79", "zip": "4106 KO", "city": "Deelen", "province": "Drenthe", "country": "NL", "contact": {"name": "Yassin van de Noordmark", "phone": "0452-876501", "email": "van-den-broekmadelief@example.org"}, "created_at": "1996-08-14 03:37:20", "updated_at": "2023-03-11 01:27:41"}, {"id": 13, "code": "LWXGNLT1", "name": "Westergeest cargo hub", "address": "Kayleighsteeg 809", "zip": "6733VP", "city": "Westergeest", "province": "Friesland", "country": "NL", "contact": {"name": "Mustafa van Wijk", "phone": "+31(0)50-3205485", "email": "ekwaadland@example.com"}, "created_at": "2010-05-13 04:17:01", "updated_at": "2010-07-16 04:07:24"}, {"id": 14, "code": "KBXWNLJ7", "name": "Meteren longterm center", "address": "Mikaboulevard 6", "zip": "1794GI", "city": "Meteren", "province": "Zuid-Holland", "country": "NL", "contact": {"name": "Zoey Vignon", "phone": "+3193 2060447", "email": "slelijveld@example.net"}, "created_at": "2001-04-28 00:43:39", "updated_at": "2018-07-01 00:54:14"}, {"id": 15, "code": "BWRXNLH6", "name": "Standdaarbuiten longterm facility", "address": "Louisedreef 0", "zip": "5149 RW", "city": "Standdaarbuiten", "province": "Flevoland", "country": "NL", "contact": {"name": "Mette Brandt", "phone": "+31879-728899", "email": "lvan-dooren@example.net"}, "created_at": "1983-07-10 13:29:30", "updated_at": "2020-05-17 04:19:20"}, {"id": 16, "code": "ABASNLBU", "name": "Noardburgum storage facility", "address": "Kaysteeg 840", "zip": "2861KI", "city": "Noardburgum", "province": "Flevoland", "country": "NL", "contact": {"name": "Sepp Emmen-van Kasteelen", "phone": "+31110-372934", "email": "overda@example.com"}, "created_at": "2020-04-07 17:21:39", "updated_at": "2021-10-24 01:09:11"}, {"id": 17, "code": "OPQVNLL7", "name": "Noordwelle storage hub", "address": "Haileysingel 07", "zip": "2338JE", "city": "Noordwelle", "province": "Utrecht", "country": "NL", "contact": {"name": "Amber Zijlemans", "phone": "0159-402718", "email": "van-voorhoutemir@example.com"}, "created_at": "1983-12-15 18:01:30", "updated_at": "1996-09-19 07:49:15"}, {"id": 18, "code": "BSCVNLHR", "name": "Gronsveld longterm facility", "address": "Lisabaan 819", "zip": "3266 NS", "city": "Gronsveld", "province": "Utrecht", "country": "NL", "contact": {"name": "Ivy van Bernicia", "phone": "(0974)-679850", "email": "larakuipers@example.com"}, "created_at": "1977-03-17 12:12:53", "updated_at": "2024-04-26 10:54:05"}, {"id": 19, "code": "IZYONLOQ", "name": "Tzummarum storage center", "address": "Angelinasingel 82", "zip": "1155SC", "city": "Tzummarum", "province": "Zeeland", "country": "NL", "contact": {"name": "Leah Olykan", "phone": "+31(0)881 668554", "email": "vtins@example.com"}, "created_at": "2002-07-04 22:20:12", "updated_at": "2017-11-17 16:11:05"}, {"id": 20, "code": "JLXDNLRH", "name": "Kerkrade distribution facility", "address": "Lucyweg 43", "zip": "2569VO", "city": "Kerkrade", "province": "Flevoland", "country": "NL", "contact": {"name": "Sylvie van Formbach", "phone": "+3169 0640203", "email": "mika45@example.com"}, "created_at": "2007-06-04 21:53:00", "updated_at": "2019-02-27 08:31:40"}, {"id": 21, "code": "QMCCNLD9", "name": "Sittard storage location", "address": "Rensbaan 1", "zip": "9890 LY", "city": "Sittard", "province": "Zeeland", "country": "NL", "contact": {"name": "Lex Louws", "phone": "+31(0)05-4740166", "email": "tinsmia@example.com"}, "created_at": "1989-02-03 23:08:57", "updated_at": "2008-12-03 23:33:50"}, {"id": 22, "code": "BJYCNLYS", "name": "Roderesch distribution hub", "address": "Juliadreef 55", "zip": "6345 BX", "city": "Roderesch", "province": "Friesland", "country": "NL", "contact": {"name": "Rens Jansen-Fechant", "phone": "099-1781807", "email": "le-grandnoor@example.net"}, "created_at": "1970-03-23 07:37:35", "updated_at": "1970-12-26 14:30:51"}, {"id": 23, "code": "PGDWNLWG", "name": "Heeswijk-Dinther longterm hub", "address": "Vigodreef 22", "zip": "5066 GI", "city": "Heeswijk-Dinther", "province": "Friesland", "country": "NL", "contact": {"name": "Lana Schatteleijn", "phone": "+31(0)25-1985675", "email": "xlathrope@example.org"}, "created_at": "1996-03-05 10:05:56", "updated_at": "2002-02-06 08:17:34"}, {"id": 24, "code": "ACBENL3A", "name": "Nieuwehorne distribution hub", "address": "Sofiaweg 913", "zip": "1802 WP", "city": "Nieuwehorne", "province": "Utrecht", "country": "NL", "contact": {"name": "Ben Fortuyn-Schrik", "phone": "+31(0)25-6865349", "email": "riley32@example.com"}, "created_at": "1977-11-17 01:10:40", "updated_at": "1983-05-05 16:17:25"}, {"id": 25, "code": "VWIZNLUF", "name": "Halle cargo center", "address": "Julessingel 5", "zip": "7374 PM", "city": "Halle", "province": "Overijssel", "country": "NL", "contact": {"name": "Bas Scholten", "phone": "+3137-8739738", "email": "sarakuipers@example.com"}, "created_at": "2004-05-16 09:41:47", "updated_at": "2018-01-05 05:33:25"}, {"id": 26, "code": "GPRPNLPT", "name": "Joppe air and road location", "address": "Lucasstraat 3", "zip": "2727 VY", "city": "Joppe", "province": "Flevoland", "country": "NL", "contact": {"name": "Rosa van 't Erve-Berendse", "phone": "(0681) 626416", "email": "van-ommerenjan@example.net"}, "created_at": "2003-03-30 04:14:17", "updated_at": "2019-11-14 08:04:39"}, {"id": 27, "code": "FXJKNL4W", "name": "Nieuwer Ter Aa cargo location", "address": "Stellalaan 2", "zip": "7158 IW", "city": "Nieuwer Ter Aa", "province": "Utrecht", "country": "NL", "contact": {"name": "Lenn de Hoogh-Verbruggen", "phone": "+31021-231813", "email": "sterre34@example.com"}, "created_at": "2008-02-28 21:06:26", "updated_at": "2013-11-06 14:01:58"}, {"id": 28, "code": "UECCNLNT", "name": "Dieverbrug longterm location", "address": "Britthof 445", "zip": "3854OR", "city": "Dieverbrug", "province": "Zuid-Holland", "country": "NL", "contact": {"name": "Liv Mulder", "phone": "+3119-9768344", "email": "ouwerkerkyara@example.net"}, "created_at": "2000-03-12 18:50:47", "updated_at": "2023-11-23 16:46:38"}, {"id": 29, "code": "UBERNLTL", "name": "Einighausen air and road center", "address": "Sophiastraat 1", "zip": "2605WX", "city": "Einighausen", "province": "Flevoland", "country": "NL", "contact": {"name": "Maurits van Doorn", "phone": "+3191 2817485", "email": "jansenevy@example.org"}, "created_at": "1975-10-19 21:04:05", "updated_at": "2005-04-22 23:58:02"}, {"id": 30, "code": "TKHJNLZM", "name": "Zuiddorpe distribution center", "address": "Kayleesteeg 34", "zip": "9163FX", "city": "Zuiddorpe", "province": "Friesland", "country": "NL", "contact": {"name": "Britt Labado", "phone": "0760 793486", "email": "keanovan-der-horst@example.com"}, "created_at": "2023-01-26 17:11:45", "updated_at": "2023-07-13 03:54:28"}, {"id": 31, "code": "JFGQNLZM", "name": "Lichtaard cargo location", "address": "Oscarbaan 0", "zip": "4396 RL", "city": "Lichtaard", "province": "Overijssel", "country": "NL", "contact": {"name": "Nynke Pierson", "phone": "0927-531893", "email": "oheribert-van-laon@example.net"}, "created_at": "1974-11-14 17:13:40", "updated_at": "2020-11-21 08:13:52"}, {"id": 32, "code": "VMYWBEWK", "name": "Itegem longterm hub", "address": "Fransstraat 15", "zip": "2042", "city": "Itegem", "province": "Oost-Vlaanderen", "country": "BE", "contact": {"name": "Jana Van Baelen", "phone": "+32(0)93-6351025", "email": "freddy95@example.net"}, "created_at": "1991-01-16 19:20:30", "updated_at": "1995-07-02 04:48:16"}, {"id": 33, "code": "WECRBELD", "name": "Westende longterm hub", "address": "Lindaboulevard 027", "zip": "6194", "city": "Westende", "province": "Oost-Vlaanderen", "country": "BE", "contact": {"name": "Jan Desmedt", "phone": "057-0359147", "email": "marc05@example.net"}, "created_at": "1971-07-12 20:27:49", "updated_at": "1974-09-27 02:25:06"}, {"id": 34, "code": "FLKTBEW4", "name": "Mons distribution facility", "address": "Janweg 9", "zip": "9002", "city": "Mons", "province": "Luxemburg", "country": "BE", "contact": {"name": "Chantal Coene", "phone": "+3268 2640689", "email": "boeckxalain@example.net"}, "created_at": "2024-06-06 02:32:30", "updated_at": "2024-08-21 21:18:33"}, {"id": 35, "code": "VJBCBEIG", "name": "Nobressart distribution hub", "address": "Andreashof 73", "zip": "3023", "city": "Nobressart", "province": "Luxemburg", "country": "BE", "contact": {"name": "Evelien De Bruyne Peeters", "phone": "+32178 271511", "email": "maria54@example.org"}, "created_at": "1982-10-26 03:50:05", "updated_at": "1991-05-07 01:00:26"}, {"id": 36, "code": "NVUVBEBZ", "name": "Hensies longterm facility", "address": "Michelbaan 634", "zip": "6256", "city": "Hensies", "province": "West-Vlaanderen", "country": "BE", "contact": {"name": "Nancy Van de Voorde", "phone": "+32312 051533", "email": "jean04@example.org"}, "created_at": "1987-11-07 11:49:00", "updated_at": "2018-06-09 20:14:26"}, {"id": 37, "code": "XBICBEJ9", "name": "Fontaine-l'Ev\u00eaque storage center", "address": "Eduardstraat 5", "zip": "3122", "city": "Fontaine-l'Ev\u00eaque", "province": "Limburg", "country": "BE", "contact": {"name": "Roger Simons", "phone": "(059)-4911137", "email": "uvervoort@example.org"}, "created_at": "2008-07-09 08:12:26", "updated_at": "2013-10-02 04:00:54"}, {"id": 38, "code": "OJGTBEH8", "name": "Lanaye distribution hub", "address": "Jeanring 018", "zip": "3229", "city": "Lanaye", "province": "Oost-Vlaanderen", "country": "BE", "contact": {"name": "Carlo Simons", "phone": "06 065 45 35", "email": "emielverbeke@example.com"}, "created_at": "2014-08-11 22:50:47", "updated_at": "2017-06-17 12:29:20"}, {"id": 39, "code": "JQUWBEPM", "name": "Cour-sur-Heure longterm center", "address": "Ellenbaan 50", "zip": "6326", "city": "Cour-sur-Heure", "province": "Namen", "country": "BE", "contact": {"name": "Sammy Segers", "phone": "+32(0)46 5073533", "email": "emmadaniels@example.com"}, "created_at": "1987-05-21 10:51:45", "updated_at": "1998-11-01 18:36:14"}, {"id": 40, "code": "ABKMBEPE", "name": "Eigenbilzen air and road location", "address": "Katjasingel 6", "zip": "6986", "city": "Eigenbilzen", "province": "Luxemburg", "country": "BE", "contact": {"name": "Els Smets", "phone": "032 5659440", "email": "xdeleu@example.com"}, "created_at": "2024-05-09 16:07:25", "updated_at": "2024-09-02 08:22:59"}, {"id": 41, "code": "YDPLBEY2", "name": "Hakendover storage hub", "address": "Marcelstraat 5", "zip": "1689", "city": "Hakendover", "province": "Henegouwen", "country": "BE", "contact": {"name": "Lotte Dobbelaere", "phone": "(0441)-027017", "email": "wsanders@example.com"}, "created_at": "1975-07-31 23:56:47", "updated_at": "1996-07-15 01:08:59"}, {"id": 42, "code": "KVLOBEUH", "name": "Mere distribution facility", "address": "Matsdreef 2", "zip": "8491", "city": "Mere", "province": "Luik", "country": "BE", "contact": {"name": "Mike Smeets", "phone": "+32(0)488-011615", "email": "rvermeiren@example.net"}, "created_at": "1990-08-01 05:20:16", "updated_at": "2004-10-02 08:57:08"}, {"id": 43, "code": "YDKGBEPS", "name": "Lens-Saint-Remy air and road facility", "address": "Freddystraat 118", "zip": "9637", "city": "Lens-Saint-Remy", "province": "Namen", "country": "BE", "contact": {"name": "Sam Peeters", "phone": "+32231-246362", "email": "yverhulst@example.com"}, "created_at": "2012-07-06 02:54:52", "updated_at": "2024-02-20 23:54:56"}, {"id": 44, "code": "GWKKBE0Y", "name": "Ch\u00e2telineau storage center", "address": "Birgitlei 2", "zip": "9082", "city": "Ch\u00e2telineau", "province": "Vlaams-Brabant", "country": "BE", "contact": {"name": "Ingrid Daems", "phone": "(003) 9537465", "email": "callensgodelieve@example.org"}, "created_at": "2020-02-11 18:51:46", "updated_at": "2020-05-17 06:40:36"}, {"id": 45, "code": "THHKBEEQ", "name": "Kieldrecht air and road facility", "address": "Rogerdreef 0", "zip": "3128", "city": "Kieldrecht", "province": "Luik", "country": "BE", "contact": {"name": "Peter Vandevelde", "phone": "+32729 166461", "email": "dirk84@example.com"}, "created_at": "2024-05-14 17:07:09", "updated_at": "2024-06-04 02:26:47"}, {"id": 46, "code": "REALBEEJ", "name": "Oekene distribution facility", "address": "Daniellaan 1", "zip": "3711", "city": "Oekene", "province": "Vlaams-Brabant", "country": "BE", "contact": {"name": "Imran Vandendriessche", "phone": "(0532)-905203", "email": "willyverhaeghe@example.com"}, "created_at": "2009-11-15 09:02:25", "updated_at": "2023-04-18 16:05:34"}, {"id": 47, "code": "FDJGBE9H", "name": "Chanly air and road center", "address": "Marinaring 92", "zip": "2605", "city": "Chanly", "province": "Namen", "country": "BE", "contact": {"name": "Bjorn Van Hecke", "phone": "+32(0)725 516583", "email": "kenismaria@example.com"}, "created_at": "2014-05-29 09:23:40", "updated_at": "2015-05-04 11:11:03"}, {"id": 48, "code": "UQOJDEE9", "name": "Gie\u00dfen distribution location", "address": "Wellerallee 3/7", "zip": "84526", "city": "Gie\u00dfen", "province": "Hamburg", "country": "DE", "contact": {"name": "Anto Kambs", "phone": "00189 385803", "email": "adlerrosalinde@example.com"}, "created_at": "1990-11-17 01:06:55", "updated_at": "2008-04-09 14:26:34"}, {"id": 49, "code": "LXXCDES7", "name": "Sankt Goarshausen longterm facility", "address": "Pruschkestr. 1", "zip": "69463", "city": "Sankt Goarshausen", "province": "Bremen", "country": "DE", "contact": {"name": "Dr. Arno Winkler B.Sc.", "phone": "+49(0)1144615012", "email": "nerminladeck@example.com"}, "created_at": "2008-04-20 11:50:13", "updated_at": "2024-03-28 22:17:37"}, {"id": 50, "code": "UXRKDE29", "name": "Badoberan longterm facility", "address": "Vollbrechtstr. 847", "zip": "74501", "city": "Badoberan", "province": "Niedersachsen", "country": "DE", "contact": {"name": "Reinhart Klemt", "phone": "+49(0)3215 856979", "email": "rochushentschel@example.net"}, "created_at": "2003-02-13 06:56:58", "updated_at": "2013-12-22 20:08:54"}, {"id": 51, "code": "OXOMDE7A", "name": "Wernigerode storage hub", "address": "Heidemarie-Birnbaum-Ring 4/3", "zip": "61818", "city": "Wernigerode", "province": "Brandenburg", "country": "DE", "contact": {"name": "Eleni Zimmer-Henschel", "phone": "04398 496300", "email": "beckertuelay@example.com"}, "created_at": "1976-08-10 06:59:29", "updated_at": "2014-07-01 07:33:54"}, {"id": 52, "code": "OCVODE54", "name": "Stollberg air and road center", "address": "Rene-Schmiedt-Allee 11", "zip": "01625", "city": "Stollberg", "province": "Nordrhein-Westfalen", "country": "DE", "contact": {"name": "Rebekka Geisler B.Sc.", "phone": "06230538431", "email": "yheydrich@example.org"}, "created_at": "2000-04-22 11:28:17", "updated_at": "2012-08-07 16:01:14"}, {"id": 53, "code": "LERPDE9L", "name": "Neustadtner Waldnaab distribution center", "address": "Franz-Peter-Hettner-Allee 6", "zip": "39261", "city": "Neustadtner Waldnaab", "province": "Sachsen", "country": "DE", "contact": {"name": "Frau Ayten Haering MBA.", "phone": "05773 584153", "email": "isabellewulff@example.net"}, "created_at": "2005-01-29 06:28:53", "updated_at": "2013-11-27 15:40:01"}, {"id": 54, "code": "BAADDEXK", "name": "Regensburg cargo center", "address": "Birgitt-Scholtz-Allee 46", "zip": "35725", "city": "Regensburg", "province": "Hamburg", "country": "DE", "contact": {"name": "Prof. Janet Sager", "phone": "03888522177", "email": "doerschnerwenke@example.com"}, "created_at": "2009-06-14 21:02:25", "updated_at": "2010-06-27 09:44:40"}, {"id": 55, "code": "IUVSDETG", "name": "Waldm\u00fcnchen longterm center", "address": "Gabriele-Junken-Ring 5/1", "zip": "35099", "city": "Waldm\u00fcnchen", "province": "Brandenburg", "country": "DE", "contact": {"name": "Bozena Steckel", "phone": "(08587) 18542", "email": "adolfinehentschel@example.net"}, "created_at": "2006-08-31 03:38:40", "updated_at": "2010-04-26 18:16:09"}, {"id": 56, "code": "BOYUDE7O", "name": "Pasewalk longterm location", "address": "Konrad-Seip-Allee 66", "zip": "49888", "city": "Pasewalk", "province": "Nordrhein-Westfalen", "country": "DE", "contact": {"name": "Ullrich Beier", "phone": "+49(0)8660 573483", "email": "vbarkholz@example.com"}, "created_at": "1979-10-03 07:33:35", "updated_at": "1993-08-05 16:12:41"}, {"id": 57, "code": "MOOODEEX", "name": "Bischofswerda longterm facility", "address": "Melissa-Bauer-Ring 1/7", "zip": "37727", "city": "Bischofswerda", "province": "Nordrhein-Westfalen", "country": "DE", "contact": {"name": "Uwe Lindau", "phone": "(06380) 715579", "email": "ilse44@example.org"}, "created_at": "1984-05-11 19:24:11", "updated_at": "2022-06-19 14:32:50"}, {"id": 58, "code": "WJKADEJE", "name": "Holzminden air and road hub", "address": "Sibilla-Hendriks-Gasse 5/8", "zip": "05955", "city": "Holzminden", "province": "Saarland", "country": "DE", "contact": {"name": "Mirco Warmer", "phone": "+49(0)0048791642", "email": "katjaklotz@example.net"}, "created_at": "1974-04-03 11:24:15", "updated_at": "2021-12-08 15:59:38"}] \ No newline at end of file +[ + { + "id": 1, + "code": "YQZZNL56", + "name": "Heemskerk cargo hub", + "address": "Karlijndreef 281", + "zip": "4002 AS", + "city": "Heemskerk", + "province": "Friesland", + "country": "NL", + "contact": { + "name": "Fem Keijzer", + "phone": "(078) 0013363", + "email": "blamore@example.net" + }, + "created_at": "1983-04-13 04:59:55", + "updated_at": "2007-02-08 20:11:00" + }, + { + "id": 2, + "code": "GIOMNL90", + "name": "Petten longterm hub", + "address": "Owenweg 731", + "zip": "4615 RB", + "city": "Petten", + "province": "Noord-Holland", + "country": "NL", + "contact": { + "name": "Maud Adryaens", + "phone": "+31836 752702", + "email": "nickteunissen@example.com" + }, + "created_at": "2008-02-22 19:55:39", + "updated_at": "2009-08-28 23:15:50" + }, + { + "id": 3, + "code": "VCKINLLK", + "name": "Naaldwijk distribution hub", + "address": "Izesteeg 807", + "zip": "1636 KI", + "city": "Naaldwijk", + "province": "Utrecht", + "country": "NL", + "contact": { + "name": "Frederique van Wallaert", + "phone": "(009) 4870289", + "email": "jelle66@example.net" + }, + "created_at": "2001-05-11 10:43:52", + "updated_at": "2017-12-19 14:32:38" + }, + { + "id": 4, + "code": "IPJMNLSY", + "name": "Bosch en Duin storage location", + "address": "Fabianweg 71", + "zip": "5701 IA", + "city": "Bosch en Duin", + "province": "Flevoland", + "country": "NL", + "contact": { + "name": "Oscar Hemma van Allemani\u00eb-Hoes", + "phone": "058 2995479", + "email": "suze00@example.org" + }, + "created_at": "2007-10-19 09:43:20", + "updated_at": "2019-11-02 07:30:52" + }, + { + "id": 5, + "code": "QAQMNLCL", + "name": "Hoogeveen distribution facility", + "address": "Noaboulevard 7", + "zip": "1735XO", + "city": "Hoogeveen", + "province": "Zuid-Holland", + "country": "NL", + "contact": { + "name": "Sjoerd Sterkman", + "phone": "0943-736616", + "email": "imkehermans@example.org" + }, + "created_at": "2017-11-03 19:21:26", + "updated_at": "2023-05-30 16:45:10" + }, + { + "id": 6, + "code": "JBDTNLFX", + "name": "Loosdrecht longterm center", + "address": "Yasminebaan 422", + "zip": "8254 IY", + "city": "Loosdrecht", + "province": "Overijssel", + "country": "NL", + "contact": { + "name": "Joey die Pelser", + "phone": "(0930)-760273", + "email": "welberts@example.com" + }, + "created_at": "2018-02-11 22:45:46", + "updated_at": "2022-09-19 14:08:52" + }, + { + "id": 7, + "code": "ZSLSNL4C", + "name": "Obdam distribution facility", + "address": "Larshof 775", + "zip": "1693NI", + "city": "Obdam", + "province": "Noord-Brabant", + "country": "NL", + "contact": { + "name": "Michael Ramaker", + "phone": "(097) 5523868", + "email": "jacepsjulian@example.com" + }, + "created_at": "1996-07-31 05:51:38", + "updated_at": "2017-11-16 02:39:09" + }, + { + "id": 8, + "code": "BQHMNLPJ", + "name": "Idaerd distribution hub", + "address": "Ceylinsteeg 95", + "zip": "4742MW", + "city": "Idaerd", + "province": "Zuid-Holland", + "country": "NL", + "contact": { + "name": "Matthijs Verbeeck", + "phone": "+3137-5511465", + "email": "jspreeuw@example.org" + }, + "created_at": "1994-10-07 19:48:40", + "updated_at": "2002-01-17 11:16:57" + }, + { + "id": 9, + "code": "QRVXNLIF", + "name": "Walsoorden air and road location", + "address": "Lizalaan 22", + "zip": "1950 YO", + "city": "Walsoorden", + "province": "Noord-Holland", + "country": "NL", + "contact": { + "name": "Sofia Kisman-Gellemeyer", + "phone": "+3118-4888384", + "email": "jelle43@example.org" + }, + "created_at": "1998-07-25 20:29:56", + "updated_at": "2024-03-17 03:08:13" + }, + { + "id": 10, + "code": "HXVLNLIJ", + "name": "Wolvega distribution center", + "address": "Juleshof 12", + "zip": "9646AO", + "city": "Wolvega", + "province": "Gelderland", + "country": "NL", + "contact": { + "name": "Demi van Cuijck", + "phone": "+31(0)64 8859265", + "email": "amelie56@example.com" + }, + "created_at": "1992-10-02 11:55:52", + "updated_at": "2019-06-17 00:14:43" + }, + { + "id": 11, + "code": "FFCVNLU9", + "name": "Stokkum distribution facility", + "address": "Ibrahimsingel 6", + "zip": "1791LM", + "city": "Stokkum", + "province": "Flevoland", + "country": "NL", + "contact": { + "name": "Jamie van Bruchem", + "phone": "+31(0)563-472814", + "email": "lizzvan-duvenvoirde@example.org" + }, + "created_at": "2001-01-26 13:25:16", + "updated_at": "2012-10-14 14:49:08" + }, + { + "id": 12, + "code": "QNPUNLGN", + "name": "Deelen distribution location", + "address": "Izebaan 79", + "zip": "4106 KO", + "city": "Deelen", + "province": "Drenthe", + "country": "NL", + "contact": { + "name": "Yassin van de Noordmark", + "phone": "0452-876501", + "email": "van-den-broekmadelief@example.org" + }, + "created_at": "1996-08-14 03:37:20", + "updated_at": "2023-03-11 01:27:41" + }, + { + "id": 13, + "code": "LWXGNLT1", + "name": "Westergeest cargo hub", + "address": "Kayleighsteeg 809", + "zip": "6733VP", + "city": "Westergeest", + "province": "Friesland", + "country": "NL", + "contact": { + "name": "Mustafa van Wijk", + "phone": "+31(0)50-3205485", + "email": "ekwaadland@example.com" + }, + "created_at": "2010-05-13 04:17:01", + "updated_at": "2010-07-16 04:07:24" + }, + { + "id": 14, + "code": "KBXWNLJ7", + "name": "Meteren longterm center", + "address": "Mikaboulevard 6", + "zip": "1794GI", + "city": "Meteren", + "province": "Zuid-Holland", + "country": "NL", + "contact": { + "name": "Zoey Vignon", + "phone": "+3193 2060447", + "email": "slelijveld@example.net" + }, + "created_at": "2001-04-28 00:43:39", + "updated_at": "2018-07-01 00:54:14" + }, + { + "id": 15, + "code": "BWRXNLH6", + "name": "Standdaarbuiten longterm facility", + "address": "Louisedreef 0", + "zip": "5149 RW", + "city": "Standdaarbuiten", + "province": "Flevoland", + "country": "NL", + "contact": { + "name": "Mette Brandt", + "phone": "+31879-728899", + "email": "lvan-dooren@example.net" + }, + "created_at": "1983-07-10 13:29:30", + "updated_at": "2020-05-17 04:19:20" + }, + { + "id": 16, + "code": "ABASNLBU", + "name": "Noardburgum storage facility", + "address": "Kaysteeg 840", + "zip": "2861KI", + "city": "Noardburgum", + "province": "Flevoland", + "country": "NL", + "contact": { + "name": "Sepp Emmen-van Kasteelen", + "phone": "+31110-372934", + "email": "overda@example.com" + }, + "created_at": "2020-04-07 17:21:39", + "updated_at": "2021-10-24 01:09:11" + }, + { + "id": 17, + "code": "OPQVNLL7", + "name": "Noordwelle storage hub", + "address": "Haileysingel 07", + "zip": "2338JE", + "city": "Noordwelle", + "province": "Utrecht", + "country": "NL", + "contact": { + "name": "Amber Zijlemans", + "phone": "0159-402718", + "email": "van-voorhoutemir@example.com" + }, + "created_at": "1983-12-15 18:01:30", + "updated_at": "1996-09-19 07:49:15" + }, + { + "id": 18, + "code": "BSCVNLHR", + "name": "Gronsveld longterm facility", + "address": "Lisabaan 819", + "zip": "3266 NS", + "city": "Gronsveld", + "province": "Utrecht", + "country": "NL", + "contact": { + "name": "Ivy van Bernicia", + "phone": "(0974)-679850", + "email": "larakuipers@example.com" + }, + "created_at": "1977-03-17 12:12:53", + "updated_at": "2024-04-26 10:54:05" + }, + { + "id": 19, + "code": "IZYONLOQ", + "name": "Tzummarum storage center", + "address": "Angelinasingel 82", + "zip": "1155SC", + "city": "Tzummarum", + "province": "Zeeland", + "country": "NL", + "contact": { + "name": "Leah Olykan", + "phone": "+31(0)881 668554", + "email": "vtins@example.com" + }, + "created_at": "2002-07-04 22:20:12", + "updated_at": "2017-11-17 16:11:05" + }, + { + "id": 20, + "code": "JLXDNLRH", + "name": "Kerkrade distribution facility", + "address": "Lucyweg 43", + "zip": "2569VO", + "city": "Kerkrade", + "province": "Flevoland", + "country": "NL", + "contact": { + "name": "Sylvie van Formbach", + "phone": "+3169 0640203", + "email": "mika45@example.com" + }, + "created_at": "2007-06-04 21:53:00", + "updated_at": "2019-02-27 08:31:40" + }, + { + "id": 21, + "code": "QMCCNLD9", + "name": "Sittard storage location", + "address": "Rensbaan 1", + "zip": "9890 LY", + "city": "Sittard", + "province": "Zeeland", + "country": "NL", + "contact": { + "name": "Lex Louws", + "phone": "+31(0)05-4740166", + "email": "tinsmia@example.com" + }, + "created_at": "1989-02-03 23:08:57", + "updated_at": "2008-12-03 23:33:50" + }, + { + "id": 22, + "code": "BJYCNLYS", + "name": "Roderesch distribution hub", + "address": "Juliadreef 55", + "zip": "6345 BX", + "city": "Roderesch", + "province": "Friesland", + "country": "NL", + "contact": { + "name": "Rens Jansen-Fechant", + "phone": "099-1781807", + "email": "le-grandnoor@example.net" + }, + "created_at": "1970-03-23 07:37:35", + "updated_at": "1970-12-26 14:30:51" + }, + { + "id": 23, + "code": "PGDWNLWG", + "name": "Heeswijk-Dinther longterm hub", + "address": "Vigodreef 22", + "zip": "5066 GI", + "city": "Heeswijk-Dinther", + "province": "Friesland", + "country": "NL", + "contact": { + "name": "Lana Schatteleijn", + "phone": "+31(0)25-1985675", + "email": "xlathrope@example.org" + }, + "created_at": "1996-03-05 10:05:56", + "updated_at": "2002-02-06 08:17:34" + }, + { + "id": 24, + "code": "ACBENL3A", + "name": "Nieuwehorne distribution hub", + "address": "Sofiaweg 913", + "zip": "1802 WP", + "city": "Nieuwehorne", + "province": "Utrecht", + "country": "NL", + "contact": { + "name": "Ben Fortuyn-Schrik", + "phone": "+31(0)25-6865349", + "email": "riley32@example.com" + }, + "created_at": "1977-11-17 01:10:40", + "updated_at": "1983-05-05 16:17:25" + }, + { + "id": 25, + "code": "VWIZNLUF", + "name": "Halle cargo center", + "address": "Julessingel 5", + "zip": "7374 PM", + "city": "Halle", + "province": "Overijssel", + "country": "NL", + "contact": { + "name": "Bas Scholten", + "phone": "+3137-8739738", + "email": "sarakuipers@example.com" + }, + "created_at": "2004-05-16 09:41:47", + "updated_at": "2018-01-05 05:33:25" + }, + { + "id": 26, + "code": "GPRPNLPT", + "name": "Joppe air and road location", + "address": "Lucasstraat 3", + "zip": "2727 VY", + "city": "Joppe", + "province": "Flevoland", + "country": "NL", + "contact": { + "name": "Rosa van 't Erve-Berendse", + "phone": "(0681) 626416", + "email": "van-ommerenjan@example.net" + }, + "created_at": "2003-03-30 04:14:17", + "updated_at": "2019-11-14 08:04:39" + }, + { + "id": 27, + "code": "FXJKNL4W", + "name": "Nieuwer Ter Aa cargo location", + "address": "Stellalaan 2", + "zip": "7158 IW", + "city": "Nieuwer Ter Aa", + "province": "Utrecht", + "country": "NL", + "contact": { + "name": "Lenn de Hoogh-Verbruggen", + "phone": "+31021-231813", + "email": "sterre34@example.com" + }, + "created_at": "2008-02-28 21:06:26", + "updated_at": "2013-11-06 14:01:58" + }, + { + "id": 28, + "code": "UECCNLNT", + "name": "Dieverbrug longterm location", + "address": "Britthof 445", + "zip": "3854OR", + "city": "Dieverbrug", + "province": "Zuid-Holland", + "country": "NL", + "contact": { + "name": "Liv Mulder", + "phone": "+3119-9768344", + "email": "ouwerkerkyara@example.net" + }, + "created_at": "2000-03-12 18:50:47", + "updated_at": "2023-11-23 16:46:38" + }, + { + "id": 29, + "code": "UBERNLTL", + "name": "Einighausen air and road center", + "address": "Sophiastraat 1", + "zip": "2605WX", + "city": "Einighausen", + "province": "Flevoland", + "country": "NL", + "contact": { + "name": "Maurits van Doorn", + "phone": "+3191 2817485", + "email": "jansenevy@example.org" + }, + "created_at": "1975-10-19 21:04:05", + "updated_at": "2005-04-22 23:58:02" + }, + { + "id": 30, + "code": "TKHJNLZM", + "name": "Zuiddorpe distribution center", + "address": "Kayleesteeg 34", + "zip": "9163FX", + "city": "Zuiddorpe", + "province": "Friesland", + "country": "NL", + "contact": { + "name": "Britt Labado", + "phone": "0760 793486", + "email": "keanovan-der-horst@example.com" + }, + "created_at": "2023-01-26 17:11:45", + "updated_at": "2023-07-13 03:54:28" + }, + { + "id": 31, + "code": "JFGQNLZM", + "name": "Lichtaard cargo location", + "address": "Oscarbaan 0", + "zip": "4396 RL", + "city": "Lichtaard", + "province": "Overijssel", + "country": "NL", + "contact": { + "name": "Nynke Pierson", + "phone": "0927-531893", + "email": "oheribert-van-laon@example.net" + }, + "created_at": "1974-11-14 17:13:40", + "updated_at": "2020-11-21 08:13:52" + }, + { + "id": 32, + "code": "VMYWBEWK", + "name": "Itegem longterm hub", + "address": "Fransstraat 15", + "zip": "2042", + "city": "Itegem", + "province": "Oost-Vlaanderen", + "country": "BE", + "contact": { + "name": "Jana Van Baelen", + "phone": "+32(0)93-6351025", + "email": "freddy95@example.net" + }, + "created_at": "1991-01-16 19:20:30", + "updated_at": "1995-07-02 04:48:16" + }, + { + "id": 33, + "code": "WECRBELD", + "name": "Westende longterm hub", + "address": "Lindaboulevard 027", + "zip": "6194", + "city": "Westende", + "province": "Oost-Vlaanderen", + "country": "BE", + "contact": { + "name": "Jan Desmedt", + "phone": "057-0359147", + "email": "marc05@example.net" + }, + "created_at": "1971-07-12 20:27:49", + "updated_at": "1974-09-27 02:25:06" + }, + { + "id": 34, + "code": "FLKTBEW4", + "name": "Mons distribution facility", + "address": "Janweg 9", + "zip": "9002", + "city": "Mons", + "province": "Luxemburg", + "country": "BE", + "contact": { + "name": "Chantal Coene", + "phone": "+3268 2640689", + "email": "boeckxalain@example.net" + }, + "created_at": "2024-06-06 02:32:30", + "updated_at": "2024-08-21 21:18:33" + }, + { + "id": 35, + "code": "VJBCBEIG", + "name": "Nobressart distribution hub", + "address": "Andreashof 73", + "zip": "3023", + "city": "Nobressart", + "province": "Luxemburg", + "country": "BE", + "contact": { + "name": "Evelien De Bruyne Peeters", + "phone": "+32178 271511", + "email": "maria54@example.org" + }, + "created_at": "1982-10-26 03:50:05", + "updated_at": "1991-05-07 01:00:26" + }, + { + "id": 36, + "code": "NVUVBEBZ", + "name": "Hensies longterm facility", + "address": "Michelbaan 634", + "zip": "6256", + "city": "Hensies", + "province": "West-Vlaanderen", + "country": "BE", + "contact": { + "name": "Nancy Van de Voorde", + "phone": "+32312 051533", + "email": "jean04@example.org" + }, + "created_at": "1987-11-07 11:49:00", + "updated_at": "2018-06-09 20:14:26" + }, + { + "id": 37, + "code": "XBICBEJ9", + "name": "Fontaine-l'Ev\u00eaque storage center", + "address": "Eduardstraat 5", + "zip": "3122", + "city": "Fontaine-l'Ev\u00eaque", + "province": "Limburg", + "country": "BE", + "contact": { + "name": "Roger Simons", + "phone": "(059)-4911137", + "email": "uvervoort@example.org" + }, + "created_at": "2008-07-09 08:12:26", + "updated_at": "2013-10-02 04:00:54" + }, + { + "id": 38, + "code": "OJGTBEH8", + "name": "Lanaye distribution hub", + "address": "Jeanring 018", + "zip": "3229", + "city": "Lanaye", + "province": "Oost-Vlaanderen", + "country": "BE", + "contact": { + "name": "Carlo Simons", + "phone": "06 065 45 35", + "email": "emielverbeke@example.com" + }, + "created_at": "2014-08-11 22:50:47", + "updated_at": "2017-06-17 12:29:20" + }, + { + "id": 39, + "code": "JQUWBEPM", + "name": "Cour-sur-Heure longterm center", + "address": "Ellenbaan 50", + "zip": "6326", + "city": "Cour-sur-Heure", + "province": "Namen", + "country": "BE", + "contact": { + "name": "Sammy Segers", + "phone": "+32(0)46 5073533", + "email": "emmadaniels@example.com" + }, + "created_at": "1987-05-21 10:51:45", + "updated_at": "1998-11-01 18:36:14" + }, + { + "id": 40, + "code": "ABKMBEPE", + "name": "Eigenbilzen air and road location", + "address": "Katjasingel 6", + "zip": "6986", + "city": "Eigenbilzen", + "province": "Luxemburg", + "country": "BE", + "contact": { + "name": "Els Smets", + "phone": "032 5659440", + "email": "xdeleu@example.com" + }, + "created_at": "2024-05-09 16:07:25", + "updated_at": "2024-09-02 08:22:59" + }, + { + "id": 41, + "code": "YDPLBEY2", + "name": "Hakendover storage hub", + "address": "Marcelstraat 5", + "zip": "1689", + "city": "Hakendover", + "province": "Henegouwen", + "country": "BE", + "contact": { + "name": "Lotte Dobbelaere", + "phone": "(0441)-027017", + "email": "wsanders@example.com" + }, + "created_at": "1975-07-31 23:56:47", + "updated_at": "1996-07-15 01:08:59" + }, + { + "id": 42, + "code": "KVLOBEUH", + "name": "Mere distribution facility", + "address": "Matsdreef 2", + "zip": "8491", + "city": "Mere", + "province": "Luik", + "country": "BE", + "contact": { + "name": "Mike Smeets", + "phone": "+32(0)488-011615", + "email": "rvermeiren@example.net" + }, + "created_at": "1990-08-01 05:20:16", + "updated_at": "2004-10-02 08:57:08" + }, + { + "id": 43, + "code": "YDKGBEPS", + "name": "Lens-Saint-Remy air and road facility", + "address": "Freddystraat 118", + "zip": "9637", + "city": "Lens-Saint-Remy", + "province": "Namen", + "country": "BE", + "contact": { + "name": "Sam Peeters", + "phone": "+32231-246362", + "email": "yverhulst@example.com" + }, + "created_at": "2012-07-06 02:54:52", + "updated_at": "2024-02-20 23:54:56" + }, + { + "id": 44, + "code": "GWKKBE0Y", + "name": "Ch\u00e2telineau storage center", + "address": "Birgitlei 2", + "zip": "9082", + "city": "Ch\u00e2telineau", + "province": "Vlaams-Brabant", + "country": "BE", + "contact": { + "name": "Ingrid Daems", + "phone": "(003) 9537465", + "email": "callensgodelieve@example.org" + }, + "created_at": "2020-02-11 18:51:46", + "updated_at": "2020-05-17 06:40:36" + }, + { + "id": 45, + "code": "THHKBEEQ", + "name": "Kieldrecht air and road facility", + "address": "Rogerdreef 0", + "zip": "3128", + "city": "Kieldrecht", + "province": "Luik", + "country": "BE", + "contact": { + "name": "Peter Vandevelde", + "phone": "+32729 166461", + "email": "dirk84@example.com" + }, + "created_at": "2024-05-14 17:07:09", + "updated_at": "2024-06-04 02:26:47" + }, + { + "id": 46, + "code": "REALBEEJ", + "name": "Oekene distribution facility", + "address": "Daniellaan 1", + "zip": "3711", + "city": "Oekene", + "province": "Vlaams-Brabant", + "country": "BE", + "contact": { + "name": "Imran Vandendriessche", + "phone": "(0532)-905203", + "email": "willyverhaeghe@example.com" + }, + "created_at": "2009-11-15 09:02:25", + "updated_at": "2023-04-18 16:05:34" + }, + { + "id": 47, + "code": "FDJGBE9H", + "name": "Chanly air and road center", + "address": "Marinaring 92", + "zip": "2605", + "city": "Chanly", + "province": "Namen", + "country": "BE", + "contact": { + "name": "Bjorn Van Hecke", + "phone": "+32(0)725 516583", + "email": "kenismaria@example.com" + }, + "created_at": "2014-05-29 09:23:40", + "updated_at": "2015-05-04 11:11:03" + }, + { + "id": 48, + "code": "UQOJDEE9", + "name": "Gie\u00dfen distribution location", + "address": "Wellerallee 3/7", + "zip": "84526", + "city": "Gie\u00dfen", + "province": "Hamburg", + "country": "DE", + "contact": { + "name": "Anto Kambs", + "phone": "00189 385803", + "email": "adlerrosalinde@example.com" + }, + "created_at": "1990-11-17 01:06:55", + "updated_at": "2008-04-09 14:26:34" + }, + { + "id": 49, + "code": "LXXCDES7", + "name": "Sankt Goarshausen longterm facility", + "address": "Pruschkestr. 1", + "zip": "69463", + "city": "Sankt Goarshausen", + "province": "Bremen", + "country": "DE", + "contact": { + "name": "Dr. Arno Winkler B.Sc.", + "phone": "+49(0)1144615012", + "email": "nerminladeck@example.com" + }, + "created_at": "2008-04-20 11:50:13", + "updated_at": "2024-03-28 22:17:37" + }, + { + "id": 50, + "code": "UXRKDE29", + "name": "Badoberan longterm facility", + "address": "Vollbrechtstr. 847", + "zip": "74501", + "city": "Badoberan", + "province": "Niedersachsen", + "country": "DE", + "contact": { + "name": "Reinhart Klemt", + "phone": "+49(0)3215 856979", + "email": "rochushentschel@example.net" + }, + "created_at": "2003-02-13 06:56:58", + "updated_at": "2013-12-22 20:08:54" + }, + { + "id": 51, + "code": "OXOMDE7A", + "name": "Wernigerode storage hub", + "address": "Heidemarie-Birnbaum-Ring 4/3", + "zip": "61818", + "city": "Wernigerode", + "province": "Brandenburg", + "country": "DE", + "contact": { + "name": "Eleni Zimmer-Henschel", + "phone": "04398 496300", + "email": "beckertuelay@example.com" + }, + "created_at": "1976-08-10 06:59:29", + "updated_at": "2014-07-01 07:33:54" + }, + { + "id": 52, + "code": "OCVODE54", + "name": "Stollberg air and road center", + "address": "Rene-Schmiedt-Allee 11", + "zip": "01625", + "city": "Stollberg", + "province": "Nordrhein-Westfalen", + "country": "DE", + "contact": { + "name": "Rebekka Geisler B.Sc.", + "phone": "06230538431", + "email": "yheydrich@example.org" + }, + "created_at": "2000-04-22 11:28:17", + "updated_at": "2012-08-07 16:01:14" + }, + { + "id": 53, + "code": "LERPDE9L", + "name": "Neustadtner Waldnaab distribution center", + "address": "Franz-Peter-Hettner-Allee 6", + "zip": "39261", + "city": "Neustadtner Waldnaab", + "province": "Sachsen", + "country": "DE", + "contact": { + "name": "Frau Ayten Haering MBA.", + "phone": "05773 584153", + "email": "isabellewulff@example.net" + }, + "created_at": "2005-01-29 06:28:53", + "updated_at": "2013-11-27 15:40:01" + }, + { + "id": 54, + "code": "BAADDEXK", + "name": "Regensburg cargo center", + "address": "Birgitt-Scholtz-Allee 46", + "zip": "35725", + "city": "Regensburg", + "province": "Hamburg", + "country": "DE", + "contact": { + "name": "Prof. Janet Sager", + "phone": "03888522177", + "email": "doerschnerwenke@example.com" + }, + "created_at": "2009-06-14 21:02:25", + "updated_at": "2010-06-27 09:44:40" + }, + { + "id": 55, + "code": "IUVSDETG", + "name": "Waldm\u00fcnchen longterm center", + "address": "Gabriele-Junken-Ring 5/1", + "zip": "35099", + "city": "Waldm\u00fcnchen", + "province": "Brandenburg", + "country": "DE", + "contact": { + "name": "Bozena Steckel", + "phone": "(08587) 18542", + "email": "adolfinehentschel@example.net" + }, + "created_at": "2006-08-31 03:38:40", + "updated_at": "2010-04-26 18:16:09" + }, + { + "id": 56, + "code": "BOYUDE7O", + "name": "Pasewalk longterm location", + "address": "Konrad-Seip-Allee 66", + "zip": "49888", + "city": "Pasewalk", + "province": "Nordrhein-Westfalen", + "country": "DE", + "contact": { + "name": "Ullrich Beier", + "phone": "+49(0)8660 573483", + "email": "vbarkholz@example.com" + }, + "created_at": "1979-10-03 07:33:35", + "updated_at": "1993-08-05 16:12:41" + }, + { + "id": 57, + "code": "MOOODEEX", + "name": "Bischofswerda longterm facility", + "address": "Melissa-Bauer-Ring 1/7", + "zip": "37727", + "city": "Bischofswerda", + "province": "Nordrhein-Westfalen", + "country": "DE", + "contact": { + "name": "Uwe Lindau", + "phone": "(06380) 715579", + "email": "ilse44@example.org" + }, + "created_at": "1984-05-11 19:24:11", + "updated_at": "2022-06-19 14:32:50" + }, + { + "id": 58, + "code": "WJKADEJE", + "name": "Holzminden air and road hub", + "address": "Sibilla-Hendriks-Gasse 5/8", + "zip": "05955", + "city": "Holzminden", + "province": "Saarland", + "country": "DE", + "contact": { + "name": "Mirco Warmer", + "phone": "+49(0)0048791642", + "email": "katjaklotz@example.net" + }, + "created_at": "1974-04-03 11:24:15", + "updated_at": "2021-12-08 15:59:38" + } +] \ No newline at end of file diff --git a/Tests/Test_locations.py b/Tests/Test_locations.py index df06893..17e8dde 100644 --- a/Tests/Test_locations.py +++ b/Tests/Test_locations.py @@ -17,6 +17,19 @@ def cleanup_test_data(test_name): assert delete_response.status_code in [ 200, 204], f"Cleanup failed in {test_name}" response = requests.get(WAREHOUSE_URL, headers=headers) +BASE_URL = "http://localhost:3000/api/v1/Locations" +WAREHOUSE_URL = "http://localhost:3000/api/v1/warehouses" +headers = {'APIKEY': "Admin"} + +def cleanup_test_data(test_name): + response = requests.get(BASE_URL, headers=headers) + if response.status_code == 200: + locations = response.json() + for location in locations: + if "Test" in location["name"] or location["code"] == "TST": + delete_response = requests.delete(f"{BASE_URL}/{location['id']}", headers=headers) + assert delete_response.status_code in [200, 204], f"Cleanup failed in {test_name}" + response = requests.get(WAREHOUSE_URL, headers=headers) if response.status_code == 200: warehouses = response.json() for warehouse in warehouses: @@ -65,6 +78,29 @@ def test_get_location_by_id(): location = response.json() assert location["id"] == location_id + } + + response = requests.post(WAREHOUSE_URL, json=new_warehouse, headers=headers) + assert response.status_code in [201, 204] + + response = requests.get(WAREHOUSE_URL, headers=headers) + for warehouse in response.json(): + if warehouse["code"] == "TST": + return warehouse["id"] + +def test_get_all_locations(): + response = requests.get(BASE_URL, headers=headers) + assert response.status_code == 200 + locations = response.json() + assert isinstance(locations, list) + assert len(locations) > 0 + +def test_get_location_by_id(): + location_id = 1 + response = requests.get(f"{BASE_URL}/{location_id}") + assert response.status_code == 200 + location = response.json() + assert location["id"] == location_id def test_add_location(): warehouse_id = Create_test_warehouse() @@ -92,6 +128,8 @@ def test_update_location(): locations = response.json() location_id = None + locations = response.json() + location_id = None for location in locations: if "Test" in location["name"] or location["code"] == "TST": @@ -99,15 +137,20 @@ def test_update_location(): break assert location_id is not None, "No test location found to update." + assert location_id is not None, "No test location found to update." updated_location = { - "name": "Test Location Updated", + "name": "Test Location Updated", "code": "TST", "warehouseId": warehouse_id, } response = requests.put(f"{BASE_URL}/{location_id}", json=updated_location, headers=headers) assert response.status_code == 200 + "warehouseId": 1, + } + response = requests.put(f"{BASE_URL}/{location_id}", json=updated_location, headers=headers) + assert response.status_code == 200 if response.headers.get('Content-Type') == 'application/json': location = response.json() @@ -131,3 +174,7 @@ def test_remove_location_invalid_id(): invalid_id = 9999 response = requests.delete(f"{BASE_URL}/{invalid_id}") assert response.status_code == 404 + + invalid_id = 9999 + response = requests.delete(f"{BASE_URL}/{invalid_id}") + assert response.status_code == 404 \ No newline at end of file diff --git a/Tests/test_helper.py b/Tests/test_helper.py index ca4a645..cbd65f0 100644 --- a/Tests/test_helper.py +++ b/Tests/test_helper.py @@ -1,3 +1,6 @@ +import re + + def have_same_structure(dict1, dict2): # First, check if both dictionaries have the same set of keys if set(dict1.keys()) != set(dict2.keys()): @@ -16,6 +19,13 @@ def have_same_structure(dict1, dict2): return True +def get_integer_from_json_string(json_string): + match = re.search(r'\d+', json_string) + if (match): + return match.group() + return 0 + + template_item_type = { "id": 0, "name": "", diff --git a/Tests/test_item_groups.py b/Tests/test_item_groups.py index de41315..fc44369 100644 --- a/Tests/test_item_groups.py +++ b/Tests/test_item_groups.py @@ -1,5 +1,6 @@ import requests -import re +import test_helper + BASE_URL = "http://localhost:3000/api/v2/ItemGroups" @@ -24,9 +25,9 @@ def test_Post(): # convert the json response to a string and look for the id of the created Entity json = str(post_response.json()) # look here for an integer (digit) - match = re.search(r'\d+', json) - assert match - generated_id = match.group() + + generated_id = test_helper.get_integer_from_json_string(json) + assert generated_id != 0 # get the same entity that has been posted get_response = requests.get(BASE_URL + f"/{generated_id}") @@ -58,10 +59,31 @@ def test_put(): # convert the json response to a string and look for the id of the created Entity json = str(post_response.json()) # look here for an integer (digit) - match = re.search(r'\d+', json) - assert match - generated_id = match.group() + generated_id = test_helper.get_integer_from_json_string(json) + assert generated_id != 0 # modify the added item group put_response = requests.put( BASE_URL + f"/{generated_id}", headers=HEADERS, json=UPDATED_ITEM_GROUP) assert put_response.status_code == 200 + + +def test_put_Item_group_that_does_not_exist(): + put_response = requests.put( + BASE_URL + "999999999999", json=VALID_ITEM_GROUP) + assert put_response.status_code == 404 + + +def test_delete(): + post_response = requests.post(BASE_URL, json=VALID_ITEM_GROUP) + json = str(post_response.json()) + generated_id = test_helper.get_integer_from_json_string(json) + assert generated_id != 0 + + delete_response = requests.delete( + BASE_URL+f"/{generated_id}") + + assert delete_response.status_code == 200 + + get_response = requests.get(BASE_URL + str(generated_id)) + assert get_response.status_code == 404 + diff --git a/Tests/test_item_lines.py b/Tests/test_item_lines.py index f3d5e10..f4ef689 100644 --- a/Tests/test_item_lines.py +++ b/Tests/test_item_lines.py @@ -1,7 +1,8 @@ import requests -import re +import test_helper -BASE_URL = "http://localhost:3000/api/v2/ItemLines" + +BASE_URL = "http://localhost:3000/api/v2/ItemGroups" VALID_ITEM_LINE = { "Name": "Test Name", @@ -24,9 +25,9 @@ def test_Post(): # convert the json response to a string and look for the id of the created Entity json = str(post_response.json()) # look here for an integer (digit) - match = re.search(r'\d+', json) - assert match - generated_id = match.group() + + generated_id = test_helper.get_integer_from_json_string(json) + assert generated_id != 0 # get the same entity that has been posted get_response = requests.get(BASE_URL + f"/{generated_id}") @@ -58,10 +59,31 @@ def test_put(): # convert the json response to a string and look for the id of the created Entity json = str(post_response.json()) # look here for an integer (digit) - match = re.search(r'\d+', json) - assert match - generated_id = match.group() + generated_id = test_helper.get_integer_from_json_string(json) + assert generated_id != 0 # modify the added item line put_response = requests.put( BASE_URL + f"/{generated_id}", headers=HEADERS, json=UPDATED_ITEM_LINE) assert put_response.status_code == 200 + + +def test_put_Item_line_that_does_not_exist(): + put_response = requests.put( + BASE_URL + "999999999999", json=VALID_ITEM_LINE) + assert put_response.status_code == 404 + + +def test_delete(): + post_response = requests.post(BASE_URL, json=VALID_ITEM_LINE) + json = str(post_response.json()) + generated_id = test_helper.get_integer_from_json_string(json) + assert generated_id != 0 + + delete_response = requests.delete( + BASE_URL+f"/{generated_id}") + + assert delete_response.status_code == 200 + + get_response = requests.get(BASE_URL + str(generated_id)) + assert get_response.status_code == 404 + diff --git a/UnitTest/CargoHub.Tests.csproj b/UnitTest/CargoHub.Test.csproj similarity index 95% rename from UnitTest/CargoHub.Tests.csproj rename to UnitTest/CargoHub.Test.csproj index 6137881..58172a5 100644 --- a/UnitTest/CargoHub.Tests.csproj +++ b/UnitTest/CargoHub.Test.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - + false false true @@ -29,4 +29,4 @@ - + \ No newline at end of file diff --git a/UnitTest/ClassificationsServiceTest.cs b/UnitTest/ClassificationsServiceTest.cs index 8887597..994ad62 100644 --- a/UnitTest/ClassificationsServiceTest.cs +++ b/UnitTest/ClassificationsServiceTest.cs @@ -1,26 +1,26 @@ -namespace CargoHub.Test; -[TestClass] -public class TestClassificationService -{ - private AppDbContext _context; - private ClassificationService _service; - [TestInitialize] - public void Setup() - { - var options = new DbContextOptionsBuilder() - .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) - .Options; +// namespace CargoHub.Test; +// [TestClass] +// public class TestClassificationService +// { +// private AppDbContext _context; +// private ClassificationService _service; +// [TestInitialize] +// public void Setup() +// { +// var options = new DbContextOptionsBuilder() +// .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) +// .Options; - _context = new AppDbContext(options); +// _context = new AppDbContext(options); - _service = new ClassificationService(_context); - } +// _service = new ClassificationService(_context); +// } - [TestMethod] - public async Task TestGetClassifications() - { +// [TestMethod] +// public async Task TestGetClassifications() +// { - } +// } -} \ No newline at end of file +// } \ No newline at end of file diff --git a/UnitTest/ItemGroupServiceTest.cs b/UnitTest/ItemGroupServiceTest.cs index da6f65f..45361aa 100644 --- a/UnitTest/ItemGroupServiceTest.cs +++ b/UnitTest/ItemGroupServiceTest.cs @@ -1,139 +1,139 @@ -using Microsoft.AspNetCore.Http.Features; -namespace CargoHub.Test; - -// note: in-memory database is used because it's faster than an actual database -// TestSetup() : is used to setup the in-memory database before each test so the tests don't effect each other -// TestCleanup() : is used to delete the in-memory database so - -[TestClass] -public class TestItemGroupsService -{ - private AppDbContext _context; - private BaseStorageService _service; - [TestInitialize] - public void Setup() - { - var options = new DbContextOptionsBuilder() - .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) - .Options; - - _context = new AppDbContext(options); - - _service = new BaseStorageService(_context); - } - [TestMethod] - public async Task TestPostItemGroup() - { - // Try adding an item group with a value of null - ItemGroup? NullItemGroup = null; - int? NullResult = await _service.AddRow(NullItemGroup); - Assert.IsNull(NullResult); - - // Try to add a test item group - ItemGroup Ig = TestHelper.TestItemGroup1; - int? result = await _service.AddRow(Ig); - - // Get the added Item Group and check the properties - ItemGroup? FoundIg = await _context.ItemGroups.FindAsync(result); - Assert.IsNotNull(FoundIg); - Assert.IsNotNull(FoundIg.CreatedAt); - Assert.IsNotNull(FoundIg.UpdatedAt); - Assert.AreEqual(Ig.Name, FoundIg.Name); - - - } - [TestMethod] - public async Task TesGetItemGroup() - { - // Add an Item Group using DBcontext - ItemGroup Ig = TestHelper.TestItemGroup1; - await _context.ItemGroups.AddAsync(Ig); - await _context.SaveChangesAsync(); - - // Check if the properties are returned correctly - ItemGroup? result = await _service.GetRow(1); - Assert.IsNotNull(result); - Assert.AreEqual(Ig.Name, result.Name); - Assert.AreEqual(Ig.Description, result.Description); - - - } - - [TestMethod] - public async Task TestUpdateItemGroup() - { - // Add an item group object to the db - ItemGroup Ig = TestHelper.TestItemGroup1; - await _context.ItemGroups.AddAsync(Ig); - await _context.SaveChangesAsync(); - - // Update the inserted item group - ItemGroup UpdatedIg = TestHelper.TestItemGroup2; - bool result = await _service.UpdateRow(Ig.Id, UpdatedIg); - Assert.IsTrue(result); - Assert.IsTrue(Ig.UpdatedAt > Ig.CreatedAt); - } - - [TestMethod] - public async Task TestUpdateInvalidItemGroup() - { - // try to update an ItemGroup that doesn't exist - ItemGroup UpdatedIg = TestHelper.TestItemGroup2; - bool Result1 = await _service.UpdateRow(999, UpdatedIg); - Assert.IsFalse(Result1); - - // Add an ItemGroup to the DB - ItemGroup Ig = TestHelper.TestItemGroup1; - await _context.ItemGroups.AddAsync(Ig); - await _context.SaveChangesAsync(); - - // Test Updating the item group - bool result = await _service.UpdateRow(Ig.Id, UpdatedIg); - Assert.IsTrue(result); - - } - - [TestMethod] - public async Task TestDeleteItemGroup() - { - // try deleting an entity that doesn't exist - bool Result1 = await _service.DeleteRow(1); - Assert.IsFalse(Result1); - - ItemGroup Ig = TestHelper.TestItemGroup1; - await _context.ItemGroups.AddAsync(Ig); - await _context.SaveChangesAsync(); - bool Result2 = await _service.DeleteRow(1); - Assert.IsTrue(Result2); - } - - [TestMethod] - public async Task TestGetAll() - { - // Add a couple hundred pages to test the paganation - for (int i = 0; i < 300; i++) - { - ItemGroup Random_IG = TestHelper.CreateRandomItemGroup(); - await _context.ItemGroups.AddAsync(Random_IG); - } - await _context.SaveChangesAsync(); - - // try to get the first page with size 100 (including 100 x ItemGroup) - List ItemGroups = await _service.GetAllRows(1, 100); - Assert.AreEqual(ItemGroups[0].Id, 1); - Assert.AreEqual(ItemGroups.Last().Id, 100); - Assert.IsTrue(ItemGroups.All(Ig => Ig.Id <= 100)); - - // try to get the second Page with size 150 - - - - - } - [TestCleanup] - public void Cleanup() - { - _context.Database.EnsureDeleted(); - _context.Dispose(); - } -} \ No newline at end of file +// using Microsoft.AspNetCore.Http.Features; +// namespace CargoHub.Test; + +// // note: in-memory database is used because it's faster than an actual database +// // TestSetup() : is used to setup the in-memory database before each test so the tests don't effect each other +// // TestCleanup() : is used to delete the in-memory database so + +// [TestClass] +// public class TestItemGroupsService +// { +// private AppDbContext _context; +// private BaseStorageService _service; +// [TestInitialize] +// public void Setup() +// { +// var options = new DbContextOptionsBuilder() +// .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) +// .Options; + +// _context = new AppDbContext(options); + +// _service = new BaseStorageService(_context); +// } +// [TestMethod] +// public async Task TestPostItemGroup() +// { +// // Try adding an item group with a value of null +// ItemGroup? NullItemGroup = null; +// int? NullResult = await _service.AddRow(NullItemGroup); +// Assert.IsNull(NullResult); + +// // Try to add a test item group +// ItemGroup Ig = TestHelper.TestItemGroup1; +// int? result = await _service.AddRow(Ig); + +// // Get the added Item Group and check the properties +// ItemGroup? FoundIg = await _context.ItemGroups.FindAsync(result); +// Assert.IsNotNull(FoundIg); +// Assert.IsNotNull(FoundIg.CreatedAt); +// Assert.IsNotNull(FoundIg.UpdatedAt); +// Assert.AreEqual(Ig.Name, FoundIg.Name); + + +// } +// [TestMethod] +// public async Task TesGetItemGroup() +// { +// // Add an Item Group using DBcontext +// ItemGroup Ig = TestHelper.TestItemGroup1; +// await _context.ItemGroups.AddAsync(Ig); +// await _context.SaveChangesAsync(); + +// // Check if the properties are returned correctly +// ItemGroup? result = await _service.GetRow(1); +// Assert.IsNotNull(result); +// Assert.AreEqual(Ig.Name, result.Name); +// Assert.AreEqual(Ig.Description, result.Description); + + +// } + +// [TestMethod] +// public async Task TestUpdateItemGroup() +// { +// // Add an item group object to the db +// ItemGroup Ig = TestHelper.TestItemGroup1; +// await _context.ItemGroups.AddAsync(Ig); +// await _context.SaveChangesAsync(); + +// // Update the inserted item group +// ItemGroup UpdatedIg = TestHelper.TestItemGroup2; +// bool result = await _service.UpdateRow(Ig.Id, UpdatedIg); +// Assert.IsTrue(result); +// Assert.IsTrue(Ig.UpdatedAt > Ig.CreatedAt); +// } + +// [TestMethod] +// public async Task TestUpdateInvalidItemGroup() +// { +// // try to update an ItemGroup that doesn't exist +// ItemGroup UpdatedIg = TestHelper.TestItemGroup2; +// bool Result1 = await _service.UpdateRow(999, UpdatedIg); +// Assert.IsFalse(Result1); + +// // Add an ItemGroup to the DB +// ItemGroup Ig = TestHelper.TestItemGroup1; +// await _context.ItemGroups.AddAsync(Ig); +// await _context.SaveChangesAsync(); + +// // Test Updating the item group +// bool result = await _service.UpdateRow(Ig.Id, UpdatedIg); +// Assert.IsTrue(result); + +// } + +// [TestMethod] +// public async Task TestDeleteItemGroup() +// { +// // try deleting an entity that doesn't exist +// bool Result1 = await _service.DeleteRow(1); +// Assert.IsFalse(Result1); + +// ItemGroup Ig = TestHelper.TestItemGroup1; +// await _context.ItemGroups.AddAsync(Ig); +// await _context.SaveChangesAsync(); +// bool Result2 = await _service.DeleteRow(1); +// Assert.IsTrue(Result2); +// } + +// [TestMethod] +// public async Task TestGetAll() +// { +// // Add a couple hundred pages to test the paganation +// for (int i = 0; i < 300; i++) +// { +// ItemGroup Random_IG = TestHelper.CreateRandomItemGroup(); +// await _context.ItemGroups.AddAsync(Random_IG); +// } +// await _context.SaveChangesAsync(); + +// // try to get the first page with size 100 (including 100 x ItemGroup) +// List ItemGroups = await _service.GetAllRows(1, 100); +// Assert.AreEqual(ItemGroups[0].Id, 1); +// Assert.AreEqual(ItemGroups.Last().Id, 100); +// Assert.IsTrue(ItemGroups.All(Ig => Ig.Id <= 100)); + +// // try to get the second Page with size 150 + + + + +// } +// [TestCleanup] +// public void Cleanup() +// { +// _context.Database.EnsureDeleted(); +// _context.Dispose(); +// } +// } \ No newline at end of file diff --git a/UnitTest/ItemLinesServiceTest.cs b/UnitTest/ItemLinesServiceTest.cs index 8d02eef..d30e044 100644 --- a/UnitTest/ItemLinesServiceTest.cs +++ b/UnitTest/ItemLinesServiceTest.cs @@ -1,139 +1,139 @@ -using Microsoft.AspNetCore.Http.Features; -namespace CargoHub.Test; - -// note: in-memory database is used because it's faster than an actual database -// TestSetup() : is used to setup the in-memory database before each test so the tests don't effect each other -// TestCleanup() : is used to delete the in-memory database so - -[TestClass] -public class TestItemLinesService -{ - private AppDbContext _context; - private BaseStorageService _service; - [TestInitialize] - public void Setup() - { - var options = new DbContextOptionsBuilder() - .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) - .Options; - - _context = new AppDbContext(options); - - _service = new BaseStorageService(_context); - } - [TestMethod] - public async Task TestPostItemLine() - { - // Try adding an item line with a value of null - ItemLine? NullItemLine = null; - int? NullResult = await _service.AddRow(NullItemLine); - Assert.IsNull(NullResult); - - // Try to add a test item line - ItemLine IL = TestHelper.TestItemLine1; - int? result = await _service.AddRow(IL); - - // Get the added Item line and check the properties - ItemLine? FoundIL = await _context.ItemLines.FindAsync(result); - Assert.IsNotNull(FoundIL); - Assert.IsNotNull(FoundIL.CreatedAt); - Assert.IsNotNull(FoundIL.UpdatedAt); - Assert.AreEqual(IL.Name, FoundIL.Name); - - - } - [TestMethod] - public async Task TesGetItemLine() - { - // Add an Item line using DBcontext - ItemLine IL = TestHelper.TestItemLine1; - await _context.ItemLines.AddAsync(IL); - await _context.SaveChangesAsync(); - - // Check if the properties are returned correctly - ItemLine? result = await _service.GetRow(1); - Assert.IsNotNull(result); - Assert.AreEqual(IL.Name, result.Name); - Assert.AreEqual(IL.Description, result.Description); - - - } - - [TestMethod] - public async Task TestUpdateItemLine() - { - // Add an item line object to the db - ItemLine IL = TestHelper.TestItemLine1; - await _context.ItemLines.AddAsync(IL); - await _context.SaveChangesAsync(); - - // Update the inserted item line - ItemLine UpdatedIL = TestHelper.TestItemLine2; - bool result = await _service.UpdateRow(IL.Id, UpdatedIL); - Assert.IsTrue(result); - Assert.IsTrue(IL.UpdatedAt > IL.CreatedAt); - } - - [TestMethod] - public async Task TestUpdateInvalidItemLine() - { - // try to update an ItemLine that doesn't exist - ItemLine UpdatedIL = TestHelper.TestItemLine2; - bool Result1 = await _service.UpdateRow(999, UpdatedIL); - Assert.IsFalse(Result1); - - // Add an ItemLine to the DB - ItemLine IL = TestHelper.TestItemLine1; - await _context.ItemLines.AddAsync(IL); - await _context.SaveChangesAsync(); - - // Test Updating the item line - bool result = await _service.UpdateRow(IL.Id, UpdatedIL); - Assert.IsTrue(result); - - } - - [TestMethod] - public async Task TestDeleteItemLine() - { - // try deleting an entity that doesn't exist - bool Result1 = await _service.DeleteRow(1); - Assert.IsFalse(Result1); - - ItemLine IL = TestHelper.TestItemLine1; - await _context.ItemLines.AddAsync(IL); - await _context.SaveChangesAsync(); - bool Result2 = await _service.DeleteRow(1); - Assert.IsTrue(Result2); - } - - [TestMethod] - public async Task TestGetAll() - { - // Add a couple hundred pages to test the paganation - for (int i = 0; i < 300; i++) - { - ItemLine Random_IL = TestHelper.CreateRandomItemLine(); - await _context.ItemLines.AddAsync(Random_IL); - } - await _context.SaveChangesAsync(); - - // try to get the first page with size 100 (including 100 x ItemLine) - List ItemLines = await _service.GetAllRows(1, 100); - Assert.AreEqual(ItemLines[0].Id, 1); - Assert.AreEqual(ItemLines.Last().Id, 100); - Assert.IsTrue(ItemLines.All(IL => IL.Id <= 100)); - - // try to get the second Page with size 150 - - - - - } - [TestCleanup] - public void Cleanup() - { - _context.Database.EnsureDeleted(); - _context.Dispose(); - } -} \ No newline at end of file +// using Microsoft.AspNetCore.Http.Features; +// namespace CargoHub.Test; + +// // note: in-memory database is used because it's faster than an actual database +// // TestSetup() : is used to setup the in-memory database before each test so the tests don't effect each other +// // TestCleanup() : is used to delete the in-memory database so + +// [TestClass] +// public class TestItemLinesService +// { +// private AppDbContext _context; +// private BaseStorageService _service; +// [TestInitialize] +// public void Setup() +// { +// var options = new DbContextOptionsBuilder() +// .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) +// .Options; + +// _context = new AppDbContext(options); + +// _service = new BaseStorageService(_context); +// } +// [TestMethod] +// public async Task TestPostItemLine() +// { +// // Try adding an item line with a value of null +// ItemLine? NullItemLine = null; +// int? NullResult = await _service.AddRow(NullItemLine); +// Assert.IsNull(NullResult); + +// // Try to add a test item line +// ItemLine IL = TestHelper.TestItemLine1; +// int? result = await _service.AddRow(IL); + +// // Get the added Item line and check the properties +// ItemLine? FoundIL = await _context.ItemLines.FindAsync(result); +// Assert.IsNotNull(FoundIL); +// Assert.IsNotNull(FoundIL.CreatedAt); +// Assert.IsNotNull(FoundIL.UpdatedAt); +// Assert.AreEqual(IL.Name, FoundIL.Name); + + +// } +// [TestMethod] +// public async Task TesGetItemLine() +// { +// // Add an Item line using DBcontext +// ItemLine IL = TestHelper.TestItemLine1; +// await _context.ItemLines.AddAsync(IL); +// await _context.SaveChangesAsync(); + +// // Check if the properties are returned correctly +// ItemLine? result = await _service.GetRow(1); +// Assert.IsNotNull(result); +// Assert.AreEqual(IL.Name, result.Name); +// Assert.AreEqual(IL.Description, result.Description); + + +// } + +// [TestMethod] +// public async Task TestUpdateItemLine() +// { +// // Add an item line object to the db +// ItemLine IL = TestHelper.TestItemLine1; +// await _context.ItemLines.AddAsync(IL); +// await _context.SaveChangesAsync(); + +// // Update the inserted item line +// ItemLine UpdatedIL = TestHelper.TestItemLine2; +// bool result = await _service.UpdateRow(IL.Id, UpdatedIL); +// Assert.IsTrue(result); +// Assert.IsTrue(IL.UpdatedAt > IL.CreatedAt); +// } + +// [TestMethod] +// public async Task TestUpdateInvalidItemLine() +// { +// // try to update an ItemLine that doesn't exist +// ItemLine UpdatedIL = TestHelper.TestItemLine2; +// bool Result1 = await _service.UpdateRow(999, UpdatedIL); +// Assert.IsFalse(Result1); + +// // Add an ItemLine to the DB +// ItemLine IL = TestHelper.TestItemLine1; +// await _context.ItemLines.AddAsync(IL); +// await _context.SaveChangesAsync(); + +// // Test Updating the item line +// bool result = await _service.UpdateRow(IL.Id, UpdatedIL); +// Assert.IsTrue(result); + +// } + +// [TestMethod] +// public async Task TestDeleteItemLine() +// { +// // try deleting an entity that doesn't exist +// bool Result1 = await _service.DeleteRow(1); +// Assert.IsFalse(Result1); + +// ItemLine IL = TestHelper.TestItemLine1; +// await _context.ItemLines.AddAsync(IL); +// await _context.SaveChangesAsync(); +// bool Result2 = await _service.DeleteRow(1); +// Assert.IsTrue(Result2); +// } + +// [TestMethod] +// public async Task TestGetAll() +// { +// // Add a couple hundred pages to test the paganation +// for (int i = 0; i < 300; i++) +// { +// ItemLine Random_IL = TestHelper.CreateRandomItemLine(); +// await _context.ItemLines.AddAsync(Random_IL); +// } +// await _context.SaveChangesAsync(); + +// // try to get the first page with size 100 (including 100 x ItemLine) +// List ItemLines = await _service.GetAllRows(1, 100); +// Assert.AreEqual(ItemLines[0].Id, 1); +// Assert.AreEqual(ItemLines.Last().Id, 100); +// Assert.IsTrue(ItemLines.All(IL => IL.Id <= 100)); + +// // try to get the second Page with size 150 + + + + +// } +// [TestCleanup] +// public void Cleanup() +// { +// _context.Database.EnsureDeleted(); +// _context.Dispose(); +// } +// } \ No newline at end of file diff --git a/UnitTest/Test_Location.cs b/UnitTest/Test_Location.cs new file mode 100644 index 0000000..9d55dd7 --- /dev/null +++ b/UnitTest/Test_Location.cs @@ -0,0 +1,125 @@ +// using Microsoft.VisualStudio.TestTools.UnitTesting; +// using Microsoft.EntityFrameworkCore; +// using System.Collections.Generic; +// using System.Threading.Tasks; +// using CargoHub.Models; +// using CargoHub.Services; + +// namespace CargoHub.Tests +// { +// [TestClass] +// public class LocationStorageServiceTests +// { +// private LocationStorageService _locationService; +// private AppDbContext _dbContext; + +// [TestInitialize] // Setup method that runs before each test +// public void Setup() +// { +// var options = new DbContextOptionsBuilder() +// .UseInMemoryDatabase(databaseName: "TestDatabase") // Create an in-memory database +// .Options; + +// _dbContext = new AppDbContext(options); +// _locationService = new LocationStorageService(_dbContext); +// } + +// [TestCleanup] +// public void Cleanup() +// { +// _dbContext.Database.EnsureDeleted(); +// _dbContext.Dispose(); +// } + +// [TestMethod] +// public async Task GetLocationsInWarehouse_ShouldReturnCorrectLocations() +// { +// // Arrange +// _dbContext.Locations.AddRange(new List +// { +// new Location { Name = "Location 1", Code = "LOC001", WarehouseId = 1 }, +// new Location { Name = "Location 2", Code = "LOC002", WarehouseId = 2 }, +// new Location { Name = "Location 3", Code = "LOC003", WarehouseId = 1 } +// }); +// await _dbContext.SaveChangesAsync(); + +// // Act +// var result = await _locationService.GetLocationsInWarehouse(1); + +// // Assert +// Assert.AreEqual(2, result.Count); // There should be 2 locations in warehouse 1 +// Assert.IsTrue(result.Exists(l => l.Code == "LOC001")); +// Assert.IsTrue(result.Exists(l => l.Code == "LOC003")); +// } + +// [TestMethod] +// public async Task AddRow_ShouldAddLocationToDatabase() +// { +// // Arrange +// var newLocation = new Location +// { +// Name = "New Location", +// Code = "LOC004", +// WarehouseId = 3 +// }; + +// // Act +// var result = await _locationService.AddRow(newLocation); + +// // Assert +// Assert.IsNotNull(result); +// var location = await _dbContext.Locations.FindAsync(result); +// Assert.IsNotNull(location); +// Assert.AreEqual("New Location", location.Name); +// } + +// [TestMethod] +// public async Task GetRow_ShouldReturnCorrectLocation() +// { +// // Arrange +// var location = new Location { Name = "Test Location", Code = "LOC005", WarehouseId = 4 }; +// await _locationService.AddRow(location); + +// // Act +// var result = await _locationService.GetRow(location.Id); + +// // Assert +// Assert.IsNotNull(result); +// Assert.AreEqual("Test Location", result.Name); +// } + +// [TestMethod] +// public async Task UpdateRow_ShouldUpdateExistingLocation() +// { +// // Arrange +// var location = new Location { Name = "Old Name", Code = "LOC006", WarehouseId = 5 }; +// await _locationService.AddRow(location); + +// var updatedLocation = new Location { Id = location.Id, Name = "New Name", Code = "LOC006", WarehouseId = 5 }; + +// // Act +// var result = await _locationService.UpdateRow(location.Id, updatedLocation); + +// // Assert +// Assert.IsTrue(result); +// var updated = await _dbContext.Locations.FindAsync(location.Id); +// Assert.AreEqual("New Name", updated.Name); +// } + +// [TestMethod] +// public async Task DeleteRow_ShouldRemoveLocationFromDatabase() +// { +// // Arrange +// var location = new Location { Name = "Location to Delete", Code = "LOC007", WarehouseId = 6 }; +// await _locationService.AddRow(location); + +// // Act +// var result = await _locationService.DeleteRow(location.Id); + +// // Assert +// Assert.IsTrue(result); +// var deletedLocation = await _dbContext.Locations.FindAsync(location.Id); +// Assert.IsNull(deletedLocation); +// } +// } +// } diff --git a/UnitTest/Test_OrdersU.cs b/UnitTest/Test_OrdersU.cs new file mode 100644 index 0000000..846e2e8 --- /dev/null +++ b/UnitTest/Test_OrdersU.cs @@ -0,0 +1,1378 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using CargoHub.Models; +using CargoHub.Services; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace CargoHub.Tests +{ + [TestClass] + public class OrderServiceTests + { + private OrderService _orderService; + private AppDbContext _dbContext; + + [TestInitialize] + public void Setup() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: "TestDatabase") + .Options; + + _dbContext = new AppDbContext(options); + _orderService = new OrderService(_dbContext); + } + + [TestCleanup] + public void Cleanup() + { + _dbContext.Database.EnsureDeleted(); + _dbContext.Dispose(); + } + + [TestMethod] + public async Task GetOrderWithItems_ShouldReturnOrder_WhenOrderExists() + { + // Arrange + var item1 = new Item + { + Uid = "ITEM001", + Description = "Test Item 1", + Code = "CODE001", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + var item2 = new Item + { + Uid = "ITEM002", + Description = "Test Item 2", + Code = "CODE002", + ShortDescription = "Short Desc 2", + UpcCode = "UPC002", + ModelNumber = "MODEL002", + CommodityCode = "COMMODITY002", + ItemLine = 2, + ItemGroup = 2, + ItemType = 2, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 2, + SupplierCode = "SUPPLIER002", + SupplierPartNumber = "PART002" + }; + + var order = new Order + { + Reference = "Test Order", + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 2, Item = item1 }, + new OrderItem { ItemUid = "ITEM002", Amount = 3, Item = item2 } + } + }; + + _dbContext.Items.AddRange(item1, item2); + _dbContext.Orders.Add(order); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrderWithItems(order.Id); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(order.Id, result.Id); + Assert.AreEqual(2, result.Items.Count); + Assert.AreEqual("ITEM001", result.Items[0].ItemId); + Assert.AreEqual("ITEM002", result.Items[1].ItemId); + } + + [TestMethod] + public async Task GetOrderWithItems_ShouldReturnNull_WhenOrderDoesNotExist() + { + // Act + var result = await _orderService.GetOrderWithItems(999); + + // Assert + Assert.IsNull(result); + } + + [TestMethod] + public async Task GetOrderWithItems_ShouldReturnOrderWithNoItems_WhenOrderHasNoItems() + { + // Arrange + var order = new Order + { + Reference = "Test Order", + OrderItems = new List() // No items + }; + + _dbContext.Orders.Add(order); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrderWithItems(order.Id); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(order.Id, result.Id); + Assert.AreEqual(0, result.Items.Count); + } + + [TestMethod] + public async Task GetAllOrdersWithItems_ShouldReturnAllOrdersWithItems() + { + // Arrange + var item1 = new Item + { + Uid = "ITEM001", + Description = "Test Item 1", + Code = "CODE001", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + var item2 = new Item + { + Uid = "ITEM002", + Description = "Test Item 2", + Code = "CODE002", + ShortDescription = "Short Desc 2", + UpcCode = "UPC002", + ModelNumber = "MODEL002", + CommodityCode = "COMMODITY002", + ItemLine = 2, + ItemGroup = 2, + ItemType = 2, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 2, + SupplierCode = "SUPPLIER002", + SupplierPartNumber = "PART002" + }; + + var order1 = new Order + { + Reference = "Order 1", + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 2, Item = item1 } + } + }; + + var order2 = new Order + { + Reference = "Order 2", + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM002", Amount = 3, Item = item2 } + } + }; + + _dbContext.Items.AddRange(item1, item2); + _dbContext.Orders.AddRange(order1, order2); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetAllOrdersWithItems(); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + + var resultOrder1 = result.First(o => o.Reference == "Order 1"); + Assert.AreEqual(1, resultOrder1.Items.Count); + Assert.AreEqual("ITEM001", resultOrder1.Items[0].ItemId); + + var resultOrder2 = result.First(o => o.Reference == "Order 2"); + Assert.AreEqual(1, resultOrder2.Items.Count); + Assert.AreEqual("ITEM002", resultOrder2.Items[0].ItemId); + } + + [TestMethod] + public async Task GetAllOrdersWithItems_ShouldReturnEmptyList_WhenNoOrdersExist() + { + // Act + var result = await _orderService.GetAllOrdersWithItems(); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task GetAllOrdersWithItems_ShouldIncludeOrdersWithoutItems() + { + // Arrange + var order1 = new Order + { + Reference = "Order 1", + OrderItems = new List() // No items + }; + + var order2 = new Order + { + Reference = "Order 2", + OrderItems = new List() // No items + }; + + _dbContext.Orders.AddRange(order1, order2); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetAllOrdersWithItems(); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + + var resultOrder1 = result.First(o => o.Reference == "Order 1"); + Assert.AreEqual(0, resultOrder1.Items.Count); + + var resultOrder2 = result.First(o => o.Reference == "Order 2"); + Assert.AreEqual(0, resultOrder2.Items.Count); + } + + [TestMethod] + public async Task GetOrderItems_ShouldReturnItemsForExistingOrder() + { + // Arrange + var item1 = new Item + { + Uid = "ITEM001", + Description = "Test Item 1", + Code = "CODE001", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + var item2 = new Item + { + Uid = "ITEM002", + Description = "Test Item 2", + Code = "CODE002", + ShortDescription = "Short Desc 2", + UpcCode = "UPC002", + ModelNumber = "MODEL002", + CommodityCode = "COMMODITY002", + ItemLine = 2, + ItemGroup = 2, + ItemType = 2, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 2, + SupplierCode = "SUPPLIER002", + SupplierPartNumber = "PART002" + }; + + var order = new Order + { + Id = 1, + Reference = "Test Order", + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 2, Item = item1 }, + new OrderItem { ItemUid = "ITEM002", Amount = 3, Item = item2 } + } + }; + + _dbContext.Items.AddRange(item1, item2); + _dbContext.Orders.Add(order); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrderItems(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + Assert.IsTrue(result.Any(i => i.ItemId == "ITEM001" && i.Amount == 2)); + Assert.IsTrue(result.Any(i => i.ItemId == "ITEM002" && i.Amount == 3)); + } + + [TestMethod] + public async Task GetOrderItems_ShouldReturnEmptyList_WhenOrderHasNoItems() + { + // Arrange + var order = new Order + { + Id = 1, + Reference = "Empty Order", + OrderItems = new List() // No items + }; + + _dbContext.Orders.Add(order); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrderItems(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task GetOrderItems_ShouldThrowException_WhenOrderDoesNotExist() + { + // Act & Assert + var exception = await Assert.ThrowsExceptionAsync(async () => + { + await _orderService.GetOrderItems(999999); + }); + + Assert.AreEqual("Order met ID 999999 niet gevonden.", exception.Message); + } + + [TestMethod] + public async Task GetOrdersClient_ShouldReturnOrdersForBillToClient() + { + // Arrange + _dbContext.Orders.AddRange(new List + { + new Order { Id = 1, BillTo = 1, Reference = "Order 1" }, + new Order { Id = 2, BillTo = 1, Reference = "Order 2" }, + new Order { Id = 3, ShipTo = 2, Reference = "Order 3" } + }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersCLient(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + Assert.IsTrue(result.Any(o => o.Reference == "Order 1")); + Assert.IsTrue(result.Any(o => o.Reference == "Order 2")); + } + + [TestMethod] + public async Task GetOrdersClient_ShouldReturnOrdersForShipToClient() + { + // Arrange + _dbContext.Orders.AddRange(new List + { + new Order { Id = 1, ShipTo = 1, Reference = "Order 1" }, + new Order { Id = 2, ShipTo = 1, Reference = "Order 2" }, + new Order { Id = 3, BillTo = 2, Reference = "Order 3" } + }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersCLient(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + Assert.IsTrue(result.Any(o => o.Reference == "Order 1")); + Assert.IsTrue(result.Any(o => o.Reference == "Order 2")); + } + + [TestMethod] + public async Task GetOrdersClient_ShouldReturnOrdersForBothBillToAndShipToClient() + { + // Arrange + _dbContext.Orders.AddRange(new List + { + new Order { Id = 1, BillTo = 1, Reference = "Order 1" }, + new Order { Id = 2, ShipTo = 1, Reference = "Order 2" }, + new Order { Id = 3, BillTo = 2, Reference = "Order 3" } + }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersCLient(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + Assert.IsTrue(result.Any(o => o.Reference == "Order 1")); + Assert.IsTrue(result.Any(o => o.Reference == "Order 2")); + } + + [TestMethod] + public async Task GetOrdersClient_ShouldReturnEmptyList_WhenClientHasNoOrders() + { + // Arrange + _dbContext.Orders.AddRange(new List + { + new Order { Id = 1, BillTo = 2, Reference = "Order 1" }, + new Order { Id = 2, ShipTo = 2, Reference = "Order 2" } + }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersCLient(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task GetOrdersClient_ShouldReturnEmptyList_WhenDatabaseIsEmpty() + { + // Act + var result = await _orderService.GetOrdersCLient(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task GetOrdersLinkedWithWarehouseId_ShouldReturnOrdersForGivenWarehouseId() + { + // Arrange + _dbContext.Orders.AddRange(new List + { + new Order { Id = 1, WarehouseId = 1, Reference = "Order 1" }, + new Order { Id = 2, WarehouseId = 1, Reference = "Order 2" }, + new Order { Id = 3, WarehouseId = 2, Reference = "Order 3" } + }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersLinkedWithWarehouseId(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + Assert.IsTrue(result.Any(o => o.Reference == "Order 1")); + Assert.IsTrue(result.Any(o => o.Reference == "Order 2")); + } + + [TestMethod] + public async Task GetOrdersLinkedWithWarehouseId_ShouldReturnEmptyList_WhenWarehouseIdDoesNotExist() + { + // Arrange + _dbContext.Orders.Add(new Order { Id = 1, WarehouseId = 2, Reference = "Order 1" }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersLinkedWithWarehouseId(999); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task GetOrdersLinkedWithSourceId_ShouldReturnOrdersForGivenSourceId() + { + // Arrange + _dbContext.Orders.AddRange(new List + { + new Order { Id = 1, SourceId = 1, Reference = "Order 1" }, + new Order { Id = 2, SourceId = 1, Reference = "Order 2" }, + new Order { Id = 3, SourceId = 2, Reference = "Order 3" } + }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersLinkedWithSourceId(1); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + Assert.IsTrue(result.Any(o => o.Reference == "Order 1")); + Assert.IsTrue(result.Any(o => o.Reference == "Order 2")); + } + + [TestMethod] + public async Task GetOrdersLinkedWithSourceId_ShouldReturnEmptyList_WhenSourceIdDoesNotExist() + { + // Arrange + _dbContext.Orders.Add(new Order { Id = 1, SourceId = 2, Reference = "Order 1" }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersLinkedWithSourceId(999); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task GetOrdersStatus_ShouldReturnOrdersWithGivenStatus() + { + // Arrange + _dbContext.Orders.AddRange(new List + { + new Order { Id = 1, OrderStatus = "Pending", Reference = "Order 1" }, + new Order { Id = 2, OrderStatus = "Completed", Reference = "Order 2" }, + new Order { Id = 3, OrderStatus = "Pending", Reference = "Order 3" } + }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersStatus("Pending"); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count); + Assert.IsTrue(result.Any(o => o.Reference == "Order 1")); + Assert.IsTrue(result.Any(o => o.Reference == "Order 3")); + } + + [TestMethod] + public async Task GetOrdersStatus_ShouldReturnEmptyList_WhenStatusDoesNotExist() + { + // Arrange + _dbContext.Orders.Add(new Order { Id = 1, OrderStatus = "Shipped", Reference = "Order 1" }); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.GetOrdersStatus("NonExistentStatus"); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task CreateOrder_ShouldAddOrderAndItemsToDatabase() + { + // Arrange + var item = new Item + { + Uid = "ITEM001", + Code = "CODE001", + Description = "Test Item 1", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + var inventory = new Inventory + { + ItemId = "ITEM001", + TotalAvailable = 10, + TotalAllocated = 0, + Description = "Test Inventory", + ItemReference = "ITEMREF001", + LocationIds = new List { 1, 2 }, + TotalOnHand = 10, + TotalExpected = 5, + TotalOrdered = 15 + }; + + _dbContext.Items.Add(item); + _dbContext.Inventory.Add(inventory); + await _dbContext.SaveChangesAsync(); + + var order = new Order { Reference = "Test Order", TotalAmount = 100.0 }; + var itemDTOs = new List { new ItemDTO { ItemId = "ITEM001", Amount = 6 } }; + + // Act + var result = await _orderService.CreateOrder(order, itemDTOs); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("Test Order", result.Reference); + + var savedOrder = await _dbContext.Orders.Include(o => o.OrderItems).FirstOrDefaultAsync(o => o.Id == result.Id); + Assert.IsNotNull(savedOrder); + Assert.AreEqual(1, savedOrder.OrderItems.Count); + Assert.AreEqual("ITEM001", savedOrder.OrderItems.First().ItemUid); + + var updatedInventory = await _dbContext.Inventory.FirstOrDefaultAsync(i => i.ItemId == "ITEM001"); + Assert.IsNotNull(updatedInventory); + Assert.AreEqual(4, updatedInventory.TotalAvailable); + Assert.AreEqual(6, updatedInventory.TotalAllocated); + } + + [TestMethod] + public async Task CreateOrder_ShouldThrowException_WhenItemDoesNotExist() + { + // Arrange + var order = new Order { Reference = "Test Order" }; + var itemDTOs = new List { new ItemDTO { ItemId = "NonExistentItem", Amount = 1 } }; + + // Act & Assert + var exception = await Assert.ThrowsExceptionAsync(async () => + { + await _orderService.CreateOrder(order, itemDTOs); + }); + + Assert.AreEqual("Item met Uid NonExistentItem bestaat niet.", exception.Message); + } + + [TestMethod] + public async Task CreateOrder_ShouldThrowException_WhenAmountLessThanPackOrderQuantity() + { + // Arrange + var item = new Item + { + Uid = "ITEM001", + Code = "CODE001", + Description = "Test Item 1", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + _dbContext.Items.Add(item); + await _dbContext.SaveChangesAsync(); + + var order = new Order { Reference = "Test Order" }; + var itemDTOs = new List { new ItemDTO { ItemId = "ITEM001", Amount = 4 } }; + + // Act & Assert + var exception = await Assert.ThrowsExceptionAsync(async () => + { + await _orderService.CreateOrder(order, itemDTOs); + }); + + Assert.AreEqual("Hoeveelheid voor item ITEM001 moet minimaal 5 zijn.", exception.Message); + } + + [TestMethod] + public async Task CreateOrder_ShouldThrowException_WhenAmountNotMultipleOfUnitOrderQuantity() + { + // Arrange + var item = new Item + { + Uid = "ITEM001", + Code = "CODE001", + Description = "Test Item 1", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + _dbContext.Items.Add(item); + await _dbContext.SaveChangesAsync(); + + var order = new Order { Reference = "Test Order" }; + var itemDTOs = new List { new ItemDTO { ItemId = "ITEM001", Amount = 7 } }; + + // Act & Assert + var exception = await Assert.ThrowsExceptionAsync(async () => + { + await _orderService.CreateOrder(order, itemDTOs); + }); + + Assert.AreEqual("Hoeveelheid voor item ITEM001 moet een veelvoud zijn van 2.", exception.Message); + } + + [TestMethod] + public async Task CreateOrder_ShouldThrowException_WhenInventoryDoesNotExist() + { + // Arrange + var item = new Item + { + Uid = "ITEM001", + Code = "CODE001", + Description = "Test Item 1", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + _dbContext.Items.Add(item); + await _dbContext.SaveChangesAsync(); + + var order = new Order { Reference = "Test Order" }; + var itemDTOs = new List { new ItemDTO { ItemId = "ITEM001", Amount = 6 } }; + + // Act & Assert + var exception = await Assert.ThrowsExceptionAsync(async () => + { + await _orderService.CreateOrder(order, itemDTOs); + }); + + Assert.AreEqual("Geen inventaris gevonden voor item met Uid ITEM001.", exception.Message); + } + + [TestMethod] + public async Task CreateOrder_ShouldThrowException_WhenInsufficientInventory() + { + // Arrange + var item = new Item + { + Uid = "ITEM001", + Code = "CODE001", + Description = "Test Item 1", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + var inventory = new Inventory + { + ItemId = "ITEM001", + TotalAvailable = 4, + TotalAllocated = 0, + Description = "Test Inventory", + ItemReference = "ITEMREF001", + LocationIds = new List { 1, 2 }, + TotalOnHand = 4, + TotalExpected = 0, + TotalOrdered = 4 + }; + + _dbContext.Items.Add(item); + _dbContext.Inventory.Add(inventory); + await _dbContext.SaveChangesAsync(); + + var order = new Order { Reference = "Test Order" }; + var itemDTOs = new List { new ItemDTO { ItemId = "ITEM001", Amount = 6 } }; + + // Act & Assert + var exception = await Assert.ThrowsExceptionAsync(async () => + { + await _orderService.CreateOrder(order, itemDTOs); + }); + + Assert.AreEqual("Niet genoeg voorraad voor item met Uid ITEM001. Beschikbaar: 4, gevraagd: 6", exception.Message); + } + + [TestMethod] + public async Task UpdateOrder_ShouldUpdateOrderFieldsAndItems() + { + // Arrange + var order = new Order + { + Reference = "Test Order", + TotalAmount = 100.0, + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 2 }, + new OrderItem { ItemUid = "ITEM002", Amount = 3 } + } + }; + + _dbContext.Orders.Add(order); + + _dbContext.Items.AddRange(new List + { + new Item + { + Uid = "ITEM001", + Code = "CODE001", + Description = "Test Item 1", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 1, + PackOrderQuantity = 1, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }, + new Item + { + Uid = "ITEM002", + Code = "CODE002", + Description = "Test Item 2", + ShortDescription = "Short Desc 2", + UpcCode = "UPC002", + ModelNumber = "MODEL002", + CommodityCode = "COMMODITY002", + ItemLine = 2, + ItemGroup = 2, + ItemType = 2, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 1, + PackOrderQuantity = 1, + SupplierId = 2, + SupplierCode = "SUPPLIER002", + SupplierPartNumber = "PART002" + }, + new Item + { + Uid = "ITEM003", + Code = "CODE003", + Description = "Test Item 3", + ShortDescription = "Short Desc 3", + UpcCode = "UPC003", + ModelNumber = "MODEL003", + CommodityCode = "COMMODITY003", + ItemLine = 3, + ItemGroup = 3, + ItemType = 3, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 4, + SupplierId = 3, + SupplierCode = "SUPPLIER003", + SupplierPartNumber = "PART003" + } + }); + + _dbContext.Inventory.AddRange(new List + { + new Inventory { ItemId = "ITEM001", TotalAvailable = 10, TotalAllocated = 2, Description = "Description 1", ItemReference = "Reference 1", LocationIds = new List { 1 }, TotalOnHand = 10, TotalExpected = 0, TotalOrdered = 10 }, + new Inventory { ItemId = "ITEM002", TotalAvailable = 7, TotalAllocated = 3, Description = "Description 2", ItemReference = "Reference 2", LocationIds = new List { 2 }, TotalOnHand = 7, TotalExpected = 0, TotalOrdered = 7 }, + new Inventory { ItemId = "ITEM003", TotalAvailable = 8, TotalAllocated = 0, Description = "Description 3", ItemReference = "Reference 3", LocationIds = new List { 3 }, TotalOnHand = 8, TotalExpected = 0, TotalOrdered = 8 } + }); + + await _dbContext.SaveChangesAsync(); + + var updatedOrderDto = new OrderWithItemsDTO + { + Reference = "Updated Order", + TotalAmount = 150.0, + Items = new List + { + new ItemDTO { ItemId = "ITEM001", Amount = 3 }, + new ItemDTO { ItemId = "ITEM003", Amount = 4 } + } + }; + + // Act + var result = await _orderService.UpdateOrder(order.Id, updatedOrderDto); + + // Assert + Assert.AreEqual($"Order met ID {order.Id} is succesvol bijgewerkt.", result); + + var updatedOrder = await _dbContext.Orders.Include(o => o.OrderItems).FirstOrDefaultAsync(o => o.Id == order.Id); + Assert.IsNotNull(updatedOrder); + Assert.AreEqual("Updated Order", updatedOrder.Reference); + Assert.AreEqual(150.0, updatedOrder.TotalAmount); + + // Debug and verify item allocations + var inventory1 = await _dbContext.Inventory.FirstAsync(i => i.ItemId == "ITEM001"); + var inventory3 = await _dbContext.Inventory.FirstAsync(i => i.ItemId == "ITEM003"); + + Console.WriteLine($"ITEM001 - TotalAllocated: {inventory1.TotalAllocated}, TotalAvailable: {inventory1.TotalAvailable}"); + Console.WriteLine($"ITEM003 - TotalAllocated: {inventory3.TotalAllocated}, TotalAvailable: {inventory3.TotalAvailable}"); + + Assert.AreEqual(9, inventory1.TotalAllocated); // Adjustment: +1 + Assert.AreEqual(6, inventory3.TotalAllocated); // Adjustment: +4 + Assert.AreEqual(9, inventory1.TotalAvailable); // Adjustment: -1 + Assert.AreEqual(4, inventory3.TotalAvailable); // Adjustment: -4 + } + + + [TestMethod] + public async Task UpdateOrder_ShouldReturnError_WhenOrderDoesNotExist() + { + // Arrange + var updatedOrderDto = new OrderWithItemsDTO + { + Reference = "Updated Order", + Items = new List { new ItemDTO { ItemId = "ITEM001", Amount = 2 } } + }; + + // Act + var result = await _orderService.UpdateOrder(999, updatedOrderDto); + + // Assert + Assert.AreEqual("Order met ID 999 is niet gevonden.", result); + } + + [TestMethod] + public async Task UpdateItemsInOrder_ShouldReturnError_WhenItemDoesNotExist() + { + // Arrange + var order = new Order + { + Reference = "Test Order", + TotalAmount = 100.0 + }; + + _dbContext.Orders.Add(order); + await _dbContext.SaveChangesAsync(); + + var itemDTOs = new List + { + new ItemDTO { ItemId = "NonExistentItem", Amount = 1 } + }; + + // Act + var result = await _orderService.UpdateItemsInOrder(order.Id, itemDTOs); + + // Assert + Assert.AreEqual("Item met ID NonExistentItem is niet gevonden.", result); + } + + [TestMethod] + public async Task UpdateItemsInOrder_ShouldAddNewItemAndAdjustInventory() + { + // Arrange + var order = new Order + { + Reference = "Test Order", + TotalAmount = 100.0, + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 2 } + } + }; + + _dbContext.Orders.Add(order); + + _dbContext.Items.AddRange(new List + { + new Item + { + Uid = "ITEM001", + Code = "CODE001", + Description = "Test Item 1", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 1, + PackOrderQuantity = 1, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }, + new Item + { + Uid = "ITEM003", + Code = "CODE003", + Description = "Test Item 3", + ShortDescription = "Short Desc 3", + UpcCode = "UPC003", + ModelNumber = "MODEL003", + CommodityCode = "COMMODITY003", + ItemLine = 3, + ItemGroup = 3, + ItemType = 3, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 1, + PackOrderQuantity = 1, + SupplierId = 3, + SupplierCode = "SUPPLIER003", + SupplierPartNumber = "PART003" + } + }); + + _dbContext.Inventory.AddRange(new List + { + new Inventory { ItemId = "ITEM001", TotalAvailable = 8, TotalAllocated = 2, Description = "Description 1", ItemReference = "Reference 1", LocationIds = new List { 1 }, TotalOnHand = 10, TotalExpected = 0, TotalOrdered = 10 }, + new Inventory { ItemId = "ITEM003", TotalAvailable = 5, TotalAllocated = 0, Description = "Description 3", ItemReference = "Reference 3", LocationIds = new List { 3 }, TotalOnHand = 8, TotalExpected = 0, TotalOrdered = 8 } + }); + + await _dbContext.SaveChangesAsync(); + + var itemDTOs = new List + { + new ItemDTO { ItemId = "ITEM003", Amount = 3 } + }; + + // Act + var result = await _orderService.UpdateItemsInOrder(order.Id, itemDTOs); + + // Assert + Assert.AreEqual($"Order met ID {order.Id} is succesvol bijgewerkt.", result); + + var updatedOrder = await _dbContext.Orders.Include(o => o.OrderItems).FirstOrDefaultAsync(o => o.Id == order.Id); + Assert.AreEqual(2, updatedOrder.OrderItems.Count); + Assert.AreEqual(3, updatedOrder.OrderItems.First(i => i.ItemUid == "ITEM003").Amount); + + var inventory3 = await _dbContext.Inventory.FirstAsync(i => i.ItemId == "ITEM003"); + Assert.AreEqual(2, inventory3.TotalAvailable); + Assert.AreEqual(3, inventory3.TotalAllocated); + } + + [TestMethod] + public async Task UpdateItemsInOrder_ShouldRemoveItemAndRestoreInventory() + { + // Arrange + var order = new Order + { + Reference = "Test Order", + TotalAmount = 100.0, + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 5 } + } + }; + + _dbContext.Orders.Add(order); + + _dbContext.Inventory.Add(new Inventory + { + ItemId = "ITEM001", + TotalAvailable = 5, + TotalAllocated = 5, + Description = "Description", + ItemReference = "Reference", + LocationIds = new List { 1 }, + TotalOnHand = 10, + TotalExpected = 0, + TotalOrdered = 10 + }); + + await _dbContext.SaveChangesAsync(); + + var itemDTOs = new List(); // No items provided means removing all current items + + // Act + var result = await _orderService.UpdateItemsInOrder(order.Id, itemDTOs); + + // Assert + Assert.AreEqual($"Order met ID {order.Id} is succesvol bijgewerkt.", result); + + var updatedOrder = await _dbContext.Orders.Include(o => o.OrderItems).FirstOrDefaultAsync(o => o.Id == order.Id); + Assert.AreEqual(0, updatedOrder.OrderItems.Count); + + var inventory1 = await _dbContext.Inventory.FirstAsync(i => i.ItemId == "ITEM001"); + Assert.AreEqual(10, inventory1.TotalAvailable); + Assert.AreEqual(0, inventory1.TotalAllocated); + } + + [TestMethod] + public async Task DeleteOrder_ShouldRemoveOrderAndRestoreInventory() + { + // Arrange + var item1 = new Item + { + Uid = "ITEM001", + Description = "Test Item 1", + Code = "CODE001", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + var item2 = new Item + { + Uid = "ITEM002", + Description = "Test Item 2", + Code = "CODE002", + ShortDescription = "Short Desc 2", + UpcCode = "UPC002", + ModelNumber = "MODEL002", + CommodityCode = "COMMODITY002", + ItemLine = 2, + ItemGroup = 2, + ItemType = 2, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 2, + SupplierCode = "SUPPLIER002", + SupplierPartNumber = "PART002" + }; + _dbContext.Items.AddRange(item1, item2); + + var inventory1 = new Inventory + { + ItemId = "ITEM001", + TotalAvailable = 5, + TotalAllocated = 5, + Description = "Description for ITEM001", + ItemReference = "Reference for ITEM001", + LocationIds = new List { 1 }, + TotalOnHand = 10, + TotalExpected = 0, + TotalOrdered = 10 + }; + var inventory2 = new Inventory + { + ItemId = "ITEM002", + TotalAvailable = 2, + TotalAllocated = 3, + Description = "Description for ITEM002", + ItemReference = "Reference for ITEM002", + LocationIds = new List { 2 }, + TotalOnHand = 5, + TotalExpected = 0, + TotalOrdered = 5 + }; + _dbContext.Inventory.AddRange(inventory1, inventory2); + + var order = new Order + { + Reference = "Order to Delete", + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 5 }, + new OrderItem { ItemUid = "ITEM002", Amount = 3 } + } + }; + _dbContext.Orders.Add(order); + + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.DeleteOrder(order.Id); + + // Assert + Assert.IsTrue(result); + + // Controleer dat de order is verwijderd + var deletedOrder = await _dbContext.Orders.FindAsync(order.Id); + Assert.IsNull(deletedOrder); + + // Controleer dat de voorraad is hersteld + var updatedInventory1 = await _dbContext.Inventory.FirstAsync(i => i.ItemId == "ITEM001"); + var updatedInventory2 = await _dbContext.Inventory.FirstAsync(i => i.ItemId == "ITEM002"); + Assert.AreEqual(10, updatedInventory1.TotalAvailable); + Assert.AreEqual(0, updatedInventory1.TotalAllocated); + Assert.AreEqual(5, updatedInventory2.TotalAvailable); + Assert.AreEqual(0, updatedInventory2.TotalAllocated); + } + + [TestMethod] + public async Task DeleteOrder_ShouldReturnFalse_WhenOrderDoesNotExist() + { + // Act + var result = await _orderService.DeleteOrder(999); + + // Assert + Assert.IsFalse(result); + } + + [TestMethod] + public async Task DeleteOrder_ShouldNotAdjustInventory_WhenNoItemsExist() + { + // Arrange + var order = new Order + { + Reference = "Order to Delete" + }; + _dbContext.Orders.Add(order); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.DeleteOrder(order.Id); + + // Assert + Assert.IsTrue(result); + + // Controleer dat de order is verwijderd + var deletedOrder = await _dbContext.Orders.FindAsync(order.Id); + Assert.IsNull(deletedOrder); + + // Controleer dat er geen wijzigingen zijn in de inventaris + var inventoryCount = await _dbContext.Inventory.CountAsync(); + Assert.AreEqual(0, inventoryCount); + } + + [TestMethod] + public async Task DeleteOrder_ShouldHandlePartialInventoryRestoration() + { + // Arrange + var item1 = new Item + { + Uid = "ITEM001", + Description = "Test Item 1", + Code = "CODE001", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + _dbContext.Items.Add(item1); + + var inventory1 = new Inventory + { + ItemId = "ITEM001", + TotalAvailable = 5, + TotalAllocated = 5, + Description = "Description for ITEM001", + ItemReference = "Reference for ITEM001", + LocationIds = new List { 1 }, + TotalOnHand = 10, + TotalExpected = 0, + TotalOrdered = 10 + }; + _dbContext.Inventory.Add(inventory1); + + var order = new Order + { + Reference = "Order to Delete", + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 3 } + } + }; + _dbContext.Orders.Add(order); + + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.DeleteOrder(order.Id); + + // Assert + Assert.IsTrue(result); + + // Controleer dat de voorraad correct is hersteld + var updatedInventory1 = await _dbContext.Inventory.FirstAsync(i => i.ItemId == "ITEM001"); + Assert.AreEqual(8, updatedInventory1.TotalAvailable); + Assert.AreEqual(2, updatedInventory1.TotalAllocated); + } + + [TestMethod] + public async Task DeleteOrder_ShouldHandleNegativeAllocatedInventorySafely() + { + // Arrange + var item1 = new Item + { + Uid = "ITEM001", + Description = "Test Item 1", + Code = "CODE001", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 1, + UnitOrderQuantity = 2, + PackOrderQuantity = 5, + SupplierId = 1, + SupplierCode = "SUPPLIER001", + SupplierPartNumber = "PART001" + }; + _dbContext.Items.Add(item1); + + var inventory1 = new Inventory + { + ItemId = "ITEM001", + TotalAvailable = 5, + TotalAllocated = 1, + Description = "Description for ITEM001", + ItemReference = "Reference for ITEM001", + LocationIds = new List { 1 }, + TotalOnHand = 10, + TotalExpected = 0, + TotalOrdered = 10 + }; + _dbContext.Inventory.Add(inventory1); + + var order = new Order + { + Reference = "Order to Delete", + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 3 } + } + }; + _dbContext.Orders.Add(order); + + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _orderService.DeleteOrder(order.Id); + + // Assert + Assert.IsTrue(result); + + // Controleer dat de allocatie nooit negatief is + var updatedInventory1 = await _dbContext.Inventory.FirstAsync(i => i.ItemId == "ITEM001"); + Assert.AreEqual(8, updatedInventory1.TotalAvailable); + Assert.AreEqual(0, updatedInventory1.TotalAllocated); + } + + + + + } +} diff --git a/UnitTest/Test_Shipments.cs b/UnitTest/Test_Shipments.cs new file mode 100644 index 0000000..ed1ac00 --- /dev/null +++ b/UnitTest/Test_Shipments.cs @@ -0,0 +1,385 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using CargoHub.Services; +using CargoHub.Models; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace CargoHub.Tests +{ + [TestClass] + public class ShipmentServiceTests + { + private AppDbContext _dbContext; + private ShipmentService _shipmentService; + + [TestInitialize] + public void Setup() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: "TestDatabase") + .Options; + + _dbContext = new AppDbContext(options); + _shipmentService = new ShipmentService(_dbContext); + } + + [TestCleanup] + public void Cleanup() + { + _dbContext.Database.EnsureDeleted(); + _dbContext.Dispose(); + } + + [TestMethod] + public async Task GetAllShipmentsWithItems_ShouldReturnShipments() + { + // Arrange: Voeg eerst de items toe aan de database + _dbContext.Items.Add(new Item + { + Uid = "ITEM001", + Description = "Test Item 1", + UnitOrderQuantity = 100, + Code = "CODE001", + ShortDescription = "Short Desc 1", + UpcCode = "UPC001", + ModelNumber = "MODEL001", + CommodityCode = "COMMODITY001", + ItemLine = 1, + ItemGroup = 1, + ItemType = 1, + UnitPurchaseQuantity = 50, + PackOrderQuantity = 10, + SupplierId = 1, + SupplierCode = "SUP001", + SupplierPartNumber = "PART001" + }); + _dbContext.Items.Add(new Item + { + Uid = "ITEM002", + Description = "Test Item 2", + UnitOrderQuantity = 100, + Code = "CODE002", + ShortDescription = "Short Desc 2", + UpcCode = "UPC002", + ModelNumber = "MODEL002", + CommodityCode = "COMMODITY002", + ItemLine = 2, + ItemGroup = 2, + ItemType = 2, + UnitPurchaseQuantity = 60, + PackOrderQuantity = 15, + SupplierId = 2, + SupplierCode = "SUP002", + SupplierPartNumber = "PART002" + }); + await _dbContext.SaveChangesAsync(); // Zorg ervoor dat de items eerst worden opgeslagen + + // Voeg een zending met orders en orderitems toe + _dbContext.Shipments.Add(new Shipment + { + ShipmentDate = DateTime.UtcNow, + ShipmentType = "Standard", + ShipmentStatus = "Pending", + Notes = "Test shipment", + orders = new List + { + new Order + { + Reference = "ORD001", + OrderItems = new List + { + new OrderItem { ItemUid = "ITEM001", Amount = 5 }, + new OrderItem { ItemUid = "ITEM002", Amount = 3 } + } + } + } + }); + await _dbContext.SaveChangesAsync(); // Sla de zending met gekoppelde data op + + // Act: Roep de methode aan + var result = await _shipmentService.GetAllShipmentsWithItems(); + + // Assert: Controleer of de data correct is geretourneerd + Assert.IsNotNull(result); + Assert.AreEqual(1, result.Count); // Controleer dat er één zending is + Assert.AreEqual("Standard", result[0].ShipmentType); // Controleer het type + Assert.AreEqual(2, result[0].Orders.First().Items.Count); // Controleer dat er 2 items zijn + Assert.AreEqual("ITEM001", result[0].Orders.First().Items.First().ItemId); // Controleer het eerste item + Assert.AreEqual(5, result[0].Orders.First().Items.First().Amount); // Controleer de hoeveelheid van het eerste item + } + + + [TestMethod] + public async Task GetShipmentByIdWithOrderDetails_ShouldReturnCorrectShipment() + { + // Arrange + var shipment = new Shipment + { + ShipmentDate = DateTime.UtcNow, + ShipmentType = "Express", + ShipmentStatus = "Delivered", + Notes = "Urgent", + CarrierCode = "C456", + CarrierDescription = "Premium Carrier", + orders = new List + { + new Order + { + Reference = "ORD002", + OrderDate = DateTime.UtcNow, + RequestDate = DateTime.UtcNow.AddDays(1), + OrderStatus = "Delivered" + } + } + }; + + _dbContext.Shipments.Add(shipment); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _shipmentService.GetShipmentByIdWithOrderDetails(shipment.Id); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(shipment.Id, result.Id); + Assert.AreEqual("Express", result.ShipmentType); + Assert.AreEqual("ORD002", result.Orders.First().Reference); + } + + [TestMethod] + public async Task CreateShipment_ShouldAddShipmentToDatabase() + { + // Arrange + var shipment = new Shipment + { + ShipmentDate = DateTime.UtcNow, + ShipmentType = "Economy", + ShipmentStatus = "Pending", + Notes = "No rush", + CarrierCode = "C789", + TotalPackageCount = 20, + TotalPackageWeight = 100.0 + }; + + // Act + var result = await _shipmentService.CreateShipment(shipment); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("Economy", result.ShipmentType); + Assert.AreEqual(1, _dbContext.Shipments.Count()); + } + + [TestMethod] + public async Task DeleteShipment_ShouldRemoveShipment() + { + // Arrange + var shipment = new Shipment + { + ShipmentDate = DateTime.UtcNow, + ShipmentType = "Freight", + ShipmentStatus = "Completed" + }; + + _dbContext.Shipments.Add(shipment); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _shipmentService.DeleteShipment(shipment.Id); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(0, _dbContext.Shipments.Count()); + } + + [TestMethod] + public async Task DeleteShipment_ShouldRemoveShipmentAndUnlinkOrders() + { + // Arrange: Voeg een zending met gekoppelde orders toe + var shipment = new Shipment + { + ShipmentDate = DateTime.UtcNow, + ShipmentType = "Freight", + ShipmentStatus = "Completed", + orders = new List + { + new Order { Reference = "ORD001", OrderStatus = "Packed", ShipmentId = 1 }, + new Order { Reference = "ORD002", OrderStatus = "Packed", ShipmentId = 1 } + } + }; + + _dbContext.Shipments.Add(shipment); + await _dbContext.SaveChangesAsync(); + + // Act: Verwijder de zending + var result = await _shipmentService.DeleteShipment(shipment.Id); + + // Assert: Controleer of de zending is verwijderd + Assert.IsTrue(result); + Assert.AreEqual(0, _dbContext.Shipments.Count()); + + // Controleer of de orders zijn losgekoppeld van de zending + var orders = await _dbContext.Orders.ToListAsync(); + foreach (var order in orders) + { + Assert.IsNull(order.ShipmentId); + Assert.AreEqual("Scheduled", order.OrderStatus); + } + } + + [TestMethod] + public async Task UpdateShipmentFields_ShouldUpdateFields_WhenShipmentExists() + { + // Arrange + var shipment = new Shipment + { + Id = 1, + ShipmentStatus = "Pending", + ShipmentType = "Air" + }; + + _dbContext.Shipments.Add(shipment); + await _dbContext.SaveChangesAsync(); + + var updatedShipmentDto = new ShipmentDTO + { + ShipmentStatus = "Transit", + ShipmentType = "Sea", + Notes = "Updated shipment details", + TotalPackageCount = 10, + TotalPackageWeight = 50.0 + }; + + // Act + var result = await _shipmentService.UpdateShipmentFields(1, updatedShipmentDto); + + // Assert + Assert.AreEqual("Shipment met ID 1 is succesvol bijgewerkt.", result); + var updatedShipment = await _dbContext.Shipments.FindAsync(1); + Assert.AreEqual("Transit", updatedShipment.ShipmentStatus); + Assert.AreEqual("Sea", updatedShipment.ShipmentType); + Assert.AreEqual(10, updatedShipment.TotalPackageCount); + Assert.AreEqual(50.0, updatedShipment.TotalPackageWeight); + } + + [TestMethod] + public async Task UpdateShipmentFields_ShouldThrowException_WhenUpdatingToPendingFromTransitOrDelivered() + { + // Arrange + var shipment = new Shipment + { + Id = 1, + ShipmentStatus = "Transit" + }; + + _dbContext.Shipments.Add(shipment); + await _dbContext.SaveChangesAsync(); + + var updatedShipmentDto = new ShipmentDTO + { + ShipmentStatus = "Pending" + }; + + // Act & Assert + await Assert.ThrowsExceptionAsync( + () => _shipmentService.UpdateShipmentFields(1, updatedShipmentDto) + ); + } + + [TestMethod] + public async Task UpdateOrdersInShipment_ShouldUpdateOrders_WhenOrdersExist() + { + // Arrange + var shipment = new Shipment { Id = 1 }; + + var order1 = new Order { Id = 1, ShipmentId = 1, OrderStatus = "Packed" }; + var order2 = new Order { Id = 2, ShipmentId = 1, OrderStatus = "Packed" }; + var order3 = new Order { Id = 3 }; + + _dbContext.Shipments.Add(shipment); + _dbContext.Orders.AddRange(order1, order2, order3); + await _dbContext.SaveChangesAsync(); + + var newOrderIds = new List { 3 }; + + // Act + var result = await _shipmentService.UpdateOrdersInShipment(1, newOrderIds); + + // Assert + Assert.IsTrue(result); + + var updatedOrder1 = await _dbContext.Orders.FindAsync(1); + var updatedOrder2 = await _dbContext.Orders.FindAsync(2); + var updatedOrder3 = await _dbContext.Orders.FindAsync(3); + + Assert.IsNull(updatedOrder1.ShipmentId); + Assert.AreEqual("Scheduled", updatedOrder1.OrderStatus); + + Assert.IsNull(updatedOrder2.ShipmentId); + Assert.AreEqual("Scheduled", updatedOrder2.OrderStatus); + + Assert.AreEqual(1, updatedOrder3.ShipmentId); + Assert.AreEqual("Packed", updatedOrder3.OrderStatus); + } + + [TestMethod] + public async Task UpdateOrdersInShipment_ShouldReturnTrue_WhenNoChangesNeeded() + { + // Arrange + var shipment = new Shipment { Id = 1 }; + var order = new Order { Id = 1, ShipmentId = 1, OrderStatus = "Packed" }; + + _dbContext.Shipments.Add(shipment); + _dbContext.Orders.Add(order); + await _dbContext.SaveChangesAsync(); + + var orderIds = new List { 1 }; + + // Act + var result = await _shipmentService.UpdateOrdersInShipment(1, orderIds); + + // Assert + Assert.IsTrue(result); + var updatedOrder = await _dbContext.Orders.FindAsync(1); + Assert.AreEqual(1, updatedOrder.ShipmentId); + Assert.AreEqual("Packed", updatedOrder.OrderStatus); + } + + + + [TestMethod] + public async Task AssignOrdersToShipment_ShouldLinkOrdersToShipment() + { + // Arrange + var shipment = new Shipment + { + ShipmentDate = DateTime.UtcNow, + ShipmentType = "Ground", + ShipmentStatus = "Scheduled" + }; + + var orders = new List + { + new Order { Reference = "ORD003", OrderDate = DateTime.UtcNow }, + new Order { Reference = "ORD004", OrderDate = DateTime.UtcNow } + }; + + _dbContext.Shipments.Add(shipment); + _dbContext.Orders.AddRange(orders); + await _dbContext.SaveChangesAsync(); + + var orderIds = orders.Select(o => o.Id).ToList(); + + // Act + var result = await _shipmentService.AssignOrdersToShipment(shipment.Id, orderIds); + + // Assert + Assert.IsTrue(result); + var updatedOrders = await _dbContext.Orders.Where(o => o.ShipmentId == shipment.Id).ToListAsync(); + Assert.AreEqual(2, updatedOrders.Count); + } + } +} diff --git a/daily_log.txt b/daily_log.txt new file mode 100644 index 0000000..a2cafd4 Binary files /dev/null and b/daily_log.txt differ diff --git a/data/orders.json b/data/orders.json index 5b8267d..6f1efdf 100644 --- a/data/orders.json +++ b/data/orders.json @@ -1,4 +1,4 @@ -aardappel[ +[ { "id": 1, "source_id": 33, diff --git a/detailed_commits.txt b/detailed_commits.txt new file mode 100644 index 0000000..eeb93a0 Binary files /dev/null and b/detailed_commits.txt differ diff --git a/my_commits.txt b/my_commits.txt new file mode 100644 index 0000000..f61b8f0 Binary files /dev/null and b/my_commits.txt differ