From 346d4331966185eec334276315680965d15ec999 Mon Sep 17 00:00:00 2001 From: Loretta Date: Mon, 8 Dec 2025 15:50:57 +0100 Subject: [PATCH] Refactor, enhance, and improve test coverage Refactored `OnDataSourceLoaded` to be asynchronous for better state handling. Downgraded `Newtonsoft.Json` to version `13.0.3` across multiple projects for compatibility. Enhanced `MeasuringItemPalletBase` with `SetParentPropToNull` and `SetForeignKey` methods. Refactored `OrderItemPallet`, `ShippingItemPallet`, and `StockTakingItemPallet` to simplify table attributes and improve parent-child relationship handling. Added `IsReadyForClose` to `StockTaking` for better closure validation. Updated SignalR tag constants to reflect new functionality. Improved Razor components (`PalletItemComponent`, `StockTakingTemplate`, `MeasuringIn`, `MeasuringOut`) to streamline logic and maintain proper references. Introduced `JsonExtensionTests` for comprehensive validation of JSON serialization/deserialization, including deep hierarchies, circular references, and hybrid references. Added `test_debug.ps1` for streamlined test debugging. Performed general code cleanup and improved test coverage. --- .../FruitBank.Common.Server.csproj | 2 +- .../Entities/MeasuringItemPalletBase.cs | 3 + FruitBank.Common/Entities/OrderItemPallet.cs | 11 +- .../Entities/ShippingItemPallet.cs | 15 +- FruitBank.Common/Entities/StockTaking.cs | 6 +- .../Entities/StockTakingItemPallet.cs | 9 +- FruitBank.Common/FruitBank.Common.csproj | 2 +- .../Interfaces/IMeasuringItemPalletBase.cs | 2 + FruitBank.Common/SignalRs/SignalRTags.cs | 11 +- .../FruitBankHybrid.Shared.Common.csproj | 2 +- .../FruitBankClientTests.cs | 20 +- .../FruitBankHybrid.Shared.Tests.csproj | 4 + .../JsonExtensionTests.cs | 714 ++++++++++++++++++ .../OrderClientTests.cs | 57 +- FruitBankHybrid.Shared.Tests/test_debug.ps1 | 17 + .../Components/PalletItemComponent.razor | 2 + .../StockTakings/StockTakingTemplate.razor | 29 +- .../FruitBankHybrid.Shared.csproj | 2 +- .../Pages/MeasuringIn.razor.cs | 10 +- .../Pages/MeasuringOut.razor.cs | 40 +- .../FruitBankHybrid.Web.Client.csproj | 2 +- .../FruitBankHybrid.Web.csproj | 2 +- FruitBankHybrid/FruitBankHybrid.csproj | 1 + 23 files changed, 909 insertions(+), 54 deletions(-) create mode 100644 FruitBankHybrid.Shared.Tests/JsonExtensionTests.cs create mode 100644 FruitBankHybrid.Shared.Tests/test_debug.ps1 diff --git a/FruitBank.Common.Server/FruitBank.Common.Server.csproj b/FruitBank.Common.Server/FruitBank.Common.Server.csproj index 1ed463b..f73953c 100644 --- a/FruitBank.Common.Server/FruitBank.Common.Server.csproj +++ b/FruitBank.Common.Server/FruitBank.Common.Server.csproj @@ -15,7 +15,7 @@ - + diff --git a/FruitBank.Common/Entities/MeasuringItemPalletBase.cs b/FruitBank.Common/Entities/MeasuringItemPalletBase.cs index 1ef861a..97336d0 100644 --- a/FruitBank.Common/Entities/MeasuringItemPalletBase.cs +++ b/FruitBank.Common/Entities/MeasuringItemPalletBase.cs @@ -62,6 +62,9 @@ public abstract class MeasuringItemPalletBase : MgEntityBase, IMeasuringItemPall [NotColumn, System.ComponentModel.DataAnnotations.Schema.NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] public virtual MeasuringStatus MeasuringStatus => IsMeasured ? MeasuringStatus.Finnished : Id > 0 ? MeasuringStatus.Started : MeasuringStatus.NotStarted; + + public abstract void SetParentPropToNull(); + public void SetForeignKey(int foreignKey) => ForeignItemId = foreignKey; public virtual double CalculateNetWeight() => double.Round(GrossWeight - PalletWeight - (TareWeight * TrayQuantity), 1); diff --git a/FruitBank.Common/Entities/OrderItemPallet.cs b/FruitBank.Common/Entities/OrderItemPallet.cs index 1125549..1014977 100644 --- a/FruitBank.Common/Entities/OrderItemPallet.cs +++ b/FruitBank.Common/Entities/OrderItemPallet.cs @@ -5,10 +5,12 @@ using LinqToDB.Mapping; using Newtonsoft.Json; using Nop.Core.Domain.Orders; using System.ComponentModel.DataAnnotations.Schema; +using Column = LinqToDB.Mapping.ColumnAttribute; +using Table = LinqToDB.Mapping.TableAttribute; namespace FruitBank.Common.Entities; -[LinqToDB.Mapping.Table(Name = FruitBankConstClient.OrderItemPalletDbTableName)] +[Table(Name = FruitBankConstClient.OrderItemPalletDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.OrderItemPalletDbTableName)] public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet { @@ -21,6 +23,7 @@ public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet public int RevisorId { get; set; } public bool IsAudited => RevisorId > 0; + //[JsonIgnore, System.Text.Json.Serialization.JsonIgnore] [Association(ThisKey = nameof(OrderItemId), OtherKey = nameof(OrderItemDto.Id), CanBeNull = true)] public OrderItemDto? OrderItemDto { get; set; } @@ -35,6 +38,7 @@ public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore] public double AverageWeight => double.Round(NetWeight / TrayQuantity, 1); + /// /// "Szigorúbb" mint az IsValidSafeMeasuringValues() /// @@ -44,4 +48,9 @@ public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet { return OrderItemId > 0 && base.IsValidMeasuringValues(isMeasurable); } + + public override void SetParentPropToNull() + { + OrderItemDto = null; + } } \ No newline at end of file diff --git a/FruitBank.Common/Entities/ShippingItemPallet.cs b/FruitBank.Common/Entities/ShippingItemPallet.cs index 25a5642..05c5e04 100644 --- a/FruitBank.Common/Entities/ShippingItemPallet.cs +++ b/FruitBank.Common/Entities/ShippingItemPallet.cs @@ -1,11 +1,12 @@ -using System.ComponentModel.DataAnnotations; -using System.Security.Cryptography.X509Certificates; -using FruitBank.Common.Interfaces; +using FruitBank.Common.Interfaces; using LinqToDB.Mapping; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Security.Cryptography.X509Certificates; namespace FruitBank.Common.Entities; -[Table(Name = FruitBankConstClient.ShippingItemPalletDbTableName)] +[LinqToDB.Mapping.Table(Name = FruitBankConstClient.ShippingItemPalletDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.ShippingItemPalletDbTableName)] public class ShippingItemPallet : MeasuringItemPalletBase, IShippingItemPallet { @@ -15,6 +16,7 @@ public class ShippingItemPallet : MeasuringItemPalletBase, IShippingItemPallet set => ForeignItemId = value; } + //[Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore] [LinqToDB.Mapping.Association(ThisKey = nameof(ShippingItemId), OtherKey = nameof(ShippingItem.Id), CanBeNull = true)] public ShippingItem? ShippingItem { get; set; } @@ -34,4 +36,9 @@ public class ShippingItemPallet : MeasuringItemPalletBase, IShippingItemPallet { return ShippingItemId > 0 && base.IsValidMeasuringValues(isMeasurable); } + + public override void SetParentPropToNull() + { + ShippingItem = null; + } } \ No newline at end of file diff --git a/FruitBank.Common/Entities/StockTaking.cs b/FruitBank.Common/Entities/StockTaking.cs index 33376c4..ac397b5 100644 --- a/FruitBank.Common/Entities/StockTaking.cs +++ b/FruitBank.Common/Entities/StockTaking.cs @@ -7,5 +7,9 @@ namespace FruitBank.Common.Entities; [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.StockTakingDbTableName)] public class StockTaking : MgStockTaking { - + public override bool IsReadyForClose() + { + if (StockTakingItems == null || StockTakingItems.Count == 0) return false; + return StockTakingItems.Where(stockTakingItem => stockTakingItem is { IsRequiredForMeasuring: true, IsInvalid: false }).All(x => x.IsMeasured); + } } \ No newline at end of file diff --git a/FruitBank.Common/Entities/StockTakingItemPallet.cs b/FruitBank.Common/Entities/StockTakingItemPallet.cs index 4f11b68..6aba0ff 100644 --- a/FruitBank.Common/Entities/StockTakingItemPallet.cs +++ b/FruitBank.Common/Entities/StockTakingItemPallet.cs @@ -2,6 +2,7 @@ using FruitBank.Common.Interfaces; using LinqToDB.Mapping; using Mango.Nop.Core.Entities; +using System.ComponentModel.DataAnnotations.Schema; namespace FruitBank.Common.Entities; @@ -11,7 +12,7 @@ public interface IStockTakingItemPallet : IMeasuringItemPalletBase public StockTakingItem? StockTakingItem{ get; set; } } -[Table(Name = FruitBankConstClient.StockTakingItemPalletDbTableName)] +[LinqToDB.Mapping.Table(Name = FruitBankConstClient.StockTakingItemPalletDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.StockTakingItemPalletDbTableName)] public class StockTakingItemPallet : MeasuringItemPalletBase, IStockTakingItemPallet { @@ -21,6 +22,7 @@ public class StockTakingItemPallet : MeasuringItemPalletBase, IStockTakingItemPa set => ForeignItemId = value; } + //[Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore] [Association(ThisKey = nameof(StockTakingItemId), OtherKey = nameof(StockTakingItem.Id), CanBeNull = true)] public StockTakingItem? StockTakingItem { get; set; } @@ -36,4 +38,9 @@ public class StockTakingItemPallet : MeasuringItemPalletBase, IStockTakingItemPa return StockTakingItemId > 0 && TrayQuantity >= 0 && ((!isMeasurable && NetWeight == 0 && GrossWeight == 0 && PalletWeight == 0 && TareWeight == 0) || (isMeasurable && NetWeight >= 0 && GrossWeight >= 0 && PalletWeight >= 0 && TareWeight >= 0)); } + + public override void SetParentPropToNull() + { + StockTakingItem = null; + } } \ No newline at end of file diff --git a/FruitBank.Common/FruitBank.Common.csproj b/FruitBank.Common/FruitBank.Common.csproj index c0473ce..b004855 100644 --- a/FruitBank.Common/FruitBank.Common.csproj +++ b/FruitBank.Common/FruitBank.Common.csproj @@ -12,7 +12,7 @@ - + diff --git a/FruitBank.Common/Interfaces/IMeasuringItemPalletBase.cs b/FruitBank.Common/Interfaces/IMeasuringItemPalletBase.cs index 90bddcf..a3bcbb1 100644 --- a/FruitBank.Common/Interfaces/IMeasuringItemPalletBase.cs +++ b/FruitBank.Common/Interfaces/IMeasuringItemPalletBase.cs @@ -14,6 +14,8 @@ public interface IMeasuringItemPalletBase : IEntityInt, IMeasuringValues, IMeasu int? CreatorId { get; set; } int? ModifierId { get; set; } + void SetParentPropToNull(); + double CalculateNetWeight(); bool IsValidSafeMeasuringValues(); diff --git a/FruitBank.Common/SignalRs/SignalRTags.cs b/FruitBank.Common/SignalRs/SignalRTags.cs index 7ce695c..30d0730 100644 --- a/FruitBank.Common/SignalRs/SignalRTags.cs +++ b/FruitBank.Common/SignalRs/SignalRTags.cs @@ -93,11 +93,12 @@ public class SignalRTags : AcSignalRTags public const int GetStockTakings = 170; public const int AddStockTaking = 171; public const int UpdateStockTaking = 172; - public const int GetStockTakingItems = 173; - public const int GetStockTakingItemsById = 174; - public const int GetStockTakingItemsByProductId = 175; - public const int GetStockTakingItemsByStockTakingId = 176; - public const int AddOrUpdateMeasuredStockTakingItemPallet = 177; + public const int CloseStockTaking = 173; + public const int GetStockTakingItems = 174; + public const int GetStockTakingItemsById = 175; + public const int GetStockTakingItemsByProductId = 176; + public const int GetStockTakingItemsByStockTakingId = 177; + public const int AddOrUpdateMeasuredStockTakingItemPallet = 178; public const int AuthenticateUser = 195; diff --git a/FruitBankHybrid.Shared.Common/FruitBankHybrid.Shared.Common.csproj b/FruitBankHybrid.Shared.Common/FruitBankHybrid.Shared.Common.csproj index e5ce967..f0cfe0f 100644 --- a/FruitBankHybrid.Shared.Common/FruitBankHybrid.Shared.Common.csproj +++ b/FruitBankHybrid.Shared.Common/FruitBankHybrid.Shared.Common.csproj @@ -12,7 +12,7 @@ - + diff --git a/FruitBankHybrid.Shared.Tests/FruitBankClientTests.cs b/FruitBankHybrid.Shared.Tests/FruitBankClientTests.cs index 4c006ae..6d97f3c 100644 --- a/FruitBankHybrid.Shared.Tests/FruitBankClientTests.cs +++ b/FruitBankHybrid.Shared.Tests/FruitBankClientTests.cs @@ -430,16 +430,16 @@ namespace FruitBankHybrid.Shared.Tests Assert.IsTrue(users.All(x => !x.Email.IsNullOrEmpty() && !x.Deleted)); } - [TestMethod] - [DataRow(CustomerIdAasdDsserverCom)] - public async Task GetCustomerRolesByCustomerIdTest(int customerId) - { - var customerRoles = await _signalRClient.GetCustomerRolesByCustomerId(customerId); + //[TestMethod] + //[DataRow(CustomerIdAasdDsserverCom)] + //public async Task GetCustomerRolesByCustomerIdTest(int customerId) + //{ + // var customerRoles = await _signalRClient.GetCustomerRolesByCustomerId(customerId); - Assert.IsNotNull(customerRoles); - Assert.IsTrue(customerRoles.Count > 0); - Assert.IsTrue(customerRoles.Any(cr => cr.SystemName == "Measuring")); - } + // Assert.IsNotNull(customerRoles); + // Assert.IsTrue(customerRoles.Count > 0); + // Assert.IsTrue(customerRoles.Any(cr => cr.SystemName == "Measuring")); + //} #endregion Customer @@ -461,7 +461,7 @@ namespace FruitBankHybrid.Shared.Tests //[DataRow(6, false)] [DataRow(33, true)] [DataRow(64, false)] - [DataRow(7, false)] + [DataRow(7, true)] public async Task GetProductDtoByIdTest(int productId, bool isMeasurableExcepted) { await GetProductDtoByIdAsync(productId, isMeasurableExcepted); diff --git a/FruitBankHybrid.Shared.Tests/FruitBankHybrid.Shared.Tests.csproj b/FruitBankHybrid.Shared.Tests/FruitBankHybrid.Shared.Tests.csproj index 40dc96a..b7edf0c 100644 --- a/FruitBankHybrid.Shared.Tests/FruitBankHybrid.Shared.Tests.csproj +++ b/FruitBankHybrid.Shared.Tests/FruitBankHybrid.Shared.Tests.csproj @@ -14,6 +14,10 @@ true + + + + diff --git a/FruitBankHybrid.Shared.Tests/JsonExtensionTests.cs b/FruitBankHybrid.Shared.Tests/JsonExtensionTests.cs new file mode 100644 index 0000000..57b2676 --- /dev/null +++ b/FruitBankHybrid.Shared.Tests/JsonExtensionTests.cs @@ -0,0 +1,714 @@ +using AyCode.Core.Enums; +using AyCode.Core.Extensions; +using AyCode.Core.Interfaces; +using AyCode.Core.Loggers; +using AyCode.Services.SignalRs; +using AyCode.Utils.Extensions; +using FruitBank.Common; +using FruitBank.Common.Dtos; +using FruitBank.Common.Loggers; +using FruitBankHybrid.Shared.Services.SignalRs; +using FruitBankHybrid.Shared.Tests; +using Microsoft.Extensions.Options; +using Mono.Cecil; +using Newtonsoft.Json; +using Nop.Core.Domain.Orders; +using System.Runtime.Serialization; + +namespace FruitBankHybrid.Shared.Tests; + +#region Test Models for Hybrid Reference Test + +/// +/// Level 1 - Root entity implementing IId<int> (uses semantic ID: "Company_1") +/// +public class Company : IId +{ + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + + // Collection of IId items + public List Departments { get; set; } = new(); + + // Non-IId object (uses numeric ID) + public Address HeadquartersAddress { get; set; } = new(); + + // Array of IId items + public Employee[] BoardMembers { get; set; } = Array.Empty(); +} + +/// +/// Level 2 - Department implementing IId<int> (uses semantic ID: "Department_1") +/// +public class Department : IId +{ + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + + // Back-reference to parent (should use $ref to Company semantic ID) + public Company? ParentCompany { get; set; } + + // Collection of IId items + public List Employees { get; set; } = new(); + + // Non-IId object (uses numeric ID) + public Address? OfficeAddress { get; set; } + + // Array of IId items + public Project[] ActiveProjects { get; set; } = Array.Empty(); +} + +/// +/// Level 3 - Employee implementing IId<int> (uses semantic ID: "Employee_1") +/// +public class Employee : IId +{ + public int Id { get; set; } + public string FullName { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; + + // Back-reference to department (should use $ref to Department semantic ID) + public Department? Department { get; set; } + + // Non-IId object (uses numeric ID) + public ContactInfo? Contact { get; set; } + + // Collection of IId items + public List AssignedProjects { get; set; } = new(); + + // Collection of non-IId items (uses numeric IDs) + public List Skills { get; set; } = new(); +} + +/// +/// Level 4 - Project implementing IId<Guid> (uses semantic ID: "Project_guid") +/// +public class Project : IId +{ + public Guid Id { get; set; } + public string ProjectName { get; set; } = string.Empty; + public DateTime StartDate { get; set; } + + // Back-reference to department (should use $ref to Department semantic ID) + public Department? OwningDepartment { get; set; } + + // Collection of IId - circular reference to employees + public List TeamMembers { get; set; } = new(); + + // Array of non-IId items + public Milestone[] Milestones { get; set; } = Array.Empty(); + + // Collection of IId items + public List Tasks { get; set; } = new(); +} + +/// +/// Level 5 - ProjectTask implementing IId<long> (uses semantic ID: "ProjectTask_1") +/// Renamed from Task to avoid conflict with System.Threading.Tasks.Task +/// +public class ProjectTask : IId +{ + public long Id { get; set; } + public string Title { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public bool IsCompleted { get; set; } + + // Back-reference to project (should use $ref to Project semantic ID) + public Project? ParentProject { get; set; } + + // Reference to employee (should use $ref to Employee semantic ID) + public Employee? AssignedTo { get; set; } + + // Non-IId object + public TaskMetadata? Metadata { get; set; } +} + +/// +/// Non-IId class - Address (uses standard numeric $id) +/// +public class Address +{ + public string Street { get; set; } = string.Empty; + public string City { get; set; } = string.Empty; + public string Country { get; set; } = string.Empty; + public string PostalCode { get; set; } = string.Empty; +} + +/// +/// Non-IId class - ContactInfo (uses standard numeric $id) +/// +public class ContactInfo +{ + public string Phone { get; set; } = string.Empty; + public string Mobile { get; set; } = string.Empty; + + // Shared address reference (should use $ref to numeric ID) + public Address? HomeAddress { get; set; } +} + +/// +/// Non-IId class - Skill (uses standard numeric $id) +/// +public class Skill +{ + public string Name { get; set; } = string.Empty; + public int Level { get; set; } +} + +/// +/// Non-IId class - Milestone (uses standard numeric $id) +/// +public class Milestone +{ + public string Name { get; set; } = string.Empty; + public DateTime DueDate { get; set; } + public bool IsCompleted { get; set; } +} + +/// +/// Non-IId class - TaskMetadata (uses standard numeric $id) +/// +public class TaskMetadata +{ + public DateTime CreatedAt { get; set; } + public DateTime? ModifiedAt { get; set; } + public string CreatedBy { get; set; } = string.Empty; + public int Priority { get; set; } + public string[] Tags { get; set; } = Array.Empty(); +} + +#endregion + +[TestClass] +public sealed class JsonExtensionTests +{ + private FruitBankSignalRClient _signalRClient = null!; + + [TestInitialize] + public void TestInit() + { + if (!FruitBankConstClient.BaseUrl.Contains("localhost:")) throw new Exception("NEM LOCALHOST-ON TESZTELÜNK!"); + + _signalRClient = new FruitBankSignalRClient(new List + { + new SignaRClientLogItemWriter(AppType.TestUnit, LogLevel.Detail, nameof(FruitBankClientTests)) + }); + } + + [TestMethod] + public async Task GetMeasuringUsersTest() + { + var users = await _signalRClient.GetMeasuringUsers(); + + Assert.IsNotNull(users); + Assert.IsTrue(users.Count != 0); + Assert.IsTrue(users.All(x => !x.Email.IsNullOrEmpty() && !x.Deleted)); + } + + [TestMethod] + public async Task RealOrderDto_JSON_Merge_Ref_Test() + { + var initialCount = 28; + List? pendingOrderDtos = (await _signalRClient.GetPendingOrderDtos())?.Take(initialCount).ToList(); + + Assert.IsNotNull(pendingOrderDtos); + Assert.IsTrue(pendingOrderDtos.Count != 0); + + var itemToDuplicate = pendingOrderDtos[0]; + var listWithDuplication = pendingOrderDtos.ToList(); + listWithDuplication.Add(itemToDuplicate); + + var settings = SerializeObjectExtensions.Options; + var dtNow = DateTime.UtcNow; + + listWithDuplication[0].PaidDateUtc = dtNow; + + var itemWithGenericAttributes = listWithDuplication.FirstOrDefault(x => x.GenericAttributes?.Count > 0); + Assert.IsNotNull(itemWithGenericAttributes, "Nincs olyan OrderDto a listában, amelynek lenne GenericAttributes eleme!"); + + itemWithGenericAttributes.GenericAttributes[0].CreatedOrUpdatedDateUTC = dtNow; + + var json = JsonConvert.SerializeObject(listWithDuplication, settings); + + Assert.IsTrue(json.Contains("$id"), "JSON-nak tartalmaznia kell $id tokeneket"); + Assert.IsTrue(json.Contains("$ref"), "JSON-nak tartalmaznia kell $ref tokeneket"); + + pendingOrderDtos.DeepPopulateWithMerge(json, settings); + + Assert.AreEqual(initialCount, pendingOrderDtos.Count); + Assert.IsTrue(itemToDuplicate.PaidDateUtc == dtNow); + Assert.IsTrue(itemWithGenericAttributes.GenericAttributes[0].CreatedOrUpdatedDateUTC == dtNow); + } + + /// + /// Comprehensive test for hybrid reference handling: + /// - 5 levels deep hierarchy + /// - IId<int>, IId<Guid>, IId<long> types (semantic IDs) + /// - Non-IId types (numeric IDs) + /// - Collections (List<T>), Arrays, and single object properties + /// - Back-references to parent objects + /// - Shared object references + /// + [TestMethod] + public void HybridReferenceHandling_DeepHierarchy_Test() + { + // Arrange - Create test data with 5 levels of depth + var sharedAddress = new Address + { + Street = "123 Shared Street", + City = "Budapest", + Country = "Hungary", + PostalCode = "1111" + }; + + var company = new Company + { + Id = 1, + Name = "Acme Corporation", + HeadquartersAddress = sharedAddress + }; + + var department1 = new Department + { + Id = 101, + Name = "Engineering", + ParentCompany = company, // Back-reference to Level 1 + OfficeAddress = new Address + { + Street = "456 Tech Ave", + City = "Budapest", + Country = "Hungary", + PostalCode = "2222" + } + }; + + var department2 = new Department + { + Id = 102, + Name = "Marketing", + ParentCompany = company, // Back-reference to Level 1 (same company) + OfficeAddress = sharedAddress // Shared address reference + }; + + company.Departments.Add(department1); + company.Departments.Add(department2); + + var employee1 = new Employee + { + Id = 1001, + FullName = "John Doe", + Email = "john.doe@acme.com", + Department = department1, // Back-reference to Level 2 + Contact = new ContactInfo + { + Phone = "+36-1-111-1111", + Mobile = "+36-30-111-1111", + HomeAddress = sharedAddress // Shared address reference + }, + Skills = new List + { + new() { Name = "C#", Level = 5 }, + new() { Name = "Azure", Level = 4 } + } + }; + + var employee2 = new Employee + { + Id = 1002, + FullName = "Jane Smith", + Email = "jane.smith@acme.com", + Department = department1, // Back-reference to same department + Contact = new ContactInfo + { + Phone = "+36-1-222-2222", + Mobile = "+36-30-222-2222", + HomeAddress = new Address + { + Street = "789 Home Lane", + City = "Debrecen", + Country = "Hungary", + PostalCode = "3333" + } + }, + Skills = new List + { + new() { Name = "JavaScript", Level = 5 }, + new() { Name = "React", Level = 4 } + } + }; + + var employee3 = new Employee + { + Id = 1003, + FullName = "Bob Wilson", + Email = "bob.wilson@acme.com", + Department = department2, // Different department + Skills = new List + { + new() { Name = "Marketing", Level = 5 } + } + }; + + department1.Employees.Add(employee1); + department1.Employees.Add(employee2); + department2.Employees.Add(employee3); + + // Board members array + company.BoardMembers = new[] { employee1, employee3 }; // Shared employee references + + var project1 = new Project + { + Id = Guid.NewGuid(), + ProjectName = "Project Alpha", + StartDate = DateTime.UtcNow.AddMonths(-3), + OwningDepartment = department1, // Back-reference to Level 2 + TeamMembers = new List { employee1, employee2 }, // Shared employee references + Milestones = new[] + { + new Milestone { Name = "Phase 1", DueDate = DateTime.UtcNow.AddMonths(-2), IsCompleted = true }, + new Milestone { Name = "Phase 2", DueDate = DateTime.UtcNow.AddMonths(-1), IsCompleted = true }, + new Milestone { Name = "Phase 3", DueDate = DateTime.UtcNow.AddMonths(1), IsCompleted = false } + } + }; + + var project2 = new Project + { + Id = Guid.NewGuid(), + ProjectName = "Project Beta", + StartDate = DateTime.UtcNow.AddMonths(-1), + OwningDepartment = department1, // Same department + TeamMembers = new List { employee2 }, // Shared employee reference + Milestones = new[] + { + new Milestone { Name = "Initial", DueDate = DateTime.UtcNow.AddMonths(2), IsCompleted = false } + } + }; + + department1.ActiveProjects = new[] { project1, project2 }; + + employee1.AssignedProjects.Add(project1); + employee2.AssignedProjects.Add(project1); + employee2.AssignedProjects.Add(project2); + + var task1 = new ProjectTask + { + Id = 10001L, + Title = "Implement Feature X", + Description = "Detailed implementation of Feature X", + IsCompleted = false, + ParentProject = project1, // Back-reference to Level 4 + AssignedTo = employee1, // Reference to Level 3 + Metadata = new TaskMetadata + { + CreatedAt = DateTime.UtcNow.AddDays(-10), + CreatedBy = "admin", + Priority = 1, + Tags = new[] { "urgent", "feature", "backend" } + } + }; + + var task2 = new ProjectTask + { + Id = 10002L, + Title = "Write Tests", + Description = "Unit tests for Feature X", + IsCompleted = false, + ParentProject = project1, // Same project + AssignedTo = employee2, // Different employee + Metadata = new TaskMetadata + { + CreatedAt = DateTime.UtcNow.AddDays(-5), + CreatedBy = "admin", + Priority = 2, + Tags = new[] { "testing", "quality" } + } + }; + + var task3 = new ProjectTask + { + Id = 10003L, + Title = "Review Code", + Description = "Code review for Feature X", + IsCompleted = false, + ParentProject = project1, + AssignedTo = employee1, // Same employee as task1 (circular reference) + Metadata = new TaskMetadata + { + CreatedAt = DateTime.UtcNow.AddDays(-3), + CreatedBy = "lead", + Priority = 1, + Tags = new[] { "review" } + } + }; + + project1.Tasks.Add(task1); + project1.Tasks.Add(task2); + project1.Tasks.Add(task3); + + var settings = SerializeObjectExtensions.Options; + + // Act - Serialize + var json = JsonConvert.SerializeObject(company, settings); + + // Assert - JSON structure + Assert.IsNotNull(json); + Assert.IsTrue(json.Length > 0, "JSON should not be empty"); + + // Check for semantic IDs (IId types) + Assert.IsTrue(json.Contains("\"$id\":\"Company_1\""), "Should contain semantic ID for Company"); + Assert.IsTrue(json.Contains("\"$id\":\"Department_101\""), "Should contain semantic ID for Department 101"); + Assert.IsTrue(json.Contains("\"$id\":\"Department_102\""), "Should contain semantic ID for Department 102"); + Assert.IsTrue(json.Contains("\"$id\":\"Employee_1001\""), "Should contain semantic ID for Employee 1001"); + Assert.IsTrue(json.Contains("\"$id\":\"Employee_1002\""), "Should contain semantic ID for Employee 1002"); + Assert.IsTrue(json.Contains("\"$id\":\"Employee_1003\""), "Should contain semantic ID for Employee 1003"); + Assert.IsTrue(json.Contains("\"$id\":\"ProjectTask_10001\""), "Should contain semantic ID for ProjectTask 10001"); + + // Check for $ref tokens (back-references) + Assert.IsTrue(json.Contains("\"$ref\":\"Company_1\""), "Should contain $ref to Company"); + Assert.IsTrue(json.Contains("\"$ref\":\"Department_101\""), "Should contain $ref to Department"); + Assert.IsTrue(json.Contains("\"$ref\":\"Employee_1001\""), "Should contain $ref to Employee 1001"); + Assert.IsTrue(json.Contains("\"$ref\":\"Employee_1002\""), "Should contain $ref to Employee 1002"); + + // Check for numeric IDs (non-IId types like Address, ContactInfo, etc.) + // These should have simple numeric $id values + Assert.IsTrue(System.Text.RegularExpressions.Regex.IsMatch(json, @"\$id"":""[0-9]+"""), + "Should contain numeric $id for non-IId types"); + + // Act - Deserialize + var deserializedCompany = JsonConvert.DeserializeObject(json, settings); + + // Assert - Deserialized structure + Assert.IsNotNull(deserializedCompany); + Assert.AreEqual(1, deserializedCompany.Id); + Assert.AreEqual("Acme Corporation", deserializedCompany.Name); + + // Verify departments + Assert.AreEqual(2, deserializedCompany.Departments.Count); + var deserializedDept1 = deserializedCompany.Departments.First(d => d.Id == 101); + var deserializedDept2 = deserializedCompany.Departments.First(d => d.Id == 102); + + // Verify back-references to company + Assert.AreSame(deserializedCompany, deserializedDept1.ParentCompany, + "Department1's ParentCompany should be the same instance as deserializedCompany"); + Assert.AreSame(deserializedCompany, deserializedDept2.ParentCompany, + "Department2's ParentCompany should be the same instance as deserializedCompany"); + + // Verify employees + Assert.AreEqual(2, deserializedDept1.Employees.Count); + var deserializedEmp1 = deserializedDept1.Employees.First(e => e.Id == 1001); + var deserializedEmp2 = deserializedDept1.Employees.First(e => e.Id == 1002); + + // Verify employee back-references to department + Assert.AreSame(deserializedDept1, deserializedEmp1.Department, + "Employee1's Department should be the same instance as deserializedDept1"); + Assert.AreSame(deserializedDept1, deserializedEmp2.Department, + "Employee2's Department should be the same instance as deserializedDept1"); + + // Verify board members are same instances as department employees + Assert.AreEqual(2, deserializedCompany.BoardMembers.Length); + Assert.AreSame(deserializedEmp1, deserializedCompany.BoardMembers.First(e => e.Id == 1001), + "BoardMember should be the same instance as deserializedEmp1"); + + // Verify projects + Assert.AreEqual(2, deserializedDept1.ActiveProjects.Length); + var deserializedProject1 = deserializedDept1.ActiveProjects.First(p => p.ProjectName == "Project Alpha"); + + // Verify project back-reference to department + Assert.AreSame(deserializedDept1, deserializedProject1.OwningDepartment, + "Project1's OwningDepartment should be the same instance as deserializedDept1"); + + // Verify project team members are same instances + Assert.IsTrue(deserializedProject1.TeamMembers.Any(e => ReferenceEquals(e, deserializedEmp1)), + "Project1's TeamMembers should contain the same instance as deserializedEmp1"); + Assert.IsTrue(deserializedProject1.TeamMembers.Any(e => ReferenceEquals(e, deserializedEmp2)), + "Project1's TeamMembers should contain the same instance as deserializedEmp2"); + + // Verify tasks + Assert.AreEqual(3, deserializedProject1.Tasks.Count); + var deserializedTask1 = deserializedProject1.Tasks.First(t => t.Id == 10001L); + + // Verify task back-references + Assert.AreSame(deserializedProject1, deserializedTask1.ParentProject, + "Task1's ParentProject should be the same instance as deserializedProject1"); + Assert.AreSame(deserializedEmp1, deserializedTask1.AssignedTo, + "Task1's AssignedTo should be the same instance as deserializedEmp1"); + + // Verify shared Address instances (non-IId type) + Assert.AreSame(deserializedCompany.HeadquartersAddress, deserializedDept2.OfficeAddress, + "HeadquartersAddress and Dept2's OfficeAddress should be the same instance (shared Address)"); + Assert.AreSame(deserializedCompany.HeadquartersAddress, deserializedEmp1.Contact?.HomeAddress, + "HeadquartersAddress and Emp1's HomeAddress should be the same instance (shared Address)"); + + // Verify milestones (non-IId array) + Assert.AreEqual(3, deserializedProject1.Milestones.Length); + Assert.IsTrue(deserializedProject1.Milestones.Any(m => m.Name == "Phase 1" && m.IsCompleted)); + + // Verify skills (non-IId collection) + Assert.AreEqual(2, deserializedEmp1.Skills.Count); + Assert.IsTrue(deserializedEmp1.Skills.Any(s => s.Name == "C#" && s.Level == 5)); + + // Verify task metadata (non-IId object) + Assert.IsNotNull(deserializedTask1.Metadata); + Assert.AreEqual("admin", deserializedTask1.Metadata.CreatedBy); + Assert.AreEqual(1, deserializedTask1.Metadata.Priority); + Assert.AreEqual(3, deserializedTask1.Metadata.Tags.Length); + } + + /// + /// Test for DeepPopulateWithMerge with hybrid references + /// + [TestMethod] + public void HybridReferenceHandling_DeepPopulateWithMerge_Test() + { + // Arrange - Create initial data + var company = new Company + { + Id = 1, + Name = "Original Company Name", + HeadquartersAddress = new Address { City = "Original City" } + }; + + var department = new Department + { + Id = 101, + Name = "Original Department", + ParentCompany = company + }; + company.Departments.Add(department); + + var employee = new Employee + { + Id = 1001, + FullName = "Original Name", + Email = "original@email.com", + Department = department + }; + department.Employees.Add(employee); + + // Create modified version + var modifiedCompany = new Company + { + Id = 1, + Name = "Modified Company Name", + HeadquartersAddress = new Address { City = "Modified City" } + }; + + var modifiedDepartment = new Department + { + Id = 101, + Name = "Modified Department", + ParentCompany = modifiedCompany + }; + modifiedCompany.Departments.Add(modifiedDepartment); + + var modifiedEmployee = new Employee + { + Id = 1001, + FullName = "Modified Name", + Email = "modified@email.com", + Department = modifiedDepartment + }; + modifiedDepartment.Employees.Add(modifiedEmployee); + + // Add a new employee in the modified version + var newEmployee = new Employee + { + Id = 1002, + FullName = "New Employee", + Email = "new@email.com", + Department = modifiedDepartment + }; + modifiedDepartment.Employees.Add(newEmployee); + + var settings = SerializeObjectExtensions.Options; + var modifiedJson = JsonConvert.SerializeObject(modifiedCompany, settings); + + // Store original references + var originalCompanyRef = company; + var originalDepartmentRef = department; + var originalEmployeeRef = employee; + + // Act - Deep populate with merge + company.DeepPopulateWithMerge(modifiedJson, settings); + + // Assert - Same instances should be updated, not replaced + Assert.AreSame(originalCompanyRef, company, "Company instance should be the same"); + Assert.AreEqual("Modified Company Name", company.Name, "Company name should be updated"); + Assert.AreEqual("Modified City", company.HeadquartersAddress.City, "Address should be updated"); + + Assert.AreEqual(1, company.Departments.Count, "Should still have 1 department"); + Assert.AreSame(originalDepartmentRef, company.Departments[0], "Department instance should be the same"); + Assert.AreEqual("Modified Department", company.Departments[0].Name, "Department name should be updated"); + + // The original employee should be updated + var updatedEmployee = company.Departments[0].Employees.FirstOrDefault(e => e.Id == 1001); + Assert.IsNotNull(updatedEmployee); + Assert.AreSame(originalEmployeeRef, updatedEmployee, "Original employee instance should be the same"); + Assert.AreEqual("Modified Name", updatedEmployee.FullName, "Employee name should be updated"); + Assert.AreEqual("modified@email.com", updatedEmployee.Email, "Employee email should be updated"); + + // New employee should be added + Assert.AreEqual(2, company.Departments[0].Employees.Count, "Should have 2 employees after merge"); + var addedEmployee = company.Departments[0].Employees.FirstOrDefault(e => e.Id == 1002); + Assert.IsNotNull(addedEmployee, "New employee should be added"); + Assert.AreEqual("New Employee", addedEmployee.FullName); + } + + /// + /// Test that verifies circular references don't cause infinite loops + /// + [TestMethod] + public void HybridReferenceHandling_CircularReferences_NoInfiniteLoop_Test() + { + // Arrange - Create circular reference structure + var company = new Company { Id = 1, Name = "Test Company" }; + var department = new Department { Id = 101, Name = "Test Dept", ParentCompany = company }; + company.Departments.Add(department); + + var employee = new Employee { Id = 1001, FullName = "Test Employee", Department = department }; + department.Employees.Add(employee); + + var project = new Project + { + Id = Guid.NewGuid(), + ProjectName = "Test Project", + OwningDepartment = department, + TeamMembers = new List { employee } + }; + department.ActiveProjects = new[] { project }; + employee.AssignedProjects.Add(project); + + var task = new ProjectTask + { + Id = 10001L, + Title = "Test Task", + ParentProject = project, + AssignedTo = employee // Circular: Task -> Employee -> Project -> Task's Project + }; + project.Tasks.Add(task); + + var settings = SerializeObjectExtensions.Options; + + // Act - Should not throw StackOverflowException or timeout + var json = JsonConvert.SerializeObject(company, settings); + var deserialized = JsonConvert.DeserializeObject(json, settings); + + // Assert + Assert.IsNotNull(deserialized); + Assert.AreEqual(1, deserialized.Id); + + var deserializedDept = deserialized.Departments[0]; + var deserializedEmployee = deserializedDept.Employees[0]; + var deserializedProject = deserializedDept.ActiveProjects[0]; + var deserializedTask = deserializedProject.Tasks[0]; + + // Verify circular references are correctly resolved + Assert.AreSame(deserialized, deserializedDept.ParentCompany); + Assert.AreSame(deserializedDept, deserializedEmployee.Department); + Assert.AreSame(deserializedDept, deserializedProject.OwningDepartment); + Assert.AreSame(deserializedProject, deserializedTask.ParentProject); + Assert.AreSame(deserializedEmployee, deserializedTask.AssignedTo); + Assert.AreSame(deserializedEmployee, deserializedProject.TeamMembers[0]); + Assert.AreSame(deserializedProject, deserializedEmployee.AssignedProjects[0]); + } +} \ No newline at end of file diff --git a/FruitBankHybrid.Shared.Tests/OrderClientTests.cs b/FruitBankHybrid.Shared.Tests/OrderClientTests.cs index 4e8d1e7..1f3f9a0 100644 --- a/FruitBankHybrid.Shared.Tests/OrderClientTests.cs +++ b/FruitBankHybrid.Shared.Tests/OrderClientTests.cs @@ -1,10 +1,16 @@ using AyCode.Core.Enums; +using AyCode.Core.Extensions; using AyCode.Core.Loggers; using FruitBank.Common; +using FruitBank.Common.Dtos; using FruitBank.Common.Loggers; using FruitBankHybrid.Shared.Services.SignalRs; +using Newtonsoft.Json; using Nop.Core.Domain.Orders; using Nop.Core.Domain.Payments; +using System.Runtime.Serialization; +using FruitBank.Common.Entities; +using Nop.Core.Domain.Common; namespace FruitBankHybrid.Shared.Tests; @@ -27,11 +33,11 @@ public sealed class OrderClientTests }); } - + [TestMethod] public async Task GetAllStockTakings() { - var stockTakings = await _signalRClient.GetStockTakings(); + var stockTakings = await _signalRClient.GetStockTakings(true); Assert.IsNotNull(stockTakings); Assert.IsTrue(stockTakings.Count != 0); @@ -88,10 +94,53 @@ public sealed class OrderClientTests [TestMethod] public async Task GetPendingOrderDtos() { - var pendingOrderDtos = await _signalRClient.GetPendingOrderDtos(); + var initialCount = 28; + List? pendingOrderDtos = (await _signalRClient.GetPendingOrderDtos())?.Take(initialCount).ToList(); Assert.IsNotNull(pendingOrderDtos); + // Másolat létrehozása a frissítendő adatok generálásához + List? pendingOrderDtos2 = pendingOrderDtos.ToList(); + + Assert.IsNotNull(pendingOrderDtos2); + Assert.AreEqual(initialCount, pendingOrderDtos2.Count); + + // ÚJ BEÁLLÍTÁSOK A RESOLVER-REL ÉS CONTEXT-EL + //var settings = new JsonSerializerSettings + //{ + // ContractResolver = new UnifiedMergeContractResolver(), + // ObjectCreationHandling = ObjectCreationHandling.Replace, + // Context = new StreamingContext(StreamingContextStates.All, new Dictionary()), + + // // Alapvető beállítások + // PreserveReferencesHandling = PreserveReferencesHandling.Objects, + // ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + // NullValueHandling = NullValueHandling.Ignore, + //}; + + var dtNow = DateTime.UtcNow; + + // Eredeti objektum referenciájának eltárolása + var orderDto1 = pendingOrderDtos[0]; + + // Frissítjük a másolatot + pendingOrderDtos2[0].PaidDateUtc = dtNow; + pendingOrderDtos2[0].GenericAttributes[0].CreatedOrUpdatedDateUTC = dtNow; + + pendingOrderDtos2.CopyTo(pendingOrderDtos); + // Szerializálás a Merge Resolverrel + //var json = pendingOrderDtos2.ToJson(settings); + + //Assert.IsTrue(json.Contains("$id")); + //Assert.IsTrue(json.Contains("$ref")); + + //pendingOrderDtos.DeepPopulateWithMerge(json, settings); + + Assert.IsTrue(pendingOrderDtos.Count == pendingOrderDtos2.Count, $"A listák méretének egyeznie kell: {pendingOrderDtos.Count} != {pendingOrderDtos2.Count}"); + + Assert.IsTrue(orderDto1.PaidDateUtc == dtNow, "A PaidDateUtc mezőnek frissülnie kellett a Merge során."); + Assert.IsTrue(orderDto1.GenericAttributes[0].CreatedOrUpdatedDateUTC == dtNow, "A beágyazott GenericAttribute dátumának frissülnie kellett."); + Assert.IsTrue(pendingOrderDtos.All(o => o.OrderStatus == OrderStatus.Pending)); Assert.IsTrue(pendingOrderDtos.Count != 0); } @@ -108,7 +157,7 @@ public sealed class OrderClientTests } [TestMethod] - [DataRow(new[] {1,2,4,7})] + [DataRow(new[] { 1, 2, 4, 7 })] public async Task GetOrderDtoByIds(int[] orderIds) { var orderDtoList = await _signalRClient.GetAllOrderDtoByIds(orderIds); diff --git a/FruitBankHybrid.Shared.Tests/test_debug.ps1 b/FruitBankHybrid.Shared.Tests/test_debug.ps1 new file mode 100644 index 0000000..f466dd9 --- /dev/null +++ b/FruitBankHybrid.Shared.Tests/test_debug.ps1 @@ -0,0 +1,17 @@ +# Test debugger script for JsonExtensionTests +$projectPath = "H:\Applications\Mango\Source\FruitBankHybridApp" +Set-Location $projectPath + +Write-Host "Building test project..." +dotnet build FruitBankHybrid.Shared.Tests/FruitBankHybrid.Shared.Tests.csproj -c Debug + +Write-Host "`nRunning JsonExtensionTests..." +# Use --no-build to avoid the MSBuild conflict +dotnet test FruitBankHybrid.Shared.Tests/FruitBankHybrid.Shared.Tests.csproj ` + --no-build ` + -c Debug ` + --filter "ClassName=FruitBankHybrid.Shared.Tests.JsonExtensionTests" ` + 2>&1 | Tee-Object -FilePath "test_results.txt" + +Write-Host "`n=== Test Results ===" +Get-Content "test_results.txt" | Select-String -Pattern "FAILED|PASSED|Error|Assert" | tail -50 diff --git a/FruitBankHybrid.Shared/Components/PalletItemComponent.razor b/FruitBankHybrid.Shared/Components/PalletItemComponent.razor index ffa19fc..9b534e9 100644 --- a/FruitBankHybrid.Shared/Components/PalletItemComponent.razor +++ b/FruitBankHybrid.Shared/Components/PalletItemComponent.razor @@ -182,6 +182,8 @@ StateHasChanged(); //Az Audit button miatt kell a StateHasChanged(), most már van RevisorId és emiatt disabled lesz... + PalletItem.SetParentPropToNull(); + var responseShippingItemPallet = await FruitBankSignalRClient.PostDataAsync(AddOrUpdateSignalRTag!.Value, PalletItem); if (responseShippingItemPallet == null) { diff --git a/FruitBankHybrid.Shared/Components/StockTakings/StockTakingTemplate.razor b/FruitBankHybrid.Shared/Components/StockTakings/StockTakingTemplate.razor index 24f30d7..ebf7d5f 100644 --- a/FruitBankHybrid.Shared/Components/StockTakings/StockTakingTemplate.razor +++ b/FruitBankHybrid.Shared/Components/StockTakings/StockTakingTemplate.razor @@ -1,5 +1,6 @@ @using AyCode.Core.Extensions @using AyCode.Utils.Extensions +@using DevExpress.Blazor @using FruitBank.Common.Dtos @using FruitBank.Common.Entities @using FruitBank.Common.Helpers @@ -42,8 +43,7 @@ - + @@ -157,9 +157,18 @@ private async Task StockTakingComboValueChanged(StockTaking? newValue) { SelectedStockTaking = newValue; - SelectedStockTaking?.StockTakingItems = await FruitBankSignalRClient.GetStockTakingItemsByStockTakingId(SelectedStockTaking.Id); - _stockTakingItems = SelectedStockTaking?.StockTakingItems? + + PrepareStockTakingItems(SelectedStockTaking); + + SelectedStockTakingItem = _stockTakingItems.FirstOrDefault(); + + StateHasChanged(); + } + + private void PrepareStockTakingItems(StockTaking? stockTaking) + { + _stockTakingItems = stockTaking?.StockTakingItems? .OrderByDescending(x => x.IsInvalid) .ThenByDescending(x => x.IsRequiredForMeasuring) .ThenBy(x => x.Product?.Name) @@ -168,17 +177,18 @@ foreach (var stockTakingItem in _stockTakingItems) { stockTakingItem.StockTakingItemPallets ??= []; - stockTakingItem.StockTaking = SelectedStockTaking; + stockTakingItem.StockTaking = stockTaking; if (!stockTakingItem.IsInvalid && stockTakingItem.StockTakingItemPallets.Count == 0) { stockTakingItem.StockTakingItemPallets.Add(MeasurementService.CreateNewStockTakingItemPallet(stockTakingItem, LoggedInModel.CustomerDto)); } + else + { + foreach (var stockTakingItemPallet in stockTakingItem.StockTakingItemPallets) + stockTakingItemPallet.StockTakingItem = stockTakingItem; + } } - - SelectedStockTakingItem = _stockTakingItems.FirstOrDefault(); - - StateHasChanged(); } private Task OnStockTakingItemPalletValueChanged(StockTakingItemPallet stockTakingItemPallet, StockTakingItem stockTakingItem) @@ -194,6 +204,7 @@ { if (responseStockTakingItemPallet != null) { + responseStockTakingItemPallet.StockTakingItem = SelectedStockTakingItem; SelectedStockTakingItem!.MeasuredStockQuantity = responseStockTakingItemPallet.TrayQuantity; if (SelectedStockTakingItem.IsMeasurable) SelectedStockTakingItem.MeasuredNetWeight = responseStockTakingItemPallet.NetWeight; diff --git a/FruitBankHybrid.Shared/FruitBankHybrid.Shared.csproj b/FruitBankHybrid.Shared/FruitBankHybrid.Shared.csproj index 3a92d0c..80524fe 100644 --- a/FruitBankHybrid.Shared/FruitBankHybrid.Shared.csproj +++ b/FruitBankHybrid.Shared/FruitBankHybrid.Shared.csproj @@ -19,7 +19,7 @@ - + diff --git a/FruitBankHybrid.Shared/Pages/MeasuringIn.razor.cs b/FruitBankHybrid.Shared/Pages/MeasuringIn.razor.cs index 77f50a2..d917e45 100644 --- a/FruitBankHybrid.Shared/Pages/MeasuringIn.razor.cs +++ b/FruitBankHybrid.Shared/Pages/MeasuringIn.razor.cs @@ -156,6 +156,8 @@ namespace FruitBankHybrid.Shared.Pages { if (responseShippingItemPallet != null) { + responseShippingItemPallet.ShippingItem = SelectedShippingItem; + SelectedShippingItem!.ShippingItemPallets!.UpdateCollection(responseShippingItemPallet, false); SelectedShippingItem.IsMeasured = SelectedShippingItem!.ShippingItemPallets!.All(sip => sip.IsMeasuredAndValid(SelectedShippingItem.IsMeasurable)); @@ -197,8 +199,14 @@ namespace FruitBankHybrid.Shared.Pages shippingItem.ShippingItemPallets ??= new List(shippingItem.MeasuringCount); - for (var i = shippingItem.ShippingItemPallets.Count; i < shippingItem.MeasuringCount; i++) + for (var i = 0; i < shippingItem.MeasuringCount; i++) { + if (i < shippingItem.ShippingItemPallets.Count) + { + shippingItem.ShippingItemPallets[i].ShippingItem = shippingItem; + continue; + } + shippingItem.ShippingItemPallets.Add(MeasurementService.CreateNewShippingItemPallet(shippingItem, LoggedInModel.CustomerDto)); } } diff --git a/FruitBankHybrid.Shared/Pages/MeasuringOut.razor.cs b/FruitBankHybrid.Shared/Pages/MeasuringOut.razor.cs index 4550ffd..97a276c 100644 --- a/FruitBankHybrid.Shared/Pages/MeasuringOut.razor.cs +++ b/FruitBankHybrid.Shared/Pages/MeasuringOut.razor.cs @@ -93,10 +93,14 @@ namespace FruitBankHybrid.Shared.Pages if (SelectedDate != orderDto.DateOfReceipt.Value.Date) return; - var selectedOrderId = SelectedOrder?.Id; - SelectedDayOrders.UpdateCollection(orderDto, false); + //Elég lenne ez is, csak a CopyTo a Collection - ökben lévő elemeket hozzáfűzi és duplikálva lesznek... -J. + if (SelectedOrder?.Id == orderDto.Id) orderDto.CopyTo(SelectedOrder); + else SelectedDayOrders.UpdateCollection(orderDto, false); - if (selectedOrderId.GetValueOrDefault(-1) == orderDto.Id) SelectedOrder = orderDto; + //var selectedOrderId = SelectedOrder?.Id; + //SelectedDayOrders.UpdateCollection(orderDto, false); + + //if (selectedOrderId.GetValueOrDefault(-1) == orderDto.Id) SelectedOrder = orderDto; } await InvokeAsync(StateHasChanged); @@ -112,6 +116,8 @@ namespace FruitBankHybrid.Shared.Pages if (localOrderItemDto == null) return; + //orderItemDto.OrderDto = localOrderDto!; + localOrderItemDto.Quantity = orderItemDto.Quantity; localOrderItemDto.GenericAttributes.UpdateBaseEntityCollection(orderItemDto.GenericAttributes, false); } @@ -129,6 +135,7 @@ namespace FruitBankHybrid.Shared.Pages orderItemDto = orderItemDtos?.FirstOrDefault(oi => oi.Id == orderItemPallet.OrderItemId); if (orderItemDto == null) return; + orderItemPallet.OrderItemDto = orderItemDto; var orderItemPalletsCount = orderItemDto.OrderItemPallets.Count; if (orderItemDto.OrderItemPallets[orderItemPalletsCount - 1].Id == 0) orderItemDto.OrderItemPallets.Insert(orderItemPalletsCount - 1, orderItemPallet); @@ -163,7 +170,7 @@ namespace FruitBankHybrid.Shared.Pages SelectedDayOrders = orders.Where(order => MeasurementService.DaysEqual(order.DateOfReceiptOrCreated, dateTime)).OrderBy(x => x.DateOfReceipt).ToList(); - foreach (var orderDto in SelectedDayOrders) PrepareOrderDto(orderDto); + foreach (var orderDto in SelectedDayOrders) PrepareOrderItemDtos(orderDto); SelectedOrder = LoggedInModel.IsRevisor ? SelectedDayOrders.FirstOrDefault(o => o is { IsComplete: false, IsMeasured: true }) @@ -235,16 +242,18 @@ namespace FruitBankHybrid.Shared.Pages return Task.CompletedTask; } - private Task OnPalletItemAuditedClick(OrderItemPallet? orderItemPallet, OrderItemDto selectedOrderItemDto) + private async Task OnPalletItemAuditedClick(OrderItemPallet? orderItemPallet, OrderItemDto selectedOrderItemDto) { - StateHasChanged(); - return Task.CompletedTask; + if (orderItemPallet == null) return; + await OnOrderItemPalletSaved(orderItemPallet, selectedOrderItemDto); } private async Task OnOrderItemPalletSaved(OrderItemPallet? orderItemPallet, OrderItemDto selectedOrderItemDto) { if (orderItemPallet != null) { + orderItemPallet.OrderItemDto = selectedOrderItemDto; + selectedOrderItemDto.OrderItemPallets.UpdateCollection(orderItemPallet, false); //MeasuringValuesHelper.SetShippingItemTotalMeasuringValues(SelectedShippingItem); } @@ -293,7 +302,7 @@ namespace FruitBankHybrid.Shared.Pages var responseOrderDto = await FruitBankSignalRClient.StartMeasuring(SelectedOrder.Id, LoggedInModel.CustomerDto!.Id); if (responseOrderDto != null) { - PrepareOrderDto(responseOrderDto); + PrepareOrderItemDtos(responseOrderDto); //SelectedOrder.GenericAttributes.UpdateBaseEntityCollection(responseOrderDto.GenericAttributes, false); SelectedDayOrders.UpdateCollection(responseOrderDto, false); @@ -313,7 +322,7 @@ namespace FruitBankHybrid.Shared.Pages var responseOrderDto = await FruitBankSignalRClient.SetOrderStatusToComplete(SelectedOrder.Id, LoggedInModel.CustomerDto!.Id); if (responseOrderDto != null) { - PrepareOrderDto(responseOrderDto); + PrepareOrderItemDtos(responseOrderDto); SelectedDayOrders.UpdateCollection(responseOrderDto, false); SelectedOrder = responseOrderDto; @@ -327,11 +336,18 @@ namespace FruitBankHybrid.Shared.Pages } } - private void PrepareOrderDto(OrderDto orderDto) + private void PrepareOrderItemDtos(OrderDto orderDto) { - foreach (var orderItemDto in orderDto.OrderItemDtos.Where(orderItem => orderItem.OrderItemPallets.Count == 0)) + foreach (var orderItemDto in orderDto.OrderItemDtos) { - orderItemDto.OrderItemPallets.Add(MeasurementService.CreateNewOrderItemPallet(orderItemDto, LoggedInModel.CustomerDto)); + orderItemDto.OrderDto = orderDto; + + if (orderItemDto.OrderItemPallets.Count == 0) orderItemDto.OrderItemPallets.Add(MeasurementService.CreateNewOrderItemPallet(orderItemDto, LoggedInModel.CustomerDto)); + else + { + foreach (var orderItemPallet in orderItemDto.OrderItemPallets) + orderItemPallet.OrderItemDto = orderItemDto; + } } } diff --git a/FruitBankHybrid.Web.Client/FruitBankHybrid.Web.Client.csproj b/FruitBankHybrid.Web.Client/FruitBankHybrid.Web.Client.csproj index 88faca5..e3b09f6 100644 --- a/FruitBankHybrid.Web.Client/FruitBankHybrid.Web.Client.csproj +++ b/FruitBankHybrid.Web.Client/FruitBankHybrid.Web.Client.csproj @@ -17,7 +17,7 @@ - + diff --git a/FruitBankHybrid.Web/FruitBankHybrid.Web.csproj b/FruitBankHybrid.Web/FruitBankHybrid.Web.csproj index ea4588f..c1a09aa 100644 --- a/FruitBankHybrid.Web/FruitBankHybrid.Web.csproj +++ b/FruitBankHybrid.Web/FruitBankHybrid.Web.csproj @@ -23,7 +23,7 @@ - + diff --git a/FruitBankHybrid/FruitBankHybrid.csproj b/FruitBankHybrid/FruitBankHybrid.csproj index 2201a11..12b3d17 100644 --- a/FruitBankHybrid/FruitBankHybrid.csproj +++ b/FruitBankHybrid/FruitBankHybrid.csproj @@ -96,6 +96,7 @@ +