PartnerDepot API, SignalRTags fixes, and test for duplicates

- Added PartnerDepot CRUD API to IFruitBankDataControllerCommon and FruitBankSignalRClient.
- Fixed Partner entity association to ShippingDocument.PartnerId.
- Changed EkaerHistory to sealed, added ForeignKey, IsOutgoing, Created.
- Exposed GetEkaerHistoriesByForeignKey in SignalRTags.
- Fixed SignalRTags usage in ShippingDocument queries.
- Implemented ProductDtoTableItem deserialization workaround.
- Added unit test to detect duplicate SignalRTags constant values.
This commit is contained in:
Loretta 2026-06-07 07:20:07 +02:00
parent 0083a7bd6e
commit 3b22b07d02
7 changed files with 78 additions and 11 deletions

View File

@ -11,7 +11,7 @@ namespace FruitBank.Common.Entities;
[Table(Name = FruitBankConstClient.EkaerHistoryDbTableName)] [Table(Name = FruitBankConstClient.EkaerHistoryDbTableName)]
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.EkaerHistoryDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.EkaerHistoryDbTableName)]
public abstract class EkaerHistory: MgEntityBase, ITimeStampInfo public sealed class EkaerHistory: MgEntityBase, ITimeStampInfo
{ {
public int ForeignKey { get; set; } public int ForeignKey { get; set; }
public bool IsOutgoing { get; set; } public bool IsOutgoing { get; set; }

View File

@ -11,6 +11,6 @@ namespace FruitBank.Common.Entities;
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.PartnerDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.PartnerDbTableName)]
public sealed class Partner : PartnerBase, IPartner public sealed class Partner : PartnerBase, IPartner
{ {
[Association(ThisKey = nameof(Id), OtherKey = nameof(ShippingDocument.ShippingId), CanBeNull = true)] [Association(ThisKey = nameof(Id), OtherKey = nameof(ShippingDocument.PartnerId), CanBeNull = true)]
public List<ShippingDocument>? ShippingDocuments { get; set; } public List<ShippingDocument>? ShippingDocuments { get; set; }
} }

View File

@ -20,6 +20,14 @@ public interface IFruitBankDataControllerCommon
public Task<Partner?> UpdatePartner(Partner partner); public Task<Partner?> UpdatePartner(Partner partner);
#endregion Partner #endregion Partner
#region PartnerDepot
public Task<List<PartnerDepot>?> GetPartnerDepots();
public Task<PartnerDepot?> GetPartnerDepotById(int id);
public Task<List<PartnerDepot>?> GetPartnerDepotsByPartnerId(int partnerId);
public Task<PartnerDepot?> AddPartnerDepot(PartnerDepot partnerDepot);
public Task<PartnerDepot?> UpdatePartnerDepot(PartnerDepot partnerDepot);
#endregion PartnerDepot
#region CargoPartner #region CargoPartner
public Task<List<CargoPartner>?> GetCargoPartners(); public Task<List<CargoPartner>?> GetCargoPartners();
public Task<CargoPartner?> GetCargoPartnerById(int id); public Task<CargoPartner?> GetCargoPartnerById(int id);

View File

@ -120,7 +120,7 @@ public class SignalRTags : AcSignalRTags
public const int GetEkaerHistories = 185; public const int GetEkaerHistories = 185;
public const int GetEkaerHistoryById = 186; public const int GetEkaerHistoryById = 186;
//public const int GetEkaerHistoriesByForeignKey = 187; public const int GetEkaerHistoriesByForeignKey = 187;
public const int AddEkaerHistory = 188; public const int AddEkaerHistory = 188;
public const int UpdateEkaerHistory = 189; public const int UpdateEkaerHistory = 189;

View File

@ -0,0 +1,38 @@
using System.Reflection;
using FruitBank.Common.SignalRs;
namespace FruitBankHybrid.Shared.Tests
{
[TestClass]
public sealed class SignalRTagsTests
{
/// <summary>
/// A <see cref="SignalRTags"/> értékei a drót-protokoll azonosítói: két azonos értékű
/// konstans (jellemzően copy-paste után) némán másik endpointra irányítaná a hívást.
/// A kézi számkiosztás szándékos (stabil szerződés), ez a teszt csak alá feszít egy hálót:
/// kibukik a duplikátumon, és megnevezi a vétkes konstansokat.
/// </summary>
/// <remarks>
/// Csak a <see cref="SignalRTags"/>-ben DEKLARÁLT konstansokat vizsgálja (<c>DeclaredOnly</c>) —
/// ide ír a fejlesztő kézzel. A framework-ős <c>AcSignalRTags</c>-szal való átfedés
/// ellenőrzéséhez <c>BindingFlags.FlattenHierarchy</c> kellene.
/// </remarks>
[TestMethod]
public void SignalRTags_HasNoDuplicateValues()
{
var tags = typeof(SignalRTags)
.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
.Where(f => f.IsLiteral && f.FieldType == typeof(int))
.Select(f => (f.Name, Value: (int)f.GetRawConstantValue()!))
.ToList();
var duplicates = tags
.GroupBy(t => t.Value)
.Where(g => g.Count() > 1)
.Select(g => $" {g.Key} = {string.Join(", ", g.Select(t => t.Name))}")
.ToList();
Assert.AreEqual(0, duplicates.Count, $"Több SignalRTag ugyanazt az értéket kapta:{Environment.NewLine}{string.Join(Environment.NewLine, duplicates)}");
}
}
}

View File

@ -70,6 +70,8 @@ public class ProductDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : Ac
//Clear(); //Clear();
this.Replace(items); this.Replace(items);
//this.Replace(items.Cast<ProductDtoTableItem>());
//foreach (var productDto in items) //foreach (var productDto in items)
//{ //{
// this.UpdateCollection(productDto, false); // this.UpdateCollection(productDto, false);

View File

@ -66,6 +66,14 @@ namespace FruitBankHybrid.Shared.Services.SignalRs
public Task<Partner?> UpdatePartner(Partner partner) => PostDataAsync(SignalRTags.UpdatePartner, partner); public Task<Partner?> UpdatePartner(Partner partner) => PostDataAsync(SignalRTags.UpdatePartner, partner);
#endregion Partner #endregion Partner
#region PartnerDepot
public Task<List<PartnerDepot>?> GetPartnerDepots() => GetAllAsync<List<PartnerDepot>>(SignalRTags.GetPartnerDepots);
public Task<PartnerDepot?> GetPartnerDepotById(int id) => GetByIdAsync<PartnerDepot?>(SignalRTags.GetPartnerDepotById, id);
public Task<List<PartnerDepot>?> GetPartnerDepotsByPartnerId(int partnerId) => GetAllAsync<List<PartnerDepot>>(SignalRTags.GetPartnerDepotsByPartnerId, [partnerId]);
public Task<PartnerDepot?> AddPartnerDepot(PartnerDepot partnerDepot) => PostDataAsync(SignalRTags.AddPartnerDepot, partnerDepot);
public Task<PartnerDepot?> UpdatePartnerDepot(PartnerDepot partnerDepot) => PostDataAsync(SignalRTags.UpdatePartnerDepot, partnerDepot);
#endregion PartnerDepot
#region CargoPartner #region CargoPartner
public Task<List<CargoPartner>?> GetCargoPartners() => GetAllAsync<List<CargoPartner>>(SignalRTags.GetCargoPartners); public Task<List<CargoPartner>?> GetCargoPartners() => GetAllAsync<List<CargoPartner>>(SignalRTags.GetCargoPartners);
public Task<CargoPartner?> GetCargoPartnerById(int id) => GetByIdAsync<CargoPartner?>(SignalRTags.GetCargoPartnerById, id); public Task<CargoPartner?> GetCargoPartnerById(int id) => GetByIdAsync<CargoPartner?>(SignalRTags.GetCargoPartnerById, id);
@ -163,10 +171,10 @@ namespace FruitBankHybrid.Shared.Services.SignalRs
=> GetAllAsync<List<ShippingDocument>>(SignalRTags.GetShippingDocumentsByShippingId, [shippingId]); => GetAllAsync<List<ShippingDocument>>(SignalRTags.GetShippingDocumentsByShippingId, [shippingId]);
public Task<List<ShippingDocument>?> GetShippingDocumentsByProductId(int productId) public Task<List<ShippingDocument>?> GetShippingDocumentsByProductId(int productId)
=> GetAllAsync<List<ShippingDocument>>(SignalRTags.GetShippingDocumentsByShippingId, [productId]); => GetAllAsync<List<ShippingDocument>>(SignalRTags.GetShippingDocumentsByProductId, [productId]);
public Task<List<ShippingDocument>?> GetShippingDocumentsByPartnerId(int partnerId) public Task<List<ShippingDocument>?> GetShippingDocumentsByPartnerId(int partnerId)
=> GetAllAsync<List<ShippingDocument>>(SignalRTags.GetShippingDocumentsByShippingId, [partnerId]); => GetAllAsync<List<ShippingDocument>>(SignalRTags.GetShippingDocumentsByPartnerId, [partnerId]);
public Task<ShippingDocument?> AddShippingDocument(ShippingDocument shippingDocument) public Task<ShippingDocument?> AddShippingDocument(ShippingDocument shippingDocument)
=> PostDataAsync(SignalRTags.AddShippingDocument, shippingDocument); => PostDataAsync(SignalRTags.AddShippingDocument, shippingDocument);
@ -185,18 +193,29 @@ namespace FruitBankHybrid.Shared.Services.SignalRs
#endregion Customer #endregion Customer
#region Product #region Product
//TODO: itt ProductDtoTableItem kéne, csak az AycodeHubProtocol ProductDto-ra deserialize-ol! - J.
//public Task<List<ProductDto>?> GetProductDtoTableItems() => GetAllAsync<List<ProductDto>>(SignalRTags.GetProductDtos);
// IDEIGLENES gyors fix: a GetProductDtos tagon a szerver List<ProductDto>-t küld, a binár
// protokoll viszont a wire-típusba (ProductDto) deszerializál — így a közvetlen
// List<ProductDtoTableItem> kérés üres lett (a ProductDtoTableItem a ProductDto kliens-oldali
// leszármazottja, amit a szerver nem ismer). A működő GetProductDtos()-t hívjuk, és bináris
// round-trippel a kért leszármazottra alakítjuk (azonos mezők). VÉGLEGES megoldás: requestId →
// kért-típus a protokollban (AQN-leváltás) — lásd AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL.
public async Task<List<ProductDtoTableItem>?> GetProductDtoTableItems()
{
var dtos = await GetProductDtos();
if (dtos == null) return null;
public Task<List<ProductDtoTableItem>?> GetProductDtoTableItems() var bytes = SignalRSerializationHelper.SerializeToBinary(dtos);
=> GetAllAsync<List<ProductDtoTableItem>>(SignalRTags.GetProductDtos); return SignalRSerializationHelper.DeserializeFromBinary<List<ProductDtoTableItem>>(bytes);
}
public Task<List<ProductDto>?> GetProductDtos() public Task<List<ProductDto>?> GetProductDtos() => GetAllAsync<List<ProductDto>>(SignalRTags.GetProductDtos);
=> GetAllAsync<List<ProductDto>>(SignalRTags.GetProductDtos);
//public Task<List<MeasuringProductDto>?> GetAllMeasuringProductDtos() //public Task<List<MeasuringProductDto>?> GetAllMeasuringProductDtos()
// => GetAllAsync<List<MeasuringProductDto>>(SignalRTags.GetAllMeasuringProductDtos); // => GetAllAsync<List<MeasuringProductDto>>(SignalRTags.GetAllMeasuringProductDtos);
public Task<ProductDto?> GetProductDtoById(int productId) public Task<ProductDto?> GetProductDtoById(int productId) => GetByIdAsync<ProductDto?>(SignalRTags.GetMeasuringProductDtoById, productId);
=> GetByIdAsync<ProductDto?>(SignalRTags.GetMeasuringProductDtoById, productId);
#endregion Product #endregion Product