using System.Globalization; using Oms.Application.Dtos.Orders; namespace Oms.Application.Labeling; /// /// 将订单出参映射为 hiprint PrintData(camelCase)。 /// public static class LabelPrintDataBuilder { public static IReadOnlyDictionary Build( OrderOutput order, string? operatorName = null, DateTime? printTime = null) { var receiver = order.Receiver; var sender = order.Sender; var weight = PickWeight(order.WeightList); var data = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["serviceNo"] = order.ServiceNo, ["clientNo"] = order.ClientNo, ["trackNo"] = order.TrackNo, ["requestId"] = order.RequestId, ["productCode"] = order.ProductCode, ["salesProductName"] = order.ProductName, ["channelCode"] = order.ChannelCode, ["channelName"] = order.ChannelName, ["warehouseName"] = order.Warehouse, ["customerCode"] = order.CustomerCode, ["customerName"] = order.CustomerName, ["recipientName"] = receiver?.RecipientsName, ["recipientCompany"] = receiver?.CompanyName, ["recipientPhone"] = FirstNonEmpty(receiver?.Phone, receiver?.TelePhone), ["recipientEmail"] = receiver?.Email, ["recipientZip"] = receiver?.ZipCode, ["recipientCountry"] = order.ConsigneeCountry, ["recipientCountryName"] = order.ConsigneeCountryName, ["recipientProvince"] = receiver?.Province, ["recipientCity"] = receiver?.City, ["recipientStreet1"] = receiver?.StreetAddress1, ["recipientStreet2"] = receiver?.StreetAddress2, ["recipientStreet3"] = receiver?.StreetAddress3, ["recipientAddressFull"] = BuildAddressFull( receiver?.StreetAddress1, receiver?.StreetAddress2, receiver?.StreetAddress3, receiver?.StreetNumber, receiver?.City, receiver?.Province, receiver?.ZipCode, order.ConsigneeCountryName ?? order.ConsigneeCountry), ["recipientTaxNo"] = receiver?.TaxNo, ["vatNo"] = receiver?.Vat, ["eori"] = receiver?.Eori, ["senderName"] = sender?.SenderName, ["senderCompany"] = sender?.Company, ["senderPhone"] = FirstNonEmpty(sender?.Phone, sender?.TelePhone), ["senderEmail"] = sender?.Email, ["senderZip"] = sender?.ZipCode, ["senderProvince"] = sender?.Province, ["senderCity"] = sender?.City, ["senderStreet1"] = sender?.StreetAddress1, ["senderStreet2"] = sender?.StreetAddress2, ["senderStreet3"] = sender?.StreetAddress3, ["senderAddressFull"] = BuildAddressFull( sender?.StreetAddress1, sender?.StreetAddress2, sender?.StreetAddress3, sender?.HouseNumber, sender?.City, sender?.Province, sender?.ZipCode, null), ["actualWeight"] = weight?.ActualWeight, ["volumetricWeight"] = weight?.VolumetricWeight, ["chargeableWeight"] = order.ChargeableWeight ?? weight?.ChargeableWeight, ["length"] = weight?.Length, ["width"] = weight?.Width, ["height"] = weight?.Height, ["weightUnit"] = "KG", ["dimUnit"] = "CM", ["printTime"] = (printTime ?? DateTime.Now).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), ["operatorName"] = operatorName }; data["items"] = order.Items.Select(x => new Dictionary { ["skuCode"] = x.Sku, ["skuName"] = FirstNonEmpty(x.CnName, x.EnName), ["qty"] = x.Quantity, ["weight"] = x.Weight ?? x.UnitWeight, ["declareNameEn"] = x.EnName, ["declareValue"] = x.UnitPrice ?? x.Amount }).ToList(); return data; } /// /// 设计预览用的 Mock PrintData。 /// public static IReadOnlyDictionary BuildMock() => new Dictionary(StringComparer.OrdinalIgnoreCase) { ["serviceNo"] = "S202607180001", ["clientNo"] = "C-10086", ["trackNo"] = "YT1234567890", ["requestId"] = "REQ-DEMO", ["productCode"] = "DEMO-PRODUCT", ["salesProductName"] = "专线-普货", ["channelCode"] = "CH-01", ["channelName"] = "Demo Channel", ["warehouseName"] = "SZ-01", ["customerCode"] = "AF0A1", ["customerName"] = "Demo Customer", ["recipientName"] = "John Lee", ["recipientCompany"] = "ACME Inc", ["recipientPhone"] = "+1-555-0100", ["recipientEmail"] = "john@example.com", ["recipientZip"] = "90001", ["recipientCountry"] = "US", ["recipientCountryName"] = "United States", ["recipientProvince"] = "CA", ["recipientCity"] = "Los Angeles", ["recipientStreet1"] = "100 Demo Street", ["recipientStreet2"] = "Suite 8", ["recipientStreet3"] = null, ["recipientAddressFull"] = "100 Demo Street, Suite 8, Los Angeles, CA 90001, United States", ["recipientTaxNo"] = null, ["vatNo"] = null, ["eori"] = null, ["senderName"] = "OMS Warehouse", ["senderCompany"] = "OMS Co", ["senderPhone"] = "+86-755-0000000", ["senderEmail"] = "ops@example.com", ["senderZip"] = "518000", ["senderProvince"] = "Guangdong", ["senderCity"] = "Shenzhen", ["senderStreet1"] = "Warehouse Rd 1", ["senderStreet2"] = null, ["senderStreet3"] = null, ["senderAddressFull"] = "Warehouse Rd 1, Shenzhen, Guangdong 518000", ["actualWeight"] = 1.25m, ["volumetricWeight"] = 1.10m, ["chargeableWeight"] = 1.25m, ["length"] = 30m, ["width"] = 20m, ["height"] = 10m, ["weightUnit"] = "KG", ["dimUnit"] = "CM", ["printTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), ["operatorName"] = "preview", ["items"] = new List> { new() { ["skuCode"] = "SKU001", ["skuName"] = "T-Shirt", ["qty"] = 2, ["weight"] = 0.2m, ["declareNameEn"] = "T-Shirt", ["declareValue"] = 9.9m } } }; private static OrderWeightOutput? PickWeight(IReadOnlyList list) { if (list.Count == 0) { return null; } return list.FirstOrDefault(x => string.Equals(x.Type, "receive", StringComparison.OrdinalIgnoreCase) || string.Equals(x.Type, "收货", StringComparison.OrdinalIgnoreCase)) ?? list.FirstOrDefault(x => string.Equals(x.Type, "forecast", StringComparison.OrdinalIgnoreCase) || string.Equals(x.Type, "预报", StringComparison.OrdinalIgnoreCase)) ?? list[0]; } private static string? BuildAddressFull(params string?[] parts) { var values = parts .Where(x => !string.IsNullOrWhiteSpace(x)) .Select(x => x!.Trim()) .ToArray(); return values.Length == 0 ? null : string.Join(", ", values); } private static string? FirstNonEmpty(params string?[] values) => values.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x)); }