diff --git a/FruitBank.Common.Server/FruitBankConst.cs b/FruitBank.Common.Server/FruitBankConst.cs index 4c4d2a9e..c60e6ca0 100644 --- a/FruitBank.Common.Server/FruitBankConst.cs +++ b/FruitBank.Common.Server/FruitBankConst.cs @@ -19,13 +19,13 @@ namespace FruitBank.Common.Server /// DateTime generic attribute on Product. /// The start of the window during which this product is visible for preordering. /// - public const string PreorderWindowStart = "PreorderWindowStart"; + public const string PreOrderWindowStart = "PreOrderWindowStart"; /// /// DateTime generic attribute on Product. /// The end of the window during which this product is visible for preordering. /// - public const string PreorderWindowEnd = "PreorderWindowEnd"; + public const string PreOrderWindowEnd = "PreOrderWindowEnd"; static FruitBankConst() { diff --git a/FruitBank.Common/Entities/CargoTruck.cs b/FruitBank.Common/Entities/CargoTruck.cs index bc4524ba..f9f791db 100644 --- a/FruitBank.Common/Entities/CargoTruck.cs +++ b/FruitBank.Common/Entities/CargoTruck.cs @@ -1,4 +1,5 @@ using AyCode.Core.Serializers.Attributes; +using FruitBank.Common.Interfaces; using LinqToDB.Mapping; using Mango.Nop.Core.Entities; @@ -8,10 +9,17 @@ namespace FruitBank.Common.Entities; //[ToonDescription("Business partner with address and tax information", Purpose = "Represents an external legal entity, specifically a Supplier who provides goods or a business partner involved in the procurement chain")] [Table(Name = FruitBankConstClient.CargoTruckDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.CargoTruckDbTableName)] -public sealed class CargoTruck: MgEntityBase//, ICargoPartner +public sealed class CargoTruck: MgEntityBase, ICargoTruck { public int CargoPartnerId { get; set; } + + [Association(ThisKey = nameof(CargoPartnerId), OtherKey = nameof(CargoPartner.Id), CanBeNull = true)] + public CargoPartner CargoPartner { get; set; } + public string CountryCode { get; set; } public string LicencePlate { get; set; } + public bool IsTrailer { get; set; } + public DateTime Created { get; set; } + public DateTime Modified { get; set; } } diff --git a/FruitBank.Common/Entities/Preorder.cs b/FruitBank.Common/Entities/Preorder.cs index a9c987be..a16e9fa7 100644 --- a/FruitBank.Common/Entities/Preorder.cs +++ b/FruitBank.Common/Entities/Preorder.cs @@ -9,17 +9,26 @@ namespace FruitBank.Common.Entities; [AcBinarySerializable(false, true, false, true, false, false)] [Table(Name = FruitBankConstClient.PreOrderDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.PreOrderDbTableName)] -//[ToonDescription("Shipping document with partner, items and files", Purpose = "A digital representation of a supplier's delivery note or invoice associated with the shipment, used for reconciling paper-based data with measured reality")] -public sealed class Preorder : MgEntityBase +[ToonDescription("Customer advance order placed before the goods physically arrive", Purpose = "Header of a customer pre-order against an upcoming inbound delivery. Pending items are allocated from incoming stock first-come-first-served by PreOrderId when a shipping document confirms arrival, then converted into a real NopCommerce Order once any quantity is fulfilled.")] +public sealed class PreOrder : MgEntityBase { public int CustomerId { get; set; } public int StoreId { get; set; } + + [ToonDescription(Purpose = "Requested delivery date. Drives the conversion window (only preorders within PreOrderConversionWindowDays of this date are eligible for allocation) and the expiry sweep — once this date is past, any still-Pending items are Dropped.")] public DateTime DateOfReceipt { get; set; } - public PreorderStatus Status { get; set; } + + [ToonDescription(Purpose = "Header lifecycle: Pending -> Confirmed (all items Fulfilled) / PartiallyFulfilled (some Dropped or partial, none left Pending) / Cancelled.")] + public PreOrderStatus Status { get; set; } + + [ToonDescription(Purpose = "Optional free-text note entered by the customer when placing the preorder.")] public string? CustomerNote { get; set; } + public DateTime CreatedOnUtc { get; set; } public DateTime UpdatedOnUtc { get; set; } + + [ToonDescription(Purpose = "FK to the real NopCommerce Order created from this preorder. Null until the first item is fulfilled; set once on first conversion and reused so subsequent shipping documents append items to the same order.")] public int? OrderId { get; set; } - public List PreorderItems { get; set; } = new(); + public List PreOrderItems { get; set; } = []; } diff --git a/FruitBank.Common/Entities/PreorderItem.cs b/FruitBank.Common/Entities/PreorderItem.cs index 54829345..9f8f8756 100644 --- a/FruitBank.Common/Entities/PreorderItem.cs +++ b/FruitBank.Common/Entities/PreorderItem.cs @@ -9,13 +9,21 @@ namespace FruitBank.Common.Entities; [AcBinarySerializable(false, true, false, true, false, false)] [Table(Name = FruitBankConstClient.PreOrderItemDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.PreOrderItemDbTableName)] -//[ToonDescription("Shipping document with partner, items and files", Purpose = "A digital representation of a supplier's delivery note or invoice associated with the shipment, used for reconciling paper-based data with measured reality")] -public sealed class PreorderItem : MgEntityBase +[ToonDescription("Single product line of a customer preorder with fulfilment tracking", Purpose = "A requested product line within a PreOrder. Tracks requested versus cumulatively fulfilled quantity as incoming stock is allocated across one or more shipping-document conversion runs.")] +public sealed class PreOrderItem : MgEntityBase { - public int PreorderId { get; set; } + public int PreOrderId { get; set; } public int ProductId { get; set; } + + [ToonDescription(Purpose = "Quantity of the product the customer requested.")] public int RequestedQuantity { get; set; } + + [ToonDescription(Purpose = "Quantity allocated from incoming stock so far; accumulates across conversion runs until it reaches RequestedQuantity.")] public int FulfilledQuantity { get; set; } + + [ToonDescription(Purpose = "Gross unit price locked at preorder time. Used as the order-item price on conversion for non-measurable products; measurable products are priced 0 at conversion and weighed afterwards.")] public decimal UnitPriceInclTax { get; set; } - public PreorderItemStatus Status { get; set; } + + [ToonDescription(Purpose = "Item lifecycle: Pending -> Fulfilled (fully allocated) / PartiallyFulfilled (partly allocated) / Dropped (expired or no incoming stock).")] + public PreOrderItemStatus Status { get; set; } } diff --git a/FruitBank.Common/Enums/PreorderItemStatus.cs b/FruitBank.Common/Enums/PreorderItemStatus.cs index 42d3a0de..009b67d6 100644 --- a/FruitBank.Common/Enums/PreorderItemStatus.cs +++ b/FruitBank.Common/Enums/PreorderItemStatus.cs @@ -1,6 +1,6 @@ namespace FruitBank.Common.Enums; -public enum PreorderItemStatus +public enum PreOrderItemStatus { Pending = 0, Fulfilled = 10, diff --git a/FruitBank.Common/Enums/PreorderStatus.cs b/FruitBank.Common/Enums/PreorderStatus.cs index 2b01a9c5..27943ea7 100644 --- a/FruitBank.Common/Enums/PreorderStatus.cs +++ b/FruitBank.Common/Enums/PreorderStatus.cs @@ -2,7 +2,7 @@ namespace FruitBank.Common.Enums; -public enum PreorderStatus +public enum PreOrderStatus { Pending = 0, Confirmed = 10, diff --git a/FruitBank.Common/FruitBankConstClient.cs b/FruitBank.Common/FruitBankConstClient.cs index a6e97f58..74958298 100644 --- a/FruitBank.Common/FruitBankConstClient.cs +++ b/FruitBank.Common/FruitBankConstClient.cs @@ -46,8 +46,8 @@ public static class FruitBankConstClient public const string StockTakingItemPalletDbTableName = "fbStockTakingItemPallet"; public const string CustomerCreditDbTableName = "fbCustomerCredit"; - public const string PreOrderDbTableName = "fbPreorder"; - public const string PreOrderItemDbTableName = "fbPreorderItem"; + public const string PreOrderDbTableName = "fbPreOrder"; + public const string PreOrderItemDbTableName = "fbPreOrderItem"; public const string CargoPartnerDbTableName = "fbCargoPartner"; public const string CargoTruckDbTableName = "fbCargoTruck"; diff --git a/FruitBank.Common/Interfaces/ICargoTruck.cs b/FruitBank.Common/Interfaces/ICargoTruck.cs new file mode 100644 index 00000000..538d8612 --- /dev/null +++ b/FruitBank.Common/Interfaces/ICargoTruck.cs @@ -0,0 +1,17 @@ +using AyCode.Interfaces.Entities; +using AyCode.Interfaces.TimeStampInfo; +using FruitBank.Common.Entities; + +namespace FruitBank.Common.Interfaces; + +public interface ICargoTruck : IEntityInt, ITimeStampInfo +{ + public int CargoPartnerId { get; set; } + + public CargoPartner CargoPartner { get; set; } + + public string CountryCode { get; set; } + public string LicencePlate { get; set; } + + public bool IsTrailer { get; set; } +} \ No newline at end of file diff --git a/FruitBank.Common/Interfaces/IFruitBankDataControllerCommon.cs b/FruitBank.Common/Interfaces/IFruitBankDataControllerCommon.cs index 4af46ea9..39a8ae26 100644 --- a/FruitBank.Common/Interfaces/IFruitBankDataControllerCommon.cs +++ b/FruitBank.Common/Interfaces/IFruitBankDataControllerCommon.cs @@ -1,6 +1,7 @@ using FruitBank.Common.Dtos; using FruitBank.Common.Entities; using FruitBank.Common.Models; +using FruitBank.Common.SignalRs; using Mango.Nop.Core.Dtos; using Mango.Nop.Core.Entities; using Mango.Nop.Core.Models; @@ -29,6 +30,7 @@ public interface IFruitBankDataControllerCommon #region CargoTruck public Task?> GetCargoTrucks(); public Task GetCargoTruckById(int id); + public Task?> GetCargoTrucksByCargoPartnerId(int cargoPartnerId); public Task AddCargoTruck(CargoTruck cargoTruck); public Task UpdateCargoTruck(CargoTruck cargoTruck); #endregion CargoTruck diff --git a/FruitBank.Common/Interfaces/IPartner.cs b/FruitBank.Common/Interfaces/IPartner.cs index f5f53ab3..b757dc7e 100644 --- a/FruitBank.Common/Interfaces/IPartner.cs +++ b/FruitBank.Common/Interfaces/IPartner.cs @@ -4,7 +4,6 @@ using FruitBank.Common.Entities; namespace FruitBank.Common.Interfaces; - public interface ICargoPartner : IPartnerBase { List? CargoTrucks { get; set; } diff --git a/FruitBank.Common/SignalRs/SignalRTags.cs b/FruitBank.Common/SignalRs/SignalRTags.cs index e57326f4..298ca2ef 100644 --- a/FruitBank.Common/SignalRs/SignalRTags.cs +++ b/FruitBank.Common/SignalRs/SignalRTags.cs @@ -21,9 +21,10 @@ public class SignalRTags : AcSignalRTags public const int UpdateCargoPartner = 33; public const int GetCargoTrucks = 35; - public const int GetCargoTruckById = 36; - public const int AddCargoTruck = 37; - public const int UpdateCargoTruck = 38; + public const int GetCargoTrucksByCargoPartnerId = 36; + public const int GetCargoTruckById = 37; + public const int AddCargoTruck = 38; + public const int UpdateCargoTruck = 39; public const int GetShippings = 40; public const int GetNotMeasuredShippings = 41; diff --git a/FruitBankHybrid.Shared.Tests/FruitBankClientTests.cs b/FruitBankHybrid.Shared.Tests/FruitBankClientTests.cs index d18fc8a4..ed23b765 100644 --- a/FruitBankHybrid.Shared.Tests/FruitBankClientTests.cs +++ b/FruitBankHybrid.Shared.Tests/FruitBankClientTests.cs @@ -131,6 +131,7 @@ namespace FruitBankHybrid.Shared.Tests Assert.IsNotNull(cargoTrucks); Assert.IsNotEmpty(cargoTrucks); } + //[TestMethod] //[DataRow(1)] public async Task GetCargoTruckByIdTest(int cargoTruckId) @@ -143,6 +144,17 @@ namespace FruitBankHybrid.Shared.Tests return cargoTruck; } + [TestMethod] + [DataRow(1)] + public async Task GetCargoTrucksByCargoPartnerIdTest(int cargoPartnerId) + { + var cargoTrucks = await _signalRClient.GetCargoTrucksByCargoPartnerId(cargoPartnerId); + + Assert.IsNotNull(cargoTrucks); + Assert.IsNotEmpty(cargoTrucks); + } + + [TestMethod] [DataRow(1)] public async Task UpdateCargoTruckTest(int cargoTruckId) diff --git a/FruitBankHybrid.Shared.Tests/ToonTests.cs b/FruitBankHybrid.Shared.Tests/ToonTests.cs index 8f8b7576..fa8609e4 100644 --- a/FruitBankHybrid.Shared.Tests/ToonTests.cs +++ b/FruitBankHybrid.Shared.Tests/ToonTests.cs @@ -86,6 +86,7 @@ public class FullProcessModel { public List Shippings { get; set; } public List Orders { get; set; } + public List PreOrders { get; set; } public List StockTakings { get; set; } } diff --git a/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoPartner.razor b/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoPartner.razor index 8c025799..1f0730c8 100644 --- a/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoPartner.razor +++ b/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoPartner.razor @@ -44,21 +44,21 @@ @if (IsMasterGrid) { - var partner = ((CargoPartner)context.DataItem); - var shipping = partner?.Shippings ?? []; - var cargoTrucks = partner?.CargoTrucks ?? []; + var cargoPartner = ((CargoPartner)context.DataItem); + var shippings = cargoPartner?.Shippings ?? []; + var cargoTrucks = cargoPartner?.CargoTrucks ?? []; @{ - var observableShippingDocuments = new AcObservableCollection(cargoTrucks); - + var observableCargoTruck = new AcObservableCollection(cargoTrucks); + } @{ - var observableShippings = new AcObservableCollection(shipping); + var observableShippings = new AcObservableCollection(shippings); } diff --git a/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoTruck.razor b/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoTruck.razor index c264877d..43f987bf 100644 --- a/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoTruck.razor +++ b/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoTruck.razor @@ -30,6 +30,7 @@ + diff --git a/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoTruckBase.cs b/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoTruckBase.cs index 2c1f1513..de1162ab 100644 --- a/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoTruckBase.cs +++ b/FruitBankHybrid.Shared/Components/Grids/Cargos/GridCargoTruckBase.cs @@ -35,7 +35,7 @@ public class GridCargoTruckBase: FruitBankGridBase, IGrid switch (ParentDataItem) { case ICargoPartner: - GetAllMessageTag = SignalRTags.GetCargoTrucks; + GetAllMessageTag = SignalRTags.GetCargoTrucksByCargoPartnerId; if (KeyFieldNameToParentId.IsNullOrWhiteSpace()) KeyFieldNameToParentId = nameof(CargoTruck.CargoPartnerId); break; diff --git a/FruitBankHybrid.Shared/Services/SignalRs/FruitBankSignalRClient.cs b/FruitBankHybrid.Shared/Services/SignalRs/FruitBankSignalRClient.cs index e9675de6..bf590cd1 100644 --- a/FruitBankHybrid.Shared/Services/SignalRs/FruitBankSignalRClient.cs +++ b/FruitBankHybrid.Shared/Services/SignalRs/FruitBankSignalRClient.cs @@ -76,6 +76,7 @@ namespace FruitBankHybrid.Shared.Services.SignalRs #region CargoTruck public Task?> GetCargoTrucks() => GetAllAsync>(SignalRTags.GetCargoTrucks); public Task GetCargoTruckById(int id) => GetByIdAsync(SignalRTags.GetCargoTruckById, id); + public Task?> GetCargoTrucksByCargoPartnerId(int cargoPartnerId) => GetAllAsync>(SignalRTags.GetCargoTrucksByCargoPartnerId, [cargoPartnerId]); public Task AddCargoTruck(CargoTruck cargoTruck) => PostDataAsync(SignalRTags.AddCargoTruck, cargoTruck); public Task UpdateCargoTruck(CargoTruck cargoTruck) => PostDataAsync(SignalRTags.UpdateCargoTruck, cargoTruck); #endregion CargoTruck