Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/docs/EKAER/README.md

81 lines
7.4 KiB
Markdown

# EKÁER — NAV közúti áruforgalom-bejelentés (FruitBank áttekintő)
Topic `EKAER`, prefix `MGFBANKPLUG` → entry ID-k `MGFBANKPLUG-EKAER-I-<RAND>` (issue) / `-T-` (TODO) / `-B-` (bug).
A FruitBank EKÁER-bejelentés **szerver-oldali** (a kliens már standalone WASM, böngészőből CORS miatt nem hívhat NAV-ot — a kliens SignalR-en triggerel). A tényleges logika viszont **rétegekre bontva** él, nem ebben a pluginban; ez a folder a **belépő/áttekintő** + a FruitBank-/nopCommerce-specifikus nyitott döntések.
> A NAV-protokoll részletei (transport, auth, üzenet-szerkezet) az `AyCode.Core` repóban: `AyCode.Services/Nav/docs/EKAER_*.md`. Itt **nem** ismételjük.
## A teljes EKÁER-kép (4 réteg)
| Réteg | Hol | Mit ad |
|---|---|---|
| **NAV/EKÁER framework** | `AyCode.Services/Nav/` + `Nav/Ekaer/` (AyCode.Core) | transport, auth (SHA-512), generált modellek, **`EkaerTradeCardValidator`** (NAV-séma + üzleti szabályok), **`EkaerSubmitService`** (validate→send), `EkaerManageService` (HTTP). Általános — **nem** FruitBank-specifikus. |
| **FruitBank leképezés** | `FruitBank.Common/Services/Ekaer/` | **`ShippingToEkaerMapper`** — a forrást (bejövő `ShippingDocument`-csoport / kimenő `OrderDto`) egy irány-független **`EkaerConsignment`**-re képezi (`ToConsignment`), abból épül a `tradeCard` (`BuildTradeCard`). **`EkaerReportability`** — bejelentés-kötelezettség (küszöb/külföld). **`EkaerValueCalculator`** — tétel-érték HUF-ban. |
| **FruitBank fogyasztó** | `FruitBank.Common.Server/Services/Ekaer/` | **`FruitBankEkaerService`** — szerver-oldali orchestráció: credentials/options + map → submit |
| **nopCommerce-integráció (ez a plugin)** | ez a folder + a plugin kód | DI-bekötés, NAV-fiók settings, a VTSZ-forrás (`Product.Gtin`), SignalR-trigger a kliens felől, és ez a doksi |
## A beküldési lánc
```
FruitBankEkaerService.SubmitShippingAsync(shipping) // FruitBank.Common.Server
→ ShippingToEkaerMapper.MapShipping(...) // FruitBank.Common (map)
→ EkaerSubmitService.SubmitAsync(ops) // AyCode.Services (validate → send)
→ EkaerTradeCardValidator.Validate(ops) // hibalista → ha nem üres: NEM küld
→ EkaerManageService.ManageAsync(request) // auth + HTTP POST a NAV-nak
```
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):
- **`CreateMissingEkaerHistories(fromDate)`** — reconciliation-kapu: a dátumtól rekord nélküli szállítólevelekre/rendelésekre `Pending` `EkaerHistory` sorokat hoz létre, **csak ha kötelező** (lásd a kapu-szakaszt lentebb). `EkaerCreateResult`-ot ad vissza (létrehozott szám + a kihagyott tételek üzenetei).
- **`GenerateEkaerXmlDocument(foreignKey, isOutgoing)`** — egy sorra 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.
## Companion fájlok
- [`EKAER_ISSUES.md`](EKAER_ISSUES.md) — ismert problémák (pl. `MGFBANKPLUG-EKAER-I-T3X8`: GTIN≠VTSZ).
- [`EKAER_TODO.md`](EKAER_TODO.md) — a `Shipping → tradeCard` mapping nyitott üzleti döntései.
## A leképezés (tisztázott pontok)
| EKÁER | FruitBank forrás |
|---|---|
| `seller*` (feladó) | `ShippingDocument.Partner` (a beszállító) |
| `carrierText` (fuvarozó, szöveges) | **bejövő:** `Shipping.CargoPartner.Name`; **kimenő:** `Customer.Company` (a vevő viszi el az árut) |
| `vehicle` / `vehicle2` | `Shipping.CargoTruck` / `CargoTrailer` (`LicencePlate` + `CountryCode`, normalizálva) |
| tétel `productVtsz` | `ShippingItem.ProductDto.Gtin` (átmenetileg — lásd `EKAER_ISSUES.md`) |
| tétel `productName` | `ShippingItem.ProductName` (a VTSZ-szerinti csoportosítás + a csoport-név `Category`-ből: TODO **T-V9G3**) |
| tétel `weight` | `ShippingItem.MeasuredGrossWeight` (bruttó) |
| tétel `tradeReason` | `A` (beszerzés — bejövő áru). ⚠️ Az enum: `S`=értékesítés, `A`=beszerzés, `W`=bérmunka, `O`=egyéb. |
A nyitott pontok (tradeType, destination, value/deviza, granularitás, kimenő irány): [`EKAER_TODO.md`](EKAER_TODO.md).
## 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.
**`EkaerHistory` életciklus** (egy sor = egy tradeCard; `ForeignKey` = bejövő `ShippingDocument.Id` / kimenő `Order.Id` + `IsOutgoing`; a `Status` int-oszlop + `[NotColumn]` enum-nézet):
`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.
**Bejelentés-kötelezettség**`EkaerReportability.Evaluate(consignment, settings)`, a kapu hívja egységenként:
- **egység:** bejövőnél a `(Shipping, Partner)` csoport (= feladó→címzett→jármű) — a tömeg/érték a csoport **ÖSSZES** dokumentumára **aggregálva** (13/2020 PM rendelet); kimenőnél egy rendelés;
- **küszöb felett** → kötelező, az országkódtól **függetlenül** (az országkód-hibát a generate-validálás jelzi);
- **küszöb alatt** → csak a **külföldi** reláció kötelező (a feladó és a címzett országkódja **eltér**); belföld → nem; hiányzó/érvénytelen (nem ISO-2) országkód → **`DataError`** (a sor kimarad + üzenet a popupban);
- **mentesség:** `Partner.IsEkaer = false`, és a Partner nélküli (félkész) szállítólevél — csendben kimaradnak.
> **A küszöb configból jön** (`Ekaer:Thresholds:WeightKg` / `:ValueHuf`) — a kódba **NINCS drótozva**, mert a NAV-jogszabály és a beállítás szerint **változhat**. A konkrét, dátumozott értékeket és a termékkategóriákat lásd [`EKAER_TODO.md`](EKAER_TODO.md) **T-W3R8**. A NAV **mindkét irányban büntet** (alul- ÉS túljelentés), ezért a küszöbnek pontosnak kell lennie.
**Egyesített leképezés:** a bejövő/kimenő forrás egy **`EkaerConsignment`** köztes modellre képződik (két adapter), és **abból** épül MIND a tradeCard (`BuildTradeCard`), MIND a kötelezettség-döntés — így az irányfüggő rész két adapterre szorul, a közös logika egy helyen van. A `MapDocument` / `MapOrder` / `MapShipping` ennek vékony wrappere.
## Bekötés a szerveren (DI)
A plugin (vagy a szerver-startup) köti be a láncot — a NAV-fiók titkos adatai a szerver config/secret store-jából:
```csharp
services.AddSingleton<INavCredentials>(/* NAV-fiók: User/Password/SigningKey/TaxNumber/BaseUrl */);
services.AddHttpClient<EkaerManageService>(/* NAV TLS 1.2 */);
services.AddScoped<IEkaerTradeCardValidator, EkaerTradeCardValidator>();
services.AddScoped<IEkaerSubmitService, EkaerSubmitService>();
services.AddScoped<IShippingToEkaerMapper, ShippingToEkaerMapper>();
services.AddSingleton<IEkaerSettings>(/* EkaerSettings: Ekaer:Company + Site + küszöbök + EUR-HUF árfolyam — configból */);
services.AddScoped<IFruitBankEkaerService, FruitBankEkaerService>();
```