EKAER: add site config, outgoing support, refactor settings

- Added "Site" section to appsettings.json for company location.
- Increased EKAER threshold values; updated phone format.
- Refactored to use IEkaerSettings DI and registered in startup.
- GenerateEkaerXmlDocument now supports both incoming and outgoing (order) documents.
- Updated EKAER_TODO.md to reflect config and outgoing mapping changes.
This commit is contained in:
Loretta 2026-06-12 07:54:33 +02:00
parent f1db5a9a99
commit cd49b572ad
3 changed files with 43 additions and 16 deletions

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using AyCode.Core.Extensions;
using AyCode.Core.Loggers;
using AyCode.Services.Nav.Ekaer;
using AyCode.Services.SignalRs;
using DocumentFormat.OpenXml.Office2010.Excel;
using FruitBank.Common.Dtos;
@ -44,7 +45,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
ILocalizationService localizationService,
PreOrderConversionService preorderConversionService,
IFruitBankEkaerService fruitBankEkaerService,
EkaerSettings ekaerSettings,
IEkaerSettings ekaerSettings,
IEnumerable<IAcLogWriterBase> logWriters)
: BasePluginController, IFruitBankDataControllerServer
{
@ -313,17 +314,27 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
}
[SignalR(SignalRTags.GenerateEkaerXmlDocument)]
public async Task<EkaerHistory> GenerateEkaerXmlDocument(int shippingDocumentId)
public async Task<EkaerHistory> GenerateEkaerXmlDocument(int foreignKey, bool isOutgoing)
{
_logger.Detail($"GenerateEkaerXmlDocument invoked; shippingDocumentId: {shippingDocumentId}");
_logger.Detail($"GenerateEkaerXmlDocument invoked; foreignKey: {foreignKey}; isOutgoing: {isOutgoing}");
// A GetAll(true) a mapperhez kellő teljes gráfot tölti: Partner, Items+ProductDto, Shipping→járművek/fuvarozó.
var shippingDocument = await ctx.ShippingDocuments.GetByIdAsync(shippingDocumentId, true)
?? throw new ArgumentException($"ShippingDocument not found; id: {shippingDocumentId}", nameof(shippingDocumentId));
// Upsert: (ForeignKey + IsOutgoing) párra EGY rekord — az újragenerálás nem duplikál.
var ekaerHistory = await ctx.EkaerHistories.GetByForeignKey(foreignKey).FirstOrDefaultAsync(eh => eh.IsOutgoing == isOutgoing);
// Upsert: dokumentumonként EGY bejövő rekord (ForeignKey + IsOutgoing) — az újragenerálás nem duplikál.
var ekaerHistory = await ctx.EkaerHistories.GetByForeignKey(shippingDocumentId).FirstOrDefaultAsync(eh => !eh.IsOutgoing);
ekaerHistory = fruitBankEkaerService.GenerateEkaerXmlDocument(shippingDocument, ekaerHistory);
if (!isOutgoing)
{
// Bejövő: a GetAll(true) a mapperhez kellő teljes gráfot tölti (Partner, Items+ProductDto, Shipping→járművek).
var shippingDocument = await ctx.ShippingDocuments.GetByIdAsync(foreignKey, true)
?? throw new ArgumentException($"ShippingDocument not found; id: {foreignKey}", nameof(foreignKey));
ekaerHistory = fruitBankEkaerService.GenerateEkaerXmlDocument(shippingDocument, ekaerHistory);
}
else
{
// Kimenő: a GetByIdAsync(true) betölti a Customer-t, tételeket, palettákat (GrossWeight) és a ProductDto-t.
var order = await ctx.OrderDtos.GetByIdAsync(foreignKey, true)
?? throw new ArgumentException($"Order not found; id: {foreignKey}", nameof(foreignKey));
ekaerHistory = fruitBankEkaerService.GenerateEkaerXmlDocument(order, ekaerHistory);
}
if (ekaerHistory.Id > 0) await ctx.EkaerHistories.UpdateAsync(ekaerHistory);
else await ctx.EkaerHistories.InsertAsync(ekaerHistory);

View File

@ -44,6 +44,7 @@ using System.Net.Http.Headers;
using Mango.Nop.Core.Loggers;
using AyCode.Services.Nav;
using AyCode.Services.Nav.Ekaer;
using AyCode.Services.Nav.Ekaer.Models;
using FruitBank.Common.Services.Ekaer;
using FruitBank.Common.Server.Services.Ekaer;
using System.Security.Authentication;
@ -193,12 +194,14 @@ public class PluginNopStartup : INopStartup
BaseUrl = c["BaseUrl"] ?? "https://import-test-b.ekaer.nav.gov.hu", // TEST; PROD: https://import.ekaer.nav.gov.hu
};
});
// EKÁER konfiguráció — egyetlen objektum (cégadat + küszöb + árfolyam), configból (appsettings "Ekaer").
// A bejelentő cégadata: a NAV-helyes 11-jegyű adószám + telefon/e-mail itt adható meg, a webshop Store-tól függetlenül.
services.AddSingleton(sp =>
// EKÁER konfiguráció (cégadat + telephely + küszöb + árfolyam), configból (appsettings "Ekaer").
// IEkaerSettings-ként kötjük be (AyCode-kontraktus) — a fogyasztók az interfészt kérik, mint az INavCredentials-t.
services.AddSingleton<IEkaerSettings>(sp =>
{
var c = sp.GetRequiredService<IConfiguration>().GetSection("Ekaer");
var co = c.GetSection("Company");
var site = co.GetSection("Site");
return new EkaerSettings
{
Company = new EkaerCompanyInfo
@ -209,13 +212,26 @@ public class PluginNopStartup : INopStartup
PostalCode = co["PostalCode"],
City = co["City"],
Street = co["Street"],
// UnloadLocation (saját telephely): magyar címnél a NAV Name/VatNumber/Phone/Email-t is kér — TODO összeállítani.
// Telephely = fizikai fel-/lerakodási hely (bejövőnél lerakodás, kimenőnél felrakodás).
// Magyar címnél a NAV Name/VatNumber/Phone/Email-t is megköveteli. Ha = székhely, ugyanaz a cím.
Site = new LocationType
{
Name = co["Name"],
VatNumber = co["TaxId"],
Country = co["CountryCode"] ?? "HU",
ZipCode = site["PostalCode"],
City = site["City"],
Street = site["Street"],
Phone = co["Phone"],
Email = co["Email"],
},
},
// Default ÉRTÉK szándékosan nincs: be nem töltött config → 0. A 0 árfolyam a számításkor hibát dob,
// a 0 küszöb „mindent jelentünk" — egyik sem számol elavult, kódba égetett értékkel.
EurHufRate = c.GetValue<double>("ExchangeRate:EurHuf"),
ThresholdWeightKg = c.GetValue<double>("Thresholds:WeightKg"),
ThresholdValueHuf = c.GetValue<long>("Thresholds:ValueHuf"),
ThresholdValueHuf = c.GetValue<int>("Thresholds:ValueHuf"),
};
});

View File

@ -16,12 +16,12 @@ A `ShippingToEkaerMapper` megírása előtt tisztázandó pontok. Minden sor a j
| # | Téma | Jelenlegi feltételezés | Nyitott kérdés |
|---|------|------------------------|----------------|
| 1 | `tradeType` (E/I/D irány) | Bejövő = beszerzés. HU feladó → **D** (belföldi), egyébként → **I** (import). A feladó országát a `ShippingDocument.Partner` / `Country` adja. | Automatikusan az országból dőljön el, vagy kézzel (UI) állítható? A kimenő (**E**, export) egyelőre hatókörön kívül (lásd #7). |
| 2 | Célhely (destination) | Hardcode-olt FruitBank-telephely (cím). | Ne hardcode legyen — konfigból/beállításból jöjjön. Honnan (plugin settings / nopCommerce warehouse)? |
| 2 | Célhely / telephely | ✅ **Megoldva:** configból (`Ekaer:Company` + `Site` al-szekció) → `IEkaerSettings.Company` + `EkaerCompanyInfo.Site` (`LocationType`, fel-/lerakodás). Nincs hardcode. | Több telephely (mint a `PartnerDepot`) — későbbi, ha kell. |
| 3 | Érték (`value`, HUF) | ✅ **Megoldva:** `UnitPriceOnDocument × QuantityOnDocument × árfolyam` (`EkaerValueCalculator`). Pénznem a `Partner.Currency`-ből; EUR-HUF árfolyam configból (`Ekaer:ExchangeRate:EurHuf`, MNB középárfolyam). | Árfolyam dinamizálása (jelenleg „drót" config-érték) — későbbi. |
| 4 | Tömeg (`weight`) | `ShippingItem.MeasuredGrossWeight` (bruttó). | Az EKÁER **bruttó** tömeget vár — megerősíteni, hogy ez bruttó és nem nettó. |
| 5 | Granularitás | 1 `ShippingDocument` → 1 `tradeCard`; 1 `Shipping` → több művelet (több dokumentum). | Megerősíteni: tényleg dokumentumonként egy tradeCard? |
| 6 | Eladó (`seller*`) mezők | `ShippingDocument.Partner`-ből: `Name`, `TaxId` (első 8 jegy = adószám-törzs), `CountryCode`, `City`, `Street`, `PostalCode`. | A `Partner` (`PartnerBase`) pontos mezőnevei/forrásai — megerősíteni. |
| 7 | Kimenő irány (`Order` → EKÁER) | Egyelőre nincs. A vevő gyakran maga viszi el (saját fuvar) → nem mi jelentünk. | Mikor kell mégis nekünk export/kimenő (E) tradeCard-ot küldeni? |
| 7 | Kimenő irány (`Order` → EKÁER) | **Implementálva** (`MapOrder`): belföldi értékesítés (**D**/**S**), mi=eladó, vevő=címzett; tömeg `OrderItemDto.GrossWeight`, érték nettó (UnitPriceExclTax × qty), jelenleg minden HUF (rate 1). | **Nyitott:** a vonó jármű / fuvarozó forrása — az Orderen NINCS; az OrderDto-ba bekötendő (a `MapOrder` `Vehicle`/`CarrierText` TODO-ja). Export (**E**) + külföldi deviza + a `Customer.CountryId` ISO-feloldása: későbbi. |
| 8 | `productVtsz` forrás | `ProductDto.Gtin` (átmeneti). | GTIN ≠ VTSZ — lásd [`MGFBANKPLUG-EKAER-I-T3X8`](EKAER_ISSUES.md). Hosszú távon külön `Vtsz` mező. |
| 9 | tétel `tradeReason` | `A` (beszerzés) — a mapper ezt használja bejövő árura. | Korábban tévesen `S`-nek feltételezve; az enum valójában `S`=értékesítés, `A`=beszerzés. Üzletileg megerősítendő. |
| 10 | `value` mező | ✅ **Megoldva:** a value most töltve (lásd #3); 0 / ismeretlen ár esetén `null` marad. | A NAV 2021-től `value > 0`-t vár — a validátorban a `value > 0` üzleti szabály még hozzáadandó. |