using System.Text.Json.Serialization; using AyCode.Core.Serializers.Attributes; using AyCode.Core.Serializers.Toons; using AyCode.Interfaces.TimeStampInfo; using LinqToDB; using LinqToDB.Mapping; using Mango.Nop.Core.Entities; namespace FruitBank.Common.Entities; [AcBinarySerializable(false, true, false, true, false, false)] [ToonDescription("NAV EKÁER declaration lifecycle record", Purpose = "Work-queue and audit row for one EKÁER road-freight declaration. One declaration covers one or more source records via EkaerHistoryMapping (the link lives in that junction table, NOT here): inbound, the ShippingDocuments of one (Shipping, Partner, PartnerDepot) group aggregated into a single tradeCard; outbound, a single completed Order. Tracks the declaration through generation, validation and submission to the Hungarian tax authority (NAV).")] [Table(Name = FruitBankConstClient.EkaerHistoryDbTableName)] [System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.EkaerHistoryDbTableName)] public sealed class EkaerHistory: MgEntityBase, ITimeStampInfo { [ToonDescription(Purpose = "Direction of the goods movement: false = incoming shipment (Shipping), true = outgoing delivery (Order).")] public bool IsOutgoing { get; set; } [ToonDescription(Purpose = "Lifecycle state of the declaration, stored as int (see EkaerStatus): 0 Pending (auto-created, not yet generated), 1 Generated (tradeCard XML produced and valid), 2 ValidationError (generation produced errors, see ErrorText), 3 Sent (accepted by NAV, EkaerNumber filled), 4 SendError (NAV call failed, see ErrorText).")] public int StatusId { get; set; } /// A enum-nézete. A tárolt érték az int oszlop (StatusId) — a linq2db réteg /// az enum-property-t nem perzisztálta (az oszlop kimaradt az insertből, a DB default írt 0-t), ezért a nop-minta: /// int oszlop + nem-mappelt enum wrapper. [NotColumn, System.ComponentModel.DataAnnotations.Schema.NotMapped, Newtonsoft.Json.JsonIgnore, JsonIgnore] public EkaerStatus Status { get => (EkaerStatus)StatusId; set => StatusId = (int)value; } [ToonDescription(Purpose = "The generated NAV EKÁER tradeCard request XML exactly as it was (or will be) submitted — audit copy and source of the read-only detail view. Null until the first Generate.")] public string? XmlDoc { get; set; } [Column(DataType = DataType.DecFloat)] [ToonDescription(Purpose = "The conversion rate actually applied when computing this declaration's item values to HUF: 1 for domestic (HUF) suppliers (no conversion), the FX rate (e.g. EUR→HUF) for foreign suppliers. Null before the first Generate. Currency-agnostic by design — works for any source currency. Audit trail: the invoice amount times this rate yields the HUF value in the tradeCard; the NAV schema has no rate field, so this column preserves how the value was derived.")] public double? ConversionRate { get; set; } [ToonDescription(Purpose = "The EKÁER number (TCN) assigned by NAV after a successful submission. Null until the declaration is accepted.")] public string? EkaerNumber { get; set; } [ToonDescription(Purpose = "When the declaration was successfully submitted to NAV. Null until sent.")] public DateTime? SentDate { get; set; } [ToonDescription(Purpose = "Validation or NAV submission error details for the ValidationError / SendError states. Null when the last operation succeeded.")] public string? ErrorText { get; set; } /// A deklarációhoz tartozó forrás-rekordok (EkaerHistoryMapping): bejövő → N szállítólevél (ShippingDocument.Id), /// kimenő → 1 rendelés (Order.Id). NEM auto-loadol — a DbTable GetAll(loadRelations: true) tölti (LoadWith). [Association(ThisKey = nameof(Id), OtherKey = nameof(EkaerHistoryMapping.EkaerHistoryId), CanBeNull = true)] public List? Mappings { get; set; } public DateTime Created { get; set; } public DateTime Modified { get; set; } } /// Az EKÁER-bejelentés életciklus + kimenet állapota. Append-only: új érték a végére, meglévő értéke nem /// változhat (DB-ben int-ként tárolt). Az állapot egyetlen mező; a kategorizálás a /// segédekkel megy (külön oszlop nélkül) — a folyamat lineáris, ezért a single-enum állapotgép a tiszta illeszkedés. public enum EkaerStatus { /// Automatikusan létrejött, még nem volt Generate. Pending = 0, /// A tradeCard XML legenerálva és valid — küldhető. Generated = 1, /// A Generate BLOKKOLÓ (error) hibákkal zárult (ErrorText) — a forrásadat javítandó, nem küldhető. ValidationError = 2, /// NAV által befogadva (EkaerNumber + SentDate töltve), hiánytalanul. Sent = 3, /// A NAV-hívás hibával zárult (ErrorText) — újraküldhető. SendError = 4, /// Legenerálva és KÜLDHETŐ, de warninggal (pl. hiányzó rendszám, ami a felrakodás megkezdéséig pótolható). GeneratedWithWarning = 5, /// NAV-hoz beküldve, de PÓTLÁSRA VÁR (pl. a rendszám a felrakodás megkezdéséig megadandó). SentWithMissingData = 6, } /// Állapot-kategóriák — a tárolás egy mező (Status), a csoportosítás ezekkel (külön oszlop nélkül). public static class EkaerStatusExtensions { /// Blokkoló hibás állapot (a bejelentés nem küldhető / a NAV-hívás bukott). public static bool IsError(this EkaerStatus status) => status is EkaerStatus.ValidationError or EkaerStatus.SendError; /// Beküldhető: legenerálva, blokkoló hiba nélkül (warninggal is) — innen mehet a NAV-hoz. public static bool IsSubmittable(this EkaerStatus status) => status is EkaerStatus.Generated or EkaerStatus.GeneratedWithWarning; /// A NAV-nál van (akár hiányosan). public static bool IsSent(this EkaerStatus status) => status is EkaerStatus.Sent or EkaerStatus.SentWithMissingData; /// Elküldve, de pótlásra vár (hiányos adat — pl. rendszám). public static bool NeedsCompletion(this EkaerStatus status) => status is EkaerStatus.SentWithMissingData; } /// EkaerHistory-lekérdezés szűrő a tabokhoz, . A kategóriák diszjunkt /// StatusId-partíciók, ezért kombinálhatók (pl. ToSubmit | NeedsCompletion = minden, ami még nincs lezárva). /// = 0 (nincs bit = nincs szűrő → minden), egyúttal a biztonságos default; szándékosan NEM nullable. /// Vigyázat: HasFlag(All) mindig true (0 bit), ezért a szerver előbb a == All ágat nézi. [Flags] public enum EkaerHistoryFilter { /// Minden rekord (nincs szűrés). 0 = nincs bit → minden; egyúttal a biztonságos default. All = 0, /// Beküldésre váró: minden, ami még NINCS a NAV-nál (Pending/Generated/GeneratedWithWarning/ValidationError/SendError). ToSubmit = 1, /// Elküldött és hiánytalan (). Sent = 2, /// Elküldve, de pótlásra vár (). NeedsCompletion = 4, } //public sealed class EkaerHistoryShipping : EkaerHistoryBase //{ // public int ShippingId // { // get => ForeignItemId; // set => ForeignItemId = value; // } // [Association(ThisKey = nameof(ShippingId), OtherKey = nameof(Shipping.Id), CanBeNull = true)] // public Shipping? Shipping { get; set; } //} //public sealed class EkaerHistoryOrder : EkaerHistoryBase //{ // public int ShippingId // { // get => ForeignItemId; // set => ForeignItemId = value; // } // [Association(ThisKey = nameof(ShippingId), OtherKey = nameof(Shipping.Id), CanBeNull = true)] // public Shipping? Shipping { get; set; } //} //public abstract class EkaerHistoryBase : MgEntityBase, ITimeStampInfo //{ // [NotColumn] // protected int ForeignItemId; // [NotColumn] // [ToonDescription(BusinessRule = "get => ForeignItemId", Constraints = "[#SmartTypeConstraints]")] // public int ForeignKey => ForeignItemId; // public DateTime Created { get; set; } // public DateTime Modified { get; set; } //}