using AyCode.Services.Nav.Ekaer;
namespace FruitBank.Common.Services.Ekaer;
/// Egy szállítmány EKÁER bejelentés-kötelezettsége.
public enum EkaerObligation
{
/// Kötelező bejelenteni (sort kell létrehozni).
Required,
/// Nem kötelező (belföld, küszöb alatt) — NEM hiba, nincs üzenet.
NotRequired,
/// A döntés nem hozható meg adathiány/formátumhiba miatt (pl. érvénytelen országkód) — NINCS sor, az okok az üzenetekben.
DataError,
}
/// A kötelezettség-kiértékelés eredménye: a döntés + (csak DataError esetén) a felhasználónak szóló okok.
public sealed class EkaerObligationResult
{
public EkaerObligation Obligation { get; private init; }
public IReadOnlyList Errors { get; private init; } = [];
public static EkaerObligationResult Required { get; } = new() { Obligation = EkaerObligation.Required };
public static EkaerObligationResult NotRequired { get; } = new() { Obligation = EkaerObligation.NotRequired };
public static EkaerObligationResult DataError(IReadOnlyList errors) =>
new() { Obligation = EkaerObligation.DataError, Errors = errors };
}
///
/// EKÁER bejelentés-kötelezettség eldöntése egy normalizált -re — KÖZÖS a bejövő
/// (document-csoport) és a kimenő (order) ágon. A NAV mindkét irányban büntet (a felesleges bejelentés ÉS a kimaradás
/// is bírság), ezért: a bizonytalan adatot (érvénytelen országkód) NEM döntjük el magától → .
///
///
/// 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 -t (bejövőnél a (Shipping, Partner) csoport tételei).
///
public static class EkaerReportability
{
public static EkaerObligationResult Evaluate(EkaerConsignment consignment, IEkaerSettings settings)
{
ArgumentNullException.ThrowIfNull(consignment);
ArgumentNullException.ThrowIfNull(settings);
// (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);
var totalValueHuf = consignment.Lines.Sum(l => l.ValueHuf ?? 0L);
if (totalWeight >= settings.ThresholdWeightKg || totalValueHuf >= settings.ThresholdValueHuf)
return EkaerObligationResult.Required;
// (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();
if (!IsValidCountry(consignment.Seller.CountryCode))
errors.Add($"{subject}: a feladó országkódja hiányzik vagy érvénytelen ('{consignment.Seller.CountryCode}').");
if (!IsValidCountry(consignment.Buyer.CountryCode))
errors.Add($"{subject}: a címzett országkódja hiányzik vagy érvénytelen ('{consignment.Buyer.CountryCode}').");
if (errors.Count > 0)
return EkaerObligationResult.DataError(errors);
// (3) Küszöb alatt, érvényes országkódok: külföld (eltér) → kötelező, belföld (egyezik) → nem kötelező (üzenet nélkül).
return CountryEquals(consignment.Seller.CountryCode, consignment.Buyer.CountryCode)
? EkaerObligationResult.NotRequired
: EkaerObligationResult.Required;
}
/// Érvényes EKÁER országkód: pontosan 2 ASCII betű (ISO-2). Üres / más hosszúságú → érvénytelen.
private static bool IsValidCountry(string? code)
{
var c = code?.Trim();
return c is { Length: 2 } && c.All(char.IsAsciiLetter);
}
private static bool CountryEquals(string? a, string? b) => string.Equals(a?.Trim(), b?.Trim(), StringComparison.OrdinalIgnoreCase);
private static string Subject(EkaerConsignment c)
=> c.IsOutgoing ? $"Rendelés #{c.ForeignKey}" : string.IsNullOrWhiteSpace(c.Seller.Name) ? $"Szállítólevél #{c.ForeignKey}" : c.Seller.Name!;
}