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.
This commit is contained in:
parent
1b6aae83f1
commit
346d433196
|
|
@ -15,7 +15,7 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.11" />
|
||||||
<!--<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.2.0" />-->
|
<!--<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.2.0" />-->
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.11" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.11" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,9 @@ public abstract class MeasuringItemPalletBase : MgEntityBase, IMeasuringItemPall
|
||||||
[NotColumn, System.ComponentModel.DataAnnotations.Schema.NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
|
[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 virtual MeasuringStatus MeasuringStatus => IsMeasured ? MeasuringStatus.Finnished : Id > 0 ? MeasuringStatus.Started : MeasuringStatus.NotStarted;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract void SetParentPropToNull();
|
||||||
|
|
||||||
public void SetForeignKey(int foreignKey) => ForeignItemId = foreignKey;
|
public void SetForeignKey(int foreignKey) => ForeignItemId = foreignKey;
|
||||||
public virtual double CalculateNetWeight() => double.Round(GrossWeight - PalletWeight - (TareWeight * TrayQuantity), 1);
|
public virtual double CalculateNetWeight() => double.Round(GrossWeight - PalletWeight - (TareWeight * TrayQuantity), 1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ using LinqToDB.Mapping;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Nop.Core.Domain.Orders;
|
using Nop.Core.Domain.Orders;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Column = LinqToDB.Mapping.ColumnAttribute;
|
||||||
|
using Table = LinqToDB.Mapping.TableAttribute;
|
||||||
|
|
||||||
namespace FruitBank.Common.Entities;
|
namespace FruitBank.Common.Entities;
|
||||||
|
|
||||||
[LinqToDB.Mapping.Table(Name = FruitBankConstClient.OrderItemPalletDbTableName)]
|
[Table(Name = FruitBankConstClient.OrderItemPalletDbTableName)]
|
||||||
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.OrderItemPalletDbTableName)]
|
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.OrderItemPalletDbTableName)]
|
||||||
public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet
|
public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet
|
||||||
{
|
{
|
||||||
|
|
@ -21,6 +23,7 @@ public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet
|
||||||
public int RevisorId { get; set; }
|
public int RevisorId { get; set; }
|
||||||
public bool IsAudited => RevisorId > 0;
|
public bool IsAudited => RevisorId > 0;
|
||||||
|
|
||||||
|
//[JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
|
||||||
[Association(ThisKey = nameof(OrderItemId), OtherKey = nameof(OrderItemDto.Id), CanBeNull = true)]
|
[Association(ThisKey = nameof(OrderItemId), OtherKey = nameof(OrderItemDto.Id), CanBeNull = true)]
|
||||||
public OrderItemDto? OrderItemDto { get; set; }
|
public OrderItemDto? OrderItemDto { get; set; }
|
||||||
|
|
||||||
|
|
@ -35,6 +38,7 @@ public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet
|
||||||
|
|
||||||
[NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
|
[NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
|
||||||
public double AverageWeight => double.Round(NetWeight / TrayQuantity, 1);
|
public double AverageWeight => double.Round(NetWeight / TrayQuantity, 1);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Szigorúbb" mint az IsValidSafeMeasuringValues()
|
/// "Szigorúbb" mint az IsValidSafeMeasuringValues()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -44,4 +48,9 @@ public class OrderItemPallet : MeasuringItemPalletBase, IOrderItemPallet
|
||||||
{
|
{
|
||||||
return OrderItemId > 0 && base.IsValidMeasuringValues(isMeasurable);
|
return OrderItemId > 0 && base.IsValidMeasuringValues(isMeasurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetParentPropToNull()
|
||||||
|
{
|
||||||
|
OrderItemDto = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using FruitBank.Common.Interfaces;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using FruitBank.Common.Interfaces;
|
|
||||||
using LinqToDB.Mapping;
|
using LinqToDB.Mapping;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
namespace FruitBank.Common.Entities;
|
namespace FruitBank.Common.Entities;
|
||||||
|
|
||||||
[Table(Name = FruitBankConstClient.ShippingItemPalletDbTableName)]
|
[LinqToDB.Mapping.Table(Name = FruitBankConstClient.ShippingItemPalletDbTableName)]
|
||||||
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.ShippingItemPalletDbTableName)]
|
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.ShippingItemPalletDbTableName)]
|
||||||
public class ShippingItemPallet : MeasuringItemPalletBase, IShippingItemPallet
|
public class ShippingItemPallet : MeasuringItemPalletBase, IShippingItemPallet
|
||||||
{
|
{
|
||||||
|
|
@ -15,6 +16,7 @@ public class ShippingItemPallet : MeasuringItemPalletBase, IShippingItemPallet
|
||||||
set => ForeignItemId = value;
|
set => ForeignItemId = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//[Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
|
||||||
[LinqToDB.Mapping.Association(ThisKey = nameof(ShippingItemId), OtherKey = nameof(ShippingItem.Id), CanBeNull = true)]
|
[LinqToDB.Mapping.Association(ThisKey = nameof(ShippingItemId), OtherKey = nameof(ShippingItem.Id), CanBeNull = true)]
|
||||||
public ShippingItem? ShippingItem { get; set; }
|
public ShippingItem? ShippingItem { get; set; }
|
||||||
|
|
||||||
|
|
@ -34,4 +36,9 @@ public class ShippingItemPallet : MeasuringItemPalletBase, IShippingItemPallet
|
||||||
{
|
{
|
||||||
return ShippingItemId > 0 && base.IsValidMeasuringValues(isMeasurable);
|
return ShippingItemId > 0 && base.IsValidMeasuringValues(isMeasurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetParentPropToNull()
|
||||||
|
{
|
||||||
|
ShippingItem = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,5 +7,9 @@ namespace FruitBank.Common.Entities;
|
||||||
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.StockTakingDbTableName)]
|
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.StockTakingDbTableName)]
|
||||||
public class StockTaking : MgStockTaking<StockTakingItem>
|
public class StockTaking : MgStockTaking<StockTakingItem>
|
||||||
{
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using FruitBank.Common.Interfaces;
|
using FruitBank.Common.Interfaces;
|
||||||
using LinqToDB.Mapping;
|
using LinqToDB.Mapping;
|
||||||
using Mango.Nop.Core.Entities;
|
using Mango.Nop.Core.Entities;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace FruitBank.Common.Entities;
|
namespace FruitBank.Common.Entities;
|
||||||
|
|
||||||
|
|
@ -11,7 +12,7 @@ public interface IStockTakingItemPallet : IMeasuringItemPalletBase
|
||||||
public StockTakingItem? StockTakingItem{ get; set; }
|
public StockTakingItem? StockTakingItem{ get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Table(Name = FruitBankConstClient.StockTakingItemPalletDbTableName)]
|
[LinqToDB.Mapping.Table(Name = FruitBankConstClient.StockTakingItemPalletDbTableName)]
|
||||||
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.StockTakingItemPalletDbTableName)]
|
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.StockTakingItemPalletDbTableName)]
|
||||||
public class StockTakingItemPallet : MeasuringItemPalletBase, IStockTakingItemPallet
|
public class StockTakingItemPallet : MeasuringItemPalletBase, IStockTakingItemPallet
|
||||||
{
|
{
|
||||||
|
|
@ -21,6 +22,7 @@ public class StockTakingItemPallet : MeasuringItemPalletBase, IStockTakingItemPa
|
||||||
set => ForeignItemId = value;
|
set => ForeignItemId = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//[Newtonsoft.Json.JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
|
||||||
[Association(ThisKey = nameof(StockTakingItemId), OtherKey = nameof(StockTakingItem.Id), CanBeNull = true)]
|
[Association(ThisKey = nameof(StockTakingItemId), OtherKey = nameof(StockTakingItem.Id), CanBeNull = true)]
|
||||||
public StockTakingItem? StockTakingItem { get; set; }
|
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)
|
return StockTakingItemId > 0 && TrayQuantity >= 0 && ((!isMeasurable && NetWeight == 0 && GrossWeight == 0 && PalletWeight == 0 && TareWeight == 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
<PackageReference Include="MessagePack" Version="3.1.4" />
|
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||||
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.11" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.11" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ public interface IMeasuringItemPalletBase : IEntityInt, IMeasuringValues, IMeasu
|
||||||
int? CreatorId { get; set; }
|
int? CreatorId { get; set; }
|
||||||
int? ModifierId { get; set; }
|
int? ModifierId { get; set; }
|
||||||
|
|
||||||
|
void SetParentPropToNull();
|
||||||
|
|
||||||
double CalculateNetWeight();
|
double CalculateNetWeight();
|
||||||
|
|
||||||
bool IsValidSafeMeasuringValues();
|
bool IsValidSafeMeasuringValues();
|
||||||
|
|
|
||||||
|
|
@ -93,11 +93,12 @@ public class SignalRTags : AcSignalRTags
|
||||||
public const int GetStockTakings = 170;
|
public const int GetStockTakings = 170;
|
||||||
public const int AddStockTaking = 171;
|
public const int AddStockTaking = 171;
|
||||||
public const int UpdateStockTaking = 172;
|
public const int UpdateStockTaking = 172;
|
||||||
public const int GetStockTakingItems = 173;
|
public const int CloseStockTaking = 173;
|
||||||
public const int GetStockTakingItemsById = 174;
|
public const int GetStockTakingItems = 174;
|
||||||
public const int GetStockTakingItemsByProductId = 175;
|
public const int GetStockTakingItemsById = 175;
|
||||||
public const int GetStockTakingItemsByStockTakingId = 176;
|
public const int GetStockTakingItemsByProductId = 176;
|
||||||
public const int AddOrUpdateMeasuredStockTakingItemPallet = 177;
|
public const int GetStockTakingItemsByStockTakingId = 177;
|
||||||
|
public const int AddOrUpdateMeasuredStockTakingItemPallet = 178;
|
||||||
|
|
||||||
|
|
||||||
public const int AuthenticateUser = 195;
|
public const int AuthenticateUser = 195;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MessagePack" Version="3.1.4" />
|
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||||
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -430,16 +430,16 @@ namespace FruitBankHybrid.Shared.Tests
|
||||||
Assert.IsTrue(users.All(x => !x.Email.IsNullOrEmpty() && !x.Deleted));
|
Assert.IsTrue(users.All(x => !x.Email.IsNullOrEmpty() && !x.Deleted));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
//[TestMethod]
|
||||||
[DataRow(CustomerIdAasdDsserverCom)]
|
//[DataRow(CustomerIdAasdDsserverCom)]
|
||||||
public async Task GetCustomerRolesByCustomerIdTest(int customerId)
|
//public async Task GetCustomerRolesByCustomerIdTest(int customerId)
|
||||||
{
|
//{
|
||||||
var customerRoles = await _signalRClient.GetCustomerRolesByCustomerId(customerId);
|
// var customerRoles = await _signalRClient.GetCustomerRolesByCustomerId(customerId);
|
||||||
|
|
||||||
Assert.IsNotNull(customerRoles);
|
// Assert.IsNotNull(customerRoles);
|
||||||
Assert.IsTrue(customerRoles.Count > 0);
|
// Assert.IsTrue(customerRoles.Count > 0);
|
||||||
Assert.IsTrue(customerRoles.Any(cr => cr.SystemName == "Measuring"));
|
// Assert.IsTrue(customerRoles.Any(cr => cr.SystemName == "Measuring"));
|
||||||
}
|
//}
|
||||||
|
|
||||||
#endregion Customer
|
#endregion Customer
|
||||||
|
|
||||||
|
|
@ -461,7 +461,7 @@ namespace FruitBankHybrid.Shared.Tests
|
||||||
//[DataRow(6, false)]
|
//[DataRow(6, false)]
|
||||||
[DataRow(33, true)]
|
[DataRow(33, true)]
|
||||||
[DataRow(64, false)]
|
[DataRow(64, false)]
|
||||||
[DataRow(7, false)]
|
[DataRow(7, true)]
|
||||||
public async Task GetProductDtoByIdTest(int productId, bool isMeasurableExcepted)
|
public async Task GetProductDtoByIdTest(int productId, bool isMeasurableExcepted)
|
||||||
{
|
{
|
||||||
await GetProductDtoByIdAsync(productId, isMeasurableExcepted);
|
await GetProductDtoByIdAsync(productId, isMeasurableExcepted);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@
|
||||||
<TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
|
<TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FruitBank.Common\FruitBank.Common.csproj" />
|
<ProjectReference Include="..\FruitBank.Common\FruitBank.Common.csproj" />
|
||||||
<ProjectReference Include="..\FruitBankHybrid.Shared.Common\FruitBankHybrid.Shared.Common.csproj" />
|
<ProjectReference Include="..\FruitBankHybrid.Shared.Common\FruitBankHybrid.Shared.Common.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Level 1 - Root entity implementing IId<int> (uses semantic ID: "Company_1")
|
||||||
|
/// </summary>
|
||||||
|
public class Company : IId<int>
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
// Collection of IId<int> items
|
||||||
|
public List<Department> Departments { get; set; } = new();
|
||||||
|
|
||||||
|
// Non-IId object (uses numeric ID)
|
||||||
|
public Address HeadquartersAddress { get; set; } = new();
|
||||||
|
|
||||||
|
// Array of IId<int> items
|
||||||
|
public Employee[] BoardMembers { get; set; } = Array.Empty<Employee>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Level 2 - Department implementing IId<int> (uses semantic ID: "Department_1")
|
||||||
|
/// </summary>
|
||||||
|
public class Department : IId<int>
|
||||||
|
{
|
||||||
|
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<int> items
|
||||||
|
public List<Employee> Employees { get; set; } = new();
|
||||||
|
|
||||||
|
// Non-IId object (uses numeric ID)
|
||||||
|
public Address? OfficeAddress { get; set; }
|
||||||
|
|
||||||
|
// Array of IId<Guid> items
|
||||||
|
public Project[] ActiveProjects { get; set; } = Array.Empty<Project>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Level 3 - Employee implementing IId<int> (uses semantic ID: "Employee_1")
|
||||||
|
/// </summary>
|
||||||
|
public class Employee : IId<int>
|
||||||
|
{
|
||||||
|
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<Guid> items
|
||||||
|
public List<Project> AssignedProjects { get; set; } = new();
|
||||||
|
|
||||||
|
// Collection of non-IId items (uses numeric IDs)
|
||||||
|
public List<Skill> Skills { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Level 4 - Project implementing IId<Guid> (uses semantic ID: "Project_guid")
|
||||||
|
/// </summary>
|
||||||
|
public class Project : IId<Guid>
|
||||||
|
{
|
||||||
|
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<int> - circular reference to employees
|
||||||
|
public List<Employee> TeamMembers { get; set; } = new();
|
||||||
|
|
||||||
|
// Array of non-IId items
|
||||||
|
public Milestone[] Milestones { get; set; } = Array.Empty<Milestone>();
|
||||||
|
|
||||||
|
// Collection of IId<long> items
|
||||||
|
public List<ProjectTask> Tasks { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Level 5 - ProjectTask implementing IId<long> (uses semantic ID: "ProjectTask_1")
|
||||||
|
/// Renamed from Task to avoid conflict with System.Threading.Tasks.Task
|
||||||
|
/// </summary>
|
||||||
|
public class ProjectTask : IId<long>
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Non-IId class - Address (uses standard numeric $id)
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Non-IId class - ContactInfo (uses standard numeric $id)
|
||||||
|
/// </summary>
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Non-IId class - Skill (uses standard numeric $id)
|
||||||
|
/// </summary>
|
||||||
|
public class Skill
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public int Level { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Non-IId class - Milestone (uses standard numeric $id)
|
||||||
|
/// </summary>
|
||||||
|
public class Milestone
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public DateTime DueDate { get; set; }
|
||||||
|
public bool IsCompleted { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Non-IId class - TaskMetadata (uses standard numeric $id)
|
||||||
|
/// </summary>
|
||||||
|
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<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#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<IAcLogWriterClientBase>
|
||||||
|
{
|
||||||
|
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<OrderDto>? 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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
|
||||||
|
/// </summary>
|
||||||
|
[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<Skill>
|
||||||
|
{
|
||||||
|
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<Skill>
|
||||||
|
{
|
||||||
|
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<Skill>
|
||||||
|
{
|
||||||
|
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<Employee> { 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<Employee> { 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<T> 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<Company>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test for DeepPopulateWithMerge with hybrid references
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test that verifies circular references don't cause infinite loops
|
||||||
|
/// </summary>
|
||||||
|
[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> { 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<Company>(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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
using AyCode.Core.Enums;
|
using AyCode.Core.Enums;
|
||||||
|
using AyCode.Core.Extensions;
|
||||||
using AyCode.Core.Loggers;
|
using AyCode.Core.Loggers;
|
||||||
using FruitBank.Common;
|
using FruitBank.Common;
|
||||||
|
using FruitBank.Common.Dtos;
|
||||||
using FruitBank.Common.Loggers;
|
using FruitBank.Common.Loggers;
|
||||||
using FruitBankHybrid.Shared.Services.SignalRs;
|
using FruitBankHybrid.Shared.Services.SignalRs;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Nop.Core.Domain.Orders;
|
using Nop.Core.Domain.Orders;
|
||||||
using Nop.Core.Domain.Payments;
|
using Nop.Core.Domain.Payments;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using FruitBank.Common.Entities;
|
||||||
|
using Nop.Core.Domain.Common;
|
||||||
|
|
||||||
namespace FruitBankHybrid.Shared.Tests;
|
namespace FruitBankHybrid.Shared.Tests;
|
||||||
|
|
||||||
|
|
@ -27,11 +33,11 @@ public sealed class OrderClientTests
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task GetAllStockTakings()
|
public async Task GetAllStockTakings()
|
||||||
{
|
{
|
||||||
var stockTakings = await _signalRClient.GetStockTakings();
|
var stockTakings = await _signalRClient.GetStockTakings(true);
|
||||||
|
|
||||||
Assert.IsNotNull(stockTakings);
|
Assert.IsNotNull(stockTakings);
|
||||||
Assert.IsTrue(stockTakings.Count != 0);
|
Assert.IsTrue(stockTakings.Count != 0);
|
||||||
|
|
@ -88,10 +94,53 @@ public sealed class OrderClientTests
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task GetPendingOrderDtos()
|
public async Task GetPendingOrderDtos()
|
||||||
{
|
{
|
||||||
var pendingOrderDtos = await _signalRClient.GetPendingOrderDtos();
|
var initialCount = 28;
|
||||||
|
List<OrderDto>? pendingOrderDtos = (await _signalRClient.GetPendingOrderDtos())?.Take(initialCount).ToList();
|
||||||
|
|
||||||
Assert.IsNotNull(pendingOrderDtos);
|
Assert.IsNotNull(pendingOrderDtos);
|
||||||
|
|
||||||
|
// Másolat létrehozása a frissítendő adatok generálásához
|
||||||
|
List<OrderDto>? 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<object, object>()),
|
||||||
|
|
||||||
|
// // 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.All(o => o.OrderStatus == OrderStatus.Pending));
|
||||||
Assert.IsTrue(pendingOrderDtos.Count != 0);
|
Assert.IsTrue(pendingOrderDtos.Count != 0);
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +157,7 @@ public sealed class OrderClientTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[DataRow(new[] {1,2,4,7})]
|
[DataRow(new[] { 1, 2, 4, 7 })]
|
||||||
public async Task GetOrderDtoByIds(int[] orderIds)
|
public async Task GetOrderDtoByIds(int[] orderIds)
|
||||||
{
|
{
|
||||||
var orderDtoList = await _signalRClient.GetAllOrderDtoByIds(orderIds);
|
var orderDtoList = await _signalRClient.GetAllOrderDtoByIds(orderIds);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -182,6 +182,8 @@
|
||||||
|
|
||||||
StateHasChanged(); //Az Audit button miatt kell a StateHasChanged(), most már van RevisorId és emiatt disabled lesz...
|
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);
|
var responseShippingItemPallet = await FruitBankSignalRClient.PostDataAsync(AddOrUpdateSignalRTag!.Value, PalletItem);
|
||||||
if (responseShippingItemPallet == null)
|
if (responseShippingItemPallet == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
@using AyCode.Core.Extensions
|
@using AyCode.Core.Extensions
|
||||||
@using AyCode.Utils.Extensions
|
@using AyCode.Utils.Extensions
|
||||||
|
@using DevExpress.Blazor
|
||||||
@using FruitBank.Common.Dtos
|
@using FruitBank.Common.Dtos
|
||||||
@using FruitBank.Common.Entities
|
@using FruitBank.Common.Entities
|
||||||
@using FruitBank.Common.Helpers
|
@using FruitBank.Common.Helpers
|
||||||
|
|
@ -42,8 +43,7 @@
|
||||||
<DxButton Text="Módosít" Enabled="@(SelectedStockTaking?.IsClosed ?? false)" Click="() => UpdateStockTakingClick()"></DxButton>
|
<DxButton Text="Módosít" Enabled="@(SelectedStockTaking?.IsClosed ?? false)" Click="() => UpdateStockTakingClick()"></DxButton>
|
||||||
</DxFormLayoutItem>
|
</DxFormLayoutItem>
|
||||||
<DxFormLayoutItem ColSpanMd="1">
|
<DxFormLayoutItem ColSpanMd="1">
|
||||||
<DxButton Text="Lezárás" Enabled="@(SelectedStockTaking?.StockTakingItems?.Where(x => x.IsRequiredForMeasuring).All(x => x.IsMeasured) ?? false)"
|
<DxButton Text="Lezárás" Enabled="@(SelectedStockTaking?.IsReadyForClose() ?? false)" Click="() => StockTakingCloseClick()"></DxButton>
|
||||||
Click="() => StockTakingCloseClick()"></DxButton>
|
|
||||||
</DxFormLayoutItem>
|
</DxFormLayoutItem>
|
||||||
|
|
||||||
</DxFormLayout>
|
</DxFormLayout>
|
||||||
|
|
@ -157,9 +157,18 @@
|
||||||
private async Task StockTakingComboValueChanged(StockTaking? newValue)
|
private async Task StockTakingComboValueChanged(StockTaking? newValue)
|
||||||
{
|
{
|
||||||
SelectedStockTaking = newValue;
|
SelectedStockTaking = newValue;
|
||||||
|
|
||||||
SelectedStockTaking?.StockTakingItems = await FruitBankSignalRClient.GetStockTakingItemsByStockTakingId(SelectedStockTaking.Id);
|
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)
|
.OrderByDescending(x => x.IsInvalid)
|
||||||
.ThenByDescending(x => x.IsRequiredForMeasuring)
|
.ThenByDescending(x => x.IsRequiredForMeasuring)
|
||||||
.ThenBy(x => x.Product?.Name)
|
.ThenBy(x => x.Product?.Name)
|
||||||
|
|
@ -168,17 +177,18 @@
|
||||||
foreach (var stockTakingItem in _stockTakingItems)
|
foreach (var stockTakingItem in _stockTakingItems)
|
||||||
{
|
{
|
||||||
stockTakingItem.StockTakingItemPallets ??= [];
|
stockTakingItem.StockTakingItemPallets ??= [];
|
||||||
stockTakingItem.StockTaking = SelectedStockTaking;
|
stockTakingItem.StockTaking = stockTaking;
|
||||||
|
|
||||||
if (!stockTakingItem.IsInvalid && stockTakingItem.StockTakingItemPallets.Count == 0)
|
if (!stockTakingItem.IsInvalid && stockTakingItem.StockTakingItemPallets.Count == 0)
|
||||||
{
|
{
|
||||||
stockTakingItem.StockTakingItemPallets.Add(MeasurementService.CreateNewStockTakingItemPallet(stockTakingItem, LoggedInModel.CustomerDto));
|
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)
|
private Task OnStockTakingItemPalletValueChanged(StockTakingItemPallet stockTakingItemPallet, StockTakingItem stockTakingItem)
|
||||||
|
|
@ -194,6 +204,7 @@
|
||||||
{
|
{
|
||||||
if (responseStockTakingItemPallet != null)
|
if (responseStockTakingItemPallet != null)
|
||||||
{
|
{
|
||||||
|
responseStockTakingItemPallet.StockTakingItem = SelectedStockTakingItem;
|
||||||
SelectedStockTakingItem!.MeasuredStockQuantity = responseStockTakingItemPallet.TrayQuantity;
|
SelectedStockTakingItem!.MeasuredStockQuantity = responseStockTakingItemPallet.TrayQuantity;
|
||||||
|
|
||||||
if (SelectedStockTakingItem.IsMeasurable) SelectedStockTakingItem.MeasuredNetWeight = responseStockTakingItemPallet.NetWeight;
|
if (SelectedStockTakingItem.IsMeasurable) SelectedStockTakingItem.MeasuredNetWeight = responseStockTakingItemPallet.NetWeight;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.11" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,8 @@ namespace FruitBankHybrid.Shared.Pages
|
||||||
{
|
{
|
||||||
if (responseShippingItemPallet != null)
|
if (responseShippingItemPallet != null)
|
||||||
{
|
{
|
||||||
|
responseShippingItemPallet.ShippingItem = SelectedShippingItem;
|
||||||
|
|
||||||
SelectedShippingItem!.ShippingItemPallets!.UpdateCollection(responseShippingItemPallet, false);
|
SelectedShippingItem!.ShippingItemPallets!.UpdateCollection(responseShippingItemPallet, false);
|
||||||
SelectedShippingItem.IsMeasured = SelectedShippingItem!.ShippingItemPallets!.All(sip => sip.IsMeasuredAndValid(SelectedShippingItem.IsMeasurable));
|
SelectedShippingItem.IsMeasured = SelectedShippingItem!.ShippingItemPallets!.All(sip => sip.IsMeasuredAndValid(SelectedShippingItem.IsMeasurable));
|
||||||
|
|
||||||
|
|
@ -197,8 +199,14 @@ namespace FruitBankHybrid.Shared.Pages
|
||||||
|
|
||||||
shippingItem.ShippingItemPallets ??= new List<ShippingItemPallet>(shippingItem.MeasuringCount);
|
shippingItem.ShippingItemPallets ??= new List<ShippingItemPallet>(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));
|
shippingItem.ShippingItemPallets.Add(MeasurementService.CreateNewShippingItemPallet(shippingItem, LoggedInModel.CustomerDto));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,10 +93,14 @@ namespace FruitBankHybrid.Shared.Pages
|
||||||
|
|
||||||
if (SelectedDate != orderDto.DateOfReceipt.Value.Date) return;
|
if (SelectedDate != orderDto.DateOfReceipt.Value.Date) return;
|
||||||
|
|
||||||
var selectedOrderId = SelectedOrder?.Id;
|
//Elég lenne ez is, csak a CopyTo a Collection - ökben lévő elemeket hozzáfűzi és duplikálva lesznek... -J.
|
||||||
SelectedDayOrders.UpdateCollection(orderDto, false);
|
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);
|
await InvokeAsync(StateHasChanged);
|
||||||
|
|
@ -112,6 +116,8 @@ namespace FruitBankHybrid.Shared.Pages
|
||||||
|
|
||||||
if (localOrderItemDto == null) return;
|
if (localOrderItemDto == null) return;
|
||||||
|
|
||||||
|
//orderItemDto.OrderDto = localOrderDto!;
|
||||||
|
|
||||||
localOrderItemDto.Quantity = orderItemDto.Quantity;
|
localOrderItemDto.Quantity = orderItemDto.Quantity;
|
||||||
localOrderItemDto.GenericAttributes.UpdateBaseEntityCollection(orderItemDto.GenericAttributes, false);
|
localOrderItemDto.GenericAttributes.UpdateBaseEntityCollection(orderItemDto.GenericAttributes, false);
|
||||||
}
|
}
|
||||||
|
|
@ -129,6 +135,7 @@ namespace FruitBankHybrid.Shared.Pages
|
||||||
orderItemDto = orderItemDtos?.FirstOrDefault(oi => oi.Id == orderItemPallet.OrderItemId);
|
orderItemDto = orderItemDtos?.FirstOrDefault(oi => oi.Id == orderItemPallet.OrderItemId);
|
||||||
if (orderItemDto == null) return;
|
if (orderItemDto == null) return;
|
||||||
|
|
||||||
|
orderItemPallet.OrderItemDto = orderItemDto;
|
||||||
var orderItemPalletsCount = orderItemDto.OrderItemPallets.Count;
|
var orderItemPalletsCount = orderItemDto.OrderItemPallets.Count;
|
||||||
|
|
||||||
if (orderItemDto.OrderItemPallets[orderItemPalletsCount - 1].Id == 0) orderItemDto.OrderItemPallets.Insert(orderItemPalletsCount - 1, orderItemPallet);
|
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();
|
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
|
SelectedOrder = LoggedInModel.IsRevisor
|
||||||
? SelectedDayOrders.FirstOrDefault(o => o is { IsComplete: false, IsMeasured: true })
|
? SelectedDayOrders.FirstOrDefault(o => o is { IsComplete: false, IsMeasured: true })
|
||||||
|
|
@ -235,16 +242,18 @@ namespace FruitBankHybrid.Shared.Pages
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task OnPalletItemAuditedClick(OrderItemPallet? orderItemPallet, OrderItemDto selectedOrderItemDto)
|
private async Task OnPalletItemAuditedClick(OrderItemPallet? orderItemPallet, OrderItemDto selectedOrderItemDto)
|
||||||
{
|
{
|
||||||
StateHasChanged();
|
if (orderItemPallet == null) return;
|
||||||
return Task.CompletedTask;
|
await OnOrderItemPalletSaved(orderItemPallet, selectedOrderItemDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnOrderItemPalletSaved(OrderItemPallet? orderItemPallet, OrderItemDto selectedOrderItemDto)
|
private async Task OnOrderItemPalletSaved(OrderItemPallet? orderItemPallet, OrderItemDto selectedOrderItemDto)
|
||||||
{
|
{
|
||||||
if (orderItemPallet != null)
|
if (orderItemPallet != null)
|
||||||
{
|
{
|
||||||
|
orderItemPallet.OrderItemDto = selectedOrderItemDto;
|
||||||
|
|
||||||
selectedOrderItemDto.OrderItemPallets.UpdateCollection(orderItemPallet, false);
|
selectedOrderItemDto.OrderItemPallets.UpdateCollection(orderItemPallet, false);
|
||||||
//MeasuringValuesHelper.SetShippingItemTotalMeasuringValues(SelectedShippingItem);
|
//MeasuringValuesHelper.SetShippingItemTotalMeasuringValues(SelectedShippingItem);
|
||||||
}
|
}
|
||||||
|
|
@ -293,7 +302,7 @@ namespace FruitBankHybrid.Shared.Pages
|
||||||
var responseOrderDto = await FruitBankSignalRClient.StartMeasuring(SelectedOrder.Id, LoggedInModel.CustomerDto!.Id);
|
var responseOrderDto = await FruitBankSignalRClient.StartMeasuring(SelectedOrder.Id, LoggedInModel.CustomerDto!.Id);
|
||||||
if (responseOrderDto != null)
|
if (responseOrderDto != null)
|
||||||
{
|
{
|
||||||
PrepareOrderDto(responseOrderDto);
|
PrepareOrderItemDtos(responseOrderDto);
|
||||||
|
|
||||||
//SelectedOrder.GenericAttributes.UpdateBaseEntityCollection(responseOrderDto.GenericAttributes, false);
|
//SelectedOrder.GenericAttributes.UpdateBaseEntityCollection(responseOrderDto.GenericAttributes, false);
|
||||||
SelectedDayOrders.UpdateCollection(responseOrderDto, false);
|
SelectedDayOrders.UpdateCollection(responseOrderDto, false);
|
||||||
|
|
@ -313,7 +322,7 @@ namespace FruitBankHybrid.Shared.Pages
|
||||||
var responseOrderDto = await FruitBankSignalRClient.SetOrderStatusToComplete(SelectedOrder.Id, LoggedInModel.CustomerDto!.Id);
|
var responseOrderDto = await FruitBankSignalRClient.SetOrderStatusToComplete(SelectedOrder.Id, LoggedInModel.CustomerDto!.Id);
|
||||||
if (responseOrderDto != null)
|
if (responseOrderDto != null)
|
||||||
{
|
{
|
||||||
PrepareOrderDto(responseOrderDto);
|
PrepareOrderItemDtos(responseOrderDto);
|
||||||
|
|
||||||
SelectedDayOrders.UpdateCollection(responseOrderDto, false);
|
SelectedDayOrders.UpdateCollection(responseOrderDto, false);
|
||||||
SelectedOrder = responseOrderDto;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<PackageReference Include="MessagePack" Version="3.1.4" />
|
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||||
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
|
||||||
<StaticWebAssetFingerprintPattern Include="JS" Pattern="*.js" Expression="#[.{fingerprint}]!" />
|
<StaticWebAssetFingerprintPattern Include="JS" Pattern="*.js" Expression="#[.{fingerprint}]!" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="9.0.11" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.11" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.11" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="10.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="10.0.11" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.0" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue