diff --git a/db.sql b/db.sql
index 7655c82..c3e4e3f 100644
--- a/db.sql
+++ b/db.sql
@@ -57,6 +57,7 @@ DROP TABLE IF EXISTS `t_system_other_config`;
DROP TABLE IF EXISTS `t_warehouse_address`;
DROP TABLE IF EXISTS `t_notice_read`;
DROP TABLE IF EXISTS `t_notice`;
+DROP TABLE IF EXISTS `t_employee`;
DROP TABLE IF EXISTS `t_dict_type`;
DROP TABLE IF EXISTS `t_dict`;
DROP TABLE IF EXISTS `t_country`;
@@ -1106,6 +1107,44 @@ CREATE TABLE `t_notice` (
KEY `idx_notice_title` (`Title`)
) COMMENT='公告通知表';
+CREATE TABLE `t_employee` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
+ `UserId` CHAR(36) NOT NULL COMMENT '关联 RBAC user.Id(工号/手机/邮箱见 user 表)',
+ `RealName` VARCHAR(64) NOT NULL COMMENT '姓名(人事档案用)',
+ `Gender` TINYINT NOT NULL DEFAULT 0 COMMENT 'Gender:0=Unknown未知,1=Male男,2=Female女',
+ `Birthday` DATE NULL COMMENT '出生日期',
+ `IdCardNo` VARCHAR(32) NULL COMMENT '身份证号',
+ `HireDate` DATE NULL COMMENT '入职日期',
+ `ProbationEndDate` DATE NULL COMMENT '试用期结束日期',
+ `RegularizationDate` DATE NULL COMMENT '转正日期',
+ `EmploymentStatus` TINYINT NOT NULL DEFAULT 1 COMMENT 'EmploymentStatus:0=None,1=Probation试用,2=Regular正式,3=Suspended停职,4=Resigned离职',
+ `ResignationDate` DATE NULL COMMENT '离职日期',
+ `Department` VARCHAR(128) NULL COMMENT '部门',
+ `Position` VARCHAR(128) NULL COMMENT '岗位/职位',
+ `JobLevel` VARCHAR(64) NULL COMMENT '职级',
+ `EmploymentType` TINYINT NOT NULL DEFAULT 1 COMMENT 'EmploymentType:0=None,1=FullTime全职,2=PartTime兼职,3=Intern实习,4=Outsourced外包',
+ `WorkLocation` VARCHAR(128) NULL COMMENT '工作地点',
+ `ManagerUserId` CHAR(36) NULL COMMENT '直属上级 user.Id',
+ `ContractStartDate` DATE NULL COMMENT '合同开始日期',
+ `ContractEndDate` DATE NULL COMMENT '合同结束日期',
+ `ContractType` VARCHAR(64) NULL COMMENT '合同类型',
+ `EmergencyContact` VARCHAR(64) NULL COMMENT '紧急联系人',
+ `EmergencyPhone` VARCHAR(32) NULL COMMENT '紧急联系人电话',
+ `Address` VARCHAR(256) NULL COMMENT '住址',
+ `Education` VARCHAR(64) NULL COMMENT '学历',
+ `Remark` VARCHAR(512) NULL COMMENT '备注',
+ `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
+ `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) 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_employee_user` (`UserId`),
+ KEY `idx_employee_status_dept` (`EmploymentStatus`, `Department`),
+ KEY `idx_employee_manager` (`ManagerUserId`)
+) COMMENT='员工档案表(关联内部用户)';
+
CREATE TABLE `t_notice_read` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
`NoticeId` INT NOT NULL COMMENT '通知ID',
diff --git a/scripts/t_employee.sql b/scripts/t_employee.sql
new file mode 100644
index 0000000..5386883
--- /dev/null
+++ b/scripts/t_employee.sql
@@ -0,0 +1,46 @@
+-- 员工档案表(已有库增量执行)
+-- 关联 RBAC user.Id;工号/手机/邮箱以 user 表为准,本表不重复
+
+SET FOREIGN_KEY_CHECKS = 0;
+
+DROP TABLE IF EXISTS `t_employee`;
+
+CREATE TABLE `t_employee` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
+ `UserId` CHAR(36) NOT NULL COMMENT '关联 RBAC user.Id(工号/手机/邮箱见 user 表)',
+ `RealName` VARCHAR(64) NOT NULL COMMENT '姓名(人事档案用)',
+ `Gender` TINYINT NOT NULL DEFAULT 0 COMMENT 'Gender:0=Unknown未知,1=Male男,2=Female女',
+ `Birthday` DATE NULL COMMENT '出生日期',
+ `IdCardNo` VARCHAR(32) NULL COMMENT '身份证号',
+ `HireDate` DATE NULL COMMENT '入职日期',
+ `ProbationEndDate` DATE NULL COMMENT '试用期结束日期',
+ `RegularizationDate` DATE NULL COMMENT '转正日期',
+ `EmploymentStatus` TINYINT NOT NULL DEFAULT 1 COMMENT 'EmploymentStatus:0=None,1=Probation试用,2=Regular正式,3=Suspended停职,4=Resigned离职',
+ `ResignationDate` DATE NULL COMMENT '离职日期',
+ `Department` VARCHAR(128) NULL COMMENT '部门',
+ `Position` VARCHAR(128) NULL COMMENT '岗位/职位',
+ `JobLevel` VARCHAR(64) NULL COMMENT '职级',
+ `EmploymentType` TINYINT NOT NULL DEFAULT 1 COMMENT 'EmploymentType:0=None,1=FullTime全职,2=PartTime兼职,3=Intern实习,4=Outsourced外包',
+ `WorkLocation` VARCHAR(128) NULL COMMENT '工作地点',
+ `ManagerUserId` CHAR(36) NULL COMMENT '直属上级 user.Id',
+ `ContractStartDate` DATE NULL COMMENT '合同开始日期',
+ `ContractEndDate` DATE NULL COMMENT '合同结束日期',
+ `ContractType` VARCHAR(64) NULL COMMENT '合同类型',
+ `EmergencyContact` VARCHAR(64) NULL COMMENT '紧急联系人',
+ `EmergencyPhone` VARCHAR(32) NULL COMMENT '紧急联系人电话',
+ `Address` VARCHAR(256) NULL COMMENT '住址',
+ `Education` VARCHAR(64) NULL COMMENT '学历',
+ `Remark` VARCHAR(512) NULL COMMENT '备注',
+ `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
+ `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) 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_employee_user` (`UserId`),
+ KEY `idx_employee_status_dept` (`EmploymentStatus`, `Department`),
+ KEY `idx_employee_manager` (`ManagerUserId`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工档案表(关联内部用户)';
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/sql/C_parcel_arrival.sql b/sql/C_parcel_arrival.sql
deleted file mode 100644
index a891d1a..0000000
--- a/sql/C_parcel_arrival.sql
+++ /dev/null
@@ -1,20 +0,0 @@
--- 已有库增量:快递到仓表 c_parcel_arrival
--- 对应功能:操作 → 快递到仓;全量结构见根目录 db.sql
--- 可重复执行(IF NOT EXISTS)
-
-CREATE TABLE IF NOT EXISTS `c_parcel_arrival` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
- `CustomerId` INT NOT NULL COMMENT '客户ID',
- `WarehouseId` INT NOT NULL COMMENT '仓库ID',
- `ParcelId` INT NULL COMMENT '关联包裹 c_parcel.Id',
- `TrackingNo` VARCHAR(64) NOT NULL COMMENT '国内快递单号',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) 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_c_parcel_arrival_tracking` (`CustomerId`, `TrackingNo`, `WarehouseId`),
- KEY `idx_c_parcel_arrival_ctime` (`CreateTime`)
-) COMMENT='仓储-快递到仓记录';
diff --git a/sql/C_parcel_item_AttributeText.sql b/sql/C_parcel_item_AttributeText.sql
deleted file mode 100644
index 47dbc1a..0000000
--- a/sql/C_parcel_item_AttributeText.sql
+++ /dev/null
@@ -1,16 +0,0 @@
--- 已有库增量:c_parcel_item.AttributeText
--- 可重复执行
-
-SET @col_exists := (
- SELECT COUNT(1)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 'c_parcel_item'
- AND COLUMN_NAME = 'AttributeText'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `c_parcel_item` ADD COLUMN `AttributeText` VARCHAR(256) NULL COMMENT ''规格属性'' AFTER `ProductName`',
- 'SELECT ''c_parcel_item.AttributeText already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
diff --git a/sql/C_parcel_item_ImageUrl.sql b/sql/C_parcel_item_ImageUrl.sql
deleted file mode 100644
index c9dd548..0000000
--- a/sql/C_parcel_item_ImageUrl.sql
+++ /dev/null
@@ -1,16 +0,0 @@
--- 已有库增量:c_parcel_item.ImageUrl
--- 可重复执行
-
-SET @col_exists := (
- SELECT COUNT(1)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 'c_parcel_item'
- AND COLUMN_NAME = 'ImageUrl'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `c_parcel_item` ADD COLUMN `ImageUrl` VARCHAR(1024) NULL COMMENT ''商品图片URL'' AFTER `AttributeText`',
- 'SELECT ''c_parcel_item.ImageUrl already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
diff --git a/sql/fix_concurrency_stamp_missing.sql b/sql/fix_concurrency_stamp_missing.sql
deleted file mode 100644
index 4faee18..0000000
--- a/sql/fix_concurrency_stamp_missing.sql
+++ /dev/null
@@ -1,63 +0,0 @@
--- 给缺少 ConcurrencyStamp 的 OMS 表补列(可重复执行)
--- Fake AggregateRoot 自带该字段,SqlSugar 查询会带上;库表没有就会报:
--- Unknown column 'ConcurrencyStamp' in 'field list'
---
--- 注意:不要用 DEFAULT (UUID())。在 STATEMENT/MIXED 复制下会触发:
--- 1674 Statement is unsafe because it uses a system function that may return a different value on the replica.
--- 默认用固定 GUID;插入/更新时由 ORM 写入真实 UUID。
---
--- 用法:在业务库执行本脚本;若仍报错,把报错 SQL 里的表名追加到下方列表。
-
-SET @tables := 't_order_stock_bind,c_inventory,c_parcel,c_parcel_item,c_parcel_arrival,c_sku,c_bin_location,c_inbound_notice,c_inbound_box,c_inbound_box_line,c_sku_platform_map,t_sales_store,t_sales_store_order,t_sales_store_order_line,t_customer_sender_address';
-
-DROP PROCEDURE IF EXISTS sp_add_concurrency_stamp_if_missing;
-DELIMITER $$
-CREATE PROCEDURE sp_add_concurrency_stamp_if_missing()
-BEGIN
- DECLARE done INT DEFAULT 0;
- DECLARE tname VARCHAR(128);
- DECLARE cur CURSOR FOR
- SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(@tables, ',', n.n), ',', -1)) AS t
- FROM (
- SELECT a.N + b.N * 10 + 1 AS n
- FROM
- (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a,
- (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b
- ) n
- WHERE n.n <= 1 + (LENGTH(@tables) - LENGTH(REPLACE(@tables, ',', '')));
- DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-
- OPEN cur;
- read_loop: LOOP
- FETCH cur INTO tname;
- IF done THEN
- LEAVE read_loop;
- END IF;
- IF tname IS NULL OR tname = '' THEN
- ITERATE read_loop;
- END IF;
- IF NOT EXISTS (
- SELECT 1 FROM information_schema.TABLES
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = tname
- ) THEN
- ITERATE read_loop;
- END IF;
- IF NOT EXISTS (
- SELECT 1 FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = tname AND COLUMN_NAME = 'ConcurrencyStamp'
- ) THEN
- SET @ddl := CONCAT(
- 'ALTER TABLE `', tname,
- '` ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT ''00000000-0000-0000-0000-000000000000'' COMMENT ''并发戳'''
- );
- PREPARE stmt FROM @ddl;
- EXECUTE stmt;
- DEALLOCATE PREPARE stmt;
- END IF;
- END LOOP;
- CLOSE cur;
-END$$
-DELIMITER ;
-
-CALL sp_add_concurrency_stamp_if_missing();
-DROP PROCEDURE IF EXISTS sp_add_concurrency_stamp_if_missing;
diff --git a/sql/fix_sales_store_concurrency_stamp.sql b/sql/fix_sales_store_concurrency_stamp.sql
deleted file mode 100644
index f8b503b..0000000
--- a/sql/fix_sales_store_concurrency_stamp.sql
+++ /dev/null
@@ -1,41 +0,0 @@
--- 修复店铺相关表 ConcurrencyStamp 无法绑定到 Guid 的问题
--- 典型报错:ConcurrencyStamp绑定到SalesStoreOrder失败 / SalesStoreOrder ConcurrencyStamp bind error
---
--- 原因:补列时若写入空串 '',SqlSugar 无法把 '' 转成 System.Guid
--- 用法:mysql -u root -p oms < sql/fix_sales_store_concurrency_stamp.sql
-
-SET NAMES utf8mb4;
-
-UPDATE `t_sales_store`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL
- OR TRIM(`ConcurrencyStamp`) = ''
- OR LENGTH(TRIM(`ConcurrencyStamp`)) <> 36;
-
-UPDATE `t_sales_store_order`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL
- OR TRIM(`ConcurrencyStamp`) = ''
- OR LENGTH(TRIM(`ConcurrencyStamp`)) <> 36;
-
-UPDATE `t_sales_store_order_line`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL
- OR TRIM(`ConcurrencyStamp`) = ''
- OR LENGTH(TRIM(`ConcurrencyStamp`)) <> 36;
-
--- 抽查
-SELECT 't_sales_store' AS tbl,
- SUM(CASE WHEN TRIM(IFNULL(ConcurrencyStamp,'')) = '' OR LENGTH(TRIM(ConcurrencyStamp)) <> 36 THEN 1 ELSE 0 END) AS bad_cnt,
- COUNT(*) AS total
-FROM `t_sales_store`
-UNION ALL
-SELECT 't_sales_store_order',
- SUM(CASE WHEN TRIM(IFNULL(ConcurrencyStamp,'')) = '' OR LENGTH(TRIM(ConcurrencyStamp)) <> 36 THEN 1 ELSE 0 END),
- COUNT(*)
-FROM `t_sales_store_order`
-UNION ALL
-SELECT 't_sales_store_order_line',
- SUM(CASE WHEN TRIM(IFNULL(ConcurrencyStamp,'')) = '' OR LENGTH(TRIM(ConcurrencyStamp)) <> 36 THEN 1 ELSE 0 END),
- COUNT(*)
-FROM `t_sales_store_order_line`;
diff --git a/sql/migrate_drop_order_task_merge_batch.sql b/sql/migrate_drop_order_task_merge_batch.sql
deleted file mode 100644
index 722cd2f..0000000
--- a/sql/migrate_drop_order_task_merge_batch.sql
+++ /dev/null
@@ -1,6 +0,0 @@
--- 合并下单任务表到批量任务:删除 t_order_task / t_order_task_fail
--- 历史导入任务数据不再保留;Excel 导入统一走 t_order_batch_job(action=import-row)
--- 2026-07-22:触发重新发布,确保 API 不再访问已删表
-
-DROP TABLE IF EXISTS `t_order_task_fail`;
-DROP TABLE IF EXISTS `t_order_task`;
diff --git a/sql/migrate_enum_int_comments.sql b/sql/migrate_enum_int_comments.sql
deleted file mode 100644
index 46c68c5..0000000
--- a/sql/migrate_enum_int_comments.sql
+++ /dev/null
@@ -1,74 +0,0 @@
--- 已有库增量:字节枚举字段注释统一 + 发布记录 Status 改 TINYINT + 旧 0 起编码迁移
--- 对应 C# 枚举:EnableStatus / CustomerStatus / CustomerGroup / RechargeStatus / PayType / EsSnapshotStatus
--- 约定:0=None 未设置;业务值从 1 起。执行前请备份。
-
--- ---------- 1. 发布记录 Status:VARCHAR(中文) -> TINYINT(EsSnapshotStatus) ----------
-ALTER TABLE `t_sales_product_publish_record`
- ADD COLUMN `StatusInt` TINYINT NOT NULL DEFAULT 1 COMMENT 'EsSnapshotStatus:0=None,1=Active生效,2=Inactive失效' AFTER `OperatorType`;
-
-UPDATE `t_sales_product_publish_record`
-SET `StatusInt` = CASE
- WHEN TRIM(`Status`) IN ('生效', 'active', 'Active', '1') THEN 1
- WHEN TRIM(`Status`) IN ('失效', '无效', 'inactive', 'Inactive', '2') THEN 2
- ELSE 1
-END;
-
-ALTER TABLE `t_sales_product_publish_record`
- DROP COLUMN `Status`,
- CHANGE COLUMN `StatusInt` `Status` TINYINT NOT NULL DEFAULT 1 COMMENT 'EsSnapshotStatus:0=None未设置,1=Active生效,2=Inactive失效';
-
-ALTER TABLE `t_service_channel_publish_record`
- ADD COLUMN `StatusInt` TINYINT NOT NULL DEFAULT 1 COMMENT 'EsSnapshotStatus:0=None,1=Active生效,2=Inactive失效' AFTER `OperatorType`;
-
-UPDATE `t_service_channel_publish_record`
-SET `StatusInt` = CASE
- WHEN TRIM(`Status`) IN ('生效', 'active', 'Active', '1') THEN 1
- WHEN TRIM(`Status`) IN ('失效', '无效', 'inactive', 'Inactive', '2') THEN 2
- ELSE 1
-END;
-
-ALTER TABLE `t_service_channel_publish_record`
- DROP COLUMN `Status`,
- CHANGE COLUMN `StatusInt` `Status` TINYINT NOT NULL DEFAULT 1 COMMENT 'EsSnapshotStatus:0=None未设置,1=Active生效,2=Inactive失效';
-
--- ---------- 2. 旧 0 起编码 -> 1 起(若已迁移可跳过对应 UPDATE) ----------
-UPDATE `t_customer` SET `Status` = `Status` + 1 WHERE `Status` BETWEEN 0 AND 2;
-UPDATE `t_customer` SET `CustomerGroup` = `CustomerGroup` + 1 WHERE `CustomerGroup` BETWEEN 0 AND 5;
-UPDATE `t_recharge_record` SET `RechargeStatus` = `RechargeStatus` + 1 WHERE `RechargeStatus` BETWEEN 0 AND 2;
-
-UPDATE `t_sales_product` SET `IsActive` = CASE `IsActive` WHEN 0 THEN 1 WHEN 1 THEN 2 ELSE `IsActive` END WHERE `IsActive` IN (0, 1);
-UPDATE `t_service_channel` SET `IsActive` = CASE `IsActive` WHEN 0 THEN 1 WHEN 1 THEN 2 ELSE `IsActive` END WHERE `IsActive` IN (0, 1);
-UPDATE `t_sales_product_price` SET `Status` = CASE `Status` WHEN 0 THEN 1 WHEN 1 THEN 2 ELSE `Status` END WHERE `Status` IN (0, 1);
-UPDATE `t_service_channel_price` SET `Status` = CASE `Status` WHEN 0 THEN 1 WHEN 1 THEN 2 ELSE `Status` END WHERE `Status` IN (0, 1);
-UPDATE `t_auto_trigger` SET `Status` = CASE `Status` WHEN 0 THEN 1 WHEN 1 THEN 2 ELSE `Status` END WHERE `Status` IN (0, 1);
-UPDATE `t_issue_template` SET `Status` = CASE `Status` WHEN 0 THEN 1 WHEN 1 THEN 2 ELSE `Status` END WHERE `Status` IN (0, 1);
-
--- ---------- 3. 字段注释(可重复执行 MODIFY) ----------
-ALTER TABLE `t_customer`
- MODIFY COLUMN `Status` TINYINT NOT NULL DEFAULT 2 COMMENT 'CustomerStatus:0=None未设置,1=Disabled禁用,2=Normal正常,3=Frozen冻结',
- MODIFY COLUMN `CustomerGroup` TINYINT NULL COMMENT 'CustomerGroup:0=None未设置,1=Normal普通,2=Vip1…6=Vip5';
-
-ALTER TABLE `t_recharge_record`
- MODIFY COLUMN `PayType` TINYINT NOT NULL COMMENT 'PayType:0=None未设置,1=Wechat微信,2=Alipay支付宝',
- MODIFY COLUMN `RechargeStatus` TINYINT NOT NULL DEFAULT 1 COMMENT 'RechargeStatus:0=None未设置,1=Pending待审核,2=Approved通过,3=Rejected驳回';
-
-ALTER TABLE `t_sales_product`
- MODIFY COLUMN `IsActive` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None未设置,1=Disabled禁用,2=Enabled启用';
-
-ALTER TABLE `t_service_channel`
- MODIFY COLUMN `IsActive` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None未设置,1=Disabled禁用,2=Enabled启用';
-
-ALTER TABLE `t_sales_product_price`
- MODIFY COLUMN `Status` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None未设置,1=Disabled禁用,2=Enabled启用';
-
-ALTER TABLE `t_service_channel_price`
- MODIFY COLUMN `Status` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None未设置,1=Disabled禁用,2=Enabled启用';
-
-ALTER TABLE `t_auto_trigger`
- MODIFY COLUMN `Status` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None未设置,1=Disabled禁用,2=Enabled启用';
-
-ALTER TABLE `t_issue_template`
- MODIFY COLUMN `Status` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None未设置,1=Disabled禁用,2=Enabled启用';
-
-ALTER TABLE `t_dict`
- MODIFY COLUMN `DictCode` VARCHAR(64) NOT NULL COMMENT '字典编码:字符串类存语义码;数值类存整数字符串如1/2,与枚举值一致(0=None不入库)';
diff --git a/sql/migrate_label_pdf_fields.sql b/sql/migrate_label_pdf_fields.sql
deleted file mode 100644
index c7f736a..0000000
--- a/sql/migrate_label_pdf_fields.sql
+++ /dev/null
@@ -1,87 +0,0 @@
--- 已有库增量:订单面单 PDF 字段 + 销售产品 LabelTemplateId
--- 对应:docs/面单标签模板与PDF生成方案.md §4.2 / §4.3
--- 可重复执行
-
--- ========== t_order ==========
-SET @col_exists := (
- SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'LabelUrl'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `LabelUrl` VARCHAR(500) NULL COMMENT ''面单PDF相对路径'' AFTER `IsRemote`',
- 'SELECT ''t_order.LabelUrl already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @col_exists := (
- SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'LabelTemplateId'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `LabelTemplateId` INT NULL COMMENT ''面单模板Id'' AFTER `LabelUrl`',
- 'SELECT ''t_order.LabelTemplateId already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @col_exists := (
- SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'LabelGenerateStatus'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `LabelGenerateStatus` VARCHAR(32) NULL COMMENT ''Pending/Ready/Failed'' AFTER `LabelTemplateId`',
- 'SELECT ''t_order.LabelGenerateStatus already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @col_exists := (
- SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'LabelGenerateError'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `LabelGenerateError` VARCHAR(500) NULL COMMENT ''面单生成失败原因'' AFTER `LabelGenerateStatus`',
- 'SELECT ''t_order.LabelGenerateError already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @idx_exists := (
- SELECT COUNT(1) FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order' AND INDEX_NAME = 'idx_ord_label_status'
-);
-SET @sql := IF(
- @idx_exists = 0,
- 'ALTER TABLE `t_order` ADD KEY `idx_ord_label_status` (`LabelGenerateStatus`)',
- 'SELECT ''idx_ord_label_status already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ========== t_sales_product ==========
-SET @col_exists := (
- SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_sales_product' AND COLUMN_NAME = 'LabelTemplateId'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_sales_product` ADD COLUMN `LabelTemplateId` INT NULL COMMENT ''客户面单模板Id'' AFTER `CustomerWaybill`',
- 'SELECT ''t_sales_product.LabelTemplateId already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ========== 全局默认模板配置种子(AppKey 填模板 Id,Enabled=0 默认关闭)==========
-INSERT INTO `t_system_other_config`
- (`ConfigCode`, `ConfigName`, `Enabled`, `AppKey`, `TimeoutSeconds`, `Remark`, `CreateTime`)
-SELECT
- 'label_default_template',
- '全局默认面单模板',
- 0,
- NULL,
- 30,
- 'AppKey=标签模板Id;启用后产品未绑模板时回落此 Id',
- NOW()
-FROM DUAL
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_system_other_config` WHERE `ConfigCode` = 'label_default_template'
-);
diff --git a/sql/migrate_marketing_module.sql b/sql/migrate_marketing_module.sql
deleted file mode 100644
index 52f6f97..0000000
--- a/sql/migrate_marketing_module.sql
+++ /dev/null
@@ -1,336 +0,0 @@
--- 客户营销模块:裂变 / 会员等级 / 优惠券 / 推荐分成
--- 前置约定(见 docs/客户裂变与营销体系设计方案.md §2、§24):
--- 1. 子账号不参与营销,一律归主客户
--- 2. MemberLevel 替换 CustomerGroup
--- 3. CommissionBalance 独立字段,可提现或转余额
--- 4. 默认分成:实付每 1000 元 → 2 元(0.2%)
--- 表结构遵循 docs/oms系统设计-050801.md §3.1.2(ConcurrencyStamp 固定默认值,禁止 UUID())
-
--- ---------------------------------------------------------------------------
--- 1. t_customer 扩展
--- ---------------------------------------------------------------------------
-SET @col_exists := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_customer' AND COLUMN_NAME = 'ReferrerCustomerId'
-);
-SET @sql := IF(@col_exists = 0,
- 'ALTER TABLE `t_customer`
- ADD COLUMN `ReferrerCustomerId` INT NULL COMMENT ''引荐人主客户Id → t_customer.Id'' AFTER `ParentCustomerId`,
- ADD COLUMN `ReferralBindTime` DATETIME NULL COMMENT ''引荐绑定时间'' AFTER `ReferrerCustomerId`,
- ADD COLUMN `ReferralChannel` VARCHAR(32) NULL COMMENT ''引荐渠道 link/qrcode/manual'' AFTER `ReferralBindTime`,
- ADD COLUMN `MemberLevelId` INT NULL COMMENT ''会员等级Id → t_member_level.Id'' AFTER `CustomerGroup`,
- ADD COLUMN `CommissionBalance` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT ''可提现佣金余额'' AFTER `Balance`,
- ADD KEY `idx_cus_referrer` (`ReferrerCustomerId`),
- ADD KEY `idx_cus_member_level` (`MemberLevelId`)',
- 'SELECT 1');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ---------------------------------------------------------------------------
--- 2. 引荐码
--- ---------------------------------------------------------------------------
-CREATE TABLE IF NOT EXISTS `t_customer_referral_code` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
- `CustomerId` INT NOT NULL COMMENT '主客户Id → t_customer.Id',
- `InviteCode` VARCHAR(16) NOT NULL COMMENT '邀请短码,全局唯一',
- `Status` TINYINT NOT NULL DEFAULT 1 COMMENT 'ReferralCodeStatus:0=Disabled,1=Enabled',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`),
- UNIQUE KEY `uk_referral_invite_code` (`InviteCode`),
- UNIQUE KEY `uk_referral_customer` (`CustomerId`)
-) COMMENT='客户引荐码(主客户)';
-
--- ---------------------------------------------------------------------------
--- 3. 会员等级
--- ---------------------------------------------------------------------------
-CREATE TABLE IF NOT EXISTS `t_member_level` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
- `LevelCode` VARCHAR(32) NOT NULL COMMENT '等级编码,唯一',
- `LevelName` VARCHAR(64) NOT NULL COMMENT '等级名称',
- `MinPoints` INT NOT NULL DEFAULT 0 COMMENT '升级所需累计积分',
- `PriceTierKey` VARCHAR(32) NOT NULL COMMENT '价区键,对应卖价 CustomerGroupValues JSON 键',
- `ExtraDiscountRate` DECIMAL(8,4) NOT NULL DEFAULT 0.0000 COMMENT '额外折扣率,如 0.03=97折',
- `Sort` INT NOT NULL DEFAULT 0 COMMENT '排序,越小越低',
- `IconUrl` VARCHAR(255) NULL COMMENT '等级图标',
- `BenefitDesc` VARCHAR(512) NULL COMMENT '权益说明',
- `Status` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None,1=Disabled,2=Enabled',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`),
- UNIQUE KEY `uk_member_level_code` (`LevelCode`),
- KEY `idx_member_level_sort` (`Sort`, `Status`)
-) COMMENT='会员等级配置';
-
-CREATE TABLE IF NOT EXISTS `t_customer_points_account` (
- `Id` INT NOT NULL AUTO_INCREMENT,
- `CustomerId` INT NOT NULL COMMENT '主客户Id',
- `TotalPoints` INT NOT NULL DEFAULT 0 COMMENT '累计积分(含已消耗,用于定级)',
- `AvailablePoints` INT NOT NULL DEFAULT 0 COMMENT '可用积分',
- `Version` INT NOT NULL DEFAULT 0 COMMENT '乐观锁',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`),
- UNIQUE KEY `uk_points_customer` (`CustomerId`)
-) COMMENT='客户积分账户(主客户)';
-
-CREATE TABLE IF NOT EXISTS `t_customer_points_flow` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
- `CustomerId` INT NOT NULL COMMENT '主客户Id',
- `ChangeType` TINYINT NOT NULL COMMENT 'PointsChangeType:1=Earn,2=Consume,3=Adjust,4=RefundClawback',
- `Points` INT NOT NULL COMMENT '变动积分,正增负减',
- `BizType` VARCHAR(32) NOT NULL COMMENT 'orderPay/refund/adminAdjust 等',
- `BizId` INT NULL,
- `BizNo` VARCHAR(64) NULL,
- `Remark` VARCHAR(512) NULL,
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' 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_points_flow_customer_time` (`CustomerId`, `CreateTime`),
- KEY `idx_points_flow_biz` (`BizType`, `BizId`)
-) COMMENT='积分流水';
-
-CREATE TABLE IF NOT EXISTS `t_member_points_rule` (
- `Id` INT NOT NULL AUTO_INCREMENT,
- `RuleName` VARCHAR(64) NOT NULL COMMENT '规则名称',
- `PointsPerYuan` DECIMAL(10,4) NOT NULL DEFAULT 1.0000 COMMENT '实付每1元得积分',
- `FirstOrderMultiplier` DECIMAL(6,2) NOT NULL DEFAULT 1.00 COMMENT '首单积分倍数',
- `MaxPointsPerOrder` INT NOT NULL DEFAULT 10000 COMMENT '单笔积分上限',
- `Status` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None,1=Disabled,2=Enabled',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`)
-) COMMENT='积分获取规则(全局单条有效)';
-
--- ---------------------------------------------------------------------------
--- 4. 优惠券
--- ---------------------------------------------------------------------------
-CREATE TABLE IF NOT EXISTS `t_coupon_template` (
- `Id` INT NOT NULL AUTO_INCREMENT,
- `TemplateCode` VARCHAR(32) NOT NULL COMMENT '券模板编码',
- `TemplateName` VARCHAR(128) NOT NULL COMMENT '券名称',
- `CouponType` VARCHAR(32) NOT NULL COMMENT 'fixed_off/percent_off/direct_off/shipping_off',
- `FaceValue` DECIMAL(18,2) NULL COMMENT '面额(满减/立减)',
- `DiscountRate` DECIMAL(8,4) NULL COMMENT '折扣率,如0.95',
- `MaxDiscountAmount` DECIMAL(18,2) NULL COMMENT '折扣券封顶',
- `MinOrderAmount` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '使用门槛',
- `TotalQuantity` INT NOT NULL DEFAULT 0 COMMENT '发放总量,0=不限',
- `IssuedQuantity` INT NOT NULL DEFAULT 0 COMMENT '已发放数量',
- `PerCustomerLimit` INT NOT NULL DEFAULT 1 COMMENT '每客户领取上限',
- `ValidType` TINYINT NOT NULL DEFAULT 1 COMMENT '1=固定日期,2=领取后N天',
- `ValidStartTime` DATETIME NULL,
- `ValidEndTime` DATETIME NULL,
- `ValidDaysAfterReceive` INT NULL COMMENT '领取后有效天数',
- `ApplyScopeJson` JSON NULL COMMENT '适用产品/国家等 JSON',
- `GrantChannel` VARCHAR(32) NOT NULL DEFAULT 'manual' COMMENT 'manual/register/referral/level/activity',
- `Status` TINYINT NOT NULL DEFAULT 1 COMMENT 'CouponTemplateStatus:0=Draft,1=Active,2=Ended',
- `Remark` VARCHAR(512) NULL,
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`),
- UNIQUE KEY `uk_coupon_template_code` (`TemplateCode`),
- KEY `idx_coupon_template_status` (`Status`, `ValidEndTime`)
-) COMMENT='优惠券模板';
-
-CREATE TABLE IF NOT EXISTS `t_coupon_instance` (
- `Id` INT NOT NULL AUTO_INCREMENT,
- `TemplateId` INT NOT NULL COMMENT '→ t_coupon_template.Id',
- `CustomerId` INT NOT NULL COMMENT '主客户Id',
- `CouponCode` VARCHAR(32) NOT NULL COMMENT '券实例码',
- `Status` TINYINT NOT NULL DEFAULT 1 COMMENT 'CouponInstanceStatus:1=Available,2=Locked,3=Used,4=Expired',
- `ReceiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `ValidStartTime` DATETIME NOT NULL,
- `ValidEndTime` DATETIME NOT NULL,
- `UseTime` DATETIME NULL,
- `OrderId` INT NULL COMMENT '核销订单Id',
- `LockExpireTime` DATETIME NULL COMMENT '下单预占过期',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`),
- UNIQUE KEY `uk_coupon_instance_code` (`CouponCode`),
- KEY `idx_coupon_instance_customer_status` (`CustomerId`, `Status`),
- KEY `idx_coupon_instance_order` (`OrderId`)
-) COMMENT='客户优惠券实例';
-
--- ---------------------------------------------------------------------------
--- 5. 推荐分成
--- ---------------------------------------------------------------------------
-CREATE TABLE IF NOT EXISTS `t_referral_commission_rule` (
- `Id` INT NOT NULL AUTO_INCREMENT,
- `RuleName` VARCHAR(64) NOT NULL DEFAULT '默认分成规则',
- `CommissionMode` VARCHAR(32) NOT NULL DEFAULT 'per_amount' COMMENT 'per_amount=每满X元得Y元',
- `BaseAmount` DECIMAL(18,2) NOT NULL DEFAULT 1000.00 COMMENT '基数金额',
- `CommissionAmount` DECIMAL(18,2) NOT NULL DEFAULT 2.00 COMMENT '每基数分成金额',
- `FreezeDays` INT NOT NULL DEFAULT 7 COMMENT '派送成功后的结算冻结天数',
- `SettleTriggerOrderStatus` VARCHAR(32) NOT NULL DEFAULT 'deliverySuccess' COMMENT '允许结算的订单状态,固定 deliverySuccess',
- `MonthlyCap` DECIMAL(18,2) NULL COMMENT '引荐人单月分成封顶,NULL=不限',
- `Status` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None,1=Disabled,2=Enabled',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`)
-) COMMENT='引荐分成规则';
-
-CREATE TABLE IF NOT EXISTS `t_referral_commission_detail` (
- `Id` INT NOT NULL AUTO_INCREMENT,
- `ReferrerCustomerId` INT NOT NULL COMMENT '引荐人主客户Id',
- `RefereeCustomerId` INT NOT NULL COMMENT '被引荐主客户Id',
- `OrderId` INT NOT NULL COMMENT '订单Id',
- `OrderNo` VARCHAR(64) NOT NULL COMMENT '运单号快照',
- `BasePayableAmount` DECIMAL(18,2) NOT NULL COMMENT '分成基数(实付)',
- `CommissionAmount` DECIMAL(18,2) NOT NULL COMMENT '分成金额',
- `Status` TINYINT NOT NULL DEFAULT 1 COMMENT 'CommissionStatus:1=Pending,2=Settled,3=Cancelled',
- `EligibleTime` DATETIME NULL COMMENT '订单达到派送成功时间,分成计算触发点',
- `SettleTime` DATETIME NULL COMMENT '入账 CommissionBalance 时间',
- `RuleSnapshotJson` JSON NULL COMMENT '分成规则快照:BaseAmount/CommissionAmount/FreezeDays/MonthlyCap 等',
- `CancelReason` VARCHAR(256) NULL,
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`),
- UNIQUE KEY `uk_commission_order_referrer` (`OrderId`, `ReferrerCustomerId`),
- KEY `idx_commission_referrer_status` (`ReferrerCustomerId`, `Status`, `CreateTime`),
- KEY `idx_commission_referee` (`RefereeCustomerId`)
-) COMMENT='引荐分成明细';
-
-CREATE TABLE IF NOT EXISTS `t_commission_withdraw_request` (
- `Id` INT NOT NULL AUTO_INCREMENT,
- `CustomerId` INT NOT NULL COMMENT '主客户Id',
- `SerialNumber` VARCHAR(64) NOT NULL COMMENT '提现单号',
- `Amount` DECIMAL(18,2) NOT NULL COMMENT '申请金额',
- `WithdrawType` TINYINT NOT NULL COMMENT '1=提现到外部,2=转入余额',
- `Status` TINYINT NOT NULL DEFAULT 1 COMMENT 'WithdrawStatus:1=Pending,2=Approved,3=Rejected,4=Paid',
- `Remark` VARCHAR(512) NULL COMMENT '客户备注',
- `AuditRemark` VARCHAR(512) NULL COMMENT '审核备注',
- `AuditBy` VARCHAR(32) NULL,
- `AuditTime` DATETIME NULL,
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL DEFAULT 0,
- `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`),
- UNIQUE KEY `uk_commission_withdraw_serial` (`SerialNumber`),
- KEY `idx_commission_withdraw_customer` (`CustomerId`, `Status`, `CreateTime`)
-) COMMENT='佣金提现/转余额申请';
-
--- ---------------------------------------------------------------------------
--- 5.1 营销审计日志
--- ---------------------------------------------------------------------------
-CREATE TABLE IF NOT EXISTS `t_marketing_audit_log` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
- `Action` VARCHAR(64) NOT NULL COMMENT 'grantCoupon/adjustPoints/rebindReferral 等',
- `OperatorId` INT NOT NULL DEFAULT 0 COMMENT '操作人 mapId',
- `TargetType` VARCHAR(32) NOT NULL COMMENT 'customer/template/order 等',
- `TargetId` INT NULL COMMENT '目标主键',
- `BeforeJson` JSON NULL COMMENT '变更前快照',
- `AfterJson` JSON NULL COMMENT '变更后快照',
- `Remark` VARCHAR(512) NULL COMMENT '原因/备注',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' 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_marketing_audit_action_time` (`Action`, `CreateTime`),
- KEY `idx_marketing_audit_target` (`TargetType`, `TargetId`)
-) COMMENT='营销高危操作审计';
-
--- ---------------------------------------------------------------------------
--- 6. 订单营销快照
--- ---------------------------------------------------------------------------
-SET @col_exists := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'MemberLevelId'
-);
-SET @sql := IF(@col_exists = 0,
- 'ALTER TABLE `t_order`
- ADD COLUMN `MemberLevelId` INT NULL COMMENT ''下单时会员等级快照'' AFTER `CustomerId`,
- ADD COLUMN `PriceTierKey` VARCHAR(32) NULL COMMENT ''下单时价区键快照'' AFTER `MemberLevelId`,
- ADD COLUMN `ReceivableSubtotal` DECIMAL(18,2) NULL COMMENT ''等级价后小计'' AFTER `PriceTierKey`,
- ADD COLUMN `LevelDiscountAmount` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT ''等级额外折扣额'' AFTER `ReceivableSubtotal`,
- ADD COLUMN `CouponInstanceId` INT NULL COMMENT ''核销券实例Id'' AFTER `LevelDiscountAmount`,
- ADD COLUMN `CouponDiscountAmount` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT ''优惠券抵扣额'' AFTER `CouponInstanceId`,
- ADD COLUMN `PayableAmount` DECIMAL(18,2) NULL COMMENT ''应付实付'' AFTER `CouponDiscountAmount`,
- ADD KEY `idx_ord_coupon` (`CouponInstanceId`)',
- 'SELECT 1');
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- ---------------------------------------------------------------------------
--- 7. 种子:默认会员等级(映射原 CustomerGroup 价区)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_member_level`
- (`LevelCode`, `LevelName`, `MinPoints`, `PriceTierKey`, `ExtraDiscountRate`, `Sort`, `BenefitDesc`, `Status`, `CreateUserId`)
-VALUES
- ('normal', '普通会员', 0, '普通客户', 0.0000, 10, '标准运价', 2, 0),
- ('silver', '银卡会员', 5000, 'VIP1', 0.0000, 20, 'VIP1 价区', 2, 0),
- ('gold', '金卡会员', 20000, 'VIP2', 0.0100, 30, 'VIP2 价区 + 额外 1% 折', 2, 0),
- ('diamond', '钻石会员', 100000, 'VIP3', 0.0200, 40, 'VIP3 价区 + 额外 2% 折', 2, 0)
-ON DUPLICATE KEY UPDATE
- `LevelName` = VALUES(`LevelName`),
- `MinPoints` = VALUES(`MinPoints`),
- `PriceTierKey` = VALUES(`PriceTierKey`),
- `ExtraDiscountRate` = VALUES(`ExtraDiscountRate`),
- `Sort` = VALUES(`Sort`),
- `BenefitDesc` = VALUES(`BenefitDesc`);
-
--- 主客户 MemberLevelId 迁移(按原 CustomerGroup)
-UPDATE `t_customer` c
-LEFT JOIN `t_member_level` ml ON (
- (c.CustomerGroup IS NULL OR c.CustomerGroup = 0 OR c.CustomerGroup = 1) AND ml.LevelCode = 'normal'
- OR (c.CustomerGroup = 2 AND ml.LevelCode = 'silver')
- OR (c.CustomerGroup = 3 AND ml.LevelCode = 'gold')
- OR (c.CustomerGroup = 4 AND ml.LevelCode = 'diamond')
- OR (c.CustomerGroup >= 5 AND ml.LevelCode = 'diamond')
-)
-SET c.MemberLevelId = ml.Id
-WHERE c.ParentCustomerId IS NULL AND c.MemberLevelId IS NULL AND ml.Id IS NOT NULL;
-
--- 默认积分规则
-INSERT INTO `t_member_points_rule`
- (`RuleName`, `PointsPerYuan`, `FirstOrderMultiplier`, `MaxPointsPerOrder`, `Status`, `CreateUserId`)
-SELECT '默认积分规则', 1.0000, 1.00, 10000, 2, 0
-FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_member_points_rule` WHERE `IsDeleted` = 0 LIMIT 1);
-
--- 默认分成规则:每 1000 元 → 2 元
-INSERT INTO `t_referral_commission_rule`
- (`RuleName`, `CommissionMode`, `BaseAmount`, `CommissionAmount`, `FreezeDays`, `Status`, `CreateUserId`)
-SELECT '默认分成', 'per_amount', 1000.00, 2.00, 7, 2, 0
-FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_referral_commission_rule` WHERE `IsDeleted` = 0 LIMIT 1);
diff --git a/sql/migrate_order_batch_job_item_client_no.sql b/sql/migrate_order_batch_job_item_client_no.sql
deleted file mode 100644
index 48aa261..0000000
--- a/sql/migrate_order_batch_job_item_client_no.sql
+++ /dev/null
@@ -1,3 +0,0 @@
--- 批量任务明细:增加客户单号字段(Excel 导入/小包创建反馈用)
-ALTER TABLE `t_order_batch_job_item`
- ADD COLUMN `ClientNo` VARCHAR(64) NULL COMMENT '客户单号' AFTER `ServiceNo`;
diff --git a/sql/migrate_order_status_pending_allocation.sql b/sql/migrate_order_status_pending_allocation.sql
deleted file mode 100644
index 6eb6303..0000000
--- a/sql/migrate_order_status_pending_allocation.sql
+++ /dev/null
@@ -1,12 +0,0 @@
--- 订单状态:待排货(入库排货/渠道买价未成功)
--- 可重复执行(INSERT IGNORE)
-
-INSERT IGNORE INTO `t_dict` (`DictType`, `DictSort`, `DictCode`, `DictName`, `CreateUserId`)
-VALUES ('order_status', 35, 'pendingAllocation', '待排货', 0);
-
--- 历史数据:有排货失败原因但状态仍为待支付的订单,修正为待排货
-UPDATE `t_order`
-SET `OrderStatus` = 'pendingAllocation',
- `UpdateTime` = NOW()
-WHERE TRIM(IFNULL(`AllocationPendingReason`, '')) <> ''
- AND `OrderStatus` = 'pendingPayment';
diff --git a/sql/migrate_rename_warehouse_C_to_c.sql b/sql/migrate_rename_warehouse_C_to_c.sql
deleted file mode 100644
index d3a4ad7..0000000
--- a/sql/migrate_rename_warehouse_C_to_c.sql
+++ /dev/null
@@ -1,123 +0,0 @@
--- 仓储表 C_* → c_*(小写 c 前缀)
--- 不依赖 DELIMITER / 存储过程,Navicat、DMS、mysql 命令行均可整段执行
--- 可重复执行
---
--- 说明:
--- 1) 若库已开启 lower_case_table_names(Windows/部分云库),建表时 C_sku 磁盘上已是 c_sku,
--- 无需 RENAME,部署新代码即可;下方「诊断」应只看到 c_*。
--- 2) Linux 且区分大小写时,须经临时表名两步改名,否则可能报 Table 'c_sku' already exists。
--- 3) 执行前请确认已 USE 到业务库(DATABASE() 不能为 NULL)。
-
--- ========== 诊断(先看当前表名)==========
-SELECT TABLE_NAME AS warehouse_table
-FROM information_schema.TABLES
-WHERE TABLE_SCHEMA = DATABASE()
- AND (
- TABLE_NAME LIKE 'C\_%' ESCAPE '\\'
- OR TABLE_NAME LIKE 'c\_%' ESCAPE '\\'
- OR TABLE_NAME LIKE '\_\_oms\_ren\_%' ESCAPE '\\'
- )
-ORDER BY TABLE_NAME;
-
--- ========== 单表改名:大写 C_ 存在 → 临时名 → c_* ==========
--- c_sku
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_sku');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_sku` TO `__oms_ren_sku`', 'SELECT ''skip: C_sku'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_sku');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_sku` TO `c_sku`', 'SELECT ''skip: __oms_ren_sku'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_bin_location
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_bin_location');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_bin_location` TO `__oms_ren_bin_location`', 'SELECT ''skip: C_bin_location'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_bin_location');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_bin_location` TO `c_bin_location`', 'SELECT ''skip: __oms_ren_bin_location'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_inventory
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_inventory');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_inventory` TO `__oms_ren_inventory`', 'SELECT ''skip: C_inventory'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_inventory');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_inventory` TO `c_inventory`', 'SELECT ''skip: __oms_ren_inventory'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_inbound_notice
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_inbound_notice');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_inbound_notice` TO `__oms_ren_inbound_notice`', 'SELECT ''skip: C_inbound_notice'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_inbound_notice');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_inbound_notice` TO `c_inbound_notice`', 'SELECT ''skip: __oms_ren_inbound_notice'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_inbound_box
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_inbound_box');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_inbound_box` TO `__oms_ren_inbound_box`', 'SELECT ''skip: C_inbound_box'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_inbound_box');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_inbound_box` TO `c_inbound_box`', 'SELECT ''skip: __oms_ren_inbound_box'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_inbound_box_line
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_inbound_box_line');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_inbound_box_line` TO `__oms_ren_inbound_box_line`', 'SELECT ''skip: C_inbound_box_line'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_inbound_box_line');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_inbound_box_line` TO `c_inbound_box_line`', 'SELECT ''skip: __oms_ren_inbound_box_line'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_parcel
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_parcel');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_parcel` TO `__oms_ren_parcel`', 'SELECT ''skip: C_parcel'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_parcel');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_parcel` TO `c_parcel`', 'SELECT ''skip: __oms_ren_parcel'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_parcel_arrival
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_parcel_arrival');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_parcel_arrival` TO `__oms_ren_parcel_arrival`', 'SELECT ''skip: C_parcel_arrival'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_parcel_arrival');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_parcel_arrival` TO `c_parcel_arrival`', 'SELECT ''skip: __oms_ren_parcel_arrival'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_parcel_item
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_parcel_item');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_parcel_item` TO `__oms_ren_parcel_item`', 'SELECT ''skip: C_parcel_item'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_parcel_item');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_parcel_item` TO `c_parcel_item`', 'SELECT ''skip: __oms_ren_parcel_item'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- c_sku_platform_map
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND BINARY TABLE_NAME = 'C_sku_platform_map');
-SET @sql := IF(@need > 0, 'RENAME TABLE `C_sku_platform_map` TO `__oms_ren_sku_platform_map`', 'SELECT ''skip: C_sku_platform_map'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-SET @need := (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '__oms_ren_sku_platform_map');
-SET @sql := IF(@need > 0, 'RENAME TABLE `__oms_ren_sku_platform_map` TO `c_sku_platform_map`', 'SELECT ''skip: __oms_ren_sku_platform_map'' AS info');
-PREPARE _s FROM @sql; EXECUTE _s; DEALLOCATE PREPARE _s;
-
--- ========== 执行后复查 ==========
-SELECT TABLE_NAME AS warehouse_table_after
-FROM information_schema.TABLES
-WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME LIKE 'c\_%' ESCAPE '\\'
-ORDER BY TABLE_NAME;
-
--- ========== 若上面全是 skip 且已是 c_*:无需再改,直接部署后端即可 ==========
--- 若仍残留 C_*(区分大小写 Linux),可手工一次性执行(会失败则勿重复跑):
--- RENAME TABLE
--- `C_sku` TO `__oms_ren_sku`, `C_bin_location` TO `__oms_ren_bin_location`,
--- `C_inventory` TO `__oms_ren_inventory`, `C_inbound_notice` TO `__oms_ren_inbound_notice`,
--- `C_inbound_box` TO `__oms_ren_inbound_box`, `C_inbound_box_line` TO `__oms_ren_inbound_box_line`,
--- `C_parcel` TO `__oms_ren_parcel`, `C_parcel_arrival` TO `__oms_ren_parcel_arrival`,
--- `C_parcel_item` TO `__oms_ren_parcel_item`, `C_sku_platform_map` TO `__oms_ren_sku_platform_map`;
--- RENAME TABLE
--- `__oms_ren_sku` TO `c_sku`, `__oms_ren_bin_location` TO `c_bin_location`,
--- `__oms_ren_inventory` TO `c_inventory`, `__oms_ren_inbound_notice` TO `c_inbound_notice`,
--- `__oms_ren_inbound_box` TO `c_inbound_box`, `__oms_ren_inbound_box_line` TO `c_inbound_box_line`,
--- `__oms_ren_parcel` TO `c_parcel`, `__oms_ren_parcel_arrival` TO `c_parcel_arrival`,
--- `__oms_ren_parcel_item` TO `c_parcel_item`, `__oms_ren_sku_platform_map` TO `c_sku_platform_map`;
diff --git a/sql/migrate_t_customer_sender_address.sql b/sql/migrate_t_customer_sender_address.sql
deleted file mode 100644
index 1ba3960..0000000
--- a/sql/migrate_t_customer_sender_address.sql
+++ /dev/null
@@ -1,34 +0,0 @@
--- 已有库增量:客户地址簿 t_customer_sender_address(发件/退件/收件)
--- 对应功能:客户 → 地址管理;揽收订单选发件地址
--- 可重复执行(IF NOT EXISTS)
-
-CREATE TABLE IF NOT EXISTS `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收件',
- `AddressName` VARCHAR(64) NULL COMMENT '地址别名',
- `SenderName` VARCHAR(50) NOT NULL COMMENT '联系人姓名',
- `Company` VARCHAR(255) NULL COMMENT '公司',
- `Country` INT NULL COMMENT '国家 t_country.Id',
- `Province` VARCHAR(50) NULL COMMENT '州省',
- `City` VARCHAR(50) NULL COMMENT '城市',
- `ZipCode` VARCHAR(50) NULL COMMENT '邮编',
- `StreetAddress1` VARCHAR(500) NOT NULL COMMENT '地址1',
- `StreetAddress2` VARCHAR(500) NULL COMMENT '地址2',
- `StreetAddress3` VARCHAR(500) NULL COMMENT '地址3',
- `HouseNumber` VARCHAR(50) NULL COMMENT '门牌号',
- `Phone` VARCHAR(50) NULL COMMENT '手机',
- `TelePhone` VARCHAR(50) NULL COMMENT '电话',
- `Email` VARCHAR(60) NULL COMMENT '邮箱',
- `IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认:0-否,1-是(同客户同类型仅一条)',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) 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_csa_customer` (`CustomerId`, `IsDeleted`, `Id`),
- KEY `idx_csa_customer_type` (`CustomerId`, `AddressType`, `IsDeleted`, `Id`),
- KEY `idx_csa_customer_default` (`CustomerId`, `AddressType`, `IsDefault`)
-) COMMENT='客户地址簿(发件/退件/收件)';
diff --git a/sql/migrate_t_customer_sender_address_AddressType.sql b/sql/migrate_t_customer_sender_address_AddressType.sql
deleted file mode 100644
index 4eaacd4..0000000
--- a/sql/migrate_t_customer_sender_address_AddressType.sql
+++ /dev/null
@@ -1,41 +0,0 @@
--- 已有库增量:客户地址簿增加 AddressType(发件/退件/收件)
--- sender=发件,return=退件,receiver=收件;存量默认 sender
--- 可重复执行
-
-SET @col_exists := (
- SELECT COUNT(1)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_customer_sender_address'
- AND COLUMN_NAME = 'AddressType'
-);
-
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_customer_sender_address` ADD COLUMN `AddressType` VARCHAR(16) NOT NULL DEFAULT ''sender'' COMMENT ''地址类型:sender发件/return退件/receiver收件'' AFTER `CustomerId`',
- 'SELECT ''t_customer_sender_address.AddressType already exists'' AS info'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-UPDATE `t_customer_sender_address`
-SET `AddressType` = 'sender'
-WHERE `AddressType` IS NULL OR `AddressType` = '';
-
-SET @idx_exists := (
- SELECT COUNT(1)
- FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_customer_sender_address'
- AND INDEX_NAME = 'idx_csa_customer_type'
-);
-
-SET @sql := IF(
- @idx_exists = 0,
- 'ALTER TABLE `t_customer_sender_address` ADD KEY `idx_csa_customer_type` (`CustomerId`, `AddressType`, `IsDeleted`, `Id`)',
- 'SELECT ''idx_csa_customer_type already exists'' AS info'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_dict_type.sql b/sql/migrate_t_dict_type.sql
deleted file mode 100644
index f0d306b..0000000
--- a/sql/migrate_t_dict_type.sql
+++ /dev/null
@@ -1,90 +0,0 @@
--- 已有库增量:字典类型元数据 t_dict_type(类型编码 + 备注 + 排序)
--- 对应功能:系统 → 数据字典,左侧类型列表与类型备注
--- 可重复执行(IF NOT EXISTS / INSERT IGNORE;预置名称直接覆盖 Remark、TypeSort)
-
-CREATE TABLE IF NOT EXISTS `t_dict_type` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
- `DictType` VARCHAR(64) NOT NULL COMMENT '字典类型编码,与 t_dict.DictType 对应',
- `Remark` VARCHAR(512) NULL COMMENT '字典类型备注',
- `TypeSort` INT NOT NULL DEFAULT 0 COMMENT '左侧菜单排序,值越小越靠前',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) 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_dict_type_code` (`DictType`)
-) COMMENT='字典类型元数据表';
-
--- 从已有字典项回填类型(无备注)
-INSERT IGNORE INTO `t_dict_type` (`DictType`, `Remark`, `TypeSort`, `CreateUserId`)
-SELECT DISTINCT `DictType`, NULL, 0, 0
-FROM `t_dict`
-WHERE `IsDeleted` = 0 AND TRIM(`DictType`) <> '';
-
--- 预置 OMS 字典类型中文名称(与前端 dict-batch-import.ts OMS_DICT_TYPE_REMARKS 对齐)
--- 已存在记录时直接覆盖 Remark、TypeSort
-INSERT INTO `t_dict_type` (`DictType`, `TypeSort`, `Remark`, `CreateUserId`)
-VALUES
- ('area_type', 1, '分区类型', 0),
- ('auto_trigger_operation', 2, '自动触发操作', 0),
- ('auto_trigger_timing', 3, '自动触发时机', 0),
- ('billable_weight', 4, '计重取值', 0),
- ('calculation_formula', 5, '计算公式', 0),
- ('cargo_attribute', 6, '货物属性', 0),
- ('claim_type', 7, '理赔类型', 0),
- ('cost_unit', 8, '计费单位', 0),
- ('currency', 9, '币种', 0),
- ('customer_account_flow_biz_type', 10, '账户流水业务类型', 0),
- ('customer_address_type', 11, '客户地址类型', 0),
- ('customer_group', 12, '客户组', 0),
- ('customer_status', 13, '客户状态', 0),
- ('customer_waybill', 14, '客户面单', 0),
- ('data_scope', 15, '数据范围', 0),
- ('enable_status', 16, '启用状态', 0),
- ('es_snapshot_status', 17, '快照生效状态', 0),
- ('export_customs_mode', 18, '出口报关方式', 0),
- ('fee_item', 19, '费用项', 0),
- ('forecast_type', 20, '预报类型', 0),
- ('issue_notify_method', 21, '问题通知方式', 0),
- ('issue_type', 22, '问题件类型', 0),
- ('label_generate_status', 23, '面单生成状态', 0),
- ('label_template_type', 24, '面单模板类型', 0),
- ('notice_type', 25, '通知类型', 0),
- ('number_type', 26, '打印号码类型', 0),
- ('operator_type', 27, '发布操作类型', 0),
- ('order_batch_job_item_status', 28, '批量任务明细状态', 0),
- ('order_batch_job_status', 29, '批量任务状态', 0),
- ('order_fee_charging_stage', 30, '费用计费阶段', 0),
- ('order_fee_type', 31, '费用类型', 0),
- ('order_handle_status', 32, '订单处理子状态', 0),
- ('order_source', 33, '订单来源', 0),
- ('order_status', 34, '订单状态', 0),
- ('order_stock_bind_status', 35, '库存绑定状态', 0),
- ('order_stock_bind_type', 36, '库存绑定类型', 0),
- ('order_task_status', 37, '订单导入任务状态', 0),
- ('order_template_mapping_status', 38, '模板映射状态', 0),
- ('order_template_type', 39, '订单模板类型', 0),
- ('order_weight_type', 40, '件重尺类型', 0),
- ('org_scope', 41, '组织范围', 0),
- ('pay_type', 42, '支付方式', 0),
- ('pricing_factor', 43, '定价因素', 0),
- ('principal_type', 44, '主体类型', 0),
- ('publish_record_type', 45, '发布记录类型', 0),
- ('receiver_type', 46, '接收方类型', 0),
- ('recharge_status', 47, '充值审核状态', 0),
- ('sales_product_group', 48, '卖价分组', 0),
- ('sales_store_auth_status', 49, '店铺授权状态', 0),
- ('sales_store_fulfill_status', 50, '平台店铺履约状态', 0),
- ('scheme', 51, '排货方案', 0),
- ('secret_level', 52, '密级', 0),
- ('warehouse_inbound_type', 53, '入库类型', 0),
- ('warehouse_parcel_lifecycle', 54, '包裹生命周期', 0),
- ('warehouse_receipt_status', 55, '收货状态', 0),
- ('warehouse_type', 56, '仓库类型', 0),
- ('weight_rule_condition', 57, '计重条件', 0),
- ('yes_no', 58, '通用是否', 0)
-ON DUPLICATE KEY UPDATE
- `TypeSort` = VALUES(`TypeSort`),
- `Remark` = VALUES(`Remark`);
diff --git a/sql/migrate_t_order_allocation_pending_reason.sql b/sql/migrate_t_order_allocation_pending_reason.sql
deleted file mode 100644
index 46f2c57..0000000
--- a/sql/migrate_t_order_allocation_pending_reason.sql
+++ /dev/null
@@ -1,3 +0,0 @@
--- 待排货原因:入库排货/买价未成功时记录,便于运营补配置后重算应付
-ALTER TABLE `t_order`
- ADD COLUMN `AllocationPendingReason` VARCHAR(512) NULL COMMENT '待排货原因(排货或渠道买价未匹配)' AFTER `PredeclareFailReason`;
diff --git a/sql/migrate_t_order_pickup_fields.sql b/sql/migrate_t_order_pickup_fields.sql
deleted file mode 100644
index 896b0d2..0000000
--- a/sql/migrate_t_order_pickup_fields.sql
+++ /dev/null
@@ -1,75 +0,0 @@
--- 已有库增量:t_order 揽收订单字段 OrderSource / PickupTime / CustomerSenderAddressId
--- 对应功能:订单 → 揽收订单;见 oms系统设计-050801.md §4.2.1 / §4.4.4
--- 可重复执行
-
-SET @col_exists := (
- SELECT COUNT(1)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_order'
- AND COLUMN_NAME = 'OrderSource'
-);
-
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `OrderSource` VARCHAR(32) NULL COMMENT ''订单来源:manual/pickup/upload/batch/platform'' AFTER `CustomerId`',
- 'SELECT ''t_order.OrderSource already exists'' AS info'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @col_exists := (
- SELECT COUNT(1)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_order'
- AND COLUMN_NAME = 'PickupTime'
-);
-
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `PickupTime` DATETIME NULL COMMENT ''预约揽收时间'' AFTER `OrderSource`',
- 'SELECT ''t_order.PickupTime already exists'' AS info'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @col_exists := (
- SELECT COUNT(1)
- FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_order'
- AND COLUMN_NAME = 'CustomerSenderAddressId'
-);
-
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_order` ADD COLUMN `CustomerSenderAddressId` INT NULL COMMENT ''发件地址簿 Id'' AFTER `PickupTime`',
- 'SELECT ''t_order.CustomerSenderAddressId already exists'' AS info'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-UPDATE `t_order`
-SET `OrderSource` = 'manual'
-WHERE `OrderSource` IS NULL OR `OrderSource` = '';
-
-SET @idx_exists := (
- SELECT COUNT(1)
- FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_order'
- AND INDEX_NAME = 'idx_ord_source_ctime'
-);
-
-SET @sql := IF(
- @idx_exists = 0,
- 'ALTER TABLE `t_order` ADD KEY `idx_ord_source_ctime` (`OrderSource`, `CreateTime`)',
- 'SELECT ''idx_ord_source_ctime already exists'' AS info'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_order_stock_bind.sql b/sql/migrate_t_order_stock_bind.sql
deleted file mode 100644
index c27dcb5..0000000
--- a/sql/migrate_t_order_stock_bind.sql
+++ /dev/null
@@ -1,120 +0,0 @@
--- 物流单绑定包裹/库存:t_order_stock_bind + c_inventory/c_parcel_item 冻结与可用字段
--- 见 oms系统设计-050801.md §4.2.11 / §4.4.6 / §3.1.2
--- ConcurrencyStamp 默认用固定 GUID,避免 DEFAULT (UUID()) 触发复制 1674
--- 可重复执行
-
-CREATE TABLE IF NOT EXISTS `t_order_stock_bind` (
- `Id` INT NOT NULL AUTO_INCREMENT,
- `OrderId` INT NOT NULL COMMENT '物流单 t_order.Id',
- `CustomerId` INT NOT NULL COMMENT '客户隔离键',
- `WarehouseId` INT NOT NULL COMMENT '仓库',
- `BindType` VARCHAR(20) NOT NULL COMMENT 'inventory / parcelItem',
- `SkuId` INT NULL COMMENT 'SKU',
- `InventoryId` INT NULL COMMENT 'c_inventory.Id,可空=按SKU分摊',
- `BinLocationId` INT NULL COMMENT '库位快照',
- `ParcelId` INT NULL COMMENT 'c_parcel.Id',
- `ParcelItemId` INT NULL COMMENT 'c_parcel_item.Id',
- `BindQty` INT NOT NULL COMMENT '绑定数量',
- `Status` VARCHAR(20) NOT NULL DEFAULT 'bound' COMMENT 'bound/deducted/released',
- `SkuCode` VARCHAR(64) NULL,
- `SkuName` VARCHAR(128) NULL,
- `TrackingNo` VARCHAR(64) NULL,
- `ProductName` VARCHAR(256) NULL,
- `ImageUrl` VARCHAR(512) NULL,
- `AttributeText` VARCHAR(256) NULL,
- `Remark` VARCHAR(512) NULL,
- `IsDeleted` TINYINT NOT NULL DEFAULT 0,
- `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' COMMENT '并发戳',
- `CreateUserId` INT NOT NULL,
- `CreateTime` DATETIME NOT NULL,
- `UpdateUserId` INT NULL,
- `UpdateTime` DATETIME NULL,
- PRIMARY KEY (`Id`),
- KEY `idx_osb_order` (`OrderId`, `IsDeleted`, `Status`),
- KEY `idx_osb_parcel_item` (`ParcelItemId`, `Status`, `IsDeleted`),
- KEY `idx_osb_sku` (`CustomerId`, `WarehouseId`, `SkuId`, `Status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物流单仓储绑定明细';
-
--- 已建表但缺 ConcurrencyStamp 时补列(可重复执行)
-SET @col_exists := (
- SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_order_stock_bind' AND COLUMN_NAME = 'ConcurrencyStamp'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_order_stock_bind` ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT ''00000000-0000-0000-0000-000000000000'' COMMENT ''并发戳'' AFTER `IsDeleted`',
- 'SELECT ''t_order_stock_bind.ConcurrencyStamp already exists'' AS info'
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- c_inventory.FrozenQty(兼容尚未 rename 的旧表名 C_inventory)
-SET @inv_table := IF(
- EXISTS (SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'c_inventory'),
- 'c_inventory',
- IF(
- EXISTS (SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'C_inventory'),
- 'C_inventory',
- NULL
- )
-);
-SET @col_exists := IF(@inv_table IS NULL, 1,
- (SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @inv_table AND COLUMN_NAME = 'FrozenQty')
-);
-SET @sql := IF(@inv_table IS NULL OR @col_exists > 0,
- 'SELECT ''c_inventory.FrozenQty already exists or table missing'' AS info',
- CONCAT('ALTER TABLE `', @inv_table, '` ADD COLUMN `FrozenQty` INT NOT NULL DEFAULT 0 COMMENT ''冻结数量'' AFTER `Qty`')
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @col_exists := IF(@inv_table IS NULL, 1,
- (SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @inv_table AND COLUMN_NAME = 'AvailableQty')
-);
-SET @sql := IF(@inv_table IS NULL OR @col_exists > 0,
- 'SELECT ''c_inventory.AvailableQty already exists or table missing'' AS info',
- CONCAT('ALTER TABLE `', @inv_table, '` ADD COLUMN `AvailableQty` INT NOT NULL DEFAULT 0 COMMENT ''可用=Qty-FrozenQty'' AFTER `FrozenQty`')
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @sql := IF(@inv_table IS NULL,
- 'SELECT ''c_inventory table missing'' AS info',
- CONCAT('UPDATE `', @inv_table, '` SET `AvailableQty` = GREATEST(0, `Qty` - IFNULL(`FrozenQty`, 0)) WHERE `AvailableQty` <> GREATEST(0, `Qty` - IFNULL(`FrozenQty`, 0)) OR (`AvailableQty` = 0 AND `Qty` > 0 AND IFNULL(`FrozenQty`, 0) = 0)')
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
--- c_parcel_item.FrozenQty
-SET @pi_table := IF(
- EXISTS (SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'c_parcel_item'),
- 'c_parcel_item',
- IF(
- EXISTS (SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'C_parcel_item'),
- 'C_parcel_item',
- NULL
- )
-);
-SET @col_exists := IF(@pi_table IS NULL, 1,
- (SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @pi_table AND COLUMN_NAME = 'FrozenQty')
-);
-SET @sql := IF(@pi_table IS NULL OR @col_exists > 0,
- 'SELECT ''c_parcel_item.FrozenQty already exists or table missing'' AS info',
- CONCAT('ALTER TABLE `', @pi_table, '` ADD COLUMN `FrozenQty` INT NOT NULL DEFAULT 0 COMMENT ''冻结数量'' AFTER `Quantity`')
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @col_exists := IF(@pi_table IS NULL, 1,
- (SELECT COUNT(1) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @pi_table AND COLUMN_NAME = 'AvailableQty')
-);
-SET @sql := IF(@pi_table IS NULL OR @col_exists > 0,
- 'SELECT ''c_parcel_item.AvailableQty already exists or table missing'' AS info',
- CONCAT('ALTER TABLE `', @pi_table, '` ADD COLUMN `AvailableQty` INT NOT NULL DEFAULT 0 COMMENT ''可用=Quantity-FrozenQty'' AFTER `FrozenQty`')
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-SET @sql := IF(@pi_table IS NULL,
- 'SELECT ''c_parcel_item table missing'' AS info',
- CONCAT('UPDATE `', @pi_table, '` SET `AvailableQty` = GREATEST(0, `Quantity` - IFNULL(`FrozenQty`, 0)) WHERE `AvailableQty` <> GREATEST(0, `Quantity` - IFNULL(`FrozenQty`, 0)) OR (`AvailableQty` = 0 AND `Quantity` > 0 AND IFNULL(`FrozenQty`, 0) = 0)')
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_t_sales_store_order_recipient.sql b/sql/migrate_t_sales_store_order_recipient.sql
deleted file mode 100644
index 588025f..0000000
--- a/sql/migrate_t_sales_store_order_recipient.sql
+++ /dev/null
@@ -1,32 +0,0 @@
--- 店铺订单补收件人字段(可重复执行)
--- 用法:mysql -u root -p oms < sql/migrate_t_sales_store_order_recipient.sql
-
-SET NAMES utf8mb4;
-
-DROP PROCEDURE IF EXISTS sp_add_store_order_recipient_cols;
-DELIMITER $$
-CREATE PROCEDURE sp_add_store_order_recipient_cols()
-BEGIN
- DECLARE col_exists INT DEFAULT 0;
-
- SELECT COUNT(*) INTO col_exists FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 't_sales_store_order' AND COLUMN_NAME = 'RecipientName';
- IF col_exists = 0 THEN
- ALTER TABLE `t_sales_store_order`
- ADD COLUMN `RecipientName` VARCHAR(64) NULL COMMENT '收件人姓名' AFTER `OrderCountry`,
- ADD COLUMN `RecipientCompany` VARCHAR(128) NULL COMMENT '收件人公司' AFTER `RecipientName`,
- ADD COLUMN `RecipientPhone` VARCHAR(32) NULL COMMENT '收件人手机' AFTER `RecipientCompany`,
- ADD COLUMN `RecipientTelePhone` VARCHAR(32) NULL COMMENT '收件人电话' AFTER `RecipientPhone`,
- ADD COLUMN `RecipientEmail` VARCHAR(64) NULL COMMENT '收件人邮箱' AFTER `RecipientTelePhone`,
- ADD COLUMN `RecipientCountry` VARCHAR(8) NULL COMMENT '收件国家码' AFTER `RecipientEmail`,
- ADD COLUMN `RecipientProvince` VARCHAR(64) NULL COMMENT '收件省/州' AFTER `RecipientCountry`,
- ADD COLUMN `RecipientCity` VARCHAR(64) NULL COMMENT '收件城市' AFTER `RecipientProvince`,
- ADD COLUMN `RecipientZipCode` VARCHAR(32) NULL COMMENT '收件邮编' AFTER `RecipientCity`,
- ADD COLUMN `RecipientAddress1` VARCHAR(512) NULL COMMENT '收件地址1' AFTER `RecipientZipCode`,
- ADD COLUMN `RecipientAddress2` VARCHAR(512) NULL COMMENT '收件地址2' AFTER `RecipientAddress1`;
- END IF;
-END$$
-DELIMITER ;
-
-CALL sp_add_store_order_recipient_cols();
-DROP PROCEDURE IF EXISTS sp_add_store_order_recipient_cols;
diff --git a/sql/seed_marketing_customer9.sql b/sql/seed_marketing_customer9.sql
deleted file mode 100644
index b7056e9..0000000
--- a/sql/seed_marketing_customer9.sql
+++ /dev/null
@@ -1,621 +0,0 @@
--- 营销模块种子(CustomerId=9 引荐人主客户,CustomerId=8 被引荐下级)
--- 可重复执行:已存在则跳过 / 幂等更新
---
--- 用法:
--- 1) mysql -u root -p oms < sql/migrate_marketing_module.sql
--- 2) mysql -u root -p oms < sql/seed_marketing_customer9.sql
---
--- 覆盖页面:
--- 管理端:会员等级 / 积分规则 / 积分流水 / 优惠券模板 / 发券实例 /
--- 分成规则 / 分成明细 / 提现审核 / 引荐关系
--- 门户端:邀请好友 / 我的等级 / 我的优惠券 / 推荐收益
---
--- 约定:此处「子」= 引荐下级(ReferrerCustomerId),非 ParentCustomerId 子账号。
--- 8、9 均须为主客户(ParentCustomerId IS NULL),营销权益才挂得上。
-
-SET NAMES utf8mb4;
-
-SET @referrerId := 9;
-SET @refereeId := 8;
-
--- ---------------------------------------------------------------------------
--- 0. 前置校验
--- ---------------------------------------------------------------------------
-SET @seed_err := (
- SELECT
- CASE
- WHEN NOT EXISTS (SELECT 1 FROM `t_customer` WHERE `Id` = @referrerId AND `IsDeleted` = 0)
- THEN CONCAT('缺少客户 Id=', @referrerId)
- WHEN NOT EXISTS (SELECT 1 FROM `t_customer` WHERE `Id` = @refereeId AND `IsDeleted` = 0)
- THEN CONCAT('缺少客户 Id=', @refereeId)
- WHEN EXISTS (
- SELECT 1 FROM `t_customer`
- WHERE `Id` = @referrerId AND `ParentCustomerId` IS NOT NULL AND `IsDeleted` = 0
- )
- THEN CONCAT('客户 Id=', @referrerId, ' 不是主客户(存在 ParentCustomerId)')
- WHEN EXISTS (
- SELECT 1 FROM `t_customer`
- WHERE `Id` = @refereeId AND `ParentCustomerId` IS NOT NULL AND `IsDeleted` = 0
- )
- THEN CONCAT('客户 Id=', @refereeId, ' 不是主客户(存在 ParentCustomerId);请先改为主客户再跑种子')
- ELSE NULL
- END
-);
-
-SELECT IFNULL(@seed_err, 'OK') AS seed_precheck;
-
--- 校验失败则中止,避免写脏数据
-SET @__abort := IF(@seed_err IS NULL, 'SELECT 1', CONCAT('SIGNAL SQLSTATE ''45000'' SET MESSAGE_TEXT = ''', REPLACE(@seed_err, '''', ''), ''''));
-PREPARE abort_stmt FROM @__abort;
-EXECUTE abort_stmt;
-DEALLOCATE PREPARE abort_stmt;
-
--- ---------------------------------------------------------------------------
--- 1. 会员等级(migrate 已种子;此处确保存在并取 Id)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_member_level`
- (`LevelCode`, `LevelName`, `MinPoints`, `PriceTierKey`, `ExtraDiscountRate`, `Sort`, `BenefitDesc`, `Status`, `CreateUserId`)
-VALUES
- ('normal', '普通会员', 0, '普通客户', 0.0000, 10, '标准运价', 2, 0),
- ('silver', '银卡会员', 5000, 'VIP1', 0.0000, 20, 'VIP1 价区', 2, 0),
- ('gold', '金卡会员', 20000, 'VIP2', 0.0100, 30, 'VIP2 价区 + 额外 1% 折', 2, 0),
- ('diamond', '钻石会员', 100000, 'VIP3', 0.0200, 40, 'VIP3 价区 + 额外 2% 折', 2, 0)
-ON DUPLICATE KEY UPDATE
- `LevelName` = VALUES(`LevelName`),
- `MinPoints` = VALUES(`MinPoints`),
- `PriceTierKey` = VALUES(`PriceTierKey`),
- `ExtraDiscountRate` = VALUES(`ExtraDiscountRate`),
- `Sort` = VALUES(`Sort`),
- `BenefitDesc` = VALUES(`BenefitDesc`),
- `Status` = 2,
- `IsDeleted` = 0;
-
-SET @levelNormal := (SELECT `Id` FROM `t_member_level` WHERE `LevelCode` = 'normal' AND `IsDeleted` = 0 LIMIT 1);
-SET @levelSilver := (SELECT `Id` FROM `t_member_level` WHERE `LevelCode` = 'silver' AND `IsDeleted` = 0 LIMIT 1);
-SET @levelGold := (SELECT `Id` FROM `t_member_level` WHERE `LevelCode` = 'gold' AND `IsDeleted` = 0 LIMIT 1);
-
--- ---------------------------------------------------------------------------
--- 2. 积分规则 / 分成规则(全局,缺则补)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_member_points_rule`
- (`RuleName`, `PointsPerYuan`, `FirstOrderMultiplier`, `MaxPointsPerOrder`, `Status`, `CreateUserId`)
-SELECT '默认积分规则', 1.0000, 1.50, 10000, 2, 0
-FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_member_points_rule` WHERE `IsDeleted` = 0 LIMIT 1);
-
-UPDATE `t_member_points_rule`
-SET `RuleName` = '默认积分规则',
- `PointsPerYuan` = 1.0000,
- `FirstOrderMultiplier` = 1.50,
- `MaxPointsPerOrder` = 10000,
- `Status` = 2,
- `UpdateTime` = NOW()
-WHERE `Id` = (
- SELECT `Id` FROM (
- SELECT `Id` FROM `t_member_points_rule` WHERE `IsDeleted` = 0 ORDER BY `Id` LIMIT 1
- ) AS t
-);
-
-INSERT INTO `t_referral_commission_rule`
- (`RuleName`, `CommissionMode`, `BaseAmount`, `CommissionAmount`, `FreezeDays`, `SettleTriggerOrderStatus`, `MonthlyCap`, `Status`, `CreateUserId`)
-SELECT '默认分成', 'per_amount', 1000.00, 2.00, 7, 'deliverySuccess', NULL, 2, 0
-FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_referral_commission_rule` WHERE `IsDeleted` = 0 LIMIT 1);
-
-UPDATE `t_referral_commission_rule`
-SET `RuleName` = '默认分成',
- `CommissionMode` = 'per_amount',
- `BaseAmount` = 1000.00,
- `CommissionAmount` = 2.00,
- `FreezeDays` = 7,
- `SettleTriggerOrderStatus` = 'deliverySuccess',
- `Status` = 2,
- `UpdateTime` = NOW()
-WHERE `Id` = (
- SELECT `Id` FROM (
- SELECT `Id` FROM `t_referral_commission_rule` WHERE `IsDeleted` = 0 ORDER BY `Id` LIMIT 1
- ) AS t
-);
-
--- ---------------------------------------------------------------------------
--- 3. 客户:引荐关系 + 等级 + 佣金余额(9 引荐 8)
--- ---------------------------------------------------------------------------
-UPDATE `t_customer`
-SET
- `ReferrerCustomerId` = NULL,
- `ReferralBindTime` = NULL,
- `ReferralChannel` = NULL,
- `MemberLevelId` = @levelGold,
- `CommissionBalance` = 128.60,
- `UpdateTime` = NOW()
-WHERE `Id` = @referrerId AND `IsDeleted` = 0 AND `ParentCustomerId` IS NULL;
-
-UPDATE `t_customer`
-SET
- `ReferrerCustomerId` = @referrerId,
- `ReferralBindTime` = DATE_SUB(NOW(), INTERVAL 45 DAY),
- `ReferralChannel` = 'link',
- `MemberLevelId` = @levelSilver,
- `CommissionBalance` = 0.00,
- `UpdateTime` = NOW()
-WHERE `Id` = @refereeId AND `IsDeleted` = 0 AND `ParentCustomerId` IS NULL;
-
--- ---------------------------------------------------------------------------
--- 4. 引荐码(邀请好友页)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_customer_referral_code`
- (`CustomerId`, `InviteCode`, `Status`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @referrerId, 'SEED9INV', 1, 0, UUID(), 0, NOW()
-FROM DUAL
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_referral_code`
- WHERE `CustomerId` = @referrerId AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_customer_referral_code`
- (`CustomerId`, `InviteCode`, `Status`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @refereeId, 'SEED8INV', 1, 0, UUID(), 0, NOW()
-FROM DUAL
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_referral_code`
- WHERE `CustomerId` = @refereeId AND `IsDeleted` = 0
-);
-
-UPDATE `t_customer_referral_code`
-SET `InviteCode` = 'SEED9INV', `Status` = 1, `IsDeleted` = 0, `UpdateTime` = NOW()
-WHERE `CustomerId` = @referrerId AND `IsDeleted` = 0;
-
-UPDATE `t_customer_referral_code`
-SET `InviteCode` = 'SEED8INV', `Status` = 1, `IsDeleted` = 0, `UpdateTime` = NOW()
-WHERE `CustomerId` = @refereeId AND `IsDeleted` = 0;
-
--- ---------------------------------------------------------------------------
--- 5. 积分账户 + 流水(积分流水 / 我的等级)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_customer_points_account`
- (`CustomerId`, `TotalPoints`, `AvailablePoints`, `Version`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @referrerId, 26800, 24500, 0, 0, UUID(), 0, NOW()
-FROM DUAL
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_points_account` WHERE `CustomerId` = @referrerId AND `IsDeleted` = 0
-);
-
-UPDATE `t_customer_points_account`
-SET `TotalPoints` = 26800, `AvailablePoints` = 24500, `UpdateTime` = NOW()
-WHERE `CustomerId` = @referrerId AND `IsDeleted` = 0;
-
-INSERT INTO `t_customer_points_account`
- (`CustomerId`, `TotalPoints`, `AvailablePoints`, `Version`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @refereeId, 6200, 5800, 0, 0, UUID(), 0, NOW()
-FROM DUAL
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_points_account` WHERE `CustomerId` = @refereeId AND `IsDeleted` = 0
-);
-
-UPDATE `t_customer_points_account`
-SET `TotalPoints` = 6200, `AvailablePoints` = 5800, `UpdateTime` = NOW()
-WHERE `CustomerId` = @refereeId AND `IsDeleted` = 0;
-
--- 9:赚取 / 消耗 / 调账
-INSERT INTO `t_customer_points_flow`
- (`CustomerId`, `ChangeType`, `Points`, `BizType`, `BizId`, `BizNo`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @referrerId, 1, 1200, 'orderPay', 9009001, 'SEED-MKT-ORD-9001', '种子:支付赚取积分', 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 20 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_points_flow`
- WHERE `CustomerId` = @referrerId AND `BizNo` = 'SEED-MKT-ORD-9001' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_customer_points_flow`
- (`CustomerId`, `ChangeType`, `Points`, `BizType`, `BizId`, `BizNo`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @referrerId, 1, 800, 'orderPay', 9009002, 'SEED-MKT-ORD-9002', '种子:支付赚取积分', 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 12 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_points_flow`
- WHERE `CustomerId` = @referrerId AND `BizNo` = 'SEED-MKT-ORD-9002' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_customer_points_flow`
- (`CustomerId`, `ChangeType`, `Points`, `BizType`, `BizId`, `BizNo`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @referrerId, 2, -300, 'orderPay', 9009003, 'SEED-MKT-ORD-9003', '种子:下单抵扣积分', 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 8 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_points_flow`
- WHERE `CustomerId` = @referrerId AND `BizNo` = 'SEED-MKT-ORD-9003' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_customer_points_flow`
- (`CustomerId`, `ChangeType`, `Points`, `BizType`, `BizId`, `BizNo`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @referrerId, 3, 500, 'adminAdjust', NULL, 'SEED-MKT-ADJ-9001', '种子:人工调账加分(演示用不少于十字原因)', 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 3 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_points_flow`
- WHERE `CustomerId` = @referrerId AND `BizNo` = 'SEED-MKT-ADJ-9001' AND `IsDeleted` = 0
-);
-
--- 8:赚取 / 退款追回
-INSERT INTO `t_customer_points_flow`
- (`CustomerId`, `ChangeType`, `Points`, `BizType`, `BizId`, `BizNo`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @refereeId, 1, 1500, 'orderPay', 9008001, 'SEED-MKT-ORD-8001', '种子:被引荐人支付赚取', 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 30 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_points_flow`
- WHERE `CustomerId` = @refereeId AND `BizNo` = 'SEED-MKT-ORD-8001' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_customer_points_flow`
- (`CustomerId`, `ChangeType`, `Points`, `BizType`, `BizId`, `BizNo`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`)
-SELECT @refereeId, 4, -200, 'refund', 9008001, 'SEED-MKT-RF-8001', '种子:退款积分追回', 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 25 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_points_flow`
- WHERE `CustomerId` = @refereeId AND `BizNo` = 'SEED-MKT-RF-8001' AND `IsDeleted` = 0
-);
-
--- ---------------------------------------------------------------------------
--- 6. 优惠券模板(模板页)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_coupon_template` (
- `TemplateCode`, `TemplateName`, `CouponType`, `FaceValue`, `DiscountRate`, `MaxDiscountAmount`,
- `MinOrderAmount`, `TotalQuantity`, `IssuedQuantity`, `PerCustomerLimit`,
- `ValidType`, `ValidStartTime`, `ValidEndTime`, `ValidDaysAfterReceive`,
- `ApplyScopeJson`, `GrantChannel`, `Status`, `Remark`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED-FIXED-20', '种子满减券20元', 'fixed_off', 20.00, NULL, NULL,
- 100.00, 1000, 0, 2,
- 1, DATE_SUB(NOW(), INTERVAL 7 DAY), DATE_ADD(NOW(), INTERVAL 180 DAY), NULL,
- NULL, 'manual', 1, '种子:满100减20',
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_coupon_template` WHERE `TemplateCode` = 'SEED-FIXED-20' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_coupon_template` (
- `TemplateCode`, `TemplateName`, `CouponType`, `FaceValue`, `DiscountRate`, `MaxDiscountAmount`,
- `MinOrderAmount`, `TotalQuantity`, `IssuedQuantity`, `PerCustomerLimit`,
- `ValidType`, `ValidStartTime`, `ValidEndTime`, `ValidDaysAfterReceive`,
- `ApplyScopeJson`, `GrantChannel`, `Status`, `Remark`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED-PCT-95', '种子95折券', 'percent_off', NULL, 0.9500, 50.00,
- 50.00, 500, 0, 1,
- 2, NULL, NULL, 30,
- NULL, 'referral', 1, '种子:领取后30天有效,封顶50',
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_coupon_template` WHERE `TemplateCode` = 'SEED-PCT-95' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_coupon_template` (
- `TemplateCode`, `TemplateName`, `CouponType`, `FaceValue`, `DiscountRate`, `MaxDiscountAmount`,
- `MinOrderAmount`, `TotalQuantity`, `IssuedQuantity`, `PerCustomerLimit`,
- `ValidType`, `ValidStartTime`, `ValidEndTime`, `ValidDaysAfterReceive`,
- `ApplyScopeJson`, `GrantChannel`, `Status`, `Remark`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED-SHIP-10', '种子运费抵扣10元', 'shipping_off', 10.00, NULL, NULL,
- 0.00, 200, 0, 3,
- 1, DATE_SUB(NOW(), INTERVAL 3 DAY), DATE_ADD(NOW(), INTERVAL 90 DAY), NULL,
- NULL, 'activity', 1, '种子:运费抵扣',
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_coupon_template` WHERE `TemplateCode` = 'SEED-SHIP-10' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_coupon_template` (
- `TemplateCode`, `TemplateName`, `CouponType`, `FaceValue`, `DiscountRate`, `MaxDiscountAmount`,
- `MinOrderAmount`, `TotalQuantity`, `IssuedQuantity`, `PerCustomerLimit`,
- `ValidType`, `ValidStartTime`, `ValidEndTime`, `ValidDaysAfterReceive`,
- `ApplyScopeJson`, `GrantChannel`, `Status`, `Remark`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED-DRAFT-OFF', '种子草稿立减券', 'direct_off', 5.00, NULL, NULL,
- 0.00, 0, 0, 1,
- 1, NOW(), DATE_ADD(NOW(), INTERVAL 30 DAY), NULL,
- NULL, 'manual', 0, '种子:草稿态模板',
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_coupon_template` WHERE `TemplateCode` = 'SEED-DRAFT-OFF' AND `IsDeleted` = 0
-);
-
-SET @tplFixed := (SELECT `Id` FROM `t_coupon_template` WHERE `TemplateCode` = 'SEED-FIXED-20' AND `IsDeleted` = 0 LIMIT 1);
-SET @tplPct := (SELECT `Id` FROM `t_coupon_template` WHERE `TemplateCode` = 'SEED-PCT-95' AND `IsDeleted` = 0 LIMIT 1);
-SET @tplShip := (SELECT `Id` FROM `t_coupon_template` WHERE `TemplateCode` = 'SEED-SHIP-10' AND `IsDeleted` = 0 LIMIT 1);
-
--- ---------------------------------------------------------------------------
--- 7. 优惠券实例(发券列表 / 我的优惠券)
--- ---------------------------------------------------------------------------
--- 9:可用 / 已用 / 过期
-INSERT INTO `t_coupon_instance` (
- `TemplateId`, `CustomerId`, `CouponCode`, `Status`,
- `ReceiveTime`, `ValidStartTime`, `ValidEndTime`, `UseTime`, `OrderId`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @tplFixed, @referrerId, 'SEED9-FIXED-AVAIL-01', 1,
- DATE_SUB(NOW(), INTERVAL 5 DAY), DATE_SUB(NOW(), INTERVAL 7 DAY), DATE_ADD(NOW(), INTERVAL 180 DAY), NULL, NULL,
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE @tplFixed IS NOT NULL AND NOT EXISTS (
- SELECT 1 FROM `t_coupon_instance` WHERE `CouponCode` = 'SEED9-FIXED-AVAIL-01' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_coupon_instance` (
- `TemplateId`, `CustomerId`, `CouponCode`, `Status`,
- `ReceiveTime`, `ValidStartTime`, `ValidEndTime`, `UseTime`, `OrderId`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @tplPct, @referrerId, 'SEED9-PCT-USED-01', 3,
- DATE_SUB(NOW(), INTERVAL 40 DAY), DATE_SUB(NOW(), INTERVAL 40 DAY), DATE_SUB(NOW(), INTERVAL 10 DAY),
- DATE_SUB(NOW(), INTERVAL 15 DAY), 9009002,
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE @tplPct IS NOT NULL AND NOT EXISTS (
- SELECT 1 FROM `t_coupon_instance` WHERE `CouponCode` = 'SEED9-PCT-USED-01' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_coupon_instance` (
- `TemplateId`, `CustomerId`, `CouponCode`, `Status`,
- `ReceiveTime`, `ValidStartTime`, `ValidEndTime`, `UseTime`, `OrderId`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @tplShip, @referrerId, 'SEED9-SHIP-EXP-01', 4,
- DATE_SUB(NOW(), INTERVAL 60 DAY), DATE_SUB(NOW(), INTERVAL 60 DAY), DATE_SUB(NOW(), INTERVAL 1 DAY), NULL, NULL,
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE @tplShip IS NOT NULL AND NOT EXISTS (
- SELECT 1 FROM `t_coupon_instance` WHERE `CouponCode` = 'SEED9-SHIP-EXP-01' AND `IsDeleted` = 0
-);
-
--- 8:可用 / 锁定
-INSERT INTO `t_coupon_instance` (
- `TemplateId`, `CustomerId`, `CouponCode`, `Status`,
- `ReceiveTime`, `ValidStartTime`, `ValidEndTime`, `UseTime`, `OrderId`, `LockExpireTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @tplFixed, @refereeId, 'SEED8-FIXED-AVAIL-01', 1,
- DATE_SUB(NOW(), INTERVAL 2 DAY), DATE_SUB(NOW(), INTERVAL 7 DAY), DATE_ADD(NOW(), INTERVAL 180 DAY), NULL, NULL, NULL,
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE @tplFixed IS NOT NULL AND NOT EXISTS (
- SELECT 1 FROM `t_coupon_instance` WHERE `CouponCode` = 'SEED8-FIXED-AVAIL-01' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_coupon_instance` (
- `TemplateId`, `CustomerId`, `CouponCode`, `Status`,
- `ReceiveTime`, `ValidStartTime`, `ValidEndTime`, `UseTime`, `OrderId`, `LockExpireTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @tplShip, @refereeId, 'SEED8-SHIP-LOCK-01', 2,
- DATE_SUB(NOW(), INTERVAL 1 DAY), DATE_SUB(NOW(), INTERVAL 3 DAY), DATE_ADD(NOW(), INTERVAL 90 DAY),
- NULL, 9008002, DATE_ADD(NOW(), INTERVAL 30 MINUTE),
- 0, UUID(), 0, NOW()
-FROM DUAL WHERE @tplShip IS NOT NULL AND NOT EXISTS (
- SELECT 1 FROM `t_coupon_instance` WHERE `CouponCode` = 'SEED8-SHIP-LOCK-01' AND `IsDeleted` = 0
-);
-
--- 回写模板已发数量
-UPDATE `t_coupon_template` t
-SET t.`IssuedQuantity` = (
- SELECT COUNT(*) FROM `t_coupon_instance` i
- WHERE i.`TemplateId` = t.`Id` AND i.`IsDeleted` = 0
-)
-WHERE t.`TemplateCode` IN ('SEED-FIXED-20', 'SEED-PCT-95', 'SEED-SHIP-10', 'SEED-DRAFT-OFF')
- AND t.`IsDeleted` = 0;
-
--- ---------------------------------------------------------------------------
--- 8. 分成明细(分成明细 / 推荐收益):引荐人=9,被引荐人=8
--- ---------------------------------------------------------------------------
-SET @ruleSnap := JSON_OBJECT(
- 'RuleName', '默认分成',
- 'CommissionMode', 'per_amount',
- 'BaseAmount', 1000,
- 'CommissionAmount', 2,
- 'FreezeDays', 7
-);
-
--- 待结算
-INSERT INTO `t_referral_commission_detail` (
- `ReferrerCustomerId`, `RefereeCustomerId`, `OrderId`, `OrderNo`,
- `BasePayableAmount`, `CommissionAmount`, `Status`,
- `EligibleTime`, `SettleTime`, `RuleSnapshotJson`, `CancelReason`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @referrerId, @refereeId, 9008001, 'SEED-MKT-ORD-8001',
- 3500.00, 6.00, 1,
- DATE_SUB(NOW(), INTERVAL 2 DAY), NULL, @ruleSnap, NULL,
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 2 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_referral_commission_detail`
- WHERE `OrderId` = 9008001 AND `ReferrerCustomerId` = @referrerId AND `IsDeleted` = 0
-);
-
--- 已结算
-INSERT INTO `t_referral_commission_detail` (
- `ReferrerCustomerId`, `RefereeCustomerId`, `OrderId`, `OrderNo`,
- `BasePayableAmount`, `CommissionAmount`, `Status`,
- `EligibleTime`, `SettleTime`, `RuleSnapshotJson`, `CancelReason`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @referrerId, @refereeId, 9008002, 'SEED-MKT-ORD-8002',
- 5200.00, 10.00, 2,
- DATE_SUB(NOW(), INTERVAL 20 DAY), DATE_SUB(NOW(), INTERVAL 13 DAY), @ruleSnap, NULL,
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 20 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_referral_commission_detail`
- WHERE `OrderId` = 9008002 AND `ReferrerCustomerId` = @referrerId AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_referral_commission_detail` (
- `ReferrerCustomerId`, `RefereeCustomerId`, `OrderId`, `OrderNo`,
- `BasePayableAmount`, `CommissionAmount`, `Status`,
- `EligibleTime`, `SettleTime`, `RuleSnapshotJson`, `CancelReason`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @referrerId, @refereeId, 9008003, 'SEED-MKT-ORD-8003',
- 1800.00, 2.00, 2,
- DATE_SUB(NOW(), INTERVAL 35 DAY), DATE_SUB(NOW(), INTERVAL 28 DAY), @ruleSnap, NULL,
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 35 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_referral_commission_detail`
- WHERE `OrderId` = 9008003 AND `ReferrerCustomerId` = @referrerId AND `IsDeleted` = 0
-);
-
--- 已取消(人工调整演示)
-INSERT INTO `t_referral_commission_detail` (
- `ReferrerCustomerId`, `RefereeCustomerId`, `OrderId`, `OrderNo`,
- `BasePayableAmount`, `CommissionAmount`, `Status`,
- `EligibleTime`, `SettleTime`, `RuleSnapshotJson`, `CancelReason`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @referrerId, @refereeId, 9008004, 'SEED-MKT-ORD-8004',
- 1000.00, 2.00, 3,
- DATE_SUB(NOW(), INTERVAL 10 DAY), NULL, @ruleSnap, '种子:订单退款取消分成',
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 10 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_referral_commission_detail`
- WHERE `OrderId` = 9008004 AND `ReferrerCustomerId` = @referrerId AND `IsDeleted` = 0
-);
-
--- ---------------------------------------------------------------------------
--- 9. 提现申请(提现审核 / 推荐收益)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_commission_withdraw_request` (
- `CustomerId`, `SerialNumber`, `Amount`, `WithdrawType`, `Status`,
- `Remark`, `AuditRemark`, `AuditBy`, `AuditTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @referrerId, 'SEED-WD-9-PENDING-01', 50.00, 1, 1,
- '种子:申请提现到外部账户', NULL, NULL, NULL,
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 1 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_commission_withdraw_request`
- WHERE `SerialNumber` = 'SEED-WD-9-PENDING-01' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_commission_withdraw_request` (
- `CustomerId`, `SerialNumber`, `Amount`, `WithdrawType`, `Status`,
- `Remark`, `AuditRemark`, `AuditBy`, `AuditTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @referrerId, 'SEED-WD-9-APPROVED-01', 30.00, 2, 2,
- '种子:转入余额', '审核通过-种子数据', 'admin', DATE_SUB(NOW(), INTERVAL 5 DAY),
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 6 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_commission_withdraw_request`
- WHERE `SerialNumber` = 'SEED-WD-9-APPROVED-01' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_commission_withdraw_request` (
- `CustomerId`, `SerialNumber`, `Amount`, `WithdrawType`, `Status`,
- `Remark`, `AuditRemark`, `AuditBy`, `AuditTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @referrerId, 'SEED-WD-9-REJECTED-01', 20.00, 1, 3,
- '种子:提现申请', '驳回原因:收款信息不完整(种子)', 'admin', DATE_SUB(NOW(), INTERVAL 8 DAY),
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 9 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_commission_withdraw_request`
- WHERE `SerialNumber` = 'SEED-WD-9-REJECTED-01' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_commission_withdraw_request` (
- `CustomerId`, `SerialNumber`, `Amount`, `WithdrawType`, `Status`,
- `Remark`, `AuditRemark`, `AuditBy`, `AuditTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @referrerId, 'SEED-WD-9-PAID-01', 40.00, 1, 4,
- '种子:已打款', '已打款-种子数据', 'admin', DATE_SUB(NOW(), INTERVAL 15 DAY),
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 16 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_commission_withdraw_request`
- WHERE `SerialNumber` = 'SEED-WD-9-PAID-01' AND `IsDeleted` = 0
-);
-
--- ---------------------------------------------------------------------------
--- 10. 审计日志(高危操作痕迹,便于联调)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_marketing_audit_log` (
- `Action`, `OperatorId`, `TargetType`, `TargetId`,
- `BeforeJson`, `AfterJson`, `Remark`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'grantCoupon', 0, 'customer', @referrerId,
- NULL,
- JSON_OBJECT('templateCode', 'SEED-FIXED-20', 'couponCode', 'SEED9-FIXED-AVAIL-01'),
- '种子:批量发券演示',
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 5 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_marketing_audit_log`
- WHERE `Action` = 'grantCoupon' AND `Remark` = '种子:批量发券演示' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_marketing_audit_log` (
- `Action`, `OperatorId`, `TargetType`, `TargetId`,
- `BeforeJson`, `AfterJson`, `Remark`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'adjustPoints', 0, 'customer', @referrerId,
- JSON_OBJECT('availablePoints', 24000),
- JSON_OBJECT('availablePoints', 24500, 'delta', 500),
- '种子:人工调账加分(演示用不少于十字原因)',
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 3 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_marketing_audit_log`
- WHERE `Action` = 'adjustPoints' AND `TargetId` = @referrerId
- AND `Remark` LIKE '种子:人工调账%' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_marketing_audit_log` (
- `Action`, `OperatorId`, `TargetType`, `TargetId`,
- `BeforeJson`, `AfterJson`, `Remark`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'bindReferral', 0, 'customer', @refereeId,
- JSON_OBJECT('referrerCustomerId', NULL),
- JSON_OBJECT('referrerCustomerId', @referrerId, 'channel', 'link'),
- '种子:绑定引荐关系 8←9',
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 45 DAY)
-FROM DUAL WHERE NOT EXISTS (
- SELECT 1 FROM `t_marketing_audit_log`
- WHERE `Action` = 'bindReferral' AND `TargetId` = @refereeId AND `IsDeleted` = 0
-);
-
--- ---------------------------------------------------------------------------
--- 11. 结果核对
--- ---------------------------------------------------------------------------
-SELECT 'precheck_customers' AS item,
- (SELECT COUNT(*) FROM `t_customer` WHERE `Id` IN (@referrerId, @refereeId) AND `IsDeleted` = 0) AS cnt
-UNION ALL
-SELECT 'referral_bind_8_to_9',
- (SELECT COUNT(*) FROM `t_customer`
- WHERE `Id` = @refereeId AND `ReferrerCustomerId` = @referrerId AND `ParentCustomerId` IS NULL AND `IsDeleted` = 0)
-UNION ALL
-SELECT 'referral_codes',
- (SELECT COUNT(*) FROM `t_customer_referral_code`
- WHERE `CustomerId` IN (@referrerId, @refereeId) AND `IsDeleted` = 0)
-UNION ALL
-SELECT 'points_accounts',
- (SELECT COUNT(*) FROM `t_customer_points_account`
- WHERE `CustomerId` IN (@referrerId, @refereeId) AND `IsDeleted` = 0)
-UNION ALL
-SELECT 'points_flows',
- (SELECT COUNT(*) FROM `t_customer_points_flow`
- WHERE `CustomerId` IN (@referrerId, @refereeId) AND `BizNo` LIKE 'SEED-MKT-%' AND `IsDeleted` = 0)
-UNION ALL
-SELECT 'coupon_templates',
- (SELECT COUNT(*) FROM `t_coupon_template`
- WHERE `TemplateCode` LIKE 'SEED-%' AND `IsDeleted` = 0)
-UNION ALL
-SELECT 'coupon_instances',
- (SELECT COUNT(*) FROM `t_coupon_instance`
- WHERE `CouponCode` LIKE 'SEED%' AND `IsDeleted` = 0)
-UNION ALL
-SELECT 'commission_details',
- (SELECT COUNT(*) FROM `t_referral_commission_detail`
- WHERE `ReferrerCustomerId` = @referrerId AND `RefereeCustomerId` = @refereeId AND `IsDeleted` = 0)
-UNION ALL
-SELECT 'withdraw_requests',
- (SELECT COUNT(*) FROM `t_commission_withdraw_request`
- WHERE `CustomerId` = @referrerId AND `SerialNumber` LIKE 'SEED-WD-9-%' AND `IsDeleted` = 0)
-UNION ALL
-SELECT 'audit_logs',
- (SELECT COUNT(*) FROM `t_marketing_audit_log`
- WHERE `Remark` LIKE '种子:%' AND `IsDeleted` = 0);
diff --git a/sql/seed_pickup_order_customer9.sql b/sql/seed_pickup_order_customer9.sql
deleted file mode 100644
index 07388df..0000000
--- a/sql/seed_pickup_order_customer9.sql
+++ /dev/null
@@ -1,306 +0,0 @@
--- 揽收订单种子(CustomerId = 9,OrderSource = pickup)
--- 可重复执行:已存在则跳过
--- 用法:mysql -u root -p oms < sql/seed_pickup_order_customer9.sql
---
--- 依赖:t_customer.Id=9 存在;仓库/销售产品尽量取库内已有,否则用占位编码
-
-SET NAMES utf8mb4;
-
-SET @customerId := 9;
-
--- ---------------------------------------------------------------------------
--- 0. 修复 t_order 脏 ConcurrencyStamp(空串无法绑 Guid)
--- ---------------------------------------------------------------------------
-UPDATE `t_order`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL
- OR TRIM(`ConcurrencyStamp`) = ''
- OR LENGTH(TRIM(`ConcurrencyStamp`)) <> 36;
-
--- ---------------------------------------------------------------------------
--- 1. 发件地址簿(揽收创建依赖)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_customer_sender_address` (
- `CustomerId`, `AddressType`, `AddressName`, `SenderName`, `Company`,
- `Province`, `City`, `ZipCode`, `StreetAddress1`, `Phone`,
- `IsDefault`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT @customerId, 'sender', '种子-默认发件', '张三', '种子发件公司',
- '广东省', '深圳市', '518000', '南山区科技园种子路 1 号', '13800000009',
- 1, 0, UUID(), 0, NOW()
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_customer_sender_address`
- WHERE `CustomerId` = @customerId
- AND `AddressType` = 'sender'
- AND `AddressName` = '种子-默认发件'
- AND `IsDeleted` = 0
-);
-
-SET @senderAddressId := (
- SELECT `Id` FROM `t_customer_sender_address`
- WHERE `CustomerId` = @customerId
- AND `AddressType` = 'sender'
- AND `AddressName` = '种子-默认发件'
- AND `IsDeleted` = 0
- ORDER BY `Id`
- LIMIT 1
-);
-
--- 仓库:优先取已有;没有则插入一条种子仓
-INSERT INTO `t_warehouse_address` (
- `WarehouseName`, `WarehouseType`, `Recipient`, `ContactPhone`, `ShippingAddress`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT '种子-深圳仓', 'main', '仓管员', '0755-80000009', '广东省深圳市南山区仓库大道 9 号',
- 0, UUID(), 0, NOW()
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_warehouse_address` WHERE `IsDeleted` = 0 LIMIT 1
-)
-AND NOT EXISTS (
- SELECT 1 FROM `t_warehouse_address` WHERE `WarehouseName` = '种子-深圳仓' AND `IsDeleted` = 0
-);
-
-SET @warehouseId := (
- SELECT `Id` FROM `t_warehouse_address`
- WHERE `IsDeleted` = 0
- ORDER BY CASE WHEN `WarehouseName` = '种子-深圳仓' THEN 0 ELSE 1 END, `Id`
- LIMIT 1
-);
-
-SET @productCode := (
- SELECT `ProductCode` FROM `t_sales_product`
- WHERE `IsDeleted` = 0
- ORDER BY `Id`
- LIMIT 1
-);
-SET @productCode := IFNULL(NULLIF(TRIM(@productCode), ''), 'SEED-PICKUP-PRODUCT');
-
--- ---------------------------------------------------------------------------
--- 2. 揽收订单 t_order(若干状态)
--- ---------------------------------------------------------------------------
-
--- draft
-INSERT INTO `t_order` (
- `RequestId`, `ServiceNo`, `ClientNo`, `ProductCode`, `ChannelCode`,
- `ConsigneeCountry`, `ConsigneeCountryName`, `CargoAttribute`,
- `OrderStatus`, `HandleStatus`, `WarehouseId`, `CustomerId`,
- `OrderSource`, `PickupTime`, `CustomerSenderAddressId`,
- `DeclaredCurrency`, `DeclaredSum`, `Quantity`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED9-PK-REQ-001', 'SEED9-PK-001', 'PK-CLIENT-001', @productCode, @productCode,
- 'CN', '中国', 'general',
- 'draft', 'pending', @warehouseId, @customerId,
- 'pickup', DATE_ADD(NOW(), INTERVAL 1 DAY), @senderAddressId,
- 'CNY', 1.0000, 1,
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 2 DAY)
-WHERE @warehouseId IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM `t_order` WHERE `ServiceNo` = 'SEED9-PK-001');
-
--- pendingPayment
-INSERT INTO `t_order` (
- `RequestId`, `ServiceNo`, `ClientNo`, `ProductCode`, `ChannelCode`,
- `ConsigneeCountry`, `ConsigneeCountryName`, `CargoAttribute`,
- `OrderStatus`, `HandleStatus`, `WarehouseId`, `CustomerId`,
- `OrderSource`, `PickupTime`, `CustomerSenderAddressId`,
- `DeclaredCurrency`, `DeclaredSum`, `Quantity`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED9-PK-REQ-002', 'SEED9-PK-002', 'PK-CLIENT-002', @productCode, @productCode,
- 'CN', '中国', 'general',
- 'pendingPayment', 'pending', @warehouseId, @customerId,
- 'pickup', DATE_ADD(NOW(), INTERVAL 2 DAY), @senderAddressId,
- 'CNY', 1.0000, 1,
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 1 DAY)
-WHERE @warehouseId IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM `t_order` WHERE `ServiceNo` = 'SEED9-PK-002');
-
--- pendingShip
-INSERT INTO `t_order` (
- `RequestId`, `ServiceNo`, `ClientNo`, `ProductCode`, `ChannelCode`,
- `ConsigneeCountry`, `ConsigneeCountryName`, `CargoAttribute`,
- `OrderStatus`, `HandleStatus`, `WarehouseId`, `CustomerId`,
- `OrderSource`, `PickupTime`, `CustomerSenderAddressId`,
- `DeclaredCurrency`, `DeclaredSum`, `Quantity`,
- `IsPaid`, `PayTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED9-PK-REQ-003', 'SEED9-PK-003', 'PK-CLIENT-003', @productCode, @productCode,
- 'CN', '中国', 'electronics',
- 'pendingShip', 'pending', @warehouseId, @customerId,
- 'pickup', DATE_ADD(NOW(), INTERVAL 3 DAY), @senderAddressId,
- 'CNY', 1.0000, 1,
- 1, DATE_SUB(NOW(), INTERVAL 6 HOUR),
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 12 HOUR)
-WHERE @warehouseId IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM `t_order` WHERE `ServiceNo` = 'SEED9-PK-003');
-
--- received
-INSERT INTO `t_order` (
- `RequestId`, `ServiceNo`, `ClientNo`, `ProductCode`, `ChannelCode`,
- `ConsigneeCountry`, `ConsigneeCountryName`, `CargoAttribute`,
- `OrderStatus`, `HandleStatus`, `WarehouseId`, `CustomerId`,
- `OrderSource`, `PickupTime`, `CustomerSenderAddressId`,
- `DeclaredCurrency`, `DeclaredSum`, `Quantity`,
- `ReceiveTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED9-PK-REQ-004', 'SEED9-PK-004', 'PK-CLIENT-004', @productCode, @productCode,
- 'CN', '中国', 'general',
- 'received', 'processed', @warehouseId, @customerId,
- 'pickup', DATE_SUB(NOW(), INTERVAL 1 DAY), @senderAddressId,
- 'CNY', 1.0000, 1,
- DATE_SUB(NOW(), INTERVAL 8 HOUR),
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 3 DAY)
-WHERE @warehouseId IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM `t_order` WHERE `ServiceNo` = 'SEED9-PK-004');
-
--- pendingOnline
-INSERT INTO `t_order` (
- `RequestId`, `ServiceNo`, `ClientNo`, `ProductCode`, `ChannelCode`,
- `ConsigneeCountry`, `ConsigneeCountryName`, `CargoAttribute`,
- `OrderStatus`, `HandleStatus`, `WarehouseId`, `CustomerId`,
- `OrderSource`, `PickupTime`, `CustomerSenderAddressId`,
- `DeclaredCurrency`, `DeclaredSum`, `Quantity`,
- `IsPaid`, `PayTime`, `ShipTime`,
- `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT
- 'SEED9-PK-REQ-005', 'SEED9-PK-005', 'PK-CLIENT-005', @productCode, @productCode,
- 'CN', '中国', 'general',
- 'pendingOnline', 'processed', @warehouseId, @customerId,
- 'pickup', DATE_SUB(NOW(), INTERVAL 2 DAY), @senderAddressId,
- 'CNY', 1.0000, 1,
- 1, DATE_SUB(NOW(), INTERVAL 2 DAY), DATE_SUB(NOW(), INTERVAL 1 DAY),
- 0, UUID(), 0, DATE_SUB(NOW(), INTERVAL 4 DAY)
-WHERE @warehouseId IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM `t_order` WHERE `ServiceNo` = 'SEED9-PK-005');
-
--- ---------------------------------------------------------------------------
--- 3. 子表:发件人 / 收件人 / 申报 / 件重尺
--- ---------------------------------------------------------------------------
-
--- 发件人
-INSERT INTO `t_order_sender` (
- `OrderId`, `SenderName`, `Company`, `Province`, `City`, `ZipCode`,
- `StreetAddress1`, `Phone`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, '张三', '种子发件公司', '广东省', '深圳市', '518000',
- '南山区科技园种子路 1 号', '13800000009', 0, 0, NOW()
-FROM `t_order` o
-WHERE o.`ServiceNo` IN ('SEED9-PK-001','SEED9-PK-002','SEED9-PK-003','SEED9-PK-004','SEED9-PK-005')
- AND o.`CustomerId` = @customerId
- AND o.`OrderSource` = 'pickup'
- AND NOT EXISTS (SELECT 1 FROM `t_order_sender` s WHERE s.`OrderId` = o.`Id` AND s.`IsDeleted` = 0);
-
--- 收件人(仓库)
-INSERT INTO `t_order_recipient` (
- `OrderId`, `RecipientsName`, `Phone`, `ZipCode`, `StreetAddress1`,
- `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`,
- IFNULL(NULLIF(TRIM(w.`Recipient`), ''), IFNULL(w.`WarehouseName`, '种子仓')),
- w.`ContactPhone`,
- '000000',
- IFNULL(NULLIF(TRIM(w.`ShippingAddress`), ''), IFNULL(w.`WarehouseName`, '种子仓地址')),
- 0, 0, NOW()
-FROM `t_order` o
-LEFT JOIN `t_warehouse_address` w ON w.`Id` = o.`WarehouseId`
-WHERE o.`ServiceNo` IN ('SEED9-PK-001','SEED9-PK-002','SEED9-PK-003','SEED9-PK-004','SEED9-PK-005')
- AND o.`CustomerId` = @customerId
- AND o.`OrderSource` = 'pickup'
- AND NOT EXISTS (SELECT 1 FROM `t_order_recipient` r WHERE r.`OrderId` = o.`Id` AND r.`IsDeleted` = 0);
-
--- 申报行(货物名称)
-INSERT INTO `t_order_declaration` (
- `OrderId`, `CnName`, `EnName`, `UnitPrice`, `UnitWeight`, `Quantity`, `Amount`, `Weight`,
- `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`,
- CASE o.`ServiceNo`
- WHEN 'SEED9-PK-001' THEN '日用百货样品'
- WHEN 'SEED9-PK-002' THEN '服装配件'
- WHEN 'SEED9-PK-003' THEN '蓝牙耳机'
- WHEN 'SEED9-PK-004' THEN '家居收纳盒'
- ELSE '办公文具套装'
- END,
- CASE o.`ServiceNo`
- WHEN 'SEED9-PK-001' THEN 'Daily Sample Goods'
- WHEN 'SEED9-PK-002' THEN 'Apparel Accessories'
- WHEN 'SEED9-PK-003' THEN 'Bluetooth Earbuds'
- WHEN 'SEED9-PK-004' THEN 'Storage Box'
- ELSE 'Stationery Set'
- END,
- 1.00,
- CASE o.`ServiceNo`
- WHEN 'SEED9-PK-001' THEN 0.500
- WHEN 'SEED9-PK-002' THEN 1.200
- WHEN 'SEED9-PK-003' THEN 0.350
- WHEN 'SEED9-PK-004' THEN 2.000
- ELSE 0.800
- END,
- 1,
- 1.00,
- CASE o.`ServiceNo`
- WHEN 'SEED9-PK-001' THEN 0.500
- WHEN 'SEED9-PK-002' THEN 1.200
- WHEN 'SEED9-PK-003' THEN 0.350
- WHEN 'SEED9-PK-004' THEN 2.000
- ELSE 0.800
- END,
- 0, 0, NOW()
-FROM `t_order` o
-WHERE o.`ServiceNo` IN ('SEED9-PK-001','SEED9-PK-002','SEED9-PK-003','SEED9-PK-004','SEED9-PK-005')
- AND o.`CustomerId` = @customerId
- AND o.`OrderSource` = 'pickup'
- AND NOT EXISTS (SELECT 1 FROM `t_order_declaration` d WHERE d.`OrderId` = o.`Id` AND d.`IsDeleted` = 0);
-
--- 预报件重尺
-INSERT INTO `t_order_weight` (
- `OrderId`, `Type`, `Length`, `Width`, `Height`, `ActualWeight`, `VolumetricWeight`, `ChargeableWeight`,
- `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'forecast', 1.00, 1.00, 1.00,
- CASE o.`ServiceNo`
- WHEN 'SEED9-PK-001' THEN 0.500
- WHEN 'SEED9-PK-002' THEN 1.200
- WHEN 'SEED9-PK-003' THEN 0.350
- WHEN 'SEED9-PK-004' THEN 2.000
- ELSE 0.800
- END,
- 0.001,
- CASE o.`ServiceNo`
- WHEN 'SEED9-PK-001' THEN 0.500
- WHEN 'SEED9-PK-002' THEN 1.200
- WHEN 'SEED9-PK-003' THEN 0.350
- WHEN 'SEED9-PK-004' THEN 2.000
- ELSE 0.800
- END,
- 0, 0, NOW()
-FROM `t_order` o
-WHERE o.`ServiceNo` IN ('SEED9-PK-001','SEED9-PK-002','SEED9-PK-003','SEED9-PK-004','SEED9-PK-005')
- AND o.`CustomerId` = @customerId
- AND o.`OrderSource` = 'pickup'
- AND NOT EXISTS (
- SELECT 1 FROM `t_order_weight` w
- WHERE w.`OrderId` = o.`Id` AND w.`Type` = 'forecast' AND w.`IsDeleted` = 0
- );
-
--- ---------------------------------------------------------------------------
--- 4. 摘要
--- ---------------------------------------------------------------------------
-SELECT 'pickup_orders' AS tbl, COUNT(*) AS cnt
-FROM `t_order`
-WHERE `CustomerId` = @customerId AND `OrderSource` = 'pickup' AND `IsDeleted` = 0
-UNION ALL
-SELECT 'sender_address', COUNT(*)
-FROM `t_customer_sender_address`
-WHERE `CustomerId` = @customerId AND `AddressType` = 'sender' AND `IsDeleted` = 0
-UNION ALL
-SELECT 'warehouse_used', IF(@warehouseId IS NULL, 0, 1)
-UNION ALL
-SELECT 'product_code', IF(@productCode IS NULL OR @productCode = '', 0, 1);
diff --git a/sql/seed_platform_shop_other_config.sql b/sql/seed_platform_shop_other_config.sql
deleted file mode 100644
index 6da4d51..0000000
--- a/sql/seed_platform_shop_other_config.sql
+++ /dev/null
@@ -1,47 +0,0 @@
--- 店铺平台 OAuth 配置种子(其他配置页可改;已存在则跳过)
-INSERT INTO t_system_other_config
- (ConfigCode, ConfigName, Enabled, BaseUrl, AppKey, AppSecret, TimeoutSeconds, Remark, IsDeleted, CreateTime)
-SELECT 'platform_shop', '店铺授权-公共', 1, 'http://localhost:5173', NULL, NULL, 30, NULL, 0, NOW()
-WHERE NOT EXISTS (SELECT 1 FROM t_system_other_config WHERE ConfigCode = 'platform_shop' AND IsDeleted = 0);
-
-INSERT INTO t_system_other_config
- (ConfigCode, ConfigName, Enabled, BaseUrl, AppKey, AppSecret, TimeoutSeconds, Remark, IsDeleted, CreateTime)
-SELECT 'platform_shop_tiktok', '店铺授权-TikTok', 1,
- 'https://auth.tiktok-shops.com',
- '6hc64lc6vl312',
- '5a691a96ee6d844534769bab5c21de1f848fb678',
- 30,
- 'https://open-api.tiktokglobalshop.com',
- 0, NOW()
-WHERE NOT EXISTS (SELECT 1 FROM t_system_other_config WHERE ConfigCode = 'platform_shop_tiktok' AND IsDeleted = 0);
-
-INSERT INTO t_system_other_config
- (ConfigCode, ConfigName, Enabled, BaseUrl, AppKey, AppSecret, TimeoutSeconds, Remark, IsDeleted, CreateTime)
-SELECT 'platform_shop_temu', '店铺授权-Temu', 1,
- 'https://openapi-b-us.temu.com/openapi/router',
- '4ebbc9190ae410443d65b4c2faca981f',
- '4782d2d827276688bf4758bed55dbdd4bbe79a79',
- 30, NULL, 0, NOW()
-WHERE NOT EXISTS (SELECT 1 FROM t_system_other_config WHERE ConfigCode = 'platform_shop_temu' AND IsDeleted = 0);
-
-INSERT INTO t_system_other_config
- (ConfigCode, ConfigName, Enabled, BaseUrl, AppKey, AppSecret, TimeoutSeconds, Remark, IsDeleted, CreateTime)
-SELECT 'platform_shop_shopee', '店铺授权-Shopee', 1,
- 'https://partner.shopeemobile.com',
- '2004112',
- '2f385d7ea38b087d5d71f7292e06a09c9f19022ca6c3f60ec0110a8214ef7d65',
- 30,
- 'https://openplatform.shopee.cn',
- 0, NOW()
-WHERE NOT EXISTS (SELECT 1 FROM t_system_other_config WHERE ConfigCode = 'platform_shop_shopee' AND IsDeleted = 0);
-
-INSERT INTO t_system_other_config
- (ConfigCode, ConfigName, Enabled, BaseUrl, AppKey, AppSecret, TimeoutSeconds, Remark, IsDeleted, CreateTime)
-SELECT 'platform_shop_lazada', '店铺授权-Lazada', 1,
- 'https://auth.lazada.com/oauth/authorize',
- '123631',
- '7vBz2EaD6rIupeGEfwrgkabsTNsXt2ix',
- 30,
- 'https://auth.lazada.com/rest',
- 0, NOW()
-WHERE NOT EXISTS (SELECT 1 FROM t_system_other_config WHERE ConfigCode = 'platform_shop_lazada' AND IsDeleted = 0);
diff --git a/sql/seed_sales_store_customer9.sql b/sql/seed_sales_store_customer9.sql
deleted file mode 100644
index 58b9257..0000000
--- a/sql/seed_sales_store_customer9.sql
+++ /dev/null
@@ -1,510 +0,0 @@
--- 店铺授权 + 店铺订单种子(CustomerId = 9)
--- 可重复执行:已存在则跳过
--- 用法:
--- 1) mysql -u root -p oms < sql/migrate_t_sales_store_order_recipient.sql
--- 2) mysql -u root -p oms < sql/seed_sales_store_customer9.sql
---
--- 注意:ConcurrencyStamp 必须是合法 Guid 字符串;空串会导致
--- 「ConcurrencyStamp绑定到SalesStoreOrder失败」
-
-SET NAMES utf8mb4;
-
--- 先修好已有脏数据(空串 / 非 36 位)
-UPDATE `t_sales_store`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL OR TRIM(`ConcurrencyStamp`) = '' OR LENGTH(TRIM(`ConcurrencyStamp`)) <> 36;
-UPDATE `t_sales_store_order`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL OR TRIM(`ConcurrencyStamp`) = '' OR LENGTH(TRIM(`ConcurrencyStamp`)) <> 36;
-UPDATE `t_sales_store_order_line`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL OR TRIM(`ConcurrencyStamp`) = '' OR LENGTH(TRIM(`ConcurrencyStamp`)) <> 36;
-
--- ---------------------------------------------------------------------------
--- 1. 店铺授权 t_sales_store(4 个平台,覆盖 active/expired)
--- ---------------------------------------------------------------------------
-INSERT INTO `t_sales_store` (
- `CustomerId`, `PlatformCode`, `StoreNickname`, `PlatformStoreId`, `PlatformAccount`,
- `SiteCountry`, `SellerId`, `AuthStatus`, `AuthTime`, `TokenExpireTime`, `RefreshExpireTime`,
- `AccessToken`, `RefreshToken`, `IsAutoFulfill`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, 'shopee', '种子-Shopee旗舰店', 'SEED9-SHOPEE-001', 'seed9.shopee@demo.com',
- 'SG', 'SELLER-SHOPEE-9001', 'active',
- DATE_SUB(NOW(), INTERVAL 30 DAY), DATE_ADD(NOW(), INTERVAL 60 DAY), DATE_ADD(NOW(), INTERVAL 180 DAY),
- 'seed_access_token_shopee_9', 'seed_refresh_token_shopee_9', 1, 'CustomerId=9 种子店铺', 0, UUID(), 0, NOW()
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_sales_store`
- WHERE `CustomerId` = 9 AND `PlatformStoreId` = 'SEED9-SHOPEE-001' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_sales_store` (
- `CustomerId`, `PlatformCode`, `StoreNickname`, `PlatformStoreId`, `PlatformAccount`,
- `SiteCountry`, `SellerId`, `AuthStatus`, `AuthTime`, `TokenExpireTime`, `RefreshExpireTime`,
- `AccessToken`, `RefreshToken`, `IsAutoFulfill`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, 'lazada', '种子-Lazada马来店', 'SEED9-LAZADA-001', 'seed9.lazada@demo.com',
- 'MY', 'SELLER-LAZADA-9002', 'active',
- DATE_SUB(NOW(), INTERVAL 14 DAY), DATE_ADD(NOW(), INTERVAL 45 DAY), DATE_ADD(NOW(), INTERVAL 120 DAY),
- 'seed_access_token_lazada_9', 'seed_refresh_token_lazada_9', 0, 'CustomerId=9 种子店铺', 0, UUID(), 0, NOW()
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_sales_store`
- WHERE `CustomerId` = 9 AND `PlatformStoreId` = 'SEED9-LAZADA-001' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_sales_store` (
- `CustomerId`, `PlatformCode`, `StoreNickname`, `PlatformStoreId`, `PlatformAccount`,
- `SiteCountry`, `SellerId`, `AuthStatus`, `AuthTime`, `TokenExpireTime`, `RefreshExpireTime`,
- `AccessToken`, `RefreshToken`, `IsAutoFulfill`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, 'tiktok', '种子-TikTok跨境店', 'SEED9-TIKTOK-001', 'seed9.tiktok@demo.com',
- 'US', 'SELLER-TIKTOK-9003', 'active',
- DATE_SUB(NOW(), INTERVAL 7 DAY), DATE_ADD(NOW(), INTERVAL 30 DAY), DATE_ADD(NOW(), INTERVAL 90 DAY),
- 'seed_access_token_tiktok_9', 'seed_refresh_token_tiktok_9', 1, 'CustomerId=9 种子店铺', 0, UUID(), 0, NOW()
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_sales_store`
- WHERE `CustomerId` = 9 AND `PlatformStoreId` = 'SEED9-TIKTOK-001' AND `IsDeleted` = 0
-);
-
-INSERT INTO `t_sales_store` (
- `CustomerId`, `PlatformCode`, `StoreNickname`, `PlatformStoreId`, `PlatformAccount`,
- `SiteCountry`, `SellerId`, `AuthStatus`, `AuthTime`, `TokenExpireTime`, `RefreshExpireTime`,
- `AccessToken`, `RefreshToken`, `IsAutoFulfill`, `Remark`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, 'temu', '种子-Temu美区店(已过期)', 'SEED9-TEMU-001', 'seed9.temu@demo.com',
- 'US', 'SELLER-TEMU-9004', 'expired',
- DATE_SUB(NOW(), INTERVAL 90 DAY), DATE_SUB(NOW(), INTERVAL 5 DAY), DATE_SUB(NOW(), INTERVAL 1 DAY),
- 'seed_access_token_temu_9_expired', 'seed_refresh_token_temu_9_expired', 0, 'CustomerId=9 种子店铺-授权过期', 0, UUID(), 0, NOW()
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_sales_store`
- WHERE `CustomerId` = 9 AND `PlatformStoreId` = 'SEED9-TEMU-001' AND `IsDeleted` = 0
-);
-
--- ---------------------------------------------------------------------------
--- 2. 店铺订单 t_sales_store_order(覆盖各履约状态)
--- ---------------------------------------------------------------------------
-
--- pending
-INSERT INTO `t_sales_store_order` (
- `CustomerId`, `StoreId`, `PlatformCode`, `PlatformOrderNo`, `OrderCountry`,
- `ItemCount`, `TotalAmount`, `Currency`, `PlatformOrderTime`, `FulfillStatus`,
- `PlatformStatus`, `PlatformStatusLabel`, `IsMultiLabel`, `IsSuspended`,
- `LastSyncTime`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, s.`Id`, 'shopee', 'SEED9-ORD-SHOPEE-P001', 'SG',
- 2, 45.8000, 'SGD', DATE_SUB(NOW(), INTERVAL 2 HOUR), 'pending',
- 'UNPAID', '待付款', 0, 0,
- NOW(), 0, 0, NOW()
-FROM `t_sales_store` s
-WHERE s.`CustomerId` = 9 AND s.`PlatformStoreId` = 'SEED9-SHOPEE-001' AND s.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order` o
- WHERE o.`StoreId` = s.`Id` AND o.`PlatformOrderNo` = 'SEED9-ORD-SHOPEE-P001' AND o.`IsDeleted` = 0
- );
-
--- toShip
-INSERT INTO `t_sales_store_order` (
- `CustomerId`, `StoreId`, `PlatformCode`, `PlatformOrderNo`, `OrderCountry`,
- `ItemCount`, `TotalAmount`, `Currency`, `PlatformOrderTime`, `FulfillStatus`,
- `PlatformStatus`, `PlatformStatusLabel`, `IsMultiLabel`, `CustomTags`, `IsSuspended`,
- `LastSyncTime`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, s.`Id`, 'shopee', 'SEED9-ORD-SHOPEE-T001', 'SG',
- 1, 28.5000, 'SGD', DATE_SUB(NOW(), INTERVAL 1 DAY), 'toShip',
- 'READY_TO_SHIP', '待发货', 0, '急单', 0,
- NOW(), 0, 0, NOW()
-FROM `t_sales_store` s
-WHERE s.`CustomerId` = 9 AND s.`PlatformStoreId` = 'SEED9-SHOPEE-001' AND s.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order` o
- WHERE o.`StoreId` = s.`Id` AND o.`PlatformOrderNo` = 'SEED9-ORD-SHOPEE-T001' AND o.`IsDeleted` = 0
- );
-
--- shipped
-INSERT INTO `t_sales_store_order` (
- `CustomerId`, `StoreId`, `PlatformCode`, `PlatformOrderNo`, `OrderCountry`,
- `ItemCount`, `TotalAmount`, `Currency`, `PlatformOrderTime`, `FulfillStatus`,
- `PlatformStatus`, `PlatformStatusLabel`, `ShippingLabelNo`, `ShippingLabelUrl`,
- `IsMultiLabel`, `IsSuspended`, `LastSyncTime`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, s.`Id`, 'lazada', 'SEED9-ORD-LAZADA-S001', 'MY',
- 3, 129.9000, 'MYR', DATE_SUB(NOW(), INTERVAL 3 DAY), 'shipped',
- 'SHIPPED', '已发货', 'LZD-LABEL-90001', 'https://example.com/labels/lzd-90001.pdf',
- 0, 0, NOW(), 0, 0, NOW()
-FROM `t_sales_store` s
-WHERE s.`CustomerId` = 9 AND s.`PlatformStoreId` = 'SEED9-LAZADA-001' AND s.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order` o
- WHERE o.`StoreId` = s.`Id` AND o.`PlatformOrderNo` = 'SEED9-ORD-LAZADA-S001' AND o.`IsDeleted` = 0
- );
-
--- completed
-INSERT INTO `t_sales_store_order` (
- `CustomerId`, `StoreId`, `PlatformCode`, `PlatformOrderNo`, `OrderCountry`,
- `ItemCount`, `TotalAmount`, `Currency`, `PlatformOrderTime`, `FulfillStatus`,
- `PlatformStatus`, `PlatformStatusLabel`, `ShippingLabelNo`,
- `IsMultiLabel`, `IsSuspended`, `LastSyncTime`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, s.`Id`, 'tiktok', 'SEED9-ORD-TIKTOK-C001', 'US',
- 1, 19.9900, 'USD', DATE_SUB(NOW(), INTERVAL 10 DAY), 'completed',
- 'COMPLETED', '已完成', 'TT-LABEL-90002',
- 0, 0, NOW(), 0, 0, NOW()
-FROM `t_sales_store` s
-WHERE s.`CustomerId` = 9 AND s.`PlatformStoreId` = 'SEED9-TIKTOK-001' AND s.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order` o
- WHERE o.`StoreId` = s.`Id` AND o.`PlatformOrderNo` = 'SEED9-ORD-TIKTOK-C001' AND o.`IsDeleted` = 0
- );
-
--- canceled
-INSERT INTO `t_sales_store_order` (
- `CustomerId`, `StoreId`, `PlatformCode`, `PlatformOrderNo`, `OrderCountry`,
- `ItemCount`, `TotalAmount`, `Currency`, `PlatformOrderTime`, `FulfillStatus`,
- `PlatformStatus`, `PlatformStatusLabel`, `IsMultiLabel`, `IsSuspended`,
- `LastSyncTime`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, s.`Id`, 'tiktok', 'SEED9-ORD-TIKTOK-X001', 'US',
- 2, 35.5000, 'USD', DATE_SUB(NOW(), INTERVAL 5 DAY), 'canceled',
- 'CANCELLED', '已取消', 0, 0,
- NOW(), 0, 0, NOW()
-FROM `t_sales_store` s
-WHERE s.`CustomerId` = 9 AND s.`PlatformStoreId` = 'SEED9-TIKTOK-001' AND s.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order` o
- WHERE o.`StoreId` = s.`Id` AND o.`PlatformOrderNo` = 'SEED9-ORD-TIKTOK-X001' AND o.`IsDeleted` = 0
- );
-
--- suspended
-INSERT INTO `t_sales_store_order` (
- `CustomerId`, `StoreId`, `PlatformCode`, `PlatformOrderNo`, `OrderCountry`,
- `ItemCount`, `TotalAmount`, `Currency`, `PlatformOrderTime`, `FulfillStatus`,
- `PlatformStatus`, `PlatformStatusLabel`, `IsMultiLabel`, `CustomTags`, `IsSuspended`,
- `LastSyncTime`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, s.`Id`, 'lazada', 'SEED9-ORD-LAZADA-H001', 'MY',
- 1, 59.0000, 'MYR', DATE_SUB(NOW(), INTERVAL 4 DAY), 'suspended',
- 'PENDING', '待处理', 0, '缺货搁置', 1,
- NOW(), 0, 0, NOW()
-FROM `t_sales_store` s
-WHERE s.`CustomerId` = 9 AND s.`PlatformStoreId` = 'SEED9-LAZADA-001' AND s.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order` o
- WHERE o.`StoreId` = s.`Id` AND o.`PlatformOrderNo` = 'SEED9-ORD-LAZADA-H001' AND o.`IsDeleted` = 0
- );
-
--- toShip(多件)
-INSERT INTO `t_sales_store_order` (
- `CustomerId`, `StoreId`, `PlatformCode`, `PlatformOrderNo`, `OrderCountry`,
- `ItemCount`, `TotalAmount`, `Currency`, `PlatformOrderTime`, `FulfillStatus`,
- `PlatformStatus`, `PlatformStatusLabel`, `IsMultiLabel`, `IsSuspended`,
- `LastSyncTime`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT 9, s.`Id`, 'shopee', 'SEED9-ORD-SHOPEE-T002', 'PH',
- 2, 88.0000, 'PHP', DATE_SUB(NOW(), INTERVAL 6 HOUR), 'toShip',
- 'READY_TO_SHIP', '待发货', 1, 0,
- NOW(), 0, 0, NOW()
-FROM `t_sales_store` s
-WHERE s.`CustomerId` = 9 AND s.`PlatformStoreId` = 'SEED9-SHOPEE-001' AND s.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order` o
- WHERE o.`StoreId` = s.`Id` AND o.`PlatformOrderNo` = 'SEED9-ORD-SHOPEE-T002' AND o.`IsDeleted` = 0
- );
-
--- ---------------------------------------------------------------------------
--- 3. 订单明细 t_sales_store_order_line
--- ---------------------------------------------------------------------------
-
--- SEED9-ORD-SHOPEE-P001 两行
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-P001-1', 'SKU-PHONE-CASE-01', '硅胶手机壳', 'https://example.com/img/phone-case.jpg',
- '颜色:黑色;型号:iPhone15', 18.9000, 1, 'SGD', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-SHOPEE-P001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-P001-1' AND l.`IsDeleted` = 0
- );
-
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-P001-2', 'SKU-CABLE-USB-C', 'USB-C 数据线 1m', 'https://example.com/img/usb-c.jpg',
- '长度:1m', 26.9000, 1, 'SGD', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-SHOPEE-P001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-P001-2' AND l.`IsDeleted` = 0
- );
-
--- SEED9-ORD-SHOPEE-T001
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-T001-1', 'SKU-EARBUD-PRO', '无线蓝牙耳机 Pro', 'https://example.com/img/earbud.jpg',
- '颜色:白色', 28.5000, 1, 'SGD', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-SHOPEE-T001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-T001-1' AND l.`IsDeleted` = 0
- );
-
--- SEED9-ORD-LAZADA-S001 三行
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-S001-1', 'SKU-TSHIRT-M', '纯棉短袖 T 恤', 'https://example.com/img/tshirt.jpg',
- '尺码:M;颜色:藏青', 29.9000, 2, 'MYR', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-LAZADA-S001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-S001-1' AND l.`IsDeleted` = 0
- );
-
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-S001-2', 'SKU-SOCK-PACK', '运动短袜 3 双装', 'https://example.com/img/socks.jpg',
- '颜色:混色', 19.9000, 1, 'MYR', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-LAZADA-S001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-S001-2' AND l.`IsDeleted` = 0
- );
-
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-S001-3', 'SKU-CAP-BLK', '棒球帽', 'https://example.com/img/cap.jpg',
- '颜色:黑色', 50.2000, 1, 'MYR', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-LAZADA-S001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-S001-3' AND l.`IsDeleted` = 0
- );
-
--- SEED9-ORD-TIKTOK-C001
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-C001-1', 'SKU-LED-STRIP', 'LED 灯带 5m', 'https://example.com/img/led.jpg',
- '色温:暖白', 19.9900, 1, 'USD', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-TIKTOK-C001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-C001-1' AND l.`IsDeleted` = 0
- );
-
--- SEED9-ORD-TIKTOK-X001
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-X001-1', 'SKU-MOUSE-PAD', '加大鼠标垫', 'https://example.com/img/mousepad.jpg',
- '尺寸:900x400', 15.5000, 1, 'USD', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-TIKTOK-X001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-X001-1' AND l.`IsDeleted` = 0
- );
-
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-X001-2', 'SKU-KEYCAP-SET', '键帽套装 104 键', 'https://example.com/img/keycap.jpg',
- '风格:布丁', 20.0000, 1, 'USD', 1, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-TIKTOK-X001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-X001-2' AND l.`IsDeleted` = 0
- );
-
--- SEED9-ORD-LAZADA-H001
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-H001-1', 'SKU-POWERBANK-20K', '移动电源 20000mAh', 'https://example.com/img/powerbank.jpg',
- '颜色:灰色', 59.0000, 1, 'MYR', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-LAZADA-H001' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-H001-1' AND l.`IsDeleted` = 0
- );
-
--- SEED9-ORD-SHOPEE-T002 两行
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-T002-1', 'SKU-BAG-TOTE', '帆布托特包', 'https://example.com/img/tote.jpg',
- '颜色:米白', 48.0000, 1, 'PHP', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-SHOPEE-T002' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-T002-1' AND l.`IsDeleted` = 0
- );
-
-INSERT INTO `t_sales_store_order_line` (
- `StoreOrderId`, `PlatformLineId`, `PlatformSku`, `ProductName`, `ProductImageUrl`,
- `VariantText`, `UnitPrice`, `Quantity`, `Currency`, `IsShipExcluded`, `IsDeleted`, `CreateUserId`, `CreateTime`
-)
-SELECT o.`Id`, 'LINE-T002-2', 'SKU-WALLET-MINI', '迷你卡包', 'https://example.com/img/wallet.jpg',
- '颜色:棕色', 40.0000, 1, 'PHP', 0, 0, 0, NOW()
-FROM `t_sales_store_order` o
-WHERE o.`CustomerId` = 9 AND o.`PlatformOrderNo` = 'SEED9-ORD-SHOPEE-T002' AND o.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_sales_store_order_line` l
- WHERE l.`StoreOrderId` = o.`Id` AND l.`PlatformLineId` = 'LINE-T002-2' AND l.`IsDeleted` = 0
- );
-
--- ---------------------------------------------------------------------------
--- 4. 补齐收件人(需先执行 migrate_t_sales_store_order_recipient.sql)
--- ---------------------------------------------------------------------------
-UPDATE `t_sales_store_order` SET
- `RecipientName` = 'Tan Wei Ming',
- `RecipientCompany` = NULL,
- `RecipientPhone` = '+65-91234567',
- `RecipientEmail` = 'tan.wm@example.com',
- `RecipientCountry` = 'SG',
- `RecipientProvince` = 'Singapore',
- `RecipientCity` = 'Singapore',
- `RecipientZipCode` = '018956',
- `RecipientAddress1` = '10 Bayfront Avenue, Marina Bay Sands',
- `RecipientAddress2` = 'Tower 1 #12-01',
- `PlatformExtraJson` = JSON_OBJECT(
- 'recipient', JSON_OBJECT(
- 'recipientsName', 'Tan Wei Ming',
- 'phone', '+65-91234567',
- 'email', 'tan.wm@example.com',
- 'countryCode', 'SG',
- 'province', 'Singapore',
- 'city', 'Singapore',
- 'zipCode', '018956',
- 'streetAddress1', '10 Bayfront Avenue, Marina Bay Sands',
- 'streetAddress2', 'Tower 1 #12-01'
- )
- )
-WHERE `CustomerId` = 9 AND `PlatformOrderNo` = 'SEED9-ORD-SHOPEE-P001' AND `IsDeleted` = 0
- AND (`RecipientName` IS NULL OR `RecipientName` = '');
-
-UPDATE `t_sales_store_order` SET
- `RecipientName` = 'Lim Jia Hui',
- `RecipientPhone` = '+65-98887766',
- `RecipientCountry` = 'SG',
- `RecipientProvince` = 'Singapore',
- `RecipientCity` = 'Singapore',
- `RecipientZipCode` = '238801',
- `RecipientAddress1` = '313 Orchard Road',
- `PlatformExtraJson` = JSON_OBJECT(
- 'recipient', JSON_OBJECT(
- 'recipientsName', 'Lim Jia Hui',
- 'phone', '+65-98887766',
- 'countryCode', 'SG',
- 'city', 'Singapore',
- 'zipCode', '238801',
- 'streetAddress1', '313 Orchard Road'
- )
- )
-WHERE `CustomerId` = 9 AND `PlatformOrderNo` = 'SEED9-ORD-SHOPEE-T001' AND `IsDeleted` = 0
- AND (`RecipientName` IS NULL OR `RecipientName` = '');
-
-UPDATE `t_sales_store_order` SET
- `RecipientName` = 'Ahmad Faizal',
- `RecipientPhone` = '+60-12-3456789',
- `RecipientCountry` = 'MY',
- `RecipientProvince` = 'Selangor',
- `RecipientCity` = 'Petaling Jaya',
- `RecipientZipCode` = '47800',
- `RecipientAddress1` = 'No. 18, Jalan SS2/24',
- `PlatformExtraJson` = JSON_OBJECT(
- 'recipient', JSON_OBJECT(
- 'recipientsName', 'Ahmad Faizal',
- 'phone', '+60-12-3456789',
- 'countryCode', 'MY',
- 'province', 'Selangor',
- 'city', 'Petaling Jaya',
- 'zipCode', '47800',
- 'streetAddress1', 'No. 18, Jalan SS2/24'
- )
- )
-WHERE `CustomerId` = 9 AND `PlatformOrderNo` IN ('SEED9-ORD-LAZADA-S001', 'SEED9-ORD-LAZADA-H001') AND `IsDeleted` = 0
- AND (`RecipientName` IS NULL OR `RecipientName` = '');
-
-UPDATE `t_sales_store_order` SET
- `RecipientName` = 'John Smith',
- `RecipientPhone` = '+1-415-555-0198',
- `RecipientEmail` = 'john.smith@example.com',
- `RecipientCountry` = 'US',
- `RecipientProvince` = 'CA',
- `RecipientCity` = 'San Francisco',
- `RecipientZipCode` = '94105',
- `RecipientAddress1` = '1 Market St, Suite 300',
- `PlatformExtraJson` = JSON_OBJECT(
- 'recipient', JSON_OBJECT(
- 'recipientsName', 'John Smith',
- 'phone', '+1-415-555-0198',
- 'email', 'john.smith@example.com',
- 'countryCode', 'US',
- 'province', 'CA',
- 'city', 'San Francisco',
- 'zipCode', '94105',
- 'streetAddress1', '1 Market St, Suite 300'
- )
- )
-WHERE `CustomerId` = 9 AND `PlatformOrderNo` IN ('SEED9-ORD-TIKTOK-C001', 'SEED9-ORD-TIKTOK-X001') AND `IsDeleted` = 0
- AND (`RecipientName` IS NULL OR `RecipientName` = '');
-
-UPDATE `t_sales_store_order` SET
- `RecipientName` = 'Maria Santos',
- `RecipientPhone` = '+63-917-123-4567',
- `RecipientCountry` = 'PH',
- `RecipientProvince` = 'Metro Manila',
- `RecipientCity` = 'Makati',
- `RecipientZipCode` = '1226',
- `RecipientAddress1` = 'Ayala Avenue, Glorietta 4',
- `PlatformExtraJson` = JSON_OBJECT(
- 'recipient', JSON_OBJECT(
- 'recipientsName', 'Maria Santos',
- 'phone', '+63-917-123-4567',
- 'countryCode', 'PH',
- 'province', 'Metro Manila',
- 'city', 'Makati',
- 'zipCode', '1226',
- 'streetAddress1', 'Ayala Avenue, Glorietta 4'
- )
- )
-WHERE `CustomerId` = 9 AND `PlatformOrderNo` = 'SEED9-ORD-SHOPEE-T002' AND `IsDeleted` = 0
- AND (`RecipientName` IS NULL OR `RecipientName` = '');
-
--- 校验摘要(执行后可看)
-SELECT 't_sales_store' AS tbl, COUNT(*) AS cnt FROM `t_sales_store` WHERE `CustomerId` = 9 AND `IsDeleted` = 0
-UNION ALL
-SELECT 't_sales_store_order', COUNT(*) FROM `t_sales_store_order` WHERE `CustomerId` = 9 AND `IsDeleted` = 0
-UNION ALL
-SELECT 't_sales_store_order_with_recipient', COUNT(*)
-FROM `t_sales_store_order`
-WHERE `CustomerId` = 9 AND `IsDeleted` = 0 AND `RecipientName` IS NOT NULL AND `RecipientName` <> ''
-UNION ALL
-SELECT 't_sales_store_order_line', COUNT(*)
-FROM `t_sales_store_order_line` l
-INNER JOIN `t_sales_store_order` o ON o.`Id` = l.`StoreOrderId`
-WHERE o.`CustomerId` = 9 AND o.`IsDeleted` = 0 AND l.`IsDeleted` = 0;
diff --git a/src/Oms.Application/Dtos/Marketing/CouponDtos.cs b/src/Oms.Application/Dtos/Marketing/CouponDtos.cs
index 02e961e..42d15c3 100644
--- a/src/Oms.Application/Dtos/Marketing/CouponDtos.cs
+++ b/src/Oms.Application/Dtos/Marketing/CouponDtos.cs
@@ -186,6 +186,10 @@ public class CouponTemplateOutput
+ public string GrantChannelName { get; set; } = string.Empty;
+
+
+
public CouponTemplateStatus Status { get; set; }
@@ -313,6 +317,34 @@ public class CouponInstanceOutput
+ public string? CouponTypeName { get; set; }
+
+
+
+ public string? GrantChannel { get; set; }
+
+
+
+ public string? GrantChannelName { get; set; }
+
+
+
+ public decimal? FaceValue { get; set; }
+
+
+
+ public decimal? DiscountRate { get; set; }
+
+
+
+ public decimal? MaxDiscountAmount { get; set; }
+
+
+
+ public decimal MinOrderAmount { get; set; }
+
+
+
public int CustomerId { get; set; }
diff --git a/src/Oms.Application/Dtos/System/EmployeeOutput.cs b/src/Oms.Application/Dtos/System/EmployeeOutput.cs
new file mode 100644
index 0000000..6ac7ed0
--- /dev/null
+++ b/src/Oms.Application/Dtos/System/EmployeeOutput.cs
@@ -0,0 +1,63 @@
+using Oms.Domain.SystemAggregate.Enums;
+
+namespace Oms.Application.Dtos.System;
+
+///
+/// 员工档案出参(工号/手机/邮箱见用户表)。
+///
+public class EmployeeOutput
+{
+ public int Id { get; set; }
+
+ public string UserId { get; set; } = string.Empty;
+
+ public string RealName { get; set; } = string.Empty;
+
+ public Gender Gender { get; set; }
+
+ public DateTime? Birthday { get; set; }
+
+ public string? IdCardNo { get; set; }
+
+ public DateTime? HireDate { get; set; }
+
+ public DateTime? ProbationEndDate { get; set; }
+
+ public DateTime? RegularizationDate { get; set; }
+
+ public EmploymentStatus EmploymentStatus { get; set; }
+
+ public DateTime? ResignationDate { get; set; }
+
+ public string? Department { get; set; }
+
+ public string? Position { get; set; }
+
+ public string? JobLevel { get; set; }
+
+ public EmploymentType EmploymentType { get; set; }
+
+ public string? WorkLocation { get; set; }
+
+ public string? ManagerUserId { get; set; }
+
+ public DateTime? ContractStartDate { get; set; }
+
+ public DateTime? ContractEndDate { get; set; }
+
+ public string? ContractType { get; set; }
+
+ public string? EmergencyContact { get; set; }
+
+ public string? EmergencyPhone { get; set; }
+
+ public string? Address { get; set; }
+
+ public string? Education { get; set; }
+
+ public string? Remark { get; set; }
+
+ public DateTime CreateTime { get; set; }
+
+ public DateTime? UpdateTime { get; set; }
+}
diff --git a/src/Oms.Application/Dtos/System/EmployeeSaveInput.cs b/src/Oms.Application/Dtos/System/EmployeeSaveInput.cs
new file mode 100644
index 0000000..c3149e8
--- /dev/null
+++ b/src/Oms.Application/Dtos/System/EmployeeSaveInput.cs
@@ -0,0 +1,60 @@
+using Oms.Domain.SystemAggregate.Enums;
+
+namespace Oms.Application.Dtos.System;
+
+///
+/// 员工档案保存入参(按 UserId 新增或更新;工号/手机/邮箱不在此维护)。
+///
+public class EmployeeSaveInput
+{
+ ///
+ /// 关联 RBAC 用户 Id,必填。
+ ///
+ public string UserId { get; set; } = string.Empty;
+
+ public string RealName { get; set; } = string.Empty;
+
+ public Gender Gender { get; set; } = Gender.Unknown;
+
+ public DateTime? Birthday { get; set; }
+
+ public string? IdCardNo { get; set; }
+
+ public DateTime? HireDate { get; set; }
+
+ public DateTime? ProbationEndDate { get; set; }
+
+ public DateTime? RegularizationDate { get; set; }
+
+ public EmploymentStatus EmploymentStatus { get; set; } = EmploymentStatus.Probation;
+
+ public DateTime? ResignationDate { get; set; }
+
+ public string? Department { get; set; }
+
+ public string? Position { get; set; }
+
+ public string? JobLevel { get; set; }
+
+ public EmploymentType EmploymentType { get; set; } = EmploymentType.FullTime;
+
+ public string? WorkLocation { get; set; }
+
+ public string? ManagerUserId { get; set; }
+
+ public DateTime? ContractStartDate { get; set; }
+
+ public DateTime? ContractEndDate { get; set; }
+
+ public string? ContractType { get; set; }
+
+ public string? EmergencyContact { get; set; }
+
+ public string? EmergencyPhone { get; set; }
+
+ public string? Address { get; set; }
+
+ public string? Education { get; set; }
+
+ public string? Remark { get; set; }
+}
diff --git a/src/Oms.Application/Rbac/UserProfileRepository.cs b/src/Oms.Application/Rbac/UserProfileRepository.cs
index e8b0830..6a6d720 100644
--- a/src/Oms.Application/Rbac/UserProfileRepository.cs
+++ b/src/Oms.Application/Rbac/UserProfileRepository.cs
@@ -8,7 +8,10 @@ namespace Oms.Application.Rbac;
public class UserProfileRepository(FakeRbacDbContext dbContext) : IScopedDependency
{
- private static readonly Regex EmployeeNoPattern = new(@"^NE\d{4}$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ ///
+ /// 工号规则:IDE + 至少 3 位数字,如 IDE001。
+ ///
+ private static readonly Regex EmployeeNoPattern = new(@"^IDE(\d{3,})$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public async Task GetAsync(Guid userId, CancellationToken cancellationToken = default)
{
@@ -173,14 +176,14 @@ public class UserProfileRepository(FakeRbacDbContext dbContext) : IScopedDepende
continue;
}
- if (int.TryParse(value[2..], out var number))
+ if (int.TryParse(match.Groups[1].Value, out var number))
{
max = Math.Max(max, number);
}
}
var next = max + 1;
- return next > 9999 ? $"NE{next}" : $"NE{next:D4}";
+ return $"IDE{next:D3}";
}
public static bool IsValidEmployeeNo(string employeeNo) => EmployeeNoPattern.IsMatch(employeeNo.Trim());
diff --git a/src/Oms.Application/Services/Customers/CustomerService.cs b/src/Oms.Application/Services/Customers/CustomerService.cs
index 9424d17..f9172a4 100644
--- a/src/Oms.Application/Services/Customers/CustomerService.cs
+++ b/src/Oms.Application/Services/Customers/CustomerService.cs
@@ -35,6 +35,9 @@ public class CustomerService : ApplicationService
private ICustomerReferralCodeRepository ReferralCodeRepository =>
LazyServiceProvider.GetRequiredService();
+ private MarketingCouponManager CouponManager =>
+ LazyServiceProvider.GetRequiredService();
+
private UserService UserService => LazyServiceProvider.GetRequiredService();
private RoleService RoleService => LazyServiceProvider.GetRequiredService();
@@ -165,6 +168,14 @@ public class CustomerService : ApplicationService
ReferralCodeRepository,
CustomerRepository);
await CustomerRepository.InsertAsync(entity);
+ try
+ {
+ await CouponManager.GrantNewcomerCouponsAsync(entity.Id);
+ }
+ catch
+ {
+ // 新人券发放失败不回滚注册
+ }
}
catch
{
diff --git a/src/Oms.Application/Services/Marketing/MarketingCommissionAdminService.cs b/src/Oms.Application/Services/Marketing/MarketingCommissionAdminService.cs
index f10077e..75f867e 100644
--- a/src/Oms.Application/Services/Marketing/MarketingCommissionAdminService.cs
+++ b/src/Oms.Application/Services/Marketing/MarketingCommissionAdminService.cs
@@ -131,7 +131,7 @@ public class MarketingCommissionAdminService : ApplicationService
}
var customer = await CustomerRepository.GetByCustomerCodeAsync(code)
- ?? throw new BusinessException(`"客户编号 {code} 不存在`");
+ ?? throw new BusinessException($"客户编号 {code} 不存在");
input.CustomerId = customer.ParentCustomerId ?? customer.Id;
}
diff --git a/src/Oms.Application/Services/Marketing/MarketingCouponGrantService.cs b/src/Oms.Application/Services/Marketing/MarketingCouponGrantService.cs
index e9af4de..9899c3d 100644
--- a/src/Oms.Application/Services/Marketing/MarketingCouponGrantService.cs
+++ b/src/Oms.Application/Services/Marketing/MarketingCouponGrantService.cs
@@ -207,6 +207,13 @@ public class MarketingCouponGrantService : ApplicationService
TemplateId = entity.TemplateId,
TemplateName = template?.TemplateName,
CouponType = template?.CouponType,
+ CouponTypeName = template == null ? null : MarketingEnumNames.OfCouponType(template.CouponType),
+ GrantChannel = template?.GrantChannel,
+ GrantChannelName = MarketingEnumNames.OfGrantChannel(template?.GrantChannel),
+ FaceValue = template?.FaceValue,
+ DiscountRate = template?.DiscountRate,
+ MaxDiscountAmount = template?.MaxDiscountAmount,
+ MinOrderAmount = template?.MinOrderAmount ?? 0,
CustomerId = entity.CustomerId,
CustomerCode = customerCode,
CouponCode = entity.CouponCode,
diff --git a/src/Oms.Application/Services/Marketing/MarketingCouponTemplateService.cs b/src/Oms.Application/Services/Marketing/MarketingCouponTemplateService.cs
index 9537819..d45d478 100644
--- a/src/Oms.Application/Services/Marketing/MarketingCouponTemplateService.cs
+++ b/src/Oms.Application/Services/Marketing/MarketingCouponTemplateService.cs
@@ -234,6 +234,7 @@ public class MarketingCouponTemplateService : ApplicationService
ValidDaysAfterReceive = entity.ValidDaysAfterReceive,
ApplyScopeJson = entity.ApplyScopeJson,
GrantChannel = entity.GrantChannel,
+ GrantChannelName = MarketingEnumNames.OfGrantChannel(entity.GrantChannel),
Status = entity.Status,
StatusName = MarketingEnumNames.Of(entity.Status),
Remark = entity.Remark,
diff --git a/src/Oms.Application/Services/Rbac/OmsUserService.cs b/src/Oms.Application/Services/Rbac/OmsUserService.cs
index cbf4c37..106a20e 100644
--- a/src/Oms.Application/Services/Rbac/OmsUserService.cs
+++ b/src/Oms.Application/Services/Rbac/OmsUserService.cs
@@ -1,4 +1,5 @@
using Fake.Application;
+using Fake.Domain.Exceptions;
using Fake.Rbac.Application.Dtos.Common;
using Fake.Rbac.Application.Dtos.Role;
using Fake.Rbac.Application.Dtos.User;
@@ -7,6 +8,9 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Rbac;
using Oms.Application.Rbac;
+using Oms.Domain.SystemAggregate.Entities;
+using Oms.Domain.SystemAggregate.Enums;
+using Oms.Domain.SystemAggregate.Repositories;
namespace Oms.Application.Services.Rbac;
@@ -15,7 +19,10 @@ namespace Oms.Application.Services.Rbac;
///
[Authorize]
[ApiExplorerSettings(GroupName = "RBAC-User")]
-public class OmsUserService(UserService userService, UserProfileRepository profileRepository) : ApplicationService
+public class OmsUserService(
+ UserService userService,
+ UserProfileRepository profileRepository,
+ IEmployeeRepository employeeRepository) : ApplicationService
{
///
/// 获取用户详情(含扩展资料)。
@@ -105,6 +112,8 @@ public class OmsUserService(UserService userService, UserProfileRepository profi
},
cancellationToken);
+ await EnsureEmployeeProfileAsync(user.Id, input, cancellationToken);
+
var profile = await profileRepository.GetAsync(user.Id, cancellationToken);
return OmsUserProfileMapper.ToDetailDto(user, profile);
}
@@ -215,7 +224,7 @@ public class OmsUserService(UserService userService, UserProfileRepository profi
if (!UserProfileRepository.IsValidEmployeeNo(employeeNo))
{
- throw new BusinessException("工号格式无效,应为 NE + 4 位数字");
+ throw new BusinessException("工号格式无效,应为 IDE + 至少 3 位数字,如 IDE001");
}
if (await profileRepository.IsEmployeeNoTakenAsync(employeeNo, null, cancellationToken))
@@ -225,4 +234,27 @@ public class OmsUserService(UserService userService, UserProfileRepository profi
return employeeNo;
}
+
+ private async Task EnsureEmployeeProfileAsync(
+ Guid userId,
+ OmsUserCreateInput input,
+ CancellationToken cancellationToken)
+ {
+ var userIdText = userId.ToString();
+ if (await employeeRepository.ExistsByUserIdAsync(userIdText, null, cancellationToken))
+ {
+ return;
+ }
+
+ await employeeRepository.InsertAsync(
+ new Employee
+ {
+ UserId = userIdText,
+ RealName = string.IsNullOrWhiteSpace(input.Name) ? string.Empty : input.Name.Trim(),
+ HireDate = DateTime.Today,
+ EmploymentStatus = EmploymentStatus.Probation,
+ EmploymentType = EmploymentType.FullTime,
+ },
+ cancellationToken);
+ }
}
diff --git a/src/Oms.Application/Services/System/EmployeeService.cs b/src/Oms.Application/Services/System/EmployeeService.cs
new file mode 100644
index 0000000..b42f6dd
--- /dev/null
+++ b/src/Oms.Application/Services/System/EmployeeService.cs
@@ -0,0 +1,147 @@
+using Fake.Application;
+using Fake.Domain.Exceptions;
+using Microsoft.AspNetCore.Mvc;
+using Oms.Application.Dtos.System;
+using Oms.Domain.SystemAggregate.Entities;
+using Oms.Domain.SystemAggregate.Enums;
+using Oms.Domain.SystemAggregate.Repositories;
+
+namespace Oms.Application.Services.System;
+
+///
+/// 员工档案 API(关联 RBAC 用户;工号/手机/邮箱以用户表为准)。
+///
+[ApiExplorerSettings(GroupName = "OMS-System")]
+public class EmployeeService : ApplicationService
+{
+ private IEmployeeRepository EmployeeRepository =>
+ LazyServiceProvider.GetRequiredService();
+
+ ///
+ /// 按用户 Id 查询员工档案。
+ ///
+ [HttpGet("/system/employee/get-by-user")]
+ public async Task GetByUserAsync(
+ [FromQuery] Guid userId,
+ CancellationToken cancellationToken = default)
+ {
+ if (userId == Guid.Empty)
+ {
+ throw new BusinessException("用户 Id 无效");
+ }
+
+ var entity = await EmployeeRepository.GetByUserIdAsync(userId.ToString(), cancellationToken);
+ return entity == null ? null : MapOutput(entity);
+ }
+
+ ///
+ /// 保存员工档案(不存在则新增,存在则更新)。
+ ///
+ [HttpPost("/system/employee/save")]
+ public async Task SaveAsync(
+ [FromBody] EmployeeSaveInput input,
+ CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(input.UserId) || !Guid.TryParse(input.UserId.Trim(), out var userGuid))
+ {
+ throw new BusinessException("用户 Id 无效");
+ }
+
+ var realName = input.RealName?.Trim() ?? string.Empty;
+ if (string.IsNullOrWhiteSpace(realName))
+ {
+ throw new BusinessException("姓名不能为空");
+ }
+
+ var userId = userGuid.ToString();
+ var entity = await EmployeeRepository.GetByUserIdAsync(userId, cancellationToken);
+ if (entity == null)
+ {
+ entity = new Employee { UserId = userId };
+ MapToEntity(input, entity, realName);
+ await EmployeeRepository.InsertAsync(entity, cancellationToken);
+ }
+ else
+ {
+ MapToEntity(input, entity, realName);
+ await EmployeeRepository.UpdateAsync(entity, cancellationToken);
+ }
+
+ return MapOutput(entity);
+ }
+
+ private static void MapToEntity(EmployeeSaveInput input, Employee entity, string realName)
+ {
+ entity.RealName = realName;
+ entity.Gender = Enum.IsDefined(typeof(Gender), input.Gender) ? input.Gender : Gender.Unknown;
+ entity.Birthday = input.Birthday;
+ entity.IdCardNo = NormalizeOptional(input.IdCardNo);
+ entity.HireDate = input.HireDate;
+ entity.ProbationEndDate = input.ProbationEndDate;
+ entity.RegularizationDate = input.RegularizationDate;
+ entity.EmploymentStatus = Enum.IsDefined(typeof(EmploymentStatus), input.EmploymentStatus)
+ ? input.EmploymentStatus
+ : EmploymentStatus.Probation;
+ entity.ResignationDate = input.ResignationDate;
+ entity.Department = NormalizeOptional(input.Department);
+ entity.Position = NormalizeOptional(input.Position);
+ entity.JobLevel = NormalizeOptional(input.JobLevel);
+ entity.EmploymentType = Enum.IsDefined(typeof(EmploymentType), input.EmploymentType)
+ ? input.EmploymentType
+ : EmploymentType.FullTime;
+ entity.WorkLocation = NormalizeOptional(input.WorkLocation);
+ entity.ManagerUserId = NormalizeGuidOptional(input.ManagerUserId);
+ entity.ContractStartDate = input.ContractStartDate;
+ entity.ContractEndDate = input.ContractEndDate;
+ entity.ContractType = NormalizeOptional(input.ContractType);
+ entity.EmergencyContact = NormalizeOptional(input.EmergencyContact);
+ entity.EmergencyPhone = NormalizeOptional(input.EmergencyPhone);
+ entity.Address = NormalizeOptional(input.Address);
+ entity.Education = NormalizeOptional(input.Education);
+ entity.Remark = NormalizeOptional(input.Remark);
+ }
+
+ private static EmployeeOutput MapOutput(Employee entity) => new()
+ {
+ Id = entity.Id,
+ UserId = entity.UserId,
+ RealName = entity.RealName,
+ Gender = entity.Gender,
+ Birthday = entity.Birthday,
+ IdCardNo = entity.IdCardNo,
+ HireDate = entity.HireDate,
+ ProbationEndDate = entity.ProbationEndDate,
+ RegularizationDate = entity.RegularizationDate,
+ EmploymentStatus = entity.EmploymentStatus,
+ ResignationDate = entity.ResignationDate,
+ Department = entity.Department,
+ Position = entity.Position,
+ JobLevel = entity.JobLevel,
+ EmploymentType = entity.EmploymentType,
+ WorkLocation = entity.WorkLocation,
+ ManagerUserId = entity.ManagerUserId,
+ ContractStartDate = entity.ContractStartDate,
+ ContractEndDate = entity.ContractEndDate,
+ ContractType = entity.ContractType,
+ EmergencyContact = entity.EmergencyContact,
+ EmergencyPhone = entity.EmergencyPhone,
+ Address = entity.Address,
+ Education = entity.Education,
+ Remark = entity.Remark,
+ CreateTime = entity.CreateTime,
+ UpdateTime = entity.UpdateTime,
+ };
+
+ private static string? NormalizeOptional(string? value) =>
+ string.IsNullOrWhiteSpace(value) ? null : value.Trim();
+
+ private static string? NormalizeGuidOptional(string? value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return null;
+ }
+
+ return Guid.TryParse(value.Trim(), out var id) ? id.ToString() : null;
+ }
+}
diff --git a/src/Oms.Application/Shared/MarketingCouponManager.cs b/src/Oms.Application/Shared/MarketingCouponManager.cs
index 402670c..d71cfe4 100644
--- a/src/Oms.Application/Shared/MarketingCouponManager.cs
+++ b/src/Oms.Application/Shared/MarketingCouponManager.cs
@@ -81,6 +81,42 @@ public class MarketingCouponManager : IScopedDependency
return instance;
}
+ ///
+ /// 注册成功后发放所有「新人券」模板(GrantChannel=newcomer 且已发布),有多少发多少;单张失败不阻断。
+ ///
+ public async Task GrantNewcomerCouponsAsync(int mainCustomerId, CancellationToken cancellationToken = default)
+ {
+ if (mainCustomerId <= 0)
+ {
+ return 0;
+ }
+
+ var templates = await _templateRepository.GetListAsync(
+ x => x.Status == CouponTemplateStatus.Active
+ && x.GrantChannel == MarketingGrantChannels.Newcomer,
+ cancellationToken);
+ if (templates.Count == 0)
+ {
+ return 0;
+ }
+
+ var granted = 0;
+ foreach (var template in templates.OrderBy(x => x.Id))
+ {
+ try
+ {
+ await GrantAsync(template.Id, mainCustomerId, "newcomer_register", cancellationToken);
+ granted++;
+ }
+ catch (BusinessException)
+ {
+ // 库存不足、已达上限等跳过
+ }
+ }
+
+ return granted;
+ }
+
public async Task LockForOrderAsync(int couponInstanceId, int mainCustomerId, int orderId, CancellationToken cancellationToken = default)
{
var instance = await GetOwnedInstanceAsync(couponInstanceId, mainCustomerId, cancellationToken);
diff --git a/src/Oms.Application/Shared/MarketingEnumNames.cs b/src/Oms.Application/Shared/MarketingEnumNames.cs
index 4f00ed5..70b884a 100644
--- a/src/Oms.Application/Shared/MarketingEnumNames.cs
+++ b/src/Oms.Application/Shared/MarketingEnumNames.cs
@@ -1,81 +1,94 @@
-using Oms.Domain.MarketingAggregate.Enums;
-using Oms.Domain.Shared.Enums;
-
-namespace Oms.Application.Shared;
-
-public static class MarketingEnumNames
-{
- public static string Of(EnableStatus status) => status switch
- {
- EnableStatus.Disabled => "禁用",
- EnableStatus.Enabled => "启用",
- _ => string.Empty
- };
-
- public static string Of(CouponTemplateStatus status) => status switch
- {
- CouponTemplateStatus.Draft => "草稿",
- CouponTemplateStatus.Active => "已发布",
- CouponTemplateStatus.Ended => "已停发",
- _ => string.Empty
- };
-
- public static string Of(CouponInstanceStatus status) => status switch
- {
- CouponInstanceStatus.Available => "可用",
- CouponInstanceStatus.Locked => "预占中",
- CouponInstanceStatus.Used => "已使用",
- CouponInstanceStatus.Expired => "已过期",
- _ => string.Empty
- };
-
- public static string Of(CommissionStatus status) => status switch
- {
- CommissionStatus.Pending => "待结算",
- CommissionStatus.Settled => "已结算",
- CommissionStatus.Cancelled => "已取消",
- _ => string.Empty
- };
-
- public static string Of(CommissionWithdrawType type) => type switch
- {
- CommissionWithdrawType.External => "外部提现",
- CommissionWithdrawType.ToBalance => "转余额",
- _ => string.Empty
- };
-
- public static string Of(WithdrawStatus status) => status switch
- {
- WithdrawStatus.Pending => "待审核",
- WithdrawStatus.Approved => "已通过",
- WithdrawStatus.Rejected => "已驳回",
- WithdrawStatus.Paid => "已打款",
- _ => string.Empty
- };
-
- public static string Of(PointsChangeType type) => type switch
- {
- PointsChangeType.Earn => "获得",
- PointsChangeType.Consume => "消耗",
- PointsChangeType.Adjust => "调账",
- PointsChangeType.RefundClawback => "退款扣回",
- _ => string.Empty
- };
-
- public static string Of(ReferralCodeStatus status) => status switch
- {
- ReferralCodeStatus.Disabled => "已停用",
- ReferralCodeStatus.Enabled => "启用",
- _ => string.Empty
- };
-
- public static string OfCouponType(string couponType) => couponType switch
- {
- MarketingCouponTypeCodes.FixedOff => "满减券",
- MarketingCouponTypeCodes.PercentOff => "折扣券",
- MarketingCouponTypeCodes.DirectOff => "直减券",
- MarketingCouponTypeCodes.ShippingOff => "运费券",
- _ => couponType
- };
-}
-
\ No newline at end of file
+using Oms.Domain.MarketingAggregate.Consts;
+using Oms.Domain.MarketingAggregate.Enums;
+using Oms.Domain.Shared.Enums;
+
+namespace Oms.Application.Shared;
+
+public static class MarketingEnumNames
+{
+ public static string Of(EnableStatus status) => status switch
+ {
+ EnableStatus.Disabled => "禁用",
+ EnableStatus.Enabled => "启用",
+ _ => string.Empty
+ };
+
+ public static string Of(CouponTemplateStatus status) => status switch
+ {
+ CouponTemplateStatus.Draft => "草稿",
+ CouponTemplateStatus.Active => "已发布",
+ CouponTemplateStatus.Ended => "已停发",
+ _ => string.Empty
+ };
+
+ public static string Of(CouponInstanceStatus status) => status switch
+ {
+ CouponInstanceStatus.Available => "可用",
+ CouponInstanceStatus.Locked => "预占中",
+ CouponInstanceStatus.Used => "已使用",
+ CouponInstanceStatus.Expired => "已过期",
+ _ => string.Empty
+ };
+
+ public static string Of(CommissionStatus status) => status switch
+ {
+ CommissionStatus.Pending => "待结算",
+ CommissionStatus.Settled => "已结算",
+ CommissionStatus.Cancelled => "已取消",
+ _ => string.Empty
+ };
+
+ public static string Of(CommissionWithdrawType type) => type switch
+ {
+ CommissionWithdrawType.External => "外部提现",
+ CommissionWithdrawType.ToBalance => "转余额",
+ _ => string.Empty
+ };
+
+ public static string Of(WithdrawStatus status) => status switch
+ {
+ WithdrawStatus.Pending => "待审核",
+ WithdrawStatus.Approved => "已通过",
+ WithdrawStatus.Rejected => "已驳回",
+ WithdrawStatus.Paid => "已打款",
+ _ => string.Empty
+ };
+
+ public static string Of(PointsChangeType type) => type switch
+ {
+ PointsChangeType.Earn => "获得",
+ PointsChangeType.Consume => "消耗",
+ PointsChangeType.Adjust => "调账",
+ PointsChangeType.RefundClawback => "退款扣回",
+ _ => string.Empty
+ };
+
+ public static string Of(ReferralCodeStatus status) => status switch
+ {
+ ReferralCodeStatus.Disabled => "已停用",
+ ReferralCodeStatus.Enabled => "启用",
+ _ => string.Empty
+ };
+
+ public static string OfCouponType(string couponType) => couponType switch
+ {
+ MarketingCouponTypeCodes.FixedOff => "满减券",
+ MarketingCouponTypeCodes.PercentOff => "折扣券",
+ MarketingCouponTypeCodes.DirectOff => "直减券",
+ MarketingCouponTypeCodes.ShippingOff => "运费券",
+ _ => couponType
+ };
+
+ public static string OfGrantChannel(string? grantChannel) =>
+ string.IsNullOrWhiteSpace(grantChannel)
+ ? "手动发放"
+ : grantChannel.Trim() switch
+ {
+ MarketingGrantChannels.Newcomer => "新人券",
+ MarketingGrantChannels.SelfReceive => "客户自领",
+ MarketingGrantChannels.Portal => "门户领取",
+ MarketingGrantChannels.Manual => "手动发放",
+ _ => grantChannel
+ };
+}
+
diff --git a/src/Oms.Application/Shared/MarketingReferralBinder.cs b/src/Oms.Application/Shared/MarketingReferralBinder.cs
index 90c260b..ecb00ae 100644
--- a/src/Oms.Application/Shared/MarketingReferralBinder.cs
+++ b/src/Oms.Application/Shared/MarketingReferralBinder.cs
@@ -1,4 +1,3 @@
-using Fake.Application;
using Fake.Domain.Exceptions;
using Oms.Domain.CustomersAggregate.Entities;
using Oms.Domain.CustomersAggregate.Repositories;
@@ -33,7 +32,8 @@ public static class MarketingReferralBinder
throw new BusinessException("邀请码无效或已停用");
}
- if (referral.CustomerId == entity.Id)
+ // 新建时 entity.Id 多为 0,不能只靠 Id 判自引荐
+ if (entity.Id > 0 && referral.CustomerId == entity.Id)
{
throw new BusinessException("不能使用自己的邀请码");
}
@@ -44,8 +44,46 @@ public static class MarketingReferralBinder
throw new BusinessException("邀请码对应客户无效");
}
+ if (IsSameIdentity(entity, referrer))
+ {
+ throw new BusinessException("不能使用自己的邀请码");
+ }
+
entity.ReferrerCustomerId = referral.CustomerId;
entity.ReferralBindTime = DateTime.Now;
entity.ReferralChannel = "link";
}
+
+ private static bool IsSameIdentity(Customer entity, Customer referrer)
+ {
+ if (!string.IsNullOrWhiteSpace(entity.Phone) &&
+ !string.IsNullOrWhiteSpace(referrer.Phone) &&
+ string.Equals(entity.Phone.Trim(), referrer.Phone.Trim(), StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ if (!string.IsNullOrWhiteSpace(entity.Email) &&
+ !string.IsNullOrWhiteSpace(referrer.Email) &&
+ string.Equals(entity.Email.Trim(), referrer.Email.Trim(), StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ if (!string.IsNullOrWhiteSpace(entity.WechatOpenid) &&
+ !string.IsNullOrWhiteSpace(referrer.WechatOpenid) &&
+ string.Equals(entity.WechatOpenid.Trim(), referrer.WechatOpenid.Trim(), StringComparison.Ordinal))
+ {
+ return true;
+ }
+
+ if (!string.IsNullOrWhiteSpace(entity.CustomerCode) &&
+ !string.IsNullOrWhiteSpace(referrer.CustomerCode) &&
+ string.Equals(entity.CustomerCode.Trim(), referrer.CustomerCode.Trim(), StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/src/Oms.Domain/MarketingAggregate/Consts/MarketingConsts.cs b/src/Oms.Domain/MarketingAggregate/Consts/MarketingConsts.cs
index 3026143..db354ea 100644
--- a/src/Oms.Domain/MarketingAggregate/Consts/MarketingConsts.cs
+++ b/src/Oms.Domain/MarketingAggregate/Consts/MarketingConsts.cs
@@ -11,6 +11,20 @@ public static class MarketingCouponTypes
public const string ShippingOff = "shipping_off";
}
+///
+/// 券模板发放渠道。新人券用 Newcomer,注册成功后自动发放所有已发布模板。
+///
+public static class MarketingGrantChannels
+{
+ public const string Manual = "manual";
+
+ public const string Newcomer = "newcomer";
+
+ public const string SelfReceive = "selfReceive";
+
+ public const string Portal = "portal";
+}
+
public static class MarketingPointsBizTypes
{
public const string OrderPay = "orderPay";
diff --git a/src/Oms.Domain/SystemAggregate/Entities/Employee.cs b/src/Oms.Domain/SystemAggregate/Entities/Employee.cs
new file mode 100644
index 0000000..bbc28fa
--- /dev/null
+++ b/src/Oms.Domain/SystemAggregate/Entities/Employee.cs
@@ -0,0 +1,88 @@
+using Oms.Domain.Shared;
+using Oms.Domain.SystemAggregate.Enums;
+using SqlSugar;
+
+namespace Oms.Domain.SystemAggregate.Entities;
+
+///
+/// 员工档案,关联 RBAC 用户(user.Id)。
+/// 工号/手机/邮箱等以用户表为准,本表不重复存储。
+///
+[SugarTable("t_employee")]
+public class Employee : OmsAuditedAggregateRoot
+{
+ ///
+ /// RBAC 用户 Id(CHAR(36))。
+ ///
+ [SugarColumn(Length = 36, IsNullable = false)]
+ public string UserId { get; set; } = string.Empty;
+
+ [SugarColumn(Length = 64, IsNullable = false)]
+ public string RealName { get; set; } = string.Empty;
+
+ public Gender Gender { get; set; } = Gender.Unknown;
+
+ [SugarColumn(IsNullable = true)]
+ public DateTime? Birthday { get; set; }
+
+ [SugarColumn(Length = 32, IsNullable = true)]
+ public string? IdCardNo { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public DateTime? HireDate { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public DateTime? ProbationEndDate { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public DateTime? RegularizationDate { get; set; }
+
+ public EmploymentStatus EmploymentStatus { get; set; } = EmploymentStatus.Probation;
+
+ [SugarColumn(IsNullable = true)]
+ public DateTime? ResignationDate { get; set; }
+
+ [SugarColumn(Length = 128, IsNullable = true)]
+ public string? Department { get; set; }
+
+ [SugarColumn(Length = 128, IsNullable = true)]
+ public string? Position { get; set; }
+
+ [SugarColumn(Length = 64, IsNullable = true)]
+ public string? JobLevel { get; set; }
+
+ public EmploymentType EmploymentType { get; set; } = EmploymentType.FullTime;
+
+ [SugarColumn(Length = 128, IsNullable = true)]
+ public string? WorkLocation { get; set; }
+
+ ///
+ /// 直属上级 RBAC 用户 Id。
+ ///
+ [SugarColumn(Length = 36, IsNullable = true)]
+ public string? ManagerUserId { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public DateTime? ContractStartDate { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public DateTime? ContractEndDate { get; set; }
+
+ [SugarColumn(Length = 64, IsNullable = true)]
+ public string? ContractType { get; set; }
+
+ [SugarColumn(Length = 64, IsNullable = true)]
+ public string? EmergencyContact { get; set; }
+
+ [SugarColumn(Length = 32, IsNullable = true)]
+ public string? EmergencyPhone { get; set; }
+
+ [SugarColumn(Length = 256, IsNullable = true)]
+ public string? Address { get; set; }
+
+ [SugarColumn(Length = 64, IsNullable = true)]
+ public string? Education { get; set; }
+
+ [SugarColumn(Length = 512, IsNullable = true)]
+ public string? Remark { get; set; }
+}
diff --git a/src/Oms.Domain/SystemAggregate/Enums/EmploymentStatus.cs b/src/Oms.Domain/SystemAggregate/Enums/EmploymentStatus.cs
new file mode 100644
index 0000000..abb1bc7
--- /dev/null
+++ b/src/Oms.Domain/SystemAggregate/Enums/EmploymentStatus.cs
@@ -0,0 +1,13 @@
+namespace Oms.Domain.SystemAggregate.Enums;
+
+///
+/// 在职状态。0=未设置;1=试用;2=正式;3=停职;4=离职。
+///
+public enum EmploymentStatus : byte
+{
+ None = 0,
+ Probation = 1,
+ Regular = 2,
+ Suspended = 3,
+ Resigned = 4
+}
diff --git a/src/Oms.Domain/SystemAggregate/Enums/EmploymentType.cs b/src/Oms.Domain/SystemAggregate/Enums/EmploymentType.cs
new file mode 100644
index 0000000..d7d98e7
--- /dev/null
+++ b/src/Oms.Domain/SystemAggregate/Enums/EmploymentType.cs
@@ -0,0 +1,13 @@
+namespace Oms.Domain.SystemAggregate.Enums;
+
+///
+/// 用工类型。0=未设置;1=全职;2=兼职;3=实习;4=外包。
+///
+public enum EmploymentType : byte
+{
+ None = 0,
+ FullTime = 1,
+ PartTime = 2,
+ Intern = 3,
+ Outsourced = 4
+}
diff --git a/src/Oms.Domain/SystemAggregate/Enums/Gender.cs b/src/Oms.Domain/SystemAggregate/Enums/Gender.cs
new file mode 100644
index 0000000..9f6bfc6
--- /dev/null
+++ b/src/Oms.Domain/SystemAggregate/Enums/Gender.cs
@@ -0,0 +1,11 @@
+namespace Oms.Domain.SystemAggregate.Enums;
+
+///
+/// 性别。0=未知;1=男;2=女。
+///
+public enum Gender : byte
+{
+ Unknown = 0,
+ Male = 1,
+ Female = 2
+}
diff --git a/src/Oms.Domain/SystemAggregate/Repositories/IEmployeeRepository.cs b/src/Oms.Domain/SystemAggregate/Repositories/IEmployeeRepository.cs
new file mode 100644
index 0000000..2e46b2a
--- /dev/null
+++ b/src/Oms.Domain/SystemAggregate/Repositories/IEmployeeRepository.cs
@@ -0,0 +1,11 @@
+using Fake.Domain.Repositories;
+using Oms.Domain.SystemAggregate.Entities;
+
+namespace Oms.Domain.SystemAggregate.Repositories;
+
+public interface IEmployeeRepository : IRepository
+{
+ Task GetByUserIdAsync(string userId, CancellationToken cancellationToken = default);
+
+ Task ExistsByUserIdAsync(string userId, int? excludeId = null, CancellationToken cancellationToken = default);
+}
diff --git a/src/Oms.SqlSugarCore/System/EmployeeRepository.cs b/src/Oms.SqlSugarCore/System/EmployeeRepository.cs
new file mode 100644
index 0000000..edd6394
--- /dev/null
+++ b/src/Oms.SqlSugarCore/System/EmployeeRepository.cs
@@ -0,0 +1,29 @@
+using Fake.DependencyInjection;
+using Oms.Domain.SystemAggregate.Entities;
+using Oms.Domain.SystemAggregate.Repositories;
+using Oms.SqlSugarCore.Repositories;
+
+namespace Oms.SqlSugarCore.System;
+
+public class EmployeeRepository : OmsSqlSugarRepository, IEmployeeRepository, IScopedDependency
+{
+ public Task GetByUserIdAsync(string userId, CancellationToken cancellationToken = default)
+ {
+ var normalized = userId.Trim();
+ return FirstOrDefaultAsync(x => x.UserId == normalized, cancellationToken);
+ }
+
+ public async Task ExistsByUserIdAsync(
+ string userId,
+ int? excludeId = null,
+ CancellationToken cancellationToken = default)
+ {
+ var normalized = userId.Trim();
+ if (excludeId.HasValue)
+ {
+ return await AnyAsync(x => x.UserId == normalized && x.Id != excludeId.Value, cancellationToken);
+ }
+
+ return await AnyAsync(x => x.UserId == normalized, cancellationToken);
+ }
+}
diff --git a/src/SimpleAdmin.Api/WeChat/Dtos/WeChatDtos.cs b/src/SimpleAdmin.Api/WeChat/Dtos/WeChatDtos.cs
index 20d4685..2415f6e 100644
--- a/src/SimpleAdmin.Api/WeChat/Dtos/WeChatDtos.cs
+++ b/src/SimpleAdmin.Api/WeChat/Dtos/WeChatDtos.cs
@@ -76,6 +76,11 @@ public class WeChatCustomerRegisterInput
[MinLength(6)]
public string Password { get; set; } = string.Empty;
+ ///
+ /// 邀请码(可选)。来自邀请链接 / 二维码 ?ref=,注册时一次性绑定引荐人。
+ ///
+ public string? InviteCode { get; set; }
+
[Required]
public WeChatProfileInput Wechat { get; set; } = new();
}
diff --git a/src/SimpleAdmin.Api/WeChat/WeChatCustomerService.cs b/src/SimpleAdmin.Api/WeChat/WeChatCustomerService.cs
index 2decf16..32e3613 100644
--- a/src/SimpleAdmin.Api/WeChat/WeChatCustomerService.cs
+++ b/src/SimpleAdmin.Api/WeChat/WeChatCustomerService.cs
@@ -12,6 +12,7 @@ using Oms.Application.Shared;
using Oms.Domain.CustomersAggregate.Entities;
using Oms.Domain.CustomersAggregate.Enums;
using Oms.Domain.CustomersAggregate.Repositories;
+using Oms.Domain.MarketingAggregate.Repositories;
using SimpleAdmin.Api.WeChat.Dtos;
using SimpleAdmin.Api.WeChat.Services;
@@ -25,6 +26,8 @@ namespace SimpleAdmin.Api.WeChat;
public class WeChatCustomerService(
IWeChatMpApiClient weChatMpApiClient,
ICustomerRepository customerRepository,
+ ICustomerReferralCodeRepository referralCodeRepository,
+ MarketingCouponManager couponManager,
UserService userService,
RoleService roleService,
FakeRbacDbContext rbacDbContext,
@@ -141,7 +144,26 @@ public class WeChatCustomerService(
WechatAvatar = wechatAvatar,
Status = CustomerStatus.Normal
};
+ await MarketingReferralBinder.BindReferrerOnCreateAsync(
+ entity,
+ input.InviteCode,
+ referralCodeRepository,
+ customerRepository,
+ cancellationToken);
+ if (!string.IsNullOrWhiteSpace(input.InviteCode) && entity.ReferrerCustomerId.HasValue)
+ {
+ entity.ReferralChannel = "wechat";
+ }
await customerRepository.InsertAsync(entity);
+
+ try
+ {
+ await couponManager.GrantNewcomerCouponsAsync(entity.Id, cancellationToken);
+ }
+ catch (Exception grantEx)
+ {
+ logger.LogWarning(grantEx, "新人券发放失败: customerId={CustomerId}", entity.Id);
+ }
}
catch (Exception ex)
{