Compare commits

..

No commits in common. "3cf18efd99b2fda075c3ce3914dbbd6594607668" and "2221d4a68ebcd601d1041a35b6c67b2ee3f5cf1b" have entirely different histories.

12 changed files with 29 additions and 113 deletions

View File

@ -74,8 +74,7 @@
"WebFetch(domain:net.jogtar.hu)", "WebFetch(domain:net.jogtar.hu)",
"WebFetch(domain:www.itrack.hu)", "WebFetch(domain:www.itrack.hu)",
"WebFetch(domain:docplayer.hu)", "WebFetch(domain:docplayer.hu)",
"WebFetch(domain:supportcenter.devexpress.com)", "WebFetch(domain:supportcenter.devexpress.com)"
"PowerShell($c = Get-Command claude -ErrorAction SilentlyContinue; if \\($c\\) { $c.Source; & claude --help 2>&1 | Select-Object -First 90 } else { \"claude not on PATH\" })"
] ]
} }
} }

View File

@ -37,23 +37,19 @@ public sealed class FruitBankEkaerService : IFruitBankEkaerService
return _submitService.SubmitAsync(operations, cancellationToken); return _submitService.SubmitAsync(operations, cancellationToken);
} }
public EkaerHistory GenerateEkaerXmlDocument(IReadOnlyCollection<ShippingDocument> documents, EkaerHistory? ekaerHistory = null) public EkaerHistory GenerateEkaerXmlDocument(ShippingDocument document, EkaerHistory? ekaerHistory = null)
{ {
ArgumentNullException.ThrowIfNull(documents); ArgumentNullException.ThrowIfNull(document);
if (documents.Count == 0) throw new ArgumentException("documents is empty", nameof(documents)); ekaerHistory ??= new EkaerHistory { ForeignKey = document.Id, IsOutgoing = false };
ekaerHistory ??= new EkaerHistory { IsOutgoing = false };
// A csoport azonos Partneré (a kapu így csoportosít) → az első dokumentum pénzneme a mérvadó. var currency = document.Partner?.Currency;
var currency = documents.First().Partner?.Currency; return TryConfigError(ekaerHistory, currency) ?? Finalize(ekaerHistory, _mapper.MapDocument(document, _settings.Company), currency);
// A csoport ÖSSZES dokumentuma EGY tradeCard-dá (összevont tömeg/érték): ToConsignment → BuildTradeCard.
var tradeCard = _mapper.BuildTradeCard(_mapper.ToConsignment(documents, _settings.Company));
return TryConfigError(ekaerHistory, currency) ?? Finalize(ekaerHistory, tradeCard, currency);
} }
public EkaerHistory GenerateEkaerXmlDocument(OrderDto order, EkaerHistory? ekaerHistory = null) public EkaerHistory GenerateEkaerXmlDocument(OrderDto order, EkaerHistory? ekaerHistory = null)
{ {
ArgumentNullException.ThrowIfNull(order); ArgumentNullException.ThrowIfNull(order);
ekaerHistory ??= new EkaerHistory { IsOutgoing = true }; ekaerHistory ??= new EkaerHistory { ForeignKey = order.Id, IsOutgoing = true };
// Kimenő pénznem: jelenleg minden HUF (a deviza az OrderDto-ba kerül, amint bekötik) → ConversionRate = 1. // Kimenő pénznem: jelenleg minden HUF (a deviza az OrderDto-ba kerül, amint bekötik) → ConversionRate = 1.
const string currency = "HUF"; const string currency = "HUF";
@ -66,12 +62,6 @@ public sealed class FruitBankEkaerService : IFruitBankEkaerService
public EkaerObligationResult EvaluateObligation(OrderDto order) public EkaerObligationResult EvaluateObligation(OrderDto order)
=> EkaerReportability.Evaluate(_mapper.ToConsignment(order, _settings.Company), _settings); => EkaerReportability.Evaluate(_mapper.ToConsignment(order, _settings.Company), _settings);
public void SetSummary(EkaerHistory history, DateTime? shippingDate, string? partner)
{
history.ShippingDate = shippingDate;
history.Partner = partner;
}
/// <summary>Config-kapu: külföldi (nem HUF) feladónál az árfolyam kötelező — különben a leképezés ELŐTT /// <summary>Config-kapu: külföldi (nem HUF) feladónál az árfolyam kötelező — különben a leképezés ELŐTT
/// ValidationError (nincs félrevezető XML). <c>null</c> = rendben, mehet a generálás.</summary> /// ValidationError (nincs félrevezető XML). <c>null</c> = rendben, mehet a generálás.</summary>
private EkaerHistory? TryConfigError(EkaerHistory ekaerHistory, string? currency) private EkaerHistory? TryConfigError(EkaerHistory ekaerHistory, string? currency)

View File

@ -20,14 +20,14 @@ public interface IFruitBankEkaerService
Task<EkaerSubmitResult> SubmitShippingAsync(Shipping shipping, OperationType operation = OperationType.Create, CancellationToken cancellationToken = default); Task<EkaerSubmitResult> SubmitShippingAsync(Shipping shipping, OperationType operation = OperationType.Create, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Egy szállítólevél-CSOPORTBÓL (egy EKÁER-egység dokumentumai) legenerálja az EKÁER tradeCard XML-t és validálja — a (meglévő vagy új) /// Egy szállítólevélből legenerálja az EKÁER tradeCard XML-t és validálja — a (meglévő vagy új)
/// <see cref="EkaerHistory"/> rekordot tölti: <c>XmlDoc</c> + <c>Status</c> /// <see cref="EkaerHistory"/> rekordot tölti: <c>XmlDoc</c> + <c>Status</c>
/// (<see cref="EkaerStatus.Generated"/> / <see cref="EkaerStatus.ValidationError"/>) + <c>ErrorText</c>. /// (<see cref="EkaerStatus.Generated"/> / <see cref="EkaerStatus.ValidationError"/>) + <c>ErrorText</c>.
/// NEM perzisztál és NEM hív NAV-ot — a mentés (upsert) a hívó SignalR endpoint dolga. /// NEM perzisztál és NEM hív NAV-ot — a mentés (upsert) a hívó SignalR endpoint dolga.
/// </summary> /// </summary>
/// <param name="documents">A deklarációhoz tartozó szállítólevél-CSOPORT (egy (Shipping, Partner, PartnerDepot) egység) a betöltött gráffal (Partner, Items+ProductDto, Shipping→járművek) — összevont tömeggel/értékkel EGY tradeCard.</param> /// <param name="document">A szállítólevél a betöltött gráffal (Partner, Items+ProductDto, Shipping→járművek).</param>
/// <param name="ekaerHistory">A csoport meglévő rekordja (újrageneráláskor); <c>null</c> → új rekord készül.</param> /// <param name="ekaerHistory">A dokumentum meglévő rekordja (újrageneráláskor); <c>null</c> → új rekord készül.</param>
EkaerHistory GenerateEkaerXmlDocument(IReadOnlyCollection<ShippingDocument> documents, EkaerHistory? ekaerHistory = null); EkaerHistory GenerateEkaerXmlDocument(ShippingDocument document, EkaerHistory? ekaerHistory = null);
/// <summary> /// <summary>
/// Egy kimenő rendelésből (<see cref="OrderDto"/>) legenerálja az EKÁER tradeCard XML-t és validálja — /// Egy kimenő rendelésből (<see cref="OrderDto"/>) legenerálja az EKÁER tradeCard XML-t és validálja —
@ -45,9 +45,4 @@ public interface IFruitBankEkaerService
/// <summary>Eldönti egy kimenő rendelés EKÁER-kötelezettségét (ugyanaz a logika, a rendelés tételeire).</summary> /// <summary>Eldönti egy kimenő rendelés EKÁER-kötelezettségét (ugyanaz a logika, a rendelés tételeire).</summary>
EkaerObligationResult EvaluateObligation(OrderDto order); EkaerObligationResult EvaluateObligation(OrderDto order);
/// <summary>Beállítja a deklaráció (<see cref="EkaerHistory"/>) összegző mezőit (DB-mentes): <c>ShippingDate</c> + <c>Partner</c>.
/// A csoporton belül invariánsak; a forrás-kinyerés (bejövő: doc.ShippingDate + Partner.Name; kimenő: order.DateOfReceipt +
/// Customer.Company) a hívóé. Fallback NINCS — null/üres marad, ha hiányzik.</summary>
void SetSummary(EkaerHistory history, DateTime? shippingDate, string? partner);
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -33,7 +33,6 @@ public static class FruitBankConstClient
public const string PartnerDepotDbTableName = "fbPartnerDepot"; public const string PartnerDepotDbTableName = "fbPartnerDepot";
public const string EkaerHistoryDbTableName = "fbEkaerHistory"; public const string EkaerHistoryDbTableName = "fbEkaerHistory";
public const string EkaerHistoryMappingDbTableName = "fbEkaerHistoryMapping";
public const string OrderItemPalletDbTableName = "fbOrderItemPallet"; public const string OrderItemPalletDbTableName = "fbOrderItemPallet";

View File

@ -34,7 +34,7 @@ public interface IFruitBankDataControllerCommon
public Task<List<EkaerHistory>?> GetEkaerHistoriesByForeignKey(int foreignKey); public Task<List<EkaerHistory>?> GetEkaerHistoriesByForeignKey(int foreignKey);
public Task<EkaerHistory?> AddEkaerHistory(EkaerHistory ekaerHistory); public Task<EkaerHistory?> AddEkaerHistory(EkaerHistory ekaerHistory);
public Task<EkaerHistory?> UpdateEkaerHistory(EkaerHistory ekaerHistory); public Task<EkaerHistory?> UpdateEkaerHistory(EkaerHistory ekaerHistory);
public Task<EkaerHistory?> GenerateEkaerXmlDocument(int ekaerHistoryId); public Task<EkaerHistory?> GenerateEkaerXmlDocument(int foreignKey, bool isOutgoing);
public Task<EkaerHistory?> CreateEkaerHistory(int foreignKey, bool isOutgoing); public Task<EkaerHistory?> CreateEkaerHistory(int foreignKey, bool isOutgoing);
public Task<EkaerCreateResult?> CreateMissingEkaerHistories(DateTime fromDate); public Task<EkaerCreateResult?> CreateMissingEkaerHistories(DateTime fromDate);
public Task<int> GetEkaerHistoryCount(EkaerHistoryFilter filter); public Task<int> GetEkaerHistoryCount(EkaerHistoryFilter filter);

View File

@ -41,9 +41,8 @@ namespace FruitBankHybrid.Shared.Tests
Assert.IsNotNull(ekaerHistory, $"shippingDocument.Id: {shippingDocument.Id}"); Assert.IsNotNull(ekaerHistory, $"shippingDocument.Id: {shippingDocument.Id}");
Assert.IsGreaterThan(0, ekaerHistory.Id, $"shippingDocument.Id: {shippingDocument.Id}"); Assert.IsGreaterThan(0, ekaerHistory.Id, $"shippingDocument.Id: {shippingDocument.Id}");
Assert.AreEqual(shippingDocument.Id, ekaerHistory.ForeignKey);
Assert.IsFalse(ekaerHistory.IsOutgoing); Assert.IsFalse(ekaerHistory.IsOutgoing);
Assert.IsNotNull(ekaerHistory.Mappings, $"Mappings null (loadRelations?); shippingDocument.Id: {shippingDocument.Id}");
Assert.AreEqual(shippingDocument.Id, ekaerHistory.Mappings.Single().ForeignKey, $"A mapping nem a forrás-dokumentumra mutat; shippingDocument.Id: {shippingDocument.Id}");
} }
// Idempotencia: a második hívás a meglévőt adja vissza, nem duplikál. // Idempotencia: a második hívás a meglévőt adja vissza, nem duplikál.
@ -74,18 +73,15 @@ namespace FruitBankHybrid.Shared.Tests
foreach (var shippingDocument in shippingDocuments) foreach (var shippingDocument in shippingDocuments)
{ {
// A generálás mostantól EkaerHistory-Id alapú → előbb a (mapping-elt) rekordot hozzuk létre. var ekaerHistory = await _signalRClient.GenerateEkaerXmlDocument(shippingDocument.Id, false);
var created = await _signalRClient.CreateEkaerHistory(shippingDocument.Id, false);
Assert.IsNotNull(created, $"CreateEkaerHistory null; shippingDocument.Id: {shippingDocument.Id}");
var ekaerHistory = await _signalRClient.GenerateEkaerXmlDocument(created.Id);
// A szerver által visszaadott állapot/hibalista logolása — az assertek ELŐTT, hogy hibánál is látsszon. // A szerver által visszaadott állapot/hibalista logolása — az assertek ELŐTT, hogy hibánál is látsszon.
Console.WriteLine($"doc#{shippingDocument.Id}: Status: {(ekaerHistory == null ? "NULL VÁLASZ!" : ekaerHistory.Status.ToString())}"); Console.WriteLine($"doc#{shippingDocument.Id}: Status: {(ekaerHistory == null ? "NULL VÁLASZ!" : ekaerHistory.Status.ToString())}");
if (!string.IsNullOrWhiteSpace(ekaerHistory?.ErrorText)) Console.WriteLine($" ErrorText: {ekaerHistory.ErrorText}"); if (!string.IsNullOrWhiteSpace(ekaerHistory?.ErrorText)) Console.WriteLine($" ErrorText: {ekaerHistory.ErrorText}");
Assert.IsNotNull(ekaerHistory, $"shippingDocument.Id: {shippingDocument.Id}"); Assert.IsNotNull(ekaerHistory, $"shippingDocument.Id: {shippingDocument.Id}");
Assert.AreEqual(shippingDocument.Id, ekaerHistory.ForeignKey);
Assert.IsFalse(ekaerHistory.IsOutgoing); Assert.IsFalse(ekaerHistory.IsOutgoing);
Assert.AreEqual(shippingDocument.Id, ekaerHistory.Mappings!.Single().ForeignKey, $"A mapping nem a forrás-dokumentumra mutat; shippingDocument.Id: {shippingDocument.Id}");
Assert.IsFalse(string.IsNullOrWhiteSpace(ekaerHistory.XmlDoc), $"XmlDoc üres; shippingDocument.Id: {shippingDocument.Id}"); Assert.IsFalse(string.IsNullOrWhiteSpace(ekaerHistory.XmlDoc), $"XmlDoc üres; shippingDocument.Id: {shippingDocument.Id}");
Assert.IsTrue(ekaerHistory.Status is EkaerStatus.Generated or EkaerStatus.ValidationError, Assert.IsTrue(ekaerHistory.Status is EkaerStatus.Generated or EkaerStatus.ValidationError,
$"Status: {ekaerHistory.Status}; shippingDocument.Id: {shippingDocument.Id}; ErrorText: {ekaerHistory.ErrorText}"); $"Status: {ekaerHistory.Status}; shippingDocument.Id: {shippingDocument.Id}; ErrorText: {ekaerHistory.ErrorText}");
@ -109,12 +105,8 @@ namespace FruitBankHybrid.Shared.Tests
var shippingDocumentId = shippingDocuments[0].Id; var shippingDocumentId = shippingDocuments[0].Id;
// Generálás EkaerHistory-Id alapján → előbb a rekord (mapping-gel), majd kétszeri generálás ugyanarra az Id-ra. var first = await _signalRClient.GenerateEkaerXmlDocument(shippingDocumentId, false);
var created = await _signalRClient.CreateEkaerHistory(shippingDocumentId, false); var second = await _signalRClient.GenerateEkaerXmlDocument(shippingDocumentId, false);
Assert.IsNotNull(created);
var first = await _signalRClient.GenerateEkaerXmlDocument(created.Id);
var second = await _signalRClient.GenerateEkaerXmlDocument(created.Id);
Assert.IsNotNull(first); Assert.IsNotNull(first);
Assert.IsNotNull(second); Assert.IsNotNull(second);

View File

@ -88,7 +88,6 @@ public class FullProcessModel
public List<OrderDto> Orders { get; set; } public List<OrderDto> Orders { get; set; }
public List<PreOrder> PreOrders { get; set; } public List<PreOrder> PreOrders { get; set; }
public List<StockTaking> StockTakings { get; set; } public List<StockTaking> StockTakings { get; set; }
public List<EkaerHistory> EkaerHistories { get; set; }
} }
[TestClass] [TestClass]

View File

@ -31,27 +31,8 @@
OnGridFocusedRowChanged="Grid_FocusedRowChanged"> OnGridFocusedRowChanged="Grid_FocusedRowChanged">
<Columns> <Columns>
<DxGridDataColumn FieldName="Id" SortIndex="0" SortOrder="GridColumnSortOrder.Descending" ReadOnly="true" /> <DxGridDataColumn FieldName="Id" SortIndex="0" SortOrder="GridColumnSortOrder.Descending" ReadOnly="true" />
<DxGridDataColumn Caption="ForeignKey(s)" AllowSort="false" AllowGroup="false"> <DxGridDataColumn FieldName="@nameof(EkaerHistory.ForeignKey)" ReadOnly="true" />
@* A lefedett forrás-rekordok (ShippingDocument/Order Id-k) a betöltött Mappings-ből összefűzve — <DxGridDataColumn FieldName="@nameof(EkaerHistory.IsOutgoing)" ReadOnly="true" />
egyből látszik, ha több dokumentum van egy EKÁER-deklaráció alá vonva. *@
<CellDisplayTemplate>
@{
var row = (EkaerHistory)context.DataItem;
}
@if (row.Mappings is { Count: > 0 } maps)
{
var noun = row.IsOutgoing ? "rendelés" : "szállítólevél";
<span title="@(maps.Count > 1 ? $"{maps.Count} {noun} egy EKÁER alá vonva" : $"1 {noun}")">@string.Join(", ", maps.Select(m => $"#{m.ForeignKey}"))</span>
}
else
{
<span>—</span>
}
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(EkaerHistory.ShippingDate)" Caption="Dátum" DisplayFormat="yyyy.MM.dd" ReadOnly="true" />
<DxGridDataColumn FieldName="@nameof(EkaerHistory.Partner)" Caption="Partner" ReadOnly="true" />
<DxGridDataColumn FieldName="@nameof(EkaerHistory.IsOutgoing)" Caption="Kimenő?" ReadOnly="true" />
@* A kézi NAV-beadás fázisában a Status / EKÁER szám / SentDate kézzel szerkeszthető. *@ @* A kézi NAV-beadás fázisában a Status / EKÁER szám / SentDate kézzel szerkeszthető. *@
<DxGridDataColumn FieldName="@nameof(EkaerHistory.Status)" /> <DxGridDataColumn FieldName="@nameof(EkaerHistory.Status)" />
<DxGridDataColumn FieldName="@nameof(EkaerHistory.EkaerNumber)" Caption="EKÁER szám" /> <DxGridDataColumn FieldName="@nameof(EkaerHistory.EkaerNumber)" Caption="EKÁER szám" />
@ -228,11 +209,11 @@
try try
{ {
var updated = await FruitBankSignalRClient.GenerateEkaerXmlDocument(ekaerHistory.Id); var updated = await FruitBankSignalRClient.GenerateEkaerXmlDocument(ekaerHistory.ForeignKey, ekaerHistory.IsOutgoing);
if (updated == null) if (updated == null)
{ {
_logger.Error($"GenerateEkaerXmlDocument null választ adott; EkaerHistory #{ekaerHistory.Id}"); _logger.Error($"GenerateEkaerXmlDocument null választ adott; ForeignKey: {ekaerHistory.ForeignKey}");
return; return;
} }
@ -247,7 +228,7 @@
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error($"GenerateEkaerXmlDocument hiba; EkaerHistory #{ekaerHistory.Id}", ex); _logger.Error($"GenerateEkaerXmlDocument hiba; ForeignKey: {ekaerHistory.ForeignKey}", ex);
} }
finally finally
{ {

View File

@ -37,11 +37,9 @@ public class GridEkaerHistoryBase : FruitBankGridBase<EkaerHistory>, IGrid
{ {
if (ContextIds == null || ContextIds.Length == 0) ContextIds = [ParentDataItem!.Id]; if (ContextIds == null || ContextIds.Length == 0) ContextIds = [ParentDataItem!.Id];
// Detail-mód: a forrás-rekord (Shipping/Order/ShippingDocument) EKÁER-deklarációi a mappingen át. // A ForeignKey általános (Shipping/Order stb.) — bármely szülőnél a ForeignKey-re szűrünk.
// Megj.: az EkaerHistory már NEM hordoz per-szülő mezőt (a kapcsolat az EkaerHistoryMapping junctionben él),
// ezért a kliens-oldali KeyFieldNameToParentId itt nem alkalmazható — a szerver-oldali szűrés
// (GetEkaerHistoriesByForeignKey → mapping) adja a szülőhöz tartozó sorokat. (Jelenleg nincs detail-használat.)
GetAllMessageTag = SignalRTags.GetEkaerHistoriesByForeignKey; GetAllMessageTag = SignalRTags.GetEkaerHistoriesByForeignKey;
if (KeyFieldNameToParentId.IsNullOrWhiteSpace()) KeyFieldNameToParentId = nameof(EkaerHistory.ForeignKey);
} }
await base.OnInitializedAsync(); await base.OnInitializedAsync();

View File

@ -79,7 +79,7 @@ namespace FruitBankHybrid.Shared.Services.SignalRs
public Task<List<EkaerHistory>?> GetEkaerHistoriesByForeignKey(int foreignKey) => GetAllAsync<List<EkaerHistory>>(SignalRTags.GetEkaerHistoriesByForeignKey, [foreignKey]); public Task<List<EkaerHistory>?> GetEkaerHistoriesByForeignKey(int foreignKey) => GetAllAsync<List<EkaerHistory>>(SignalRTags.GetEkaerHistoriesByForeignKey, [foreignKey]);
public Task<EkaerHistory?> AddEkaerHistory(EkaerHistory ekaerHistory) => PostDataAsync(SignalRTags.AddEkaerHistory, ekaerHistory); public Task<EkaerHistory?> AddEkaerHistory(EkaerHistory ekaerHistory) => PostDataAsync(SignalRTags.AddEkaerHistory, ekaerHistory);
public Task<EkaerHistory?> UpdateEkaerHistory(EkaerHistory ekaerHistory) => PostDataAsync(SignalRTags.UpdateEkaerHistory, ekaerHistory); public Task<EkaerHistory?> UpdateEkaerHistory(EkaerHistory ekaerHistory) => PostDataAsync(SignalRTags.UpdateEkaerHistory, ekaerHistory);
public Task<EkaerHistory?> GenerateEkaerXmlDocument(int ekaerHistoryId) => GetByIdAsync<EkaerHistory?>(SignalRTags.GenerateEkaerXmlDocument, ekaerHistoryId); public Task<EkaerHistory?> GenerateEkaerXmlDocument(int foreignKey, bool isOutgoing) => GetByIdAsync<EkaerHistory?>(SignalRTags.GenerateEkaerXmlDocument, [foreignKey, isOutgoing]);
public Task<EkaerHistory?> CreateEkaerHistory(int foreignKey, bool isOutgoing) => GetByIdAsync<EkaerHistory?>(SignalRTags.CreateEkaerHistory, [foreignKey, isOutgoing]); public Task<EkaerHistory?> CreateEkaerHistory(int foreignKey, bool isOutgoing) => GetByIdAsync<EkaerHistory?>(SignalRTags.CreateEkaerHistory, [foreignKey, isOutgoing]);
public Task<EkaerCreateResult?> CreateMissingEkaerHistories(DateTime fromDate) => GetByIdAsync<EkaerCreateResult?>(SignalRTags.CreateMissingEkaerHistories, fromDate); public Task<EkaerCreateResult?> CreateMissingEkaerHistories(DateTime fromDate) => GetByIdAsync<EkaerCreateResult?>(SignalRTags.CreateMissingEkaerHistories, fromDate);
public Task<int> GetEkaerHistoryCount(EkaerHistoryFilter filter) => GetByIdAsync<int>(SignalRTags.GetEkaerHistoryCount, filter); public Task<int> GetEkaerHistoryCount(EkaerHistoryFilter filter) => GetByIdAsync<int>(SignalRTags.GetEkaerHistoryCount, filter);