diff --git a/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs b/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs index 6128052..0124a4b 100644 --- a/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs @@ -413,6 +413,26 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers return await ctx.EkaerHistories.GetByIdAsync(ekaerHistory.Id, true); } + /// + /// Egy legenerált (Generated/GeneratedWithWarning) EkaerHistory TÁROLT tradeCard XML-jét beküldi a NAV-nak (create). + /// A service tölti a rekordot (Sent/SentWithMissingData + EkaerNumber + SentDate, vagy SendError + ErrorText), + /// itt csak perzisztáljuk. User-vezérelt (grid „Beküldés" gomb), a kliens megerősítő dialógus után hívja. + /// + [SignalR(SignalRTags.SendEkaerToNav)] + public async Task SendEkaerToNav(int ekaerHistoryId) + { + _logger.Detail($"SendEkaerToNav invoked; ekaerHistoryId: {ekaerHistoryId}"); + + var ekaerHistory = await ctx.EkaerHistories.GetByIdAsync(ekaerHistoryId, true) + ?? throw new ArgumentException($"EkaerHistory not found; id: {ekaerHistoryId}", nameof(ekaerHistoryId)); + + ekaerHistory = await fruitBankEkaerService.SendEkaerAsync(ekaerHistory); + + await ctx.EkaerHistories.UpdateAsync(ekaerHistory); + _logger.Info($"SendEkaerToNav; id: {ekaerHistoryId}; status: {ekaerHistory.Status}; ekaerNumber: {ekaerHistory.EkaerNumber}"); + return await ctx.EkaerHistories.GetByIdAsync(ekaerHistory.Id, true); + } + /// /// Idempotens rekord-létrehozás: ha a forrás-rekordra (foreignKey + isOutgoing) már van mapping → a hozzá tartozó /// EkaerHistory-t adja vissza érintetlenül; különben új Pending rekordot + EGY mapping sort hoz létre (atomikusan). diff --git a/Nop.Plugin.Misc.AIPlugin/docs/EKAER/README.md b/Nop.Plugin.Misc.AIPlugin/docs/EKAER/README.md index 93e2007..a5d2a06 100644 --- a/Nop.Plugin.Misc.AIPlugin/docs/EKAER/README.md +++ b/Nop.Plugin.Misc.AIPlugin/docs/EKAER/README.md @@ -26,9 +26,12 @@ FruitBankEkaerService.SubmitShippingAsync(shipping) // FruitBank.Common.S ``` Validációs hiba → **hibalista** (`EkaerSubmitResult.Invalid`), nem megy ki kérés. NAV-oldali hiba → `NavReportException` propagál. -**További belépési pontok** (a kézi NAV-beadás munkafolyamathoz — `FruitBankDataController` SignalR-endpointok, kliens felől triggerelve): +> **A ténylegesen bekötött beküldő-út (2026-07):** a fenti `SubmitShippingAsync` (shipping-szintű, dokumentumonkénti) az AUTOMATA út — még NINCS triggerelve (lásd a `MapShipping`-drift a TODO-ban). A használt beküldés a **`SendEkaerToNav(ekaerHistoryId)`** endpoint (grid „Beküldés" gomb): egy legenerált `EkaerHistory` **tárolt `XmlDoc`-ját** deserializálja → create-`TradeCardOperationType` → `EkaerSubmitService.SubmitAsync` (ugyanaz a validate→send). A kettő granularitása eltér — egységesítés az automata bekötés előtt. + +**További belépési pontok** (`FruitBankDataController` SignalR-endpointok, kliens felől — a grid gombjaival — triggerelve): - **`CreateMissingEkaerHistories(fromDate)`** — reconciliation-kapu: a dátumtól még le nem fedett szállítólevelekre/rendelésekre `Pending` `EkaerHistory` sorokat hoz létre, **csak ha kötelező** (lásd a kapu-szakaszt lentebb). Bejövőnél a `(Shipping, Partner, PartnerDepot)` csoport **EGY** `EkaerHistory`-t kap, a csoport dokumentumai pedig `EkaerHistoryMapping` sorokként kapcsolódnak; kimenőnél egy rendelés = egy `EkaerHistory` + egy mapping. `EkaerCreateResult`-ot ad vissza (létrehozott szám + a kihagyott tételek üzenetei). -- **`GenerateEkaerXmlDocument(ekaerHistoryId)`** — egy `EkaerHistory`-deklarációra (a mappingben rögzített forrás-dokumentumok ÖSSZES tételét egy tradeCard-ba vonva) legenerálja + validálja a tradeCard XML-t (NEM küld NAV-ot); a `Status` / `ErrorText` / `ConversionRate` töltődik, az XML vágólapra másolható a kézi beadáshoz. +- **`GenerateEkaerXmlDocument(ekaerHistoryId)`** — egy `EkaerHistory`-deklarációra (a mappingben rögzített forrás-dokumentumok ÖSSZES tételét egy tradeCard-ba vonva) legenerálja + validálja a tradeCard XML-t (NEM küld NAV-ot); a `Status` / `ErrorText` / `ConversionRate` töltődik. +- **`SendEkaerToNav(ekaerHistoryId)`** (2026-07) — a legenerált (`Generated`/`GeneratedWithWarning`) deklaráció **TÁROLT `XmlDoc`-ját** create-műveletként beküldi a NAV-nak (`FruitBankEkaerService.SendEkaerAsync` → `EkaerSubmitService.SubmitAsync` → `EkaerManageService`). Siker → `Sent` (tiszta) / `SentWithMissingData` (warningos generálásból, pl. hiányzó rendszám) + `EkaerNumber` (a NAV `tcn`) + `SentDate`; NAV-/transport-hiba → `SendError` + `ErrorText` (a `reasonCode`/`msg`). A grid „Beküldés" gombja hívja, **megerősítő dialógus** után. A kézi út (Letöltés → NAV-web) átmeneti, ez váltja ki. ## Companion fájlok @@ -53,10 +56,10 @@ A nyitott pontok (tradeType, destination, value/deviza, granularitás, kimenő i ## Reconciliation-kapu, kötelezettség, életciklus (2026-06) -A kézi NAV-beadás munkafolyamat: a **kapu** létrehozza a sorokat → a user **generál** + másol/beküld → kézzel rögzíti a NAV-választ. +Munkafolyamat: a **kapu** létrehozza a sorokat → a user **generál** → **beküld** (grid „Beküldés" gomb → `SendEkaerToNav` → NAV, megerősítés után; a NAV-válasz — `tcn` / hiba — automatikusan rögzül). A Letöltés → NAV-web kézi út átmeneti (a beküldés bekötése előtti időszakra). **`EkaerHistory` életciklus** (egy sor = egy tradeCard; a forrás-rekordok az **`EkaerHistoryMapping`** junctionön át kapcsolódnak — bejövő: a `(Shipping, Partner, PartnerDepot)` csoport N `ShippingDocument`-je, kimenő: 1 `Order` —, az `EkaerHistory` maga **nem** hordoz forrás-kulcsot, az irány az `IsOutgoing`; a `Status` int-oszlop + `[NotColumn]` enum-nézet; a mapping a `GetAll(loadRelations: true)`-zal töltődik a `Mappings` asszociációba): -`Pending` (a kapu hozta létre) → **Generate** → `Generated` / `GeneratedWithWarning` (küldhető, de pótlandó — pl. hiányzó rendszám) / `ValidationError` (blokkoló) → kézi NAV-beadás után `Sent` / `SentWithMissingData` (pótlásra vár). A grid 3 tabja ezekre szűr (szerver-oldali `EkaerHistoryFilter`), a warning ⚠️ / error ⛔ ikonnal megkülönböztetve. +`Pending` (a kapu hozta létre) → **Generate** → `Generated` / `GeneratedWithWarning` (küldhető, de pótlandó — pl. hiányzó rendszám) / `ValidationError` (blokkoló) → **Beküldés** (`SendEkaerToNav`) → `Sent` (tiszta) / `SentWithMissingData` (warningosból, pótlásra vár) / `SendError` (a NAV-hívás bukott — újraküldhető). A grid 3 tabja ezekre szűr (szerver-oldali `EkaerHistoryFilter`), a warning ⚠️ / error ⛔ ikonnal megkülönböztetve. **Bejelentés-kötelezettség** — `EkaerReportability.Evaluate(consignment, settings)`, a kapu hívja egységenként: - **tételenkénti előfeltétel (2026-07):** minden tétel **bruttó súlya > 0** kell legyen — 0 súlyú tétel (kitöltetlen dokumentum-súly / méretlen rendelés) → `DataError` tételes üzenettel, a csoport sora NEM jön létre (a 0 csendben alul-számolná a küszöb-summát); pótlás után a következő futás felveszi;