From c5fb4c7e585f9dd118d3bd14b2d7c2dcba2b58f9 Mon Sep 17 00:00:00 2001 From: zzh <1368735060@qq.com> Date: Sun, 26 Jul 2026 23:18:57 +0800 Subject: [PATCH] feat: add employee profile, IDE employee nos, and marketing invite/coupon fixes Introduce t_employee linked to RBAC users, switch employee numbers to IDE001+, and keep invite bind/newcomer coupon backend changes. Drop retired sql/migrate and seed scripts in favor of db.sql. Co-authored-by: Cursor --- db.sql | 39 ++ scripts/t_employee.sql | 46 ++ sql/C_parcel_arrival.sql | 20 - sql/C_parcel_item_AttributeText.sql | 16 - sql/C_parcel_item_ImageUrl.sql | 16 - sql/fix_concurrency_stamp_missing.sql | 63 -- sql/fix_sales_store_concurrency_stamp.sql | 41 -- sql/migrate_drop_order_task_merge_batch.sql | 6 - sql/migrate_enum_int_comments.sql | 74 --- sql/migrate_label_pdf_fields.sql | 87 --- sql/migrate_marketing_module.sql | 336 ---------- ...migrate_order_batch_job_item_client_no.sql | 3 - ...igrate_order_status_pending_allocation.sql | 12 - sql/migrate_rename_warehouse_C_to_c.sql | 123 ---- sql/migrate_t_customer_sender_address.sql | 34 - ..._t_customer_sender_address_AddressType.sql | 41 -- sql/migrate_t_dict_type.sql | 90 --- ...rate_t_order_allocation_pending_reason.sql | 3 - sql/migrate_t_order_pickup_fields.sql | 75 --- sql/migrate_t_order_stock_bind.sql | 120 ---- sql/migrate_t_sales_store_order_recipient.sql | 32 - sql/seed_marketing_customer9.sql | 621 ------------------ sql/seed_pickup_order_customer9.sql | 306 --------- sql/seed_platform_shop_other_config.sql | 47 -- sql/seed_sales_store_customer9.sql | 510 -------------- .../Dtos/Marketing/CouponDtos.cs | 32 + .../Dtos/System/EmployeeOutput.cs | 63 ++ .../Dtos/System/EmployeeSaveInput.cs | 60 ++ .../Rbac/UserProfileRepository.cs | 9 +- .../Services/Customers/CustomerService.cs | 11 + .../MarketingCommissionAdminService.cs | 2 +- .../Marketing/MarketingCouponGrantService.cs | 7 + .../MarketingCouponTemplateService.cs | 1 + .../Services/Rbac/OmsUserService.cs | 36 +- .../Services/System/EmployeeService.cs | 147 +++++ .../Shared/MarketingCouponManager.cs | 36 + .../Shared/MarketingEnumNames.cs | 175 ++--- .../Shared/MarketingReferralBinder.cs | 42 +- .../Consts/MarketingConsts.cs | 14 + .../SystemAggregate/Entities/Employee.cs | 88 +++ .../SystemAggregate/Enums/EmploymentStatus.cs | 13 + .../SystemAggregate/Enums/EmploymentType.cs | 13 + .../SystemAggregate/Enums/Gender.cs | 11 + .../Repositories/IEmployeeRepository.cs | 11 + .../System/EmployeeRepository.cs | 29 + src/SimpleAdmin.Api/WeChat/Dtos/WeChatDtos.cs | 5 + .../WeChat/WeChatCustomerService.cs | 22 + 47 files changed, 823 insertions(+), 2765 deletions(-) create mode 100644 scripts/t_employee.sql delete mode 100644 sql/C_parcel_arrival.sql delete mode 100644 sql/C_parcel_item_AttributeText.sql delete mode 100644 sql/C_parcel_item_ImageUrl.sql delete mode 100644 sql/fix_concurrency_stamp_missing.sql delete mode 100644 sql/fix_sales_store_concurrency_stamp.sql delete mode 100644 sql/migrate_drop_order_task_merge_batch.sql delete mode 100644 sql/migrate_enum_int_comments.sql delete mode 100644 sql/migrate_label_pdf_fields.sql delete mode 100644 sql/migrate_marketing_module.sql delete mode 100644 sql/migrate_order_batch_job_item_client_no.sql delete mode 100644 sql/migrate_order_status_pending_allocation.sql delete mode 100644 sql/migrate_rename_warehouse_C_to_c.sql delete mode 100644 sql/migrate_t_customer_sender_address.sql delete mode 100644 sql/migrate_t_customer_sender_address_AddressType.sql delete mode 100644 sql/migrate_t_dict_type.sql delete mode 100644 sql/migrate_t_order_allocation_pending_reason.sql delete mode 100644 sql/migrate_t_order_pickup_fields.sql delete mode 100644 sql/migrate_t_order_stock_bind.sql delete mode 100644 sql/migrate_t_sales_store_order_recipient.sql delete mode 100644 sql/seed_marketing_customer9.sql delete mode 100644 sql/seed_pickup_order_customer9.sql delete mode 100644 sql/seed_platform_shop_other_config.sql delete mode 100644 sql/seed_sales_store_customer9.sql create mode 100644 src/Oms.Application/Dtos/System/EmployeeOutput.cs create mode 100644 src/Oms.Application/Dtos/System/EmployeeSaveInput.cs create mode 100644 src/Oms.Application/Services/System/EmployeeService.cs create mode 100644 src/Oms.Domain/SystemAggregate/Entities/Employee.cs create mode 100644 src/Oms.Domain/SystemAggregate/Enums/EmploymentStatus.cs create mode 100644 src/Oms.Domain/SystemAggregate/Enums/EmploymentType.cs create mode 100644 src/Oms.Domain/SystemAggregate/Enums/Gender.cs create mode 100644 src/Oms.Domain/SystemAggregate/Repositories/IEmployeeRepository.cs create mode 100644 src/Oms.SqlSugarCore/System/EmployeeRepository.cs 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) {