84 lines
5.0 KiB
C#
84 lines
5.0 KiB
C#
using AyCode.Services.Nav.Ekaer;
|
|
|
|
namespace FruitBank.Common.Services.Ekaer;
|
|
|
|
/// <summary>Egy szállítmány EKÁER bejelentés-kötelezettsége.</summary>
|
|
public enum EkaerObligation
|
|
{
|
|
/// <summary>Kötelező bejelenteni (sort kell létrehozni).</summary>
|
|
Required,
|
|
/// <summary>Nem kötelező (belföld, küszöb alatt) — NEM hiba, nincs üzenet.</summary>
|
|
NotRequired,
|
|
/// <summary>A döntés nem hozható meg adathiány/formátumhiba miatt (pl. érvénytelen országkód) — NINCS sor, az okok az üzenetekben.</summary>
|
|
DataError,
|
|
}
|
|
|
|
/// <summary>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.</summary>
|
|
public sealed class EkaerObligationResult
|
|
{
|
|
public EkaerObligation Obligation { get; private init; }
|
|
public IReadOnlyList<string> 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<string> errors) =>
|
|
new() { Obligation = EkaerObligation.DataError, Errors = errors };
|
|
}
|
|
|
|
/// <summary>
|
|
/// EKÁER bejelentés-kötelezettség eldöntése egy normalizált <see cref="EkaerConsignment"/>-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 → <see cref="EkaerObligation.DataError"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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>
|
|
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<string>();
|
|
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;
|
|
}
|
|
|
|
/// <summary>Érvényes EKÁER országkód: pontosan 2 ASCII betű (ISO-2). Üres / más hosszúságú → érvénytelen.</summary>
|
|
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!;
|
|
}
|