Compare commits

..

No commits in common. "b6dddd6f1f2e8a143ae62dad8a7b5ed7622ae61d" and "169f7fc133ea76a43b6a08876512d40649787f5a" have entirely different histories.

11 changed files with 41 additions and 103 deletions

File diff suppressed because one or more lines are too long

View File

@ -45,11 +45,9 @@ public sealed class FruitBankEkaerService : IFruitBankEkaerService
// A csoport azonos Partneré (a kapu így csoportosít) → az első dokumentum pénzneme a mérvadó.
var currency = documents.First().Partner?.Currency;
// Guardok a leképezés ELŐTT (nincs félrevezető XML), majd a csoport ÖSSZES dokumentuma EGY tradeCard-dá
// (összevont tömeg/érték): ToConsignment → BuildTradeCard.
return TryDepotError(ekaerHistory, documents)
?? TryConfigError(ekaerHistory, currency)
?? Finalize(ekaerHistory, _mapper.BuildTradeCard(_mapper.ToConsignment(documents, _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)
@ -74,18 +72,6 @@ public sealed class FruitBankEkaerService : IFruitBankEkaerService
history.Partner = partner;
}
/// <summary>Depot-kapu (T-D8R4): a PartnerDepot az EKÁER-hez kötelező — a felrakodási hely a depot címe. Hiányzó
/// vagy be nem töltött telephelynél a leképezés ELŐTT ValidationError (nincs félrevezető, partner-központi-címes XML).
/// <c>null</c> = rendben, mehet a generálás.</summary>
private static EkaerHistory? TryDepotError(EkaerHistory ekaerHistory, IReadOnlyCollection<ShippingDocument> documents)
{
if (documents.All(d => d.PartnerDepot != null)) return null;
ekaerHistory.Status = EkaerStatus.ValidationError;
ekaerHistory.ErrorText = "A szállítólevélhez nincs telephely (PartnerDepot) rendelve — EKÁER-hez kötelező (a felrakodási hely a telephely címe); pótlás után generáld újra.";
return ekaerHistory;
}
/// <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>
private EkaerHistory? TryConfigError(EkaerHistory ekaerHistory, string? currency)

View File

@ -117,18 +117,4 @@ public interface IFruitBankDataControllerCommon
public Task<GenericAttributeDto?> UpdateGenericAttributeDto(GenericAttributeDto genericAttributeDto);
/// <summary>
/// Returns the stored grid-layout JSON for the composite layout key, or null if none saved.
/// </summary>
public Task<string?> GetGridLayout(string key, int userId);
/// <summary>
/// Saves (upserts) the grid-layout JSON under the composite layout key for the given user.
/// </summary>
public Task<bool> SaveGridLayout(string key, string layoutJson, int userId);
/// <summary>
/// Deletes the stored grid layout for the composite layout key. Returns false if the user does not exist.
/// </summary>
public Task<bool> DeleteGridLayout(string key, int userId);
}

View File

@ -31,11 +31,10 @@ public sealed class EkaerObligationResult
/// is bírság), ezért: a bizonytalan adatot (érvénytelen országkód) NEM döntjük el magától → <see cref="EkaerObligation.DataError"/>.
/// </summary>
/// <remarks>
/// Sorrend: (0) TÉTELENKÉNTI előfeltétel — bruttó súly > 0, különben DataError (a 0 súly csendben alul-számolná a
/// küszöb-summát → alul-jelentés); (1) az AGGREGÁLT tömeg/érték küszöb FELETT → Required, az országkódtól FÜGGETLENÜL
/// — belföld+küszöb felett és külföld egyaránt kötelező; az országkód-hibát ilyenkor a generate-validálás jelzi, a sor
/// létrejön; (2) küszöb ALATT → itt számít az ország: hiányzó/érvénytelen országkód → DataError (a foreign-vs-belföld
/// nem dönthető el); (3) küszöb alatt, érvényes országkódok: külföld (eltér) → Required, belföld (egyezik) → NotRequired.
/// Sorrend: (1) az AGGREGÁLT tömeg/érték küszöb FELETT → Required, az országkódtól FÜGGETLENÜL — belföld+küszöb
/// felett és külföld egyaránt kötelező; az országkód-hibát ilyenkor a generate-validálás jelzi, a sor létrejön;
/// (2) küszöb ALATT → itt számít az ország: hiányzó/érvénytelen országkód → DataError (a foreign-vs-belföld nem
/// dönthető el); (3) küszöb alatt, érvényes országkódok: külföld (eltér) → Required, belföld (egyezik) → NotRequired.
/// A 13/2020. (XII. 23.) PM rendelet alapján a küszöb feladó→címzett→jármű relációra aggregált — a hívó már
/// így állítja össze a <see cref="EkaerConsignment.Lines"/>-t (bejövőnél a (Shipping, Partner) csoport tételei).
/// </remarks>
@ -46,18 +45,6 @@ public static class EkaerReportability
ArgumentNullException.ThrowIfNull(consignment);
ArgumentNullException.ThrowIfNull(settings);
var subject = Subject(consignment);
// (0) Tételenkénti előfeltétel: bruttó súly > 0. A 0 súlyú tétel (kitöltetlen dokumentum-súly / méretlen
// rendelés) csendben alul-számolná a küszöb-aggregátumot → alul-jelentési kockázat; a NAV amúgy is tételenként
// pozitív bruttó súlyt vár. Hiányzó súly → DataError (a sor nem jön létre; pótlás után a következő futás felveszi).
var weightErrors = consignment.Lines
.Where(l => l.WeightKg <= 0)
.Select(l => $"{subject} / {(string.IsNullOrWhiteSpace(l.Name) ? $"tétel #{l.ExternalId}" : l.Name)}: a tétel bruttó súlya hiányzik (0 kg) — a kötelezettség nem dönthető el.")
.ToList();
if (weightErrors.Count > 0)
return EkaerObligationResult.DataError(weightErrors);
// (1) Küszöb FELETT → kötelező, FÜGGETLENÜL az országkódtól: belföld+küszöb felett ÉS külföld egyaránt kötelező.
// Az országkód-hibát ilyenkor NEM itt blokkoljuk — a sor létrejön, a hibát a generate-validálás jelzi.
var totalWeight = consignment.Lines.Sum(l => l.WeightKg);
@ -67,6 +54,7 @@ public static class EkaerReportability
// (2) Küszöb ALATT: itt MÁR az ország dönt — csak a külföldi (eltérő országkód) reláció kötelező. Ehhez érvényes
// ISO-2 országkódok kellenek; hiányzó/érvénytelen → a foreign-vs-belföld nem dönthető el → DataError.
var subject = Subject(consignment);
var errors = new List<string>();
if (!IsValidCountry(consignment.Seller.CountryCode))
errors.Add($"{subject}: a feladó országkódja hiányzik vagy érvénytelen ('{consignment.Seller.CountryCode}').");

View File

@ -74,7 +74,7 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
// ── Adapterek: forrás → normalizált EkaerConsignment (az EGYETLEN irányfüggő rész) ────────────
/// <summary>Bejövő: egy vagy több <c>ShippingDocument</c> (a hívó (Shipping, Partner, PartnerDepot)-ra csoportosít) → egy
/// <summary>Bejövő: egy vagy több <c>ShippingDocument</c> (a hívó (Shipping, Partner)-re csoportosít) → egy
/// szállítmány a csoport ÖSSZES tételével. Egy dokumentummal a generáláshoz, a csoporttal a kötelezettség-summához.</summary>
public EkaerConsignment ToConsignment(IReadOnlyCollection<ShippingDocument> documents, EkaerCompanyInfo company)
{
@ -83,24 +83,19 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
if (documents.Count == 0) throw new ArgumentException("Legalább egy ShippingDocument szükséges.", nameof(documents));
var first = documents.First();
var partner = first.Partner; // a csoport azonos partneré (a hívó (Shipping, Partner, PartnerDepot)-ra csoportosít)
var partner = first.Partner; // a csoport azonos partneré (a hívó (Shipping, Partner)-re csoportosít)
var shipping = first.Shipping; // azonos Shipping; a kapunál lehet null (a jármű ott nem kell)
var rateToHuf = SafeRateToHuf(partner?.Currency);
// A depot TaxId-ja Partner-passthrough (a nested Partner-t nem töltjük külön query-vel) — ugyanaz a minta,
// mint a MapShipping `document.Shipping ??=` visszakötése.
if (first.PartnerDepot is { } depot) depot.Partner ??= partner;
var lines = documents
.SelectMany(d => d.ShippingItems ?? [])
.Select(item => new EkaerLine
{
ExternalId = item.Id.ToString(),
TradeReason = TradeReasonType.S, // S = értékesítés ÉS beszerzés (egy kód); az A kivezetett, D-nél csak S adható
TradeReason = TradeReasonType.A, // bejövő áru = beszerzés
Vtsz = NormalizeVtsz(item.ProductDto?.Gtin),
Name = item.ProductName,
// A szállítólevélen szereplő bruttó — a bejelentés a kísérő dokumentum adatairól megy (mint a value),
// nem a (későbbi) mérlegelésről; méretlen tétel így nem 0 kg-mal jelenik meg.
WeightKg = item.GrossWeightOnDocument,
WeightKg = item.MeasuredGrossWeight,
ValueHuf = EkaerValueCalculator.ItemValueHuf(item, rateToHuf),
})
.ToList();
@ -112,9 +107,7 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
Currency = partner?.Currency,
Seller = PartnerEndpoint(partner),
Buyer = CompanyEndpoint(company),
// A felrakodási hely a DEPOT címe (T-D8R4) — a generate-út betölti (LoadWith) és guardolja (TryDepotError).
// A kapu-útvonalon a depot nincs betöltve → partner-központi cím, ami ott rendben van: a kötelezettség-döntés címet nem használ.
LoadLocation = BuildLocation((ICompanyInfoBase?)first.PartnerDepot ?? partner),
LoadLocation = BuildLocation(partner), // a beszállító telephelye (a PartnerDepot-bekötés külön feladat)
UnloadLocation = company.Site, // a saját telephely (kész LocationType — mezővesztés nélkül átengedve)
Lines = lines,
Vehicle = BuildVehicle(shipping?.CargoTruck),

View File

@ -238,17 +238,6 @@ namespace FruitBankHybrid.Shared.Services.SignalRs
=> PostDataAsync<MgLoginModelRequest, MgLoginModelResponse>(SignalRTags.AuthenticateUser, loginModelRequest);
#endregion Authenticate
#region GridLayout
public Task<string?> GetGridLayout(string key, int userId)
=> GetByIdAsync<string>(SignalRTags.GetGridLayoutTag, [key, userId]);
public Task<bool> SaveGridLayout(string key, string layoutJson, int userId)
=> PostAsync<bool>(SignalRTags.SaveGridLayoutTag, [key, layoutJson, userId]);
public Task<bool> DeleteGridLayout(string key, int userId)
=> PostAsync<bool>(SignalRTags.DeleteGridLayoutTag, [key, userId]);
#endregion GridLayout
#region Orders
public Task<List<OrderDtoTableItem>?> GetAllOrderDtoTableItems()
=> GetAllAsync<List<OrderDtoTableItem>>(SignalRTags.GetAllOrderDtos);

View File

@ -8,10 +8,10 @@
"AyCode": {
"ProjectId": "aad53443-2ee2-4650-8a99-97e907265e4e",
"Urls": {
"BaseUrl": "https://localhost:59579",
"ApiBaseUrl": "https://localhost:59579"
//"BaseUrl": "https://shop.fruitbank.hu",
//"ApiBaseUrl": "https://shop.fruitbank.hu"
//"BaseUrl": "https://localhost:59579",
//"ApiBaseUrl": "https://localhost:59579"
"BaseUrl": "https://shop.fruitbank.hu",
"ApiBaseUrl": "https://shop.fruitbank.hu"
},
"Logger": {
"AppType": "Server",
@ -26,8 +26,8 @@
},
"AcHubConnection": {
"Url": "https://localhost:59579/fbHub",
//"Url": "https://shop.fruitbank.hu/fbHub",
//"Url": "https://localhost:59579/fbHub",
"Url": "https://shop.fruitbank.hu/fbHub",
"TransportMaxBufferSize": 30000000,
"ApplicationMaxBufferSize": 30000000,
"CloseTimeout": "00:00:10",

View File

@ -11,10 +11,12 @@
<WasmStripILAfterAOT>true</WasmStripILAfterAOT>
<OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
<!--<BlazorEnableCompression>false</BlazorEnableCompression>
<BlazorCacheBootResources>false</BlazorCacheBootResources>
<OptimizationPreference>Speed</OptimizationPreference>
<DevExpressBrotliCompression>false</DevExpressBrotliCompression>-->
<BlazorEnableCompression>false</BlazorEnableCompression>
<BlazorCacheBootResources>false</BlazorCacheBootResources>
<OptimizationPreference>Speed</OptimizationPreference>
<DevExpressBrotliCompression>false</DevExpressBrotliCompression>
</PropertyGroup>
<ItemGroup>

View File

@ -8,10 +8,10 @@
"AyCode": {
"ProjectId": "aad53443-2ee2-4650-8a99-97e907265e4e",
"Urls": {
"BaseUrl": "https://localhost:59579",
"ApiBaseUrl": "https://localhost:59579"
//"BaseUrl": "https://shop.fruitbank.hu",
//"ApiBaseUrl": "https://shop.fruitbank.hu"
//"BaseUrl": "https://localhost:59579",
//"ApiBaseUrl": "https://localhost:59579"
"BaseUrl": "https://shop.fruitbank.hu",
"ApiBaseUrl": "https://shop.fruitbank.hu"
},
"Logger": {
"AppType": "Server",
@ -26,8 +26,8 @@
},
"AcHubConnection": {
"Url": "https://localhost:59579/fbHub",
//"Url": "https://shop.fruitbank.hu/fbHub",
//"Url": "https://localhost:59579/fbHub",
"Url": "https://shop.fruitbank.hu/fbHub",
"TransportMaxBufferSize": 30000000,
"ApplicationMaxBufferSize": 30000000,
"CloseTimeout": "00:00:10",

View File

@ -9,8 +9,8 @@
<RunAOTCompilation>false</RunAOTCompilation>
<WasmStripILAfterAOT>true</WasmStripILAfterAOT>
<OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
<!--<BlazorEnableCompression>false</BlazorEnableCompression>
<DevExpressBrotliCompression>false</DevExpressBrotliCompression>-->
<BlazorEnableCompression>false</BlazorEnableCompression>
<DevExpressBrotliCompression>false</DevExpressBrotliCompression>
</PropertyGroup>
<ItemGroup>
@ -78,7 +78,7 @@
</Reference>
<Reference Include="Mango.Nop.Core">
<HintPath>..\..\NopCommerce.Common\4.70\Libraries\Mango.Nop.Core\bin\FruitBank\$(Configuration)\net9.0\Mango.Nop.Core.dll</HintPath>
<HintPath>..\..\NopCommerce.Common\4.70\Libraries\Mango.Nop.Core\bin\FruitBank\$(Configuration)\net9.0\Mango.Nop.Core.dll</HintPath>
</Reference>
</ItemGroup>

View File

@ -8,10 +8,10 @@
"AyCode": {
"ProjectId": "aad53443-2ee2-4650-8a99-97e907265e4e",
"Urls": {
"BaseUrl": "https://localhost:59579",
"ApiBaseUrl": "https://localhost:59579"
//"BaseUrl": "https://shop.fruitbank.hu",
//"ApiBaseUrl": "https://shop.fruitbank.hu"
//"BaseUrl": "https://localhost:59579",
//"ApiBaseUrl": "https://localhost:59579"
"BaseUrl": "https://shop.fruitbank.hu",
"ApiBaseUrl": "https://shop.fruitbank.hu"
},
"Logger": {
"AppType": "Server",
@ -26,8 +26,8 @@
},
"AcHubConnection": {
"Url": "https://localhost:59579/fbHub",
//"Url": "https://shop.fruitbank.hu/fbHub",
//"Url": "https://localhost:59579/fbHub",
"Url": "https://shop.fruitbank.hu/fbHub",
"TransportMaxBufferSize": 30000000,
"ApplicationMaxBufferSize": 30000000,
"CloseTimeout": "00:00:10",