using System; using System.Text.Json; using System.Text.Json.Serialization; namespace PayRollDAL.DTO.GateEntry { /// /// Accepts both a JSON number and a JSON string so that: /// • single-item QR → "batchQty": 14158.6 (number) /// • multi-item QR → "batchQty": "14158.6,14155" (string) /// Both deserialise to a string that the DAL splits and parses. /// internal sealed class FlexibleDecimalStringConverter : JsonConverter { public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.TokenType == JsonTokenType.Number ? reader.GetDecimal().ToString(System.Globalization.CultureInfo.InvariantCulture) : reader.GetString(); public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) => writer.WriteStringValue(value); } /// /// Parses InvoiceDate from multiple formats the QR scanner may emit: /// "01.05.2026" (DD.MM.YYYY — printed on the label) /// "2026-03-31" (ISO 8601 — standard API format) /// "01/05/2026" (DD/MM/YYYY) /// Returns null when the string is absent or unparseable. /// internal sealed class FlexibleDateOnlyConverter : JsonConverter { private static readonly string[] _Formats = { "dd.MM.yyyy", // 01.05.2026 "yyyy-MM-dd", // 2026-03-31 "dd/MM/yyyy", // 01/05/2026 "MM/dd/yyyy", // 05/01/2026 "d.M.yyyy", // 1.5.2026 }; public override DateOnly? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var s = reader.GetString(); if (string.IsNullOrWhiteSpace(s)) return null; if (DateOnly.TryParseExact(s, _Formats, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var d)) return d; return DateOnly.TryParse(s, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var d2) ? d2 : (DateOnly?)null; } public override void Write(Utf8JsonWriter writer, DateOnly? value, JsonSerializerOptions options) { if (value.HasValue) writer.WriteStringValue(value.Value.ToString("yyyy-MM-dd")); else writer.WriteNullValue(); } } /// /// Raw text values from a QR scanner / event sheet. /// /// SINGLE-ITEM (normal): /// One object → one resolved detail row. /// All fields are plain scalar values. /// /// MULTI-ITEM (comma-encoded): /// One object → N resolved detail rows. /// Per-item fields (MaterialCode, BatchNo, BatchQty, InvoiceQty, /// AllocationName, UOMName, Remarks) carry N comma-separated values. /// Header fields (SupplierName, PONumber, InvoiceNumber, InvoiceDate) /// are shared across all expanded rows. /// /// Example — 2 items in one object: /// "materialCode": "SB/1622/C000/NA000/1270,SB/1622/C000/NA000/1271" /// "batchNo": "15G2600104,15G2600105" /// "batchQty": "14158.6,14155" /// "invoiceQty": "14158.6,141544.6" /// /// Rules: /// • Count = max number of comma-separated tokens across all per-item fields. /// • Fields with fewer tokens than Count reuse their last value for the /// remaining rows (safe broadcast). /// • Fields with exactly 1 token are broadcast to all rows unchanged. /// public class GateEntryDetailRawInputDTO { // ── Header fields (shared across all expanded rows) ────────────── /// Supplier party name — resolves to PartyId/PartyCode on the gate entry header. public string SupplierName { get; set; } /// PO document number (e.g. "VFG/PO-III/4076/2025-26") — resolves to DocumentId, DocumentNumber. public string PONumber { get; set; } /// Invoice number (e.g. "S5D25260924") — stored as ReferenceNumber on the gate entry header. public string InvoiceNumber { get; set; } /// /// Invoice date — stored as ReferenceDate on the gate entry header. /// Accepts "01.05.2026" (DD.MM.YYYY), "2026-03-31" (ISO), or "01/05/2026". /// [JsonConverter(typeof(FlexibleDateOnlyConverter))] public DateOnly? InvoiceDate { get; set; } // ── Per-item fields (comma-separated for multi-item QR) ────────── /// /// Material code or name. Comma-separated for multi-item QR. /// Resolved first by ITEMCODE, then by ITEMNAME. /// public string MaterialCode { get; set; } /// Batch / lot number. Comma-separated for multi-item QR. public string BatchNo { get; set; } /// /// Batch quantity → LotQuantity. Comma-separated for multi-item QR. /// Accepts both JSON number (14158.6) and JSON string ("14158.6,14155"). /// [JsonConverter(typeof(FlexibleDecimalStringConverter))] public string BatchQty { get; set; } /// /// Invoice quantity → DocumentValue. Comma-separated for multi-item QR. /// Accepts both JSON number and JSON string. /// [JsonConverter(typeof(FlexibleDecimalStringConverter))] public string InvoiceQty { get; set; } /// Allocation name. Comma-separated for multi-item QR. public string AllocationName { get; set; } /// Unit of measure name. Comma-separated for multi-item QR. public string UOMName { get; set; } /// Free-text remarks. Comma-separated for multi-item QR. public string Remarks { get; set; } } }