From 983dff12c571bdf5d30134d8e4c33ec4cd3644a8 Mon Sep 17 00:00:00 2001 From: zzh <1368735060@qq.com> Date: Fri, 16 Oct 2026 18:01:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BA=97=E9=93=BA=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E8=90=BD=E5=BA=93=E7=89=A9=E6=B5=81=E5=95=86=E4=B8=8E=E5=B1=A5?= =?UTF-8?q?=E7=BA=A6=E7=B1=BB=E5=9E=8B=EF=BC=8C=E5=B9=B6=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E8=84=9A=E6=9C=AC=E6=97=A5=E6=9C=9F=E5=91=BD?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- README.md | 2 + sql/README.md | 4 +- ...re_order_provider_fulfillment_20261016.sql | 89 +++++++++++++++++++ .../Dtos/PlatformStore/PlatformStoreDtos.cs | 8 +- .../PlatformShopFulfillmentClient.cs | 25 +++--- .../PlatformStoreOrderFulfillmentService.cs | 3 +- .../Orders/PlatformStoreOrderParcelBuilder.cs | 6 +- .../Orders/PlatformStoreOrderService.cs | 9 +- .../Entities/SalesStoreOrder.cs | 6 +- .../Entities/SalesStoreOrderLine.cs | 2 - 10 files changed, 122 insertions(+), 32 deletions(-) create mode 100644 sql/migrate_sales_store_order_provider_fulfillment_20261016.sql diff --git a/README.md b/README.md index a729463..6e2f875 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,8 @@ public async Task BatchCreateFulfi 存量 DDL、字典初始化等脚本放在 `sql/`(说明见 `sql/README.md`),与运行时 ORM 查询分离;**运行时查询与写入必须 ORM**。 +新增增量迁移文件命名:`migrate_<主题>_YYYYMMDD.sql`(日期在末尾,例如 `migrate_xxx_20261016.sql`)。详细约定见 `sql/README.md`。 + ### 3. 上传代码前先同步远端 `test`、`master` 等共享分支会有其他人提交。**推送前必须先拉取远端,再上传**,避免覆盖或漏掉别人的提交。 diff --git a/sql/README.md b/sql/README.md index b691aa6..bb4f51a 100644 --- a/sql/README.md +++ b/sql/README.md @@ -14,4 +14,6 @@ OMS / 共用库的建表脚本已统一到仓库根目录 `db.sql`。 - 新环境:直接执行 `db.sql`(会 DROP 后重建,勿在有生产数据的库上执行) - 已有库:用 diff 对比 `db.sql` 与现库结构后手工 ALTER;本目录 `migrate_all.sql` 为存量增量迁移合集(可重复执行段已做列/表存在判断;揽收 Direction / FeePush 为裸 ALTER,已执行过请跳过) - 数据权限表(`user_org_perm` 等)若 RBAC 与 OMS 分库,请只在 RBAC 库执行 `db.sql` 末尾对应段落 -- 单次增量迁移命名:`migrate_<主题>.sql`,尽量可重复执行(先判断列/表/字典是否已存在) +- 单次增量迁移命名:`migrate_<主题>_YYYYMMDD.sql`(日期放在文件名**末尾**,如 `migrate_sales_store_order_provider_fulfillment_20261016.sql`) +- 尽量可重复执行(先判断列/表/字典是否已存在) +- **后续新增脚本一律带日期后缀**;历史未带日期的脚本不强制改名 diff --git a/sql/migrate_sales_store_order_provider_fulfillment_20261016.sql b/sql/migrate_sales_store_order_provider_fulfillment_20261016.sql new file mode 100644 index 0000000..a5a2d9d --- /dev/null +++ b/sql/migrate_sales_store_order_provider_fulfillment_20261016.sql @@ -0,0 +1,89 @@ +-- 店铺订单:落库 shipping_provider / fulfillment_type;删除多面单、自定义标签、拒发字段。 +-- 可重复执行。 + +SET @db := DATABASE(); + +-- t_sales_store_order.ShippingProvider +SET @exists := ( + SELECT COUNT(1) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @db + AND TABLE_NAME = 't_sales_store_order' + AND COLUMN_NAME = 'ShippingProvider' +); +SET @sql := IF( + @exists = 0, + 'ALTER TABLE `t_sales_store_order` ADD COLUMN `ShippingProvider` VARCHAR(128) NULL COMMENT ''平台物流商'' AFTER `ShippingLabelUrl`', + 'SELECT ''t_sales_store_order.ShippingProvider already exists'' AS info' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- t_sales_store_order.FulfillmentType +SET @exists := ( + SELECT COUNT(1) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @db + AND TABLE_NAME = 't_sales_store_order' + AND COLUMN_NAME = 'FulfillmentType' +); +SET @sql := IF( + @exists = 0, + 'ALTER TABLE `t_sales_store_order` ADD COLUMN `FulfillmentType` VARCHAR(64) NULL COMMENT ''平台履约类型'' AFTER `ShippingProvider`', + 'SELECT ''t_sales_store_order.FulfillmentType already exists'' AS info' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- drop IsMultiLabel +SET @exists := ( + SELECT COUNT(1) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @db + AND TABLE_NAME = 't_sales_store_order' + AND COLUMN_NAME = 'IsMultiLabel' +); +SET @sql := IF( + @exists > 0, + 'ALTER TABLE `t_sales_store_order` DROP COLUMN `IsMultiLabel`', + 'SELECT ''t_sales_store_order.IsMultiLabel already dropped'' AS info' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- drop CustomTags +SET @exists := ( + SELECT COUNT(1) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @db + AND TABLE_NAME = 't_sales_store_order' + AND COLUMN_NAME = 'CustomTags' +); +SET @sql := IF( + @exists > 0, + 'ALTER TABLE `t_sales_store_order` DROP COLUMN `CustomTags`', + 'SELECT ''t_sales_store_order.CustomTags already dropped'' AS info' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- drop line IsShipExcluded +SET @exists := ( + SELECT COUNT(1) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @db + AND TABLE_NAME = 't_sales_store_order_line' + AND COLUMN_NAME = 'IsShipExcluded' +); +SET @sql := IF( + @exists > 0, + 'ALTER TABLE `t_sales_store_order_line` DROP COLUMN `IsShipExcluded`', + 'SELECT ''t_sales_store_order_line.IsShipExcluded already dropped'' AS info' +); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; diff --git a/src/Oms.Application/Dtos/PlatformStore/PlatformStoreDtos.cs b/src/Oms.Application/Dtos/PlatformStore/PlatformStoreDtos.cs index 92ab5b9..f7a61ca 100644 --- a/src/Oms.Application/Dtos/PlatformStore/PlatformStoreDtos.cs +++ b/src/Oms.Application/Dtos/PlatformStore/PlatformStoreDtos.cs @@ -180,8 +180,6 @@ public class PlatformStoreOrderLineOutput public string? Currency { get; set; } - public bool IsShipExcluded { get; set; } - public int? MappedSkuId { get; set; } public string? MappedSkuCode { get; set; } @@ -245,9 +243,11 @@ public class PlatformStoreOrderOutput public string? ShippingLabelUrl { get; set; } - public bool IsMultiLabel { get; set; } + /// 平台物流商。 + public string? ShippingProvider { get; set; } - public string? CustomTags { get; set; } + /// 平台履约类型。 + public string? FulfillmentType { get; set; } public bool IsSuspended { get; set; } diff --git a/src/Oms.Application/Integrations/PlatformShop/PlatformShopFulfillmentClient.cs b/src/Oms.Application/Integrations/PlatformShop/PlatformShopFulfillmentClient.cs index 9617dcd..40bac4c 100644 --- a/src/Oms.Application/Integrations/PlatformShop/PlatformShopFulfillmentClient.cs +++ b/src/Oms.Application/Integrations/PlatformShop/PlatformShopFulfillmentClient.cs @@ -99,7 +99,9 @@ public sealed class PlatformShopPulledOrder public string? ShippingLabelUrl { get; set; } - public bool IsMultiLabel { get; set; } + public string? ShippingProvider { get; set; } + + public string? FulfillmentType { get; set; } public string? ExtraJson { get; set; } @@ -784,13 +786,10 @@ internal sealed class PlatformShopFulfillmentClient( GetString(recipient, "region")); var lines = new List(); - var packageIds = new HashSet(StringComparer.Ordinal); if (order.TryGetProperty("line_items", out var lineItems) && lineItems.ValueKind == JsonValueKind.Array) { foreach (var line in lineItems.EnumerateArray()) { - var packageId = GetString(line, "package_id"); - if (!string.IsNullOrWhiteSpace(packageId)) packageIds.Add(packageId); lines.Add(new PlatformShopPulledOrderLine { PlatformLineId = GetString(line, "id"), @@ -806,15 +805,6 @@ internal sealed class PlatformShopFulfillmentClient( } } - if (order.TryGetProperty("packages", out var packages) && packages.ValueKind == JsonValueKind.Array) - { - foreach (var pkg in packages.EnumerateArray()) - { - var packageId = GetString(pkg, "id"); - if (!string.IsNullOrWhiteSpace(packageId)) packageIds.Add(packageId); - } - } - var tracking = GetString(order, "tracking_number"); if (string.IsNullOrWhiteSpace(tracking) && order.TryGetProperty("line_items", out var itemsForTrack) @@ -824,6 +814,12 @@ internal sealed class PlatformShopFulfillmentClient( tracking = GetString(itemsForTrack[0], "tracking_number"); } + var shippingProvider = FirstNonEmpty( + GetString(order, "shipping_provider"), + lineItems.ValueKind == JsonValueKind.Array && lineItems.GetArrayLength() > 0 + ? GetString(lineItems[0], "shipping_provider_name") + : null); + return new PlatformShopPulledOrder { PlatformOrderNo = id, @@ -848,7 +844,8 @@ internal sealed class PlatformShopFulfillmentClient( PlatformStatusLabel = status, FulfillStatus = MapTiktokFulfill(status), ShippingLabelNo = tracking, - IsMultiLabel = packageIds.Count > 1, + ShippingProvider = shippingProvider, + FulfillmentType = GetString(order, "fulfillment_type"), ExtraJson = order.ValueKind == JsonValueKind.Undefined ? null : order.GetRawText(), Lines = lines }; diff --git a/src/Oms.Application/Services/Orders/PlatformStoreOrderFulfillmentService.cs b/src/Oms.Application/Services/Orders/PlatformStoreOrderFulfillmentService.cs index 6b4a8dd..72049d4 100644 --- a/src/Oms.Application/Services/Orders/PlatformStoreOrderFulfillmentService.cs +++ b/src/Oms.Application/Services/Orders/PlatformStoreOrderFulfillmentService.cs @@ -377,7 +377,8 @@ internal sealed class PlatformStoreOrderFulfillmentService( entity.FulfillStatus = pulled.FulfillStatus; entity.ShippingLabelNo = pulled.ShippingLabelNo ?? entity.ShippingLabelNo; entity.ShippingLabelUrl = pulled.ShippingLabelUrl ?? entity.ShippingLabelUrl; - entity.IsMultiLabel = pulled.IsMultiLabel || entity.IsMultiLabel; + if (!string.IsNullOrWhiteSpace(pulled.ShippingProvider)) entity.ShippingProvider = pulled.ShippingProvider; + if (!string.IsNullOrWhiteSpace(pulled.FulfillmentType)) entity.FulfillmentType = pulled.FulfillmentType; entity.PlatformExtraJson = pulled.ExtraJson ?? entity.PlatformExtraJson; entity.LastSyncTime = now; PlatformStoreOrderParcelBuilder.TryFillRecipientFields(entity, pulled.ExtraJson); diff --git a/src/Oms.Application/Services/Orders/PlatformStoreOrderParcelBuilder.cs b/src/Oms.Application/Services/Orders/PlatformStoreOrderParcelBuilder.cs index ae10249..244ad2f 100644 --- a/src/Oms.Application/Services/Orders/PlatformStoreOrderParcelBuilder.cs +++ b/src/Oms.Application/Services/Orders/PlatformStoreOrderParcelBuilder.cs @@ -107,7 +107,7 @@ public static class PlatformStoreOrderParcelBuilder IReadOnlyCollection lines) { var items = new List(); - foreach (var line in lines.Where(x => !x.IsShipExcluded)) + foreach (var line in lines) { var cnName = string.IsNullOrWhiteSpace(line.ProductName) ? (string.IsNullOrWhiteSpace(line.PlatformSku) ? "Platform Item" : line.PlatformSku.Trim()) @@ -157,7 +157,7 @@ public static class PlatformStoreOrderParcelBuilder IReadOnlyDictionary skuMap) { var items = new List(); - foreach (var line in lines.Where(x => !x.IsShipExcluded)) + foreach (var line in lines) { if (!line.MappedSkuId.HasValue || !skuMap.TryGetValue(line.MappedSkuId.Value, out var sku)) { @@ -201,7 +201,7 @@ public static class PlatformStoreOrderParcelBuilder decimal maxHeight = DefaultHeightCm; decimal totalWeightKg = 0m; - foreach (var line in lines.Where(x => !x.IsShipExcluded && x.MappedSkuId.HasValue)) + foreach (var line in lines.Where(x => x.MappedSkuId.HasValue)) { if (!skuMap.TryGetValue(line.MappedSkuId!.Value, out var sku)) { diff --git a/src/Oms.Application/Services/Orders/PlatformStoreOrderService.cs b/src/Oms.Application/Services/Orders/PlatformStoreOrderService.cs index e949a82..2f99043 100644 --- a/src/Oms.Application/Services/Orders/PlatformStoreOrderService.cs +++ b/src/Oms.Application/Services/Orders/PlatformStoreOrderService.cs @@ -553,7 +553,7 @@ public class PlatformStoreOrderService : ApplicationService var order = await GetOrderOrThrowAsync(customerId, storeOrderId); await EnsureCanCreateLogisticsAsync(order); - var lines = await StoreOrderLineRepository.GetListAsync(x => x.StoreOrderId == order.Id && !x.IsShipExcluded); + var lines = await StoreOrderLineRepository.GetListAsync(x => x.StoreOrderId == order.Id); if (lines.Count == 0) { throw new BusinessException("没有可发货的商品行"); @@ -710,7 +710,7 @@ public class PlatformStoreOrderService : ApplicationService var warehouse = await WarehouseAddressRepository.FirstOrDefaultAsync(x => x.Id == resolvedWarehouseId.Value) ?? throw new BusinessException("仓库不存在"); - var lines = await StoreOrderLineRepository.GetListAsync(x => x.StoreOrderId == order.Id && !x.IsShipExcluded); + var lines = await StoreOrderLineRepository.GetListAsync(x => x.StoreOrderId == order.Id); if (lines.Count == 0) { throw new BusinessException("没有可发货的商品行"); @@ -1103,8 +1103,8 @@ public class PlatformStoreOrderService : ApplicationService PlatformStatusLabel = order.PlatformStatusLabel, ShippingLabelNo = order.ShippingLabelNo, ShippingLabelUrl = order.ShippingLabelUrl, - IsMultiLabel = order.IsMultiLabel, - CustomTags = order.CustomTags, + ShippingProvider = order.ShippingProvider, + FulfillmentType = order.FulfillmentType, IsSuspended = order.IsSuspended, WarehouseId = order.WarehouseId, LinkedOrderId = order.LinkedOrderId, @@ -1129,7 +1129,6 @@ public class PlatformStoreOrderService : ApplicationService UnitPrice = line.UnitPrice, Quantity = line.Quantity, Currency = line.Currency, - IsShipExcluded = line.IsShipExcluded, MappedSkuId = line.MappedSkuId, MappedSkuCode = mappedSkuCode }; diff --git a/src/Oms.Domain/OrdersAggregate/Entities/SalesStoreOrder.cs b/src/Oms.Domain/OrdersAggregate/Entities/SalesStoreOrder.cs index a297d48..263d4f7 100644 --- a/src/Oms.Domain/OrdersAggregate/Entities/SalesStoreOrder.cs +++ b/src/Oms.Domain/OrdersAggregate/Entities/SalesStoreOrder.cs @@ -56,9 +56,11 @@ public class SalesStoreOrder : OmsAuditedAggregateRoot public string? ShippingLabelUrl { get; set; } - public bool IsMultiLabel { get; set; } + /// 平台物流商,如 TikTok shipping_provider。 + public string? ShippingProvider { get; set; } - public string? CustomTags { get; set; } + /// 平台履约类型,如 TikTok fulfillment_type。 + public string? FulfillmentType { get; set; } public bool IsSuspended { get; set; } diff --git a/src/Oms.Domain/OrdersAggregate/Entities/SalesStoreOrderLine.cs b/src/Oms.Domain/OrdersAggregate/Entities/SalesStoreOrderLine.cs index dab91b5..58a657a 100644 --- a/src/Oms.Domain/OrdersAggregate/Entities/SalesStoreOrderLine.cs +++ b/src/Oms.Domain/OrdersAggregate/Entities/SalesStoreOrderLine.cs @@ -24,7 +24,5 @@ public class SalesStoreOrderLine : OmsAuditedAggregateRoot public string? Currency { get; set; } - public bool IsShipExcluded { get; set; } - public int? MappedSkuId { get; set; } }