diff --git a/db.sql b/db.sql
index 3d29fcc..24f7aeb 100644
--- a/db.sql
+++ b/db.sql
@@ -233,7 +233,7 @@ CREATE TABLE `t_order_file` (
CREATE TABLE `t_customer_sender_address` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '归属客户 t_customer.Id',
- `AddressType` VARCHAR(16) NOT NULL DEFAULT 'sender' COMMENT '地址类型:sender发件/return退件/receiver收件',
+ `AddressType` VARCHAR(16) NOT NULL DEFAULT 'sender' COMMENT '地址类型:sender国内发件/return国内退件/pickup国内揽收/receiver海外收件',
`AddressName` VARCHAR(64) NULL COMMENT '地址别名',
`SenderName` VARCHAR(50) NOT NULL COMMENT '联系人姓名',
`Company` VARCHAR(255) NULL COMMENT '公司',
@@ -1850,7 +1850,8 @@ CREATE TABLE `t_pickup_order` (
`CustomerId` INT NOT NULL COMMENT '客户Id',
`OrganizationId` CHAR(36) NULL COMMENT '数据归属组织',
`SecretLevel` TINYINT NOT NULL DEFAULT 2 COMMENT '数据密级 1-4',
- `SenderAddressId` INT NOT NULL COMMENT '发件地址簿Id',
+ `SenderAddressId` INT NOT NULL COMMENT '客户揽收地址簿Id',
+ `Direction` VARCHAR(16) NOT NULL DEFAULT 'forward' COMMENT 'forward正向(客户→仓)/reverse逆向(仓→客户)',
`SenderName` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '取件联系人快照',
`SenderCompany` VARCHAR(255) NULL COMMENT '公司快照',
`SenderCountry` INT NULL COMMENT '国家 t_country.Id 快照',
@@ -1899,6 +1900,7 @@ CREATE TABLE `t_pickup_order` (
UNIQUE KEY `uk_pickup_no` (`PickupNo`),
UNIQUE KEY `uk_pickup_request_id` (`RequestId`),
KEY `idx_pickup_customer_status` (`CustomerId`, `Status`, `CreateTime`),
+ KEY `idx_pickup_direction_status` (`Direction`, `Status`, `CreateTime`),
KEY `idx_pickup_warehouse_time` (`WarehouseId`, `ExpectPickupTime`),
KEY `idx_pickup_pay` (`PayStatus`),
KEY `idx_pickup_settle` (`SettlementStatus`),
diff --git a/sql/migrate_dict_employee_position.sql b/sql/migrate_dict_employee_position.sql
deleted file mode 100644
index c0c2846..0000000
--- a/sql/migrate_dict_employee_position.sql
+++ /dev/null
@@ -1,80 +0,0 @@
--- 员工档案「岗位 / 职级」字典初始数据(幂等:已存在同 DictType+DictCode 则跳过)
--- dictType: employee_position / employee_job_level
--- MySQL 5.7+ / 8.0
-
-SET NAMES utf8mb4;
-
--- ========== 岗位 employee_position ==========
-INSERT INTO `t_dict_type` (`DictType`, `Remark`, `TypeSort`, `IsDeleted`, `CreateUserId`)
-SELECT 'employee_position', '员工岗位', 0, 0, 0
-FROM DUAL
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_dict_type` WHERE `DictType` = 'employee_position' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_dict` (`DictType`, `DictSort`, `DictCode`, `DictName`, `IsDeleted`, `CreateUserId`)
-SELECT v.`DictType`, v.`DictSort`, v.`DictCode`, v.`DictName`, 0, 0
-FROM (
- SELECT 'employee_position' AS DictType, 1 AS DictSort, 'generalManager' AS DictCode, '总经理' AS DictName
- UNION ALL SELECT 'employee_position', 2, 'deputyGeneralManager', '副总经理'
- UNION ALL SELECT 'employee_position', 3, 'logisticsAdvisor', '物流顾问'
- UNION ALL SELECT 'employee_position', 4, 'csManager', '客服主管'
- UNION ALL SELECT 'employee_position', 5, 'csSpecialist', '客服专员'
- UNION ALL SELECT 'employee_position', 6, 'opsManager', '运营经理'
- UNION ALL SELECT 'employee_position', 7, 'opsSpecialist', '运营专员'
- UNION ALL SELECT 'employee_position', 8, 'financeManager', '财务经理'
- UNION ALL SELECT 'employee_position', 9, 'financeSpecialist', '财务专员'
- UNION ALL SELECT 'employee_position', 10, 'warehouseManager', '仓储主管'
- UNION ALL SELECT 'employee_position', 11, 'warehouseClerk', '仓管员'
- UNION ALL SELECT 'employee_position', 12, 'customsSpecialist', '关务专员'
- UNION ALL SELECT 'employee_position', 13, 'productManager', '产品经理'
- UNION ALL SELECT 'employee_position', 14, 'techEngineer', '技术工程师'
- UNION ALL SELECT 'employee_position', 15, 'hrAdmin', '人事行政'
- UNION ALL SELECT 'employee_position', 16, 'marketingSpecialist', '市场专员'
- UNION ALL SELECT 'employee_position', 17, 'dispatcher', '调度员'
-) AS v
-WHERE NOT EXISTS (
- SELECT 1
- FROM `t_dict` d
- WHERE d.`DictType` = v.`DictType`
- AND d.`DictCode` = v.`DictCode`
- AND d.`IsDeleted` = 0
-);
-
-UPDATE `t_dict`
-SET `IsDeleted` = 1,
- `UpdateTime` = NOW()
-WHERE `DictType` = 'employee_position'
- AND `DictCode` IN (
- 'salesDirector',
- 'salesManager',
- 'salesSpecialist',
- 'logisticsAdvisorDirector',
- 'logisticsAdvisorManager'
- )
- AND `IsDeleted` = 0;
-
--- ========== 职级 employee_job_level(一级~五级) ==========
-INSERT INTO `t_dict_type` (`DictType`, `Remark`, `TypeSort`, `IsDeleted`, `CreateUserId`)
-SELECT 'employee_job_level', '员工职级', 0, 0, 0
-FROM DUAL
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_dict_type` WHERE `DictType` = 'employee_job_level' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_dict` (`DictType`, `DictSort`, `DictCode`, `DictName`, `IsDeleted`, `CreateUserId`)
-SELECT v.`DictType`, v.`DictSort`, v.`DictCode`, v.`DictName`, 0, 0
-FROM (
- SELECT 'employee_job_level' AS DictType, 1 AS DictSort, '1' AS DictCode, '一级' AS DictName
- UNION ALL SELECT 'employee_job_level', 2, '2', '二级'
- UNION ALL SELECT 'employee_job_level', 3, '3', '三级'
- UNION ALL SELECT 'employee_job_level', 4, '4', '四级'
- UNION ALL SELECT 'employee_job_level', 5, '5', '五级'
-) AS v
-WHERE NOT EXISTS (
- SELECT 1
- FROM `t_dict` d
- WHERE d.`DictType` = v.`DictType`
- AND d.`DictCode` = v.`DictCode`
- AND d.`IsDeleted` = 0
-);
diff --git a/sql/migrate_issue_template_handler.sql b/sql/migrate_issue_template_handler.sql
new file mode 100644
index 0000000..409cdb7
--- /dev/null
+++ b/sql/migrate_issue_template_handler.sql
@@ -0,0 +1,45 @@
+-- 存量库:为问题模板补充处理人字段(与 db.sql / IssueTemplate 实体对齐)
+-- 可重复执行;仅在列不存在时 ADD。
+-- 目标表:t_issue_template
+
+SET @db := DATABASE();
+
+-- HandlerType
+SET @exists := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db
+ AND TABLE_NAME = 't_issue_template'
+ AND COLUMN_NAME = 'HandlerType'
+);
+SET @sql := IF(
+ @exists = 0,
+ 'ALTER TABLE `t_issue_template` ADD COLUMN `HandlerType` VARCHAR(16) NULL COMMENT ''处理人类型:customer=订单所属客户,user=指定用户'' AFTER `NotifyMethod`',
+ 'SELECT ''HandlerType already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+-- HandlerUserId
+SET @exists := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db
+ AND TABLE_NAME = 't_issue_template'
+ AND COLUMN_NAME = 'HandlerUserId'
+);
+SET @sql := IF(
+ @exists = 0,
+ 'ALTER TABLE `t_issue_template` ADD COLUMN `HandlerUserId` INT NULL COMMENT ''指定处理人用户Id(HandlerType=user 时必填)'' AFTER `HandlerType`',
+ 'SELECT ''HandlerUserId already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+-- 历史数据默认按「指定用户」语义;无处理人时可在页面再编辑
+UPDATE `t_issue_template`
+SET `HandlerType` = 'user'
+WHERE (`HandlerType` IS NULL OR `HandlerType` = '')
+ AND `IsDeleted` = 0;
diff --git a/sql/migrate_pickup_direction_and_address_type.sql b/sql/migrate_pickup_direction_and_address_type.sql
new file mode 100644
index 0000000..8ebfac4
--- /dev/null
+++ b/sql/migrate_pickup_direction_and_address_type.sql
@@ -0,0 +1,16 @@
+-- 揽收方向 + 客户地址类型扩展(国内揽收)
+-- 正向 forward:客户揽收地址 → 仓库
+-- 逆向 reverse:仓库 → 客户揽收地址
+
+ALTER TABLE `t_pickup_order`
+ ADD COLUMN `Direction` VARCHAR(16) NOT NULL DEFAULT 'forward'
+ COMMENT 'forward正向(客户→仓)/reverse逆向(仓→客户)'
+ AFTER `SenderAddressId`;
+
+ALTER TABLE `t_pickup_order`
+ ADD KEY `idx_pickup_direction_status` (`Direction`, `Status`, `CreateTime`);
+
+-- 地址类型注释更新(列已存在,仅说明)
+ALTER TABLE `t_customer_sender_address`
+ MODIFY COLUMN `AddressType` VARCHAR(16) NOT NULL DEFAULT 'sender'
+ COMMENT 'sender国内发件/return国内退件/pickup国内揽收/receiver海外收件';
diff --git a/sql/migrate_sales_product_route_sort.sql b/sql/migrate_sales_product_route_sort.sql
deleted file mode 100644
index 54d6fd1..0000000
--- a/sql/migrate_sales_product_route_sort.sql
+++ /dev/null
@@ -1,36 +0,0 @@
--- t_sales_product:官网线路展示排序(幂等;列已存在则跳过)
--- 数值越小越靠前;默认 0
-
-SET @db := DATABASE();
-
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_sales_product'
- AND COLUMN_NAME = 'RouteSort'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_sales_product` ADD COLUMN `RouteSort` INT NOT NULL DEFAULT 0 COMMENT ''官网线路排序,越小越靠前'' AFTER `TradeTerms`',
- 'SELECT ''skip RouteSort'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @idx := (
- SELECT COUNT(*)
- FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_sales_product'
- AND INDEX_NAME = 'idx_sp_route_sort'
-);
-SET @sql_idx := IF(
- @idx = 0,
- 'ALTER TABLE `t_sales_product` ADD KEY `idx_sp_route_sort` (`RouteSort`, `IsActive`)',
- 'SELECT ''skip idx_sp_route_sort'' AS msg'
-);
-PREPARE stmt_idx FROM @sql_idx;
-EXECUTE stmt_idx;
-DEALLOCATE PREPARE stmt_idx;
diff --git a/sql/migrate_t_9610_align_item_fields.sql b/sql/migrate_t_9610_align_item_fields.sql
deleted file mode 100644
index 255c769..0000000
--- a/sql/migrate_t_9610_align_item_fields.sql
+++ /dev/null
@@ -1,81 +0,0 @@
--- 9610 商品明细命名对齐 t_order_declaration(幂等)
--- ItemNo→Sku, ItemName→CnName, Gcode→ExHsCode, Price→UnitPrice, Qty→Quantity,
--- TotalAmount→Amount, DeclareUnit→Unit
--- 海关专属保留:Gmodel / Barcode / DestCountry / ItemCurrency / LegalQty / LegalUnit / Freight / SortNo
-
-SET @db := DATABASE();
-
--- ItemNo → Sku
-SET @hasOld := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='ItemNo');
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Sku');
-SET @sql := IF(@hasOld>0 AND @hasNew=0,
- 'ALTER TABLE `t_9610_order_item` CHANGE COLUMN `ItemNo` `Sku` VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''SKU(对齐 t_order_declaration.Sku / 上游 itemNo)''',
- 'SELECT ''skip ItemNo->Sku'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ItemName → CnName
-SET @hasOld := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='ItemName');
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='CnName');
-SET @sql := IF(@hasOld>0 AND @hasNew=0,
- 'ALTER TABLE `t_9610_order_item` CHANGE COLUMN `ItemName` `CnName` VARCHAR(250) NOT NULL DEFAULT '''' COMMENT ''中文品名(对齐 t_order_declaration.CnName / 上游 itemName)''',
- 'SELECT ''skip ItemName->CnName'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- Gcode → ExHsCode
-SET @hasOld := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Gcode');
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='ExHsCode');
-SET @sql := IF(@hasOld>0 AND @hasNew=0,
- 'ALTER TABLE `t_9610_order_item` CHANGE COLUMN `Gcode` `ExHsCode` VARCHAR(10) NULL COMMENT ''出口海关编码(对齐 t_order_declaration.ExHsCode / 上游 gcode)''',
- 'SELECT ''skip Gcode->ExHsCode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- Price → UnitPrice
-SET @hasOld := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Price');
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='UnitPrice');
-SET @sql := IF(@hasOld>0 AND @hasNew=0,
- 'ALTER TABLE `t_9610_order_item` CHANGE COLUMN `Price` `UnitPrice` DECIMAL(19,5) NOT NULL DEFAULT 0 COMMENT ''单价(对齐 t_order_declaration.UnitPrice)''',
- 'SELECT ''skip Price->UnitPrice'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- TotalAmount → Amount(可能尚未存在 TotalAmount)
-SET @hasOld := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='TotalAmount');
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Amount');
-SET @sql := IF(@hasOld>0 AND @hasNew=0,
- 'ALTER TABLE `t_9610_order_item` CHANGE COLUMN `TotalAmount` `Amount` DECIMAL(19,5) NULL COMMENT ''总价(对齐 t_order_declaration.Amount / 上游 totalPrice)''',
- 'SELECT ''skip TotalAmount->Amount'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Amount');
-SET @sql := IF(@hasNew=0,
- 'ALTER TABLE `t_9610_order_item` ADD COLUMN `Amount` DECIMAL(19,5) NULL COMMENT ''总价(对齐 t_order_declaration.Amount)'' AFTER `UnitPrice`',
- 'SELECT ''skip add Amount'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- Qty → Quantity
-SET @hasOld := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Qty');
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Quantity');
-SET @sql := IF(@hasOld>0 AND @hasNew=0,
- 'ALTER TABLE `t_9610_order_item` CHANGE COLUMN `Qty` `Quantity` DECIMAL(19,5) NOT NULL DEFAULT 0 COMMENT ''数量(对齐 t_order_declaration.Quantity,精度保留海关小数)''',
- 'SELECT ''skip Qty->Quantity'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- DeclareUnit → Unit
-SET @hasOld := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='DeclareUnit');
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Unit');
-SET @sql := IF(@hasOld>0 AND @hasNew=0,
- 'ALTER TABLE `t_9610_order_item` CHANGE COLUMN `DeclareUnit` `Unit` VARCHAR(3) NULL COMMENT ''计量单位(对齐 t_order_declaration.Unit / 上游 unit)''',
- 'SELECT ''skip DeclareUnit->Unit'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @hasNew := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Unit');
-SET @sql := IF(@hasNew=0,
- 'ALTER TABLE `t_9610_order_item` ADD COLUMN `Unit` VARCHAR(3) NULL COMMENT ''计量单位(对齐 t_order_declaration.Unit)'' AFTER `LegalQty`',
- 'SELECT ''skip add Unit'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- Gmodel 注释:海关申报要素(由运单 Model/Specifications/Attributes/Material 拼接)
-SET @has := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Gmodel');
-SET @sql := IF(@has>0,
- 'ALTER TABLE `t_9610_order_item` MODIFY COLUMN `Gmodel` VARCHAR(255) NULL COMMENT ''申报要素(海关;由运单型号/规格等拼接,上游 gmodel)''',
- 'SELECT ''skip Gmodel comment'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_9610_align_order_nos.sql b/sql/migrate_t_9610_align_order_nos.sql
deleted file mode 100644
index 1efd19a..0000000
--- a/sql/migrate_t_9610_align_order_nos.sql
+++ /dev/null
@@ -1,118 +0,0 @@
--- 9610 单号命名对齐运单 t_order(幂等)
--- ReferenceNo → ClientNo(客户单号)
--- LogisticsNo 并入 ServiceNo(运单号)后删除 LogisticsNo
-
-SET @db := DATABASE();
-
--- 1) ReferenceNo → ClientNo
-SET @hasRef := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ReferenceNo'
-);
-SET @hasClient := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ClientNo'
-);
-SET @sql := IF(
- @hasRef > 0 AND @hasClient = 0,
- 'ALTER TABLE `t_9610_order` CHANGE COLUMN `ReferenceNo` `ClientNo` VARCHAR(48) NOT NULL DEFAULT '''' COMMENT ''客户单号(对齐 t_order.ClientNo / 上游 referenceNo)''',
- 'SELECT ''skip ReferenceNo->ClientNo'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- 索引名顺带调整(旧 idx_9610_ref → idx_9610_client_no)
-SET @idxRef := (
- SELECT COUNT(*) FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND INDEX_NAME='idx_9610_ref'
-);
-SET @idxClient := (
- SELECT COUNT(*) FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND INDEX_NAME='idx_9610_client_no'
-);
-SET @sql := IF(
- @idxRef > 0 AND @idxClient = 0,
- 'ALTER TABLE `t_9610_order` RENAME INDEX `idx_9610_ref` TO `idx_9610_client_no`',
- 'SELECT ''skip rename idx_9610_ref'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @idxClient := (
- SELECT COUNT(*) FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND INDEX_NAME='idx_9610_client_no'
-);
-SET @sql := IF(
- @idxClient = 0,
- 'ALTER TABLE `t_9610_order` ADD KEY `idx_9610_client_no` (`ClientNo`)',
- 'SELECT ''skip add idx_9610_client_no'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- 2) LogisticsNo → 回填 ServiceNo,再删列
-SET @hasLog := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='LogisticsNo'
-);
-SET @sql := IF(
- @hasLog > 0,
- 'UPDATE `t_9610_order` SET `ServiceNo` = NULLIF(TRIM(`LogisticsNo`), '''') WHERE (`ServiceNo` IS NULL OR TRIM(`ServiceNo`) = '''') AND `LogisticsNo` IS NOT NULL AND TRIM(`LogisticsNo`) <> ''''',
- 'SELECT ''skip backfill ServiceNo'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @idxLog := (
- SELECT COUNT(*) FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND INDEX_NAME='idx_9610_logistics'
-);
-SET @sql := IF(
- @idxLog > 0,
- 'ALTER TABLE `t_9610_order` DROP INDEX `idx_9610_logistics`',
- 'SELECT ''skip drop idx_9610_logistics'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @hasLog := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='LogisticsNo'
-);
-SET @sql := IF(
- @hasLog > 0,
- 'ALTER TABLE `t_9610_order` DROP COLUMN `LogisticsNo`',
- 'SELECT ''skip drop LogisticsNo'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ServiceNo 索引(检索)
-SET @idxSvc := (
- SELECT COUNT(*) FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND INDEX_NAME='idx_9610_service_no'
-);
-SET @sql := IF(
- @idxSvc = 0,
- 'ALTER TABLE `t_9610_order` ADD KEY `idx_9610_service_no` (`ServiceNo`)',
- 'SELECT ''skip idx_9610_service_no'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- OrderNo 注释对齐:海关下游订单编号(非运单 DownstreamServiceNo)
-SET @hasOrderNo := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='OrderNo'
-);
-SET @sql := IF(
- @hasOrderNo > 0,
- 'ALTER TABLE `t_9610_order` MODIFY COLUMN `OrderNo` VARCHAR(32) NULL COMMENT ''海关下游订单编号(申报回写,非 t_order.DownstreamServiceNo)''',
- 'SELECT ''skip OrderNo comment'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- DownstreamRefNo 注释
-SET @hasDr := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='DownstreamRefNo'
-);
-SET @sql := IF(
- @hasDr > 0,
- 'ALTER TABLE `t_9610_order` MODIFY COLUMN `DownstreamRefNo` VARCHAR(32) NULL COMMENT ''申报回写的 referenceNo 快照''',
- 'SELECT ''skip DownstreamRefNo comment'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_9610_manifest_fields.sql b/sql/migrate_t_9610_manifest_fields.sql
deleted file mode 100644
index 59df813..0000000
--- a/sql/migrate_t_9610_manifest_fields.sql
+++ /dev/null
@@ -1,170 +0,0 @@
--- 9610:补齐「获取清单数据」回写字段(幂等;列已存在则跳过)
--- 字段名为 OMS 自有命名,与上游 CEB 字段对照见注释
-
-SET @db := DATABASE();
-
--- ========== t_9610_order ==========
-
--- EnterpriseBizNo ← copNo 企业唯一编号
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EnterpriseBizNo');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `EnterpriseBizNo` VARCHAR(48) NULL COMMENT ''企业唯一编号(上游 copNo)'' AFTER `DownstreamRefNo`', 'SELECT ''skip EnterpriseBizNo'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ManifestNo ← invtNo 清单编号
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ManifestNo');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `ManifestNo` VARCHAR(48) NULL COMMENT ''清单编号(上游 invtNo)'' AFTER `EnterpriseBizNo`', 'SELECT ''skip ManifestNo'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ClearanceTime ← clearanceTime 结关日期(原文,格式不固定)
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ClearanceTime');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `ClearanceTime` VARCHAR(48) NULL COMMENT ''结关日期原文'' AFTER `ManifestNo`', 'SELECT ''skip ClearanceTime'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- CustomsInboundTime ← warehouseTime 海关入库时间
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='CustomsInboundTime');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `CustomsInboundTime` VARCHAR(48) NULL COMMENT ''海关入库时间原文'' AFTER `ClearanceTime`', 'SELECT ''skip CustomsInboundTime'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- CustomsState ← customsStatus 海关状态
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='CustomsState');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `CustomsState` VARCHAR(4) NULL COMMENT ''海关状态'' AFTER `CustomsInboundTime`', 'SELECT ''skip CustomsState'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- DeclareCustomsCode ← customsCode 申报地海关
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='DeclareCustomsCode');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `DeclareCustomsCode` VARCHAR(4) NULL COMMENT ''申报地海关代码'' AFTER `CustomsState`', 'SELECT ''skip DeclareCustomsCode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- EbpCode ← ebpCode
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EbpCode');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `EbpCode` VARCHAR(18) NULL COMMENT ''电商平台代码'' AFTER `DeclareCustomsCode`', 'SELECT ''skip EbpCode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- EbpName ← ebpName
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EbpName');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `EbpName` VARCHAR(100) NULL COMMENT ''电商平台名称'' AFTER `EbpCode`', 'SELECT ''skip EbpName'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- LogisticsCorpCode ← logisticsCode
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='LogisticsCorpCode');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `LogisticsCorpCode` VARCHAR(18) NULL COMMENT ''物流企业代码'' AFTER `EbpName`', 'SELECT ''skip LogisticsCorpCode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- LogisticsCorpName ← logisticsName
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='LogisticsCorpName');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `LogisticsCorpName` VARCHAR(100) NULL COMMENT ''物流企业名称'' AFTER `LogisticsCorpCode`', 'SELECT ''skip LogisticsCorpName'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- IeMark ← ieFlag I/E
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='IeMark');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `IeMark` VARCHAR(4) NULL COMMENT ''进出口标记 I/E'' AFTER `LogisticsCorpName`', 'SELECT ''skip IeMark'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ExportPortCode ← portCode
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ExportPortCode');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `ExportPortCode` VARCHAR(4) NULL COMMENT ''出口口岸代码'' AFTER `IeMark`', 'SELECT ''skip ExportPortCode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ExportDate ← ieDate
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ExportDate');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `ExportDate` VARCHAR(32) NULL COMMENT ''出口日期原文'' AFTER `ExportPortCode`', 'SELECT ''skip ExportDate'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- DeclareAgentCode ← agentCode
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='DeclareAgentCode');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `DeclareAgentCode` VARCHAR(18) NULL COMMENT ''申报企业代码'' AFTER `ExportDate`', 'SELECT ''skip DeclareAgentCode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- DeclareAgentName ← agentName
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='DeclareAgentName');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `DeclareAgentName` VARCHAR(100) NULL COMMENT ''申报企业名称'' AFTER `DeclareAgentCode`', 'SELECT ''skip DeclareAgentName'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- TradeModeCode ← tradeMode
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='TradeModeCode');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `TradeModeCode` VARCHAR(4) NULL COMMENT ''贸易方式代码'' AFTER `DeclareAgentName`', 'SELECT ''skip TradeModeCode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- TransportMode ← trafMode
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='TransportMode');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `TransportMode` VARCHAR(4) NULL COMMENT ''运输方式代码'' AFTER `TradeModeCode`', 'SELECT ''skip TransportMode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- FreightCurrency ← fCurrency
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='FreightCurrency');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `FreightCurrency` VARCHAR(4) NULL COMMENT ''运费币制'' AFTER `Freight`', 'SELECT ''skip FreightCurrency'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- FreightMark ← fFlag 1率/2单价/3总价
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='FreightMark');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `FreightMark` INT NULL COMMENT ''运费标志 1率2单价3总价'' AFTER `FreightCurrency`', 'SELECT ''skip FreightMark'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- PackageType ← wrapType
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='PackageType');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `PackageType` INT NULL COMMENT ''包装种类代码'' AFTER `FreightMark`', 'SELECT ''skip PackageType'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- PackageQty ← packNo
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='PackageQty');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `PackageQty` INT NULL COMMENT ''件数'' AFTER `PackageType`', 'SELECT ''skip PackageQty'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ManifestSyncTime 最近一次清单回写时间
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ManifestSyncTime');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order` ADD COLUMN `ManifestSyncTime` DATETIME NULL COMMENT ''清单数据最近同步时间'' AFTER `DeclareTime`', 'SELECT ''skip ManifestSyncTime'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- 运费精度对齐上游 DECIMAL(19,5)
-SET @colType := (
- SELECT COLUMN_TYPE FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='Freight'
-);
-SET @sql := IF(
- @colType IS NOT NULL AND @colType NOT LIKE 'decimal(19,5)%',
- 'ALTER TABLE `t_9610_order` MODIFY COLUMN `Freight` DECIMAL(19,5) NULL COMMENT ''运费''',
- 'SELECT ''skip Freight precision'' AS msg'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ManifestNo 索引(幂等)
-SET @idx := (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND INDEX_NAME='idx_9610_manifest');
-SET @sql := IF(@idx=0, 'ALTER TABLE `t_9610_order` ADD KEY `idx_9610_manifest` (`ManifestNo`)', 'SELECT ''skip idx_9610_manifest'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ========== t_9610_order_item ==========
-
--- Barcode ← barCode
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Barcode');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order_item` ADD COLUMN `Barcode` VARCHAR(255) NULL COMMENT ''条形码'' AFTER `Gmodel`', 'SELECT ''skip Barcode'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- DestCountry ← country 目的国
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='DestCountry');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order_item` ADD COLUMN `DestCountry` VARCHAR(255) NULL COMMENT ''目的国(地区)代码'' AFTER `Barcode`', 'SELECT ''skip DestCountry'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ItemCurrency ← currency
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='ItemCurrency');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order_item` ADD COLUMN `ItemCurrency` VARCHAR(3) NULL COMMENT ''币制'' AFTER `DestCountry`', 'SELECT ''skip ItemCurrency'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- LegalQty ← qty1 法定数量
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='LegalQty');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order_item` ADD COLUMN `LegalQty` DECIMAL(19,5) NULL COMMENT ''法定数量'' AFTER `Quantity`', 'SELECT ''skip LegalQty'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- Unit ← unit(对齐运单;旧名 DeclareUnit 由 align_item_fields 迁移)
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Unit');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order_item` ADD COLUMN `Unit` VARCHAR(3) NULL COMMENT ''计量单位'' AFTER `LegalQty`', 'SELECT ''skip Unit'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- LegalUnit ← unit1
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='LegalUnit');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order_item` ADD COLUMN `LegalUnit` VARCHAR(3) NULL COMMENT ''法定计量单位'' AFTER `Unit`', 'SELECT ''skip LegalUnit'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- Amount ← totalPrice
-SET @col := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Amount');
-SET @sql := IF(@col=0, 'ALTER TABLE `t_9610_order_item` ADD COLUMN `Amount` DECIMAL(19,5) NULL COMMENT ''总价'' AFTER `UnitPrice`', 'SELECT ''skip Amount'' AS msg');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_9610_order.sql b/sql/migrate_t_9610_order.sql
deleted file mode 100644
index c83185b..0000000
--- a/sql/migrate_t_9610_order.sql
+++ /dev/null
@@ -1,123 +0,0 @@
--- 9610 汇总申报单(ExportCustomsMode=9610Summary)
--- 幂等:表已存在则跳过
-
-SET @db := DATABASE();
-
--- t_9610_order
-SET @exists := (
- SELECT COUNT(*)
- FROM information_schema.TABLES
- WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_9610_order'
-);
-SET @sql := IF(
- @exists = 0,
- 'CREATE TABLE `t_9610_order` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT ''主键'',
- `OrderId` INT NOT NULL COMMENT ''关联运单 t_order.Id'',
- `ServiceNo` VARCHAR(64) NULL COMMENT ''运单号冗余'',
- `CustomerId` INT NOT NULL DEFAULT 0 COMMENT ''客户Id'',
- `Status` VARCHAR(16) NOT NULL DEFAULT ''pending'' COMMENT ''pending待申报 / declared已申报'',
- `PlatformCode` VARCHAR(16) NOT NULL DEFAULT '''' COMMENT ''电商平台'',
- `EcomCorpCode` VARCHAR(18) NULL COMMENT ''电商企业代码'',
- `EcomCorpName` VARCHAR(100) NULL COMMENT ''电商企业名称'',
- `ProducerCode` VARCHAR(18) NULL COMMENT ''生产销售单位代码'',
- `ProducerName` VARCHAR(100) NULL COMMENT ''生产销售单位'',
- `ClientNo` VARCHAR(48) NOT NULL DEFAULT '''' COMMENT ''客户单号(对齐 t_order.ClientNo)'',
- `BusinessType` CHAR(1) NOT NULL DEFAULT ''B'' COMMENT ''业务类型 A简化/B汇总'',
- `Region` VARCHAR(10) NULL COMMENT ''区域 SZ/other'',
- `AgentDeclare` VARCHAR(2) NULL COMMENT ''是否代理申报 是/否'',
- `ActualSellerCode` VARCHAR(18) NULL COMMENT ''实际卖家信用代码'',
- `PreRecordFlag` CHAR(1) NULL COMMENT ''汇总预录 0已预录 1未预录'',
- `IsSummarySimple` TINYINT NOT NULL DEFAULT 0 COMMENT ''是否汇总简化申报'',
- `GrossWeight` DECIMAL(19,5) NOT NULL DEFAULT 0 COMMENT ''毛重KG'',
- `Currency` VARCHAR(4) NOT NULL DEFAULT ''CNY'' COMMENT ''币制'',
- `DestCountry` VARCHAR(4) NOT NULL DEFAULT '''' COMMENT ''目的国'',
- `Freight` DECIMAL(19,5) NULL COMMENT ''运费'',
- `FreightCurrency` VARCHAR(4) NULL COMMENT ''运费币制'',
- `FreightMark` INT NULL COMMENT ''运费标志 1率2单价3总价'',
- `PackageType` INT NULL COMMENT ''包装种类代码'',
- `PackageQty` INT NULL COMMENT ''件数'',
- `ShipmentNo` VARCHAR(32) NULL COMMENT ''出货单号'',
- `CustomsOrderNo` VARCHAR(32) NULL COMMENT ''海关订单号(申报回写)'',
- `DownstreamRefNo` VARCHAR(32) NULL COMMENT ''申报回写的 referenceNo 快照'',
- `EnterpriseBizNo` VARCHAR(48) NULL COMMENT ''企业唯一编号(上游 copNo)'',
- `ManifestNo` VARCHAR(48) NULL COMMENT ''清单编号(上游 invtNo)'',
- `ClearanceTime` VARCHAR(48) NULL COMMENT ''结关日期原文'',
- `CustomsInboundTime` VARCHAR(48) NULL COMMENT ''海关入库时间原文'',
- `CustomsState` VARCHAR(4) NULL COMMENT ''海关状态'',
- `DeclareCustomsCode` VARCHAR(4) NULL COMMENT ''申报地海关代码'',
- `PlatformCorpCode` VARCHAR(18) NULL COMMENT ''电商平台代码'',
- `PlatformName` VARCHAR(100) NULL COMMENT ''电商平台名称'',
- `LogisticsCorpCode` VARCHAR(18) NULL COMMENT ''物流企业代码'',
- `LogisticsCorpName` VARCHAR(100) NULL COMMENT ''物流企业名称'',
- `IeMark` VARCHAR(4) NULL COMMENT ''进出口标记 I/E'',
- `ExportPortCode` VARCHAR(4) NULL COMMENT ''出口口岸代码'',
- `ExportDate` VARCHAR(32) NULL COMMENT ''出口日期原文'',
- `DeclareAgentCode` VARCHAR(18) NULL COMMENT ''申报企业代码'',
- `DeclareAgentName` VARCHAR(100) NULL COMMENT ''申报企业名称'',
- `TradeModeCode` VARCHAR(4) NULL COMMENT ''贸易方式代码'',
- `TransportMode` VARCHAR(4) NULL COMMENT ''运输方式代码'',
- `DeclareTime` DATETIME NULL COMMENT ''申报成功时间'',
- `ManifestSyncTime` DATETIME NULL COMMENT ''清单数据最近同步时间'',
- `FailReason` VARCHAR(512) NULL COMMENT ''最近失败原因'',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT ''软删除'',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '''' COMMENT ''并发戳'',
- `CreateUserId` INT NOT NULL DEFAULT 0 COMMENT ''创建人'',
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''创建时间'',
- `UpdateUserId` INT NULL COMMENT ''更新人'',
- `UpdateTime` DATETIME NULL COMMENT ''更新时间'',
- PRIMARY KEY (`Id`),
- UNIQUE KEY `uk_9610_order_id` (`OrderId`),
- KEY `idx_9610_status_ctime` (`Status`, `CreateTime`),
- KEY `idx_9610_service_no` (`ServiceNo`),
- KEY `idx_9610_client_no` (`ClientNo`),
- KEY `idx_9610_customer` (`CustomerId`, `CreateTime`),
- KEY `idx_9610_manifest` (`ManifestNo`)
-) COMMENT=''9610汇总申报单''',
- 'SELECT ''skip t_9610_order'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- t_9610_order_item
-SET @exists := (
- SELECT COUNT(*)
- FROM information_schema.TABLES
- WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_9610_order_item'
-);
-SET @sql := IF(
- @exists = 0,
- 'CREATE TABLE `t_9610_order_item` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT ''主键'',
- `Customs9610OrderId` INT NOT NULL COMMENT ''t_9610_order.Id'',
- `OrderDeclarationId` INT NULL COMMENT ''溯源 t_order_declaration.Id'',
- `Sku` VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''SKU(对齐 t_order_declaration.Sku)'',
- `CnName` VARCHAR(250) NOT NULL DEFAULT '''' COMMENT ''中文品名(对齐 t_order_declaration.CnName)'',
- `ExHsCode` VARCHAR(10) NULL COMMENT ''出口海关编码(对齐 t_order_declaration.ExHsCode)'',
- `DeclareElement` VARCHAR(255) NULL COMMENT ''申报要素'',
- `Barcode` VARCHAR(255) NULL COMMENT ''条形码'',
- `DestCountry` VARCHAR(255) NULL COMMENT ''目的国(地区)代码'',
- `ItemCurrency` VARCHAR(3) NULL COMMENT ''币制'',
- `UnitPrice` DECIMAL(19,5) NOT NULL DEFAULT 0 COMMENT ''单价(对齐 t_order_declaration.UnitPrice)'',
- `Amount` DECIMAL(19,5) NULL COMMENT ''总价(对齐 t_order_declaration.Amount)'',
- `Quantity` DECIMAL(19,5) NOT NULL DEFAULT 0 COMMENT ''数量(对齐 t_order_declaration.Quantity)'',
- `LegalQty` DECIMAL(19,5) NULL COMMENT ''法定数量'',
- `Unit` VARCHAR(3) NULL COMMENT ''计量单位(对齐 t_order_declaration.Unit)'',
- `LegalUnit` VARCHAR(3) NULL COMMENT ''法定计量单位'',
- `Freight` DECIMAL(12,4) NULL COMMENT ''行运费'',
- `SortNo` INT NOT NULL DEFAULT 0 COMMENT ''排序'',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT ''软删除'',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '''' COMMENT ''并发戳'',
- `CreateUserId` INT NOT NULL DEFAULT 0 COMMENT ''创建人'',
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''创建时间'',
- `UpdateUserId` INT NULL COMMENT ''更新人'',
- `UpdateTime` DATETIME NULL COMMENT ''更新时间'',
- PRIMARY KEY (`Id`),
- KEY `idx_9610_item_header` (`Customs9610OrderId`, `IsDeleted`)
-) COMMENT=''9610申报商品明细''',
- 'SELECT ''skip t_9610_order_item'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_9610_order_item_concurrency_stamp.sql b/sql/migrate_t_9610_order_item_concurrency_stamp.sql
deleted file mode 100644
index 7a9ddfa..0000000
--- a/sql/migrate_t_9610_order_item_concurrency_stamp.sql
+++ /dev/null
@@ -1,33 +0,0 @@
--- t_9610_order_item 补齐 Fake AggregateRoot 并发戳(幂等)
--- 现象:详情/申报查明细时报 Unknown column 'ConcurrencyStamp' in 'field list'
--- 原因:实体继承 OmsAuditedAggregateRoot → AggregateRoot 含 ConcurrencyStamp,头表有、明细表缺
--- 注意:勿用 DEFAULT (UUID())——Galera/主从会报 Statement is unsafe(副本上 UUID 不一致)
-
-SET @db := DATABASE();
-
-SET @has := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_9610_order_item'
- AND COLUMN_NAME = 'ConcurrencyStamp'
-);
-
-SET @sql := IF(
- @has = 0,
- 'ALTER TABLE `t_9610_order_item` ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '''' COMMENT ''并发戳'' AFTER `IsDeleted`',
- 'SELECT ''skip t_9610_order_item.ConcurrencyStamp'' AS msg'
-);
-
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- 已有行补确定性戳(基于主键,主从一致);新写入由 ORM 覆盖
-UPDATE `t_9610_order_item`
-SET `ConcurrencyStamp` = LOWER(CONCAT(
- LPAD(HEX(`Id`), 8, '0'),
- '-0000-4000-8000-',
- LPAD(HEX(`Id`), 12, '0')
-))
-WHERE `ConcurrencyStamp` = '' OR `ConcurrencyStamp` IS NULL;
diff --git a/sql/migrate_t_9610_rename_by_meaning.sql b/sql/migrate_t_9610_rename_by_meaning.sql
deleted file mode 100644
index 0a3a452..0000000
--- a/sql/migrate_t_9610_rename_by_meaning.sql
+++ /dev/null
@@ -1,90 +0,0 @@
--- 9610 其余字段按业务含义重命名(幂等 CHANGE)
--- 申报头:Ebp→PlatformCode, Ebc*→EcomCorp*, Owner*→Producer*, FormType→BusinessType,
--- IsAgent→AgentDeclare, ActBuyer→ActualSellerCode, SoLabelFlag→PreRecordFlag,
--- IsSimple→IsSummarySimple, Country→DestCountry, BlNo→ShipmentNo,
--- EbpCode/EbpName→PlatformCorpCode/PlatformName, OrderNo→CustomsOrderNo
--- 明细:Gmodel→DeclareElement
-
-SET @db := DATABASE();
-
--- helper pattern repeated
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='Ebp');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='PlatformCode');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `Ebp` `PlatformCode` VARCHAR(16) NOT NULL DEFAULT '''' COMMENT ''电商平台''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EbcCode');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EcomCorpCode');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `EbcCode` `EcomCorpCode` VARCHAR(18) NULL COMMENT ''电商企业代码''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EbcName');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EcomCorpName');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `EbcName` `EcomCorpName` VARCHAR(100) NULL COMMENT ''电商企业名称''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='OwnerCode');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ProducerCode');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `OwnerCode` `ProducerCode` VARCHAR(18) NULL COMMENT ''生产销售单位代码''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='OwnerName');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ProducerName');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `OwnerName` `ProducerName` VARCHAR(100) NULL COMMENT ''生产销售单位''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='FormType');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='BusinessType');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `FormType` `BusinessType` CHAR(1) NOT NULL DEFAULT ''B'' COMMENT ''业务类型 A简化/B汇总''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='IsAgent');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='AgentDeclare');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `IsAgent` `AgentDeclare` VARCHAR(2) NULL COMMENT ''是否代理申报 是/否''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ActBuyer');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ActualSellerCode');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `ActBuyer` `ActualSellerCode` VARCHAR(18) NULL COMMENT ''实际卖家信用代码''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='SoLabelFlag');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='PreRecordFlag');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `SoLabelFlag` `PreRecordFlag` CHAR(1) NULL COMMENT ''汇总预录 0已预录/1未预录''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='IsSimple');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='IsSummarySimple');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `IsSimple` `IsSummarySimple` TINYINT NOT NULL DEFAULT 0 COMMENT ''是否汇总简化申报''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='Country');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='DestCountry');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `Country` `DestCountry` VARCHAR(4) NOT NULL DEFAULT '''' COMMENT ''目的国''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='BlNo');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='ShipmentNo');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `BlNo` `ShipmentNo` VARCHAR(32) NULL COMMENT ''出货单号''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='OrderNo');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='CustomsOrderNo');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `OrderNo` `CustomsOrderNo` VARCHAR(32) NULL COMMENT ''海关订单号''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EbpCode');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='PlatformCorpCode');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `EbpCode` `PlatformCorpCode` VARCHAR(18) NULL COMMENT ''电商平台代码''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='EbpName');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order' AND COLUMN_NAME='PlatformName');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order` CHANGE COLUMN `EbpName` `PlatformName` VARCHAR(100) NULL COMMENT ''电商平台名称''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-
-SET @o:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='Gmodel');
-SET @n:=(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='t_9610_order_item' AND COLUMN_NAME='DeclareElement');
-SET @sql:=IF(@o>0 AND @n=0,'ALTER TABLE `t_9610_order_item` CHANGE COLUMN `Gmodel` `DeclareElement` VARCHAR(255) NULL COMMENT ''申报要素''','SELECT 1');
-PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
diff --git a/sql/migrate_t_order_declaration_sku_image.sql b/sql/migrate_t_order_declaration_sku_image.sql
deleted file mode 100644
index 7daa0af..0000000
--- a/sql/migrate_t_order_declaration_sku_image.sql
+++ /dev/null
@@ -1,27 +0,0 @@
--- t_order_declaration.SkuImage:库内 SKU 选图后写入签名 URL 易超 VARCHAR(255)
--- 后端已改为存 storage key;列宽对齐仓库 SkuImageUrl,兼容外链
-
-SET @db := DATABASE();
-
-SET @need := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order_declaration'
- AND COLUMN_NAME = 'SkuImage'
- AND (
- DATA_TYPE <> 'varchar'
- OR CHARACTER_MAXIMUM_LENGTH IS NULL
- OR CHARACTER_MAXIMUM_LENGTH < 512
- )
-);
-
-SET @sql := IF(
- @need > 0,
- 'ALTER TABLE `t_order_declaration` MODIFY COLUMN `SkuImage` VARCHAR(512) NULL COMMENT ''图片(存 storage key 或短 URL)''',
- 'SELECT ''skip t_order_declaration.SkuImage'' AS msg'
-);
-
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_order_exception_event_handler.sql b/sql/migrate_t_order_exception_event_handler.sql
deleted file mode 100644
index 96e6284..0000000
--- a/sql/migrate_t_order_exception_event_handler.sql
+++ /dev/null
@@ -1,118 +0,0 @@
--- 订单异常事件表:补齐 Handler* / ConcurrencyStamp(幂等;列已存在则自动跳过)
--- 修复:Unknown column 'HandlerNames' / 'ConcurrencyStamp' in 'field list'
--- MySQL 5.7+ / 8.0
-
-SET @db := DATABASE();
-
--- HandlerNames
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order_exception_event'
- AND COLUMN_NAME = 'HandlerNames'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_order_exception_event` ADD COLUMN `HandlerNames` VARCHAR(256) NULL COMMENT ''处理人快照''',
- 'SELECT ''skip HandlerNames'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- HandlerType
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order_exception_event'
- AND COLUMN_NAME = 'HandlerType'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_order_exception_event` ADD COLUMN `HandlerType` VARCHAR(16) NULL COMMENT ''处理人类型''',
- 'SELECT ''skip HandlerType'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- HandlerUserId
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order_exception_event'
- AND COLUMN_NAME = 'HandlerUserId'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_order_exception_event` ADD COLUMN `HandlerUserId` INT NULL COMMENT ''处理人用户Id(customer 时为订单客户账号)''',
- 'SELECT ''skip HandlerUserId'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- ConcurrencyStamp(AggregateRoot 并发戳;避免 DEFAULT(UUID()) 触发 1674 复制不安全)
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order_exception_event'
- AND COLUMN_NAME = 'ConcurrencyStamp'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_order_exception_event` ADD COLUMN `ConcurrencyStamp` CHAR(36) NULL COMMENT ''并发戳''',
- 'SELECT ''skip ConcurrencyStamp add'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order_exception_event'
- AND COLUMN_NAME = 'ConcurrencyStamp'
-);
-SET @sql := IF(
- @col > 0,
- 'UPDATE `t_order_exception_event`
- SET `ConcurrencyStamp` = LOWER(CONCAT(
- LPAD(HEX(`Id`), 8, ''0''),
- ''-0000-4000-8000-'',
- LPAD(HEX(`Id` * 9973), 12, ''0'')
- ))
- WHERE `ConcurrencyStamp` IS NULL OR `ConcurrencyStamp` = ''''',
- 'SELECT ''skip ConcurrencyStamp backfill'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order_exception_event'
- AND COLUMN_NAME = 'ConcurrencyStamp'
-);
-SET @isNullable := (
- SELECT IFNULL(MAX(CASE WHEN IS_NULLABLE = 'YES' THEN 1 ELSE 0 END), 0)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order_exception_event'
- AND COLUMN_NAME = 'ConcurrencyStamp'
-);
-SET @sql := IF(
- @col > 0 AND @isNullable = 1,
- 'ALTER TABLE `t_order_exception_event` MODIFY COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL COMMENT ''并发戳''',
- 'SELECT ''skip ConcurrencyStamp not null'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_order_fulfillment_type.sql b/sql/migrate_t_order_fulfillment_type.sql
deleted file mode 100644
index ff3cd2c..0000000
--- a/sql/migrate_t_order_fulfillment_type.sql
+++ /dev/null
@@ -1,70 +0,0 @@
--- 代发订单:t_order 履约类型字段(幂等;列/索引已存在则自动跳过)
--- MySQL 5.7+ / 8.0
-
-SET @db := DATABASE();
-
--- FulfillmentType
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order'
- AND COLUMN_NAME = 'FulfillmentType'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `FulfillmentType` VARCHAR(16) NULL DEFAULT ''direct'' COMMENT ''履约类型 direct/warehouse'' AFTER `AdditionalServices`',
- 'SELECT ''skip FulfillmentType'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- FulfillmentSource
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order'
- AND COLUMN_NAME = 'FulfillmentSource'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `FulfillmentSource` VARCHAR(32) NULL COMMENT ''代发来源 storeFulfill/postBind'' AFTER `FulfillmentType`',
- 'SELECT ''skip FulfillmentSource'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- idx_ord_fulfillment_customer
-SET @idx := (
- SELECT COUNT(*)
- FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_order'
- AND INDEX_NAME = 'idx_ord_fulfillment_customer'
-);
-SET @sql := IF(
- @idx = 0,
- 'ALTER TABLE `t_order` ADD KEY `idx_ord_fulfillment_customer` (`FulfillmentType`, `CustomerId`, `OrderStatus`)',
- 'SELECT ''skip idx_ord_fulfillment_customer'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- 历史:已有绑定行的订单标记为 warehouse
-UPDATE `t_order` o
-INNER JOIN (
- SELECT DISTINCT b.`OrderId`
- FROM `t_order_stock_bind` b
- WHERE b.`IsDeleted` = 0
- AND b.`Status` IN ('bound', 'deducted')
-) x ON x.`OrderId` = o.`Id`
-SET o.`FulfillmentType` = 'warehouse';
-
--- 其余空值兜底为 direct
-UPDATE `t_order`
-SET `FulfillmentType` = 'direct'
-WHERE `FulfillmentType` IS NULL OR `FulfillmentType` = '';
diff --git a/sql/migrate_t_pickup_order_line_service_no.sql b/sql/migrate_t_pickup_order_line_service_no.sql
deleted file mode 100644
index db7d663..0000000
--- a/sql/migrate_t_pickup_order_line_service_no.sql
+++ /dev/null
@@ -1,49 +0,0 @@
--- 揽收明细:补齐运单号/客户单号快照(幂等;列已存在则跳过)
--- 对应实体 PickupOrderLine.ServiceNo / ClientNo
--- 报错 Unknown column 'ServiceNo' in 'field list' 时执行本脚本
--- MySQL 5.7+ / 8.0
-
-SET @db := DATABASE();
-
--- ServiceNo
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_pickup_order_line'
- AND COLUMN_NAME = 'ServiceNo'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_pickup_order_line` ADD COLUMN `ServiceNo` VARCHAR(64) NULL COMMENT ''运单号快照(便于列表)'' AFTER `OrderId`',
- 'SELECT ''skip ServiceNo'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- ClientNo
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 't_pickup_order_line'
- AND COLUMN_NAME = 'ClientNo'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `t_pickup_order_line` ADD COLUMN `ClientNo` VARCHAR(64) NULL COMMENT ''客户单号快照'' AFTER `ServiceNo`',
- 'SELECT ''skip ClientNo'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
--- 存量行从订单表回填快照(仅空值)
-UPDATE `t_pickup_order_line` pl
-INNER JOIN `t_order` o ON o.`Id` = pl.`OrderId`
-SET
- pl.`ServiceNo` = IFNULL(NULLIF(pl.`ServiceNo`, ''), o.`ServiceNo`),
- pl.`ClientNo` = IFNULL(NULLIF(pl.`ClientNo`, ''), o.`ClientNo`)
-WHERE pl.`IsDeleted` = 0
- AND (pl.`ServiceNo` IS NULL OR pl.`ServiceNo` = '' OR pl.`ClientNo` IS NULL OR pl.`ClientNo` = '');
diff --git a/sql/migrate_user_wecom_kf_url.sql b/sql/migrate_user_wecom_kf_url.sql
deleted file mode 100644
index 29d1e8a..0000000
--- a/sql/migrate_user_wecom_kf_url.sql
+++ /dev/null
@@ -1,20 +0,0 @@
--- user 表:企业微信客服接入链接(幂等;列已存在则跳过)
--- MySQL 5.7+ / 8.0
-
-SET @db := DATABASE();
-
-SET @col := (
- SELECT COUNT(*)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = @db
- AND TABLE_NAME = 'user'
- AND COLUMN_NAME = 'WecomKfUrl'
-);
-SET @sql := IF(
- @col = 0,
- 'ALTER TABLE `user` ADD COLUMN `WecomKfUrl` VARCHAR(512) NULL COMMENT ''企业微信客服接入链接''',
- 'SELECT ''skip WecomKfUrl'' AS msg'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
diff --git a/src/Oms.Application/Dtos/Orders/CustomerSenderAddressDtos.cs b/src/Oms.Application/Dtos/Orders/CustomerSenderAddressDtos.cs
index da181ec..1ba0dc4 100644
--- a/src/Oms.Application/Dtos/Orders/CustomerSenderAddressDtos.cs
+++ b/src/Oms.Application/Dtos/Orders/CustomerSenderAddressDtos.cs
@@ -187,6 +187,11 @@ public class OrderPickupCreateInput
[Required]
public int SenderAddressId { get; set; }
+ ///
+ /// 揽收方向:forward / reverse。默认正向。
+ ///
+ public string? Direction { get; set; }
+
[Required]
public DateTime PickupTime { get; set; }
diff --git a/src/Oms.Application/Dtos/Orders/OrderParcelCreateInput.cs b/src/Oms.Application/Dtos/Orders/OrderParcelCreateInput.cs
index 700ec1d..f3048f6 100644
--- a/src/Oms.Application/Dtos/Orders/OrderParcelCreateInput.cs
+++ b/src/Oms.Application/Dtos/Orders/OrderParcelCreateInput.cs
@@ -170,6 +170,11 @@ public class OrderParcelCreateInput
///
public DateTime? ExpectPickupTime { get; set; }
+ ///
+ /// 揽收方向:forward / reverse(上门揽收挂载揽收单时使用)。
+ ///
+ public string? PickupDirection { get; set; }
+
///
/// 承运商编码(可后补)。
///
diff --git a/src/Oms.Application/Dtos/Orders/PickupOrderDtos.cs b/src/Oms.Application/Dtos/Orders/PickupOrderDtos.cs
index cebd222..0706a9f 100644
--- a/src/Oms.Application/Dtos/Orders/PickupOrderDtos.cs
+++ b/src/Oms.Application/Dtos/Orders/PickupOrderDtos.cs
@@ -14,6 +14,11 @@ public class PickupOrderCreateInput
[Required]
public int SenderAddressId { get; set; }
+ ///
+ /// 揽收方向:forward 正向(客户地址→仓库)/ reverse 逆向(仓库→客户地址)。默认正向。
+ ///
+ public string? Direction { get; set; }
+
[Required]
public int WarehouseId { get; set; }
@@ -102,6 +107,11 @@ public class PickupOrderListInput
public int? WarehouseId { get; set; }
+ ///
+ /// 揽收方向:forward / reverse。
+ ///
+ public string? Direction { get; set; }
+
public DateTime? CreateTimeStart { get; set; }
public DateTime? CreateTimeEnd { get; set; }
@@ -208,6 +218,11 @@ public class PickupOrderOutput
public int SenderAddressId { get; set; }
+ ///
+ /// 揽收方向:forward / reverse。
+ ///
+ public string Direction { get; set; } = "forward";
+
public string SenderName { get; set; } = string.Empty;
public string? SenderPhone { get; set; }
diff --git a/src/Oms.Application/Services/Orders/OrderService.Pickup.cs b/src/Oms.Application/Services/Orders/OrderService.Pickup.cs
index e8158d4..ea6aefb 100644
--- a/src/Oms.Application/Services/Orders/OrderService.Pickup.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.Pickup.cs
@@ -22,7 +22,7 @@ public partial class OrderService
if (input.SenderAddressId <= 0)
{
- throw new BusinessException("发件地址不能为空");
+ throw new BusinessException("揽收地址不能为空");
}
if (string.IsNullOrWhiteSpace(input.ProductCode))
@@ -55,15 +55,15 @@ public partial class OrderService
var senderAddress = await CustomerSenderAddressRepository.GetOwnedAsync(input.SenderAddressId, customerId);
if (senderAddress == null)
{
- throw new BusinessException("发件地址不存在");
+ throw new BusinessException("揽收地址不存在");
}
var addressType = string.IsNullOrWhiteSpace(senderAddress.AddressType)
? CustomerAddressTypeCodes.Sender
: senderAddress.AddressType;
- if (!string.Equals(addressType, CustomerAddressTypeCodes.Sender, StringComparison.OrdinalIgnoreCase))
+ if (!CustomerAddressTypeCodes.IsPickupEligible(addressType))
{
- throw new BusinessException("揽收订单仅可选择发件地址");
+ throw new BusinessException("揽收订单请选择「国内揽收」类型地址");
}
var warehouse = await WarehouseAddressRepository.FirstOrDefaultAsync(x => x.Id == input.WarehouseId);
diff --git a/src/Oms.Application/Services/Orders/OrderService.cs b/src/Oms.Application/Services/Orders/OrderService.cs
index cce98db..131f975 100644
--- a/src/Oms.Application/Services/Orders/OrderService.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.cs
@@ -541,7 +541,7 @@ public partial class OrderService : ApplicationService
if (input.SenderAddressId is not > 0)
{
- output.PickupCreateError = "上门揽收需选择发件地址";
+ output.PickupCreateError = "上门揽收需选择揽收地址";
return;
}
@@ -564,6 +564,7 @@ public partial class OrderService : ApplicationService
{
CustomerId = input.CustomerId,
SenderAddressId = input.SenderAddressId.Value,
+ Direction = PickupDirectionCodes.NormalizeOrDefault(input.PickupDirection),
WarehouseId = input.WarehouseId.Value,
CarrierCode = input.CarrierCode,
CarrierService = input.CarrierService,
diff --git a/src/Oms.Application/Services/Orders/PickupOrderParcelBuilder.cs b/src/Oms.Application/Services/Orders/PickupOrderParcelBuilder.cs
index 27b6de5..3e83f88 100644
--- a/src/Oms.Application/Services/Orders/PickupOrderParcelBuilder.cs
+++ b/src/Oms.Application/Services/Orders/PickupOrderParcelBuilder.cs
@@ -23,13 +23,71 @@ public static class PickupOrderParcelBuilder
? $"PK{DateTime.Now:yyyyMMddHHmmss}{Random.Shared.Next(1000, 9999)}"
: input.ClientNo.Trim();
- var receiverName = string.IsNullOrWhiteSpace(warehouse.Recipient)
+ var warehouseContact = string.IsNullOrWhiteSpace(warehouse.Recipient)
? warehouse.WarehouseName
: warehouse.Recipient!.Trim();
- var street = string.IsNullOrWhiteSpace(warehouse.ShippingAddress)
+ var warehouseStreet = string.IsNullOrWhiteSpace(warehouse.ShippingAddress)
? warehouse.WarehouseName
: warehouse.ShippingAddress!.Trim();
+ var isReverse = string.Equals(
+ PickupDirectionCodes.NormalizeOrDefault(input.Direction),
+ PickupDirectionCodes.Reverse,
+ StringComparison.OrdinalIgnoreCase);
+
+ // 正向:客户揽收地址 → 仓库;逆向:仓库 → 客户揽收地址
+ var sender = isReverse
+ ? new OrderParcelSenderInput
+ {
+ SenderName = warehouseContact,
+ Phone = warehouse.ContactPhone,
+ CountryCode = "CN",
+ StreetAddress1 = warehouseStreet,
+ ZipCode = "000000"
+ }
+ : new OrderParcelSenderInput
+ {
+ SenderName = senderAddress.SenderName,
+ Company = senderAddress.Company,
+ Phone = senderAddress.Phone,
+ TelePhone = senderAddress.TelePhone,
+ Email = senderAddress.Email,
+ CountryCode = senderCountryCode ?? "CN",
+ Province = senderAddress.Province,
+ City = senderAddress.City,
+ ZipCode = senderAddress.ZipCode,
+ StreetAddress1 = senderAddress.StreetAddress1,
+ StreetAddress2 = senderAddress.StreetAddress2,
+ StreetAddress3 = senderAddress.StreetAddress3,
+ HouseNumber = senderAddress.HouseNumber
+ };
+
+ var receiver = isReverse
+ ? new OrderParcelReceiverInput
+ {
+ RecipientsName = senderAddress.SenderName,
+ CompanyName = senderAddress.Company,
+ Phone = senderAddress.Phone,
+ TelePhone = senderAddress.TelePhone,
+ Email = senderAddress.Email,
+ CountryCode = senderCountryCode ?? "CN",
+ Province = senderAddress.Province,
+ City = senderAddress.City,
+ ZipCode = senderAddress.ZipCode ?? "000000",
+ StreetAddress1 = senderAddress.StreetAddress1,
+ StreetAddress2 = senderAddress.StreetAddress2,
+ StreetAddress3 = senderAddress.StreetAddress3,
+ StreetNumber = senderAddress.HouseNumber
+ }
+ : new OrderParcelReceiverInput
+ {
+ RecipientsName = warehouseContact,
+ Phone = warehouse.ContactPhone,
+ CountryCode = "CN",
+ ZipCode = "000000",
+ StreetAddress1 = warehouseStreet
+ };
+
return new OrderParcelCreateInput
{
RequestId = string.IsNullOrWhiteSpace(input.RequestId) ? null : input.RequestId.Trim(),
@@ -47,30 +105,12 @@ public static class PickupOrderParcelBuilder
DeclaredCurrency = "CNY",
DeclaredSum = 1,
Quantity = 1,
- Sender = new OrderParcelSenderInput
- {
- SenderName = senderAddress.SenderName,
- Company = senderAddress.Company,
- Phone = senderAddress.Phone,
- TelePhone = senderAddress.TelePhone,
- Email = senderAddress.Email,
- CountryCode = senderCountryCode ?? "CN",
- Province = senderAddress.Province,
- City = senderAddress.City,
- ZipCode = senderAddress.ZipCode,
- StreetAddress1 = senderAddress.StreetAddress1,
- StreetAddress2 = senderAddress.StreetAddress2,
- StreetAddress3 = senderAddress.StreetAddress3,
- HouseNumber = senderAddress.HouseNumber
- },
- Receiver = new OrderParcelReceiverInput
- {
- RecipientsName = receiverName,
- Phone = warehouse.ContactPhone,
- CountryCode = "CN",
- ZipCode = "000000",
- StreetAddress1 = street
- },
+ InboundMethod = OrderInboundMethodCodes.DoorPickup,
+ SenderAddressId = input.SenderAddressId,
+ ExpectPickupTime = input.PickupTime,
+ PickupDirection = PickupDirectionCodes.NormalizeOrDefault(input.Direction),
+ Sender = sender,
+ Receiver = receiver,
Items =
[
new OrderParcelItemInput
diff --git a/src/Oms.Application/Services/Orders/PickupOrderService.cs b/src/Oms.Application/Services/Orders/PickupOrderService.cs
index e00debf..3f5aeaa 100644
--- a/src/Oms.Application/Services/Orders/PickupOrderService.cs
+++ b/src/Oms.Application/Services/Orders/PickupOrderService.cs
@@ -63,7 +63,7 @@ public class PickupOrderService : ApplicationService
if (input.SenderAddressId <= 0)
{
- throw new BusinessException("发件地址不能为空");
+ throw new BusinessException("揽收地址不能为空");
}
if (input.WarehouseId <= 0)
@@ -76,6 +76,8 @@ public class PickupOrderService : ApplicationService
throw new BusinessException("期望揽收时间不能为空");
}
+ var direction = PickupDirectionCodes.NormalizeOrDefault(input.Direction);
+
var orderIds = (input.OrderIds ?? []).Where(x => x > 0).Distinct().ToList();
if (orderIds.Count == 0)
{
@@ -85,15 +87,15 @@ public class PickupOrderService : ApplicationService
var senderAddress = await CustomerSenderAddressRepository.GetOwnedAsync(input.SenderAddressId, customerId);
if (senderAddress == null)
{
- throw new BusinessException("发件地址不存在");
+ throw new BusinessException("揽收地址不存在");
}
var addressType = string.IsNullOrWhiteSpace(senderAddress.AddressType)
? CustomerAddressTypeCodes.Sender
: senderAddress.AddressType;
- if (!string.Equals(addressType, CustomerAddressTypeCodes.Sender, StringComparison.OrdinalIgnoreCase))
+ if (!CustomerAddressTypeCodes.IsPickupEligible(addressType))
{
- throw new BusinessException("揽收单仅可选择发件地址");
+ throw new BusinessException("揽收单请选择「国内揽收」类型地址");
}
var warehouse = await WarehouseAddressRepository.FirstOrDefaultAsync(x => x.Id == input.WarehouseId);
@@ -198,6 +200,7 @@ public class PickupOrderService : ApplicationService
OrganizationId = orgId,
SecretLevel = secretLevel,
SenderAddressId = senderAddress.Id,
+ Direction = direction,
SenderName = senderAddress.SenderName ?? string.Empty,
SenderCompany = senderAddress.Company,
SenderCountry = senderAddress.Country,
@@ -408,9 +411,13 @@ public class PickupOrderService : ApplicationService
var keyword = NormalizeOptional(input.Keyword);
var status = NormalizeOptional(input.Status);
var payStatus = NormalizeOptional(input.PayStatus);
+ var direction = string.IsNullOrWhiteSpace(input.Direction)
+ ? null
+ : PickupDirectionCodes.NormalizeOrDefault(input.Direction);
var all = await PickupOrderRepository.GetListAsync(x =>
(customerId == null || x.CustomerId == customerId.Value) &&
+ (direction == null || x.Direction == direction) &&
(status == null || x.Status == status) &&
(payStatus == null || x.PayStatus == payStatus) &&
(input.WarehouseId == null || input.WarehouseId <= 0 || x.WarehouseId == input.WarehouseId.Value) &&
@@ -438,15 +445,22 @@ public class PickupOrderService : ApplicationService
/// 揽收单状态计数(Tab 徽章)。
///
[HttpGet("/order/pickup-order/status-counts")]
- public async Task GetStatusCountsAsync([FromQuery] int? customerId)
+ public async Task GetStatusCountsAsync(
+ [FromQuery] int? customerId,
+ [FromQuery] string? direction = null)
{
var resolvedCustomerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
CustomerRepository,
CurrentUser,
customerId);
+ var directionFilter = string.IsNullOrWhiteSpace(direction)
+ ? null
+ : PickupDirectionCodes.NormalizeOrDefault(direction);
+
var all = await PickupOrderRepository.GetListAsync(x =>
- resolvedCustomerId == null || x.CustomerId == resolvedCustomerId.Value);
+ (resolvedCustomerId == null || x.CustomerId == resolvedCustomerId.Value) &&
+ (directionFilter == null || x.Direction == directionFilter));
var terminal = new[] { PickupOrderStatusCodes.Cancelled, PickupOrderStatusCodes.Failed };
var pendingPayment = all.Count(x =>
@@ -929,6 +943,7 @@ public class PickupOrderService : ApplicationService
OrganizationId = entity.OrganizationId,
SecretLevel = entity.SecretLevel,
SenderAddressId = entity.SenderAddressId,
+ Direction = PickupDirectionCodes.NormalizeOrDefault(entity.Direction),
SenderName = entity.SenderName,
SenderPhone = entity.SenderPhone,
SenderTelePhone = entity.SenderTelePhone,
diff --git a/src/Oms.Domain/OrdersAggregate/Consts/CustomerAddressTypeCodes.cs b/src/Oms.Domain/OrdersAggregate/Consts/CustomerAddressTypeCodes.cs
index 34b5f48..26dd7fb 100644
--- a/src/Oms.Domain/OrdersAggregate/Consts/CustomerAddressTypeCodes.cs
+++ b/src/Oms.Domain/OrdersAggregate/Consts/CustomerAddressTypeCodes.cs
@@ -1,18 +1,27 @@
namespace Oms.Domain.OrdersAggregate.Consts;
///
-/// 客户地址类型:发件 / 退件 / 收件。
+/// 客户地址类型:国内发件 / 国内退件 / 国内揽收 / 海外收件。
///
public static class CustomerAddressTypeCodes
{
+ /// 国内发件(国际件发件人地址)
public const string Sender = "sender";
+
+ /// 国内退件
public const string Return = "return";
+
+ /// 国内揽收(上门取件地址)
+ public const string Pickup = "pickup";
+
+ /// 海外收件
public const string Receiver = "receiver";
public static readonly HashSet All = new(StringComparer.OrdinalIgnoreCase)
{
Sender,
Return,
+ Pickup,
Receiver
};
@@ -21,7 +30,7 @@ public static class CustomerAddressTypeCodes
var code = string.IsNullOrWhiteSpace(addressType) ? Sender : addressType.Trim();
if (!All.Contains(code))
{
- throw new ArgumentException("地址类型不合法,仅支持 sender/return/receiver");
+ throw new ArgumentException("地址类型不合法,仅支持 sender/return/pickup/receiver");
}
return All.First(x => string.Equals(x, code, StringComparison.OrdinalIgnoreCase));
@@ -31,10 +40,19 @@ public static class CustomerAddressTypeCodes
{
return addressType?.Trim().ToLowerInvariant() switch
{
- Sender => "发件",
- Return => "退件",
- Receiver => "收件",
+ Sender => "国内发件",
+ Return => "国内退件",
+ Pickup => "国内揽收",
+ Receiver => "海外收件",
_ => addressType ?? string.Empty
};
}
+
+ /// 是否可作为揽收单客户地址(国内揽收;兼容历史发件地址)。
+ public static bool IsPickupEligible(string? addressType)
+ {
+ var code = string.IsNullOrWhiteSpace(addressType) ? Sender : addressType.Trim();
+ return string.Equals(code, Pickup, StringComparison.OrdinalIgnoreCase)
+ || string.Equals(code, Sender, StringComparison.OrdinalIgnoreCase);
+ }
}
diff --git a/src/Oms.Domain/OrdersAggregate/Consts/PickupDirectionCodes.cs b/src/Oms.Domain/OrdersAggregate/Consts/PickupDirectionCodes.cs
new file mode 100644
index 0000000..530255d
--- /dev/null
+++ b/src/Oms.Domain/OrdersAggregate/Consts/PickupDirectionCodes.cs
@@ -0,0 +1,39 @@
+namespace Oms.Domain.OrdersAggregate.Consts;
+
+///
+/// 揽收方向:正向(客户地址→仓库)/ 逆向(仓库→客户地址)。
+///
+public static class PickupDirectionCodes
+{
+ /// 正向:客户揽收地址 → 仓库
+ public const string Forward = "forward";
+
+ /// 逆向:仓库 → 客户揽收地址
+ public const string Reverse = "reverse";
+
+ public static readonly HashSet All = new(StringComparer.OrdinalIgnoreCase)
+ {
+ Forward,
+ Reverse
+ };
+
+ public static string NormalizeOrDefault(string? direction)
+ {
+ var code = string.IsNullOrWhiteSpace(direction) ? Forward : direction.Trim();
+ if (!All.Contains(code))
+ {
+ return Forward;
+ }
+
+ return All.First(x => string.Equals(x, code, StringComparison.OrdinalIgnoreCase));
+ }
+
+ public static string GetDisplayName(string? direction)
+ {
+ return NormalizeOrDefault(direction) switch
+ {
+ Reverse => "逆向",
+ _ => "正向"
+ };
+ }
+}
diff --git a/src/Oms.Domain/OrdersAggregate/Entities/PickupOrder.cs b/src/Oms.Domain/OrdersAggregate/Entities/PickupOrder.cs
index f758144..b8de6ce 100644
--- a/src/Oms.Domain/OrdersAggregate/Entities/PickupOrder.cs
+++ b/src/Oms.Domain/OrdersAggregate/Entities/PickupOrder.cs
@@ -24,6 +24,12 @@ public class PickupOrder : OmsAuditedAggregateRoot
public int SenderAddressId { get; set; }
+ ///
+ /// 揽收方向:forward 正向(客户→仓)/ reverse 逆向(仓→客户)。
+ ///
+ [SugarColumn(Length = 16)]
+ public string Direction { get; set; } = "forward";
+
[SugarColumn(Length = 50)]
public string SenderName { get; set; } = string.Empty;