diff --git a/db.sql b/db.sql
index 91ca9b1..b0ff82d 100644
--- a/db.sql
+++ b/db.sql
@@ -29,6 +29,11 @@ DROP TABLE IF EXISTS `role_data_scope`;
DROP TABLE IF EXISTS `role_org_perm`;
DROP TABLE IF EXISTS `user_org_perm`;
DROP TABLE IF EXISTS `t_xhs_media`;
+DROP TABLE IF EXISTS `t_kb_article`;
+DROP TABLE IF EXISTS `t_kb_category`;
+DROP TABLE IF EXISTS `t_mcp_tool`;
+DROP TABLE IF EXISTS `t_pickup_order_line`;
+DROP TABLE IF EXISTS `t_pickup_order`;
DROP TABLE IF EXISTS `t_ai_skill`;
DROP TABLE IF EXISTS `t_ai_provider`;
DROP TABLE IF EXISTS `t_xhs_ai_provider`;
@@ -119,6 +124,9 @@ CREATE TABLE `t_order` (
`ExportCustomsMode` VARCHAR(32) NULL COMMENT '出口报关方式',
`PredeclareFailReason` VARCHAR(512) NULL COMMENT '预报失败原因',
`AllocationPendingReason` VARCHAR(512) NULL COMMENT '待排货原因(排货或渠道买价未匹配)',
+ `AllocationScheme` VARCHAR(32) NULL COMMENT '最近一次排货方案 costLowest/timeFastest/overallBest/designated',
+ `AllocationTraceJson` JSON NULL COMMENT '最近一次排货过程快照 JSON',
+ `AllocationTraceTime` DATETIME NULL COMMENT '排货快照写入时间',
`SalesProductRulesVersion` VARCHAR(64) NULL COMMENT '销售产品规则快照版本',
`SalesProductPriceVersion` VARCHAR(64) NULL COMMENT '销售产品价格快照版本',
`OrderStatus` VARCHAR(32) NOT NULL COMMENT '订单状态',
@@ -137,9 +145,20 @@ CREATE TABLE `t_order` (
`PreviousOrderStatus` VARCHAR(32) NULL COMMENT '进入异常状态前的订单状态',
`WarehouseId` INT NULL COMMENT '仓库ID',
`CustomerId` INT NULL COMMENT '客户ID',
+ `MemberLevelId` INT NULL COMMENT '下单时会员等级Id快照',
+ `PriceTierKey` VARCHAR(64) NULL COMMENT '下单时价区键快照',
+ `ReceivableSubtotal` DECIMAL(18,4) NULL COMMENT '应收小计(折扣前)',
+ `ForecastReceivableAmount` DECIMAL(18,4) NULL COMMENT '预报应收快照(创建预报后固化,入库不覆盖)',
+ `ForecastPayableAmount` DECIMAL(18,4) NULL COMMENT '预报应付快照(创建预报后固化,入库不覆盖)',
+ `LevelDiscountAmount` DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '会员等级折扣金额',
+ `CouponInstanceId` INT NULL COMMENT '使用的优惠券实例Id',
+ `CouponDiscountAmount` DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '优惠券抵扣金额',
+ `PayableAmount` DECIMAL(18,4) NULL COMMENT '应付金额(对客应收)',
`OrderSource` VARCHAR(32) NULL COMMENT '订单来源:manual/pickup/upload/batch/platform',
`PickupTime` DATETIME NULL COMMENT '预约揽收时间',
`CustomerSenderAddressId` INT NULL COMMENT '发件地址簿 Id',
+ `InboundMethod` VARCHAR(16) NULL COMMENT '到仓方式 selfShip/doorPickup',
+ `PickupOrderId` INT NULL COMMENT '关联揽收单Id(冗余)',
`OrganizationId` CHAR(36) NULL COMMENT '数据归属组织',
`SecretLevel` TINYINT NOT NULL DEFAULT 2 COMMENT '数据密级 1-4',
`SenderId` INT NULL COMMENT '发件人ID',
@@ -158,6 +177,7 @@ CREATE TABLE `t_order` (
`Quantity` INT NULL COMMENT '包裹数量',
`IsIntercept` TINYINT NOT NULL DEFAULT 0 COMMENT '是否拦截:0-否,1-是',
`IsRemote` TINYINT NOT NULL DEFAULT 0 COMMENT '是否偏远:0-否,1-是',
+ `AdditionalServices` VARCHAR(512) NULL COMMENT '客户勾选附加服务字典code JSON数组',
`LabelTemplateId` INT NULL COMMENT '出单标签模板Id',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
@@ -177,7 +197,9 @@ CREATE TABLE `t_order` (
KEY `idx_ord_recipient` (`RecipientId`),
KEY `idx_ord_declaration` (`DeclarationId`),
KEY `idx_ord_org_secret_ctime` (`OrganizationId`, `SecretLevel`, `CreateTime`),
- KEY `idx_ord_source_ctime` (`OrderSource`, `CreateTime`)
+ KEY `idx_ord_source_ctime` (`OrderSource`, `CreateTime`),
+ KEY `idx_order_pickup` (`PickupOrderId`),
+ KEY `idx_order_inbound_method` (`InboundMethod`)
) COMMENT='订单表';
CREATE TABLE `t_order_file` (
@@ -454,6 +476,9 @@ CREATE TABLE `t_order_exception_event` (
`Content` TEXT NULL COMMENT '内容快照',
`IssueTemplateId` INT NULL COMMENT '模板Id',
`NotifyMethod` VARCHAR(64) NULL COMMENT '通知方式快照',
+ `HandlerNames` VARCHAR(256) NULL COMMENT '处理人快照',
+ `HandlerType` VARCHAR(16) NULL COMMENT '处理人类型',
+ `HandlerUserId` INT NULL COMMENT '处理人用户Id(customer 时为订单客户账号)',
`ClaimType` VARCHAR(32) NULL COMMENT '理赔类型',
`ClaimAmount` DECIMAL(18,4) NULL COMMENT '索赔金额',
`ClaimCurrency` VARCHAR(16) NULL COMMENT '索赔币种',
@@ -475,6 +500,8 @@ CREATE TABLE `t_sales_product` (
`ProductGroup` VARCHAR(32) NULL COMMENT '分组(专线/快递/邮政)',
`MinTimeliness` INT NULL COMMENT '最小时效(天)',
`MaxTimeliness` INT NULL COMMENT '最大时效(天)',
+ `TradeTerms` VARCHAR(16) NULL COMMENT '贸易条款:DDP/DDU',
+ `AdditionalServices` VARCHAR(512) NULL COMMENT '可选附加服务字典code JSON数组',
`CustomerWaybill` VARCHAR(32) NULL COMMENT '系统面单/客户面单',
`BlacklistAreaId` INT NULL COMMENT '黑名单区ID',
`RemoteAreaId` INT NULL COMMENT '偏远分区ID',
@@ -578,6 +605,7 @@ CREATE TABLE `t_sales_product_publish_record` (
`PublishUser` VARCHAR(64) NOT NULL COMMENT '发布人',
`PublishTime` DATETIME NOT NULL COMMENT '发布时间',
`Description` VARCHAR(512) NULL COMMENT '版本备注',
+ `AiAnalysisReport` MEDIUMTEXT NULL COMMENT '价格发布AI风险分析报告',
`Content` JSON NULL COMMENT '发布内容JSON快照',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
@@ -615,6 +643,7 @@ CREATE TABLE `t_service_channel` (
`ForecastType` VARCHAR(32) NULL COMMENT '预报单号类型(customer/waybill/tracking)',
`ForecastCode` VARCHAR(128) NULL COMMENT '预报单号',
`Description` TEXT COMMENT '描述',
+ `RemoteAreaId` INT NULL COMMENT '偏远分区KPI AreaId',
`PreScript` TEXT COMMENT '入库前脚本',
`IsActive` TINYINT NOT NULL DEFAULT 2 COMMENT 'EnableStatus:0=None未设置,1=Disabled禁用,2=Enabled启用',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
@@ -825,6 +854,8 @@ CREATE TABLE `t_issue_template` (
`Title` VARCHAR(128) NOT NULL COMMENT '问题标题',
`Content` TEXT NOT NULL COMMENT '问题内容',
`NotifyMethod` VARCHAR(64) NOT NULL COMMENT '通知方式,逗号分隔',
+ `HandlerType` VARCHAR(16) NULL COMMENT '处理人类型:customer=订单所属客户 user=指定用户',
+ `HandlerUserId` INT NULL COMMENT '指定处理人用户Id(HandlerType=user 时必填)',
`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 (UUID()) COMMENT '并发戳',
@@ -934,6 +965,8 @@ CREATE TABLE `t_customer` (
`WechatNickname` VARCHAR(64) NULL COMMENT '微信昵称',
`Email` VARCHAR(64) NULL COMMENT '邮箱,用于登录/找回密码',
`Phone` VARCHAR(16) NULL COMMENT '手机号,用于联系;可空,唯一(NULL 可多条)',
+ `MemberLevelId` INT NULL COMMENT '会员等级Id',
+ `PriceTierKey` VARCHAR(64) NULL COMMENT '价区键(卖价 CustomerGroupValues JSON 键)',
`Balance` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '账户余额',
`TotalQuota` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '总额度',
`UsedQuota` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '已用额度',
@@ -1777,6 +1810,151 @@ CREATE TABLE `t_ai_skill` (
KEY `idx_ai_skill_scene` (`Scene`, `Enabled`, `SortOrder`)
) COMMENT='平台级 AI Skill(提示词/规范)';
+CREATE TABLE `t_mcp_tool` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
+ `ToolKey` VARCHAR(64) NOT NULL COMMENT '工具编码,如 oms.price_check',
+ `DisplayName` VARCHAR(128) NOT NULL COMMENT '显示名称',
+ `Description` VARCHAR(1000) NOT NULL COMMENT '给 AI 的工具描述',
+ `Enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用:0-否,1-是',
+ `SortOrder` INT NOT NULL DEFAULT 0 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_mcp_tool_key` (`ToolKey`),
+ KEY `idx_mcp_tool_enabled` (`Enabled`, `SortOrder`, `Id`)
+) COMMENT='MCP 工具配置表';
+
+CREATE TABLE `t_pickup_order` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
+ `PickupNo` VARCHAR(32) NOT NULL COMMENT '揽收单号',
+ `RequestId` VARCHAR(64) NULL COMMENT '请求幂等ID',
+ `CustomerId` INT NOT NULL COMMENT '客户Id',
+ `OrganizationId` CHAR(36) NULL COMMENT '数据归属组织',
+ `SecretLevel` TINYINT NOT NULL DEFAULT 2 COMMENT '数据密级 1-4',
+ `SenderAddressId` INT NOT NULL COMMENT '发件地址簿Id',
+ `SenderName` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '取件联系人快照',
+ `SenderCompany` VARCHAR(255) NULL COMMENT '公司快照',
+ `SenderCountry` INT NULL COMMENT '国家 t_country.Id 快照',
+ `SenderCountryCode` VARCHAR(8) NULL COMMENT '国家码快照',
+ `SenderProvince` VARCHAR(50) NULL COMMENT '省快照',
+ `SenderCity` VARCHAR(50) NULL COMMENT '市快照',
+ `SenderZipCode` VARCHAR(50) NULL COMMENT '邮编快照',
+ `SenderStreetAddress1` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '地址1快照',
+ `SenderStreetAddress2` VARCHAR(500) NULL COMMENT '地址2快照',
+ `SenderStreetAddress3` VARCHAR(500) NULL COMMENT '地址3快照',
+ `SenderHouseNumber` VARCHAR(50) NULL COMMENT '门牌号快照',
+ `SenderPhone` VARCHAR(50) NULL COMMENT '手机快照',
+ `SenderTelePhone` VARCHAR(50) NULL COMMENT '电话快照',
+ `SenderEmail` VARCHAR(60) NULL COMMENT '邮箱快照',
+ `WarehouseId` INT NOT NULL COMMENT '送到仓库Id',
+ `CarrierCode` VARCHAR(64) NULL COMMENT '承运商编码(draft可空)',
+ `CarrierService` VARCHAR(64) NULL COMMENT '承运服务(draft可空)',
+ `CarrierWaybillNo` VARCHAR(64) NULL COMMENT '承运商回执单号',
+ `ExpectPickupTime` DATETIME NOT NULL COMMENT '期望揽收时间',
+ `PickupWindowStart` DATETIME NULL COMMENT '时间窗起',
+ `PickupWindowEnd` DATETIME NULL COMMENT '时间窗止',
+ `ActualPickupTime` DATETIME NULL COMMENT '实际取件时间',
+ `Status` VARCHAR(32) NOT NULL DEFAULT 'draft' COMMENT 'draft/scheduled/dispatched/picked/inbound/cancelled/failed',
+ `ParcelCount` INT NOT NULL DEFAULT 0 COMMENT '关联票数',
+ `TotalActualWeight` DECIMAL(18,3) NULL COMMENT '汇总实重',
+ `ChargeableWeight` DECIMAL(18,3) NULL COMMENT '计费重',
+ `Currency` VARCHAR(8) NOT NULL DEFAULT 'CNY' COMMENT '币种',
+ `FreightAmount` DECIMAL(18,2) NULL COMMENT '对客揽收运费',
+ `OtherFeeAmount` DECIMAL(18,2) NULL COMMENT '对客其他费',
+ `ReceivableAmount` DECIMAL(18,2) NULL COMMENT '对客应收合计',
+ `PayStatus` VARCHAR(16) NOT NULL DEFAULT 'unpaid' COMMENT 'unpaid/paid',
+ `PayTime` DATETIME NULL COMMENT '支付时间',
+ `PayMode` VARCHAR(16) NOT NULL DEFAULT 'prepaid' COMMENT 'prepaid/collect',
+ `CarrierPayableAmount` DECIMAL(18,2) NULL COMMENT '应付承运商',
+ `SettlementStatus` VARCHAR(16) NOT NULL DEFAULT 'none' COMMENT 'none/pending/settled',
+ `SettlementBatchNo` VARCHAR(64) NULL COMMENT '结算批次号',
+ `SettledAt` DATETIME 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_pickup_no` (`PickupNo`),
+ UNIQUE KEY `uk_pickup_request_id` (`RequestId`),
+ KEY `idx_pickup_customer_status` (`CustomerId`, `Status`, `CreateTime`),
+ KEY `idx_pickup_warehouse_time` (`WarehouseId`, `ExpectPickupTime`),
+ KEY `idx_pickup_pay` (`PayStatus`),
+ KEY `idx_pickup_settle` (`SettlementStatus`),
+ KEY `idx_pickup_org_secret_ctime` (`OrganizationId`, `SecretLevel`, `CreateTime`)
+) COMMENT='揽收单(上门取件履约+对客收款+承运结算)';
+
+CREATE TABLE `t_pickup_order_line` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
+ `PickupOrderId` INT NOT NULL COMMENT '揽收单Id',
+ `OrderId` INT NOT NULL COMMENT '物流订单Id',
+ `ServiceNo` VARCHAR(64) NULL COMMENT '运单号快照(便于列表)',
+ `ClientNo` VARCHAR(64) NULL COMMENT '客户单号快照',
+ `SortNo` 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_pickup_line_order` (`OrderId`),
+ UNIQUE KEY `uk_pickup_line_pair` (`PickupOrderId`, `OrderId`),
+ KEY `idx_pickup_line_header` (`PickupOrderId`, `IsDeleted`)
+) COMMENT='揽收单关联物流订单(1揽收:N物流)';
+
+CREATE TABLE `t_kb_category` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `Code` VARCHAR(64) NOT NULL COMMENT '稳定键,如 pricing',
+ `Name` VARCHAR(128) NOT NULL COMMENT '展示名(中文)',
+ `SortOrder` INT NOT NULL DEFAULT 0 COMMENT '排序,越小越前',
+ `Enabled` TINYINT NOT NULL DEFAULT 1 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`),
+ UNIQUE KEY `uk_kb_category_code` (`Code`),
+ KEY `idx_kb_category_enabled_sort` (`Enabled`, `SortOrder`)
+) COMMENT='知识库分类';
+
+CREATE TABLE `t_kb_article` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `CategoryId` INT NOT NULL COMMENT '分类 Id',
+ `Title` VARCHAR(200) NOT NULL COMMENT '标题(中文)',
+ `Summary` VARCHAR(500) NULL COMMENT '列表摘要',
+ `Content` LONGTEXT NOT NULL COMMENT 'Markdown 正文(中文)',
+ `Audience` VARCHAR(16) NOT NULL DEFAULT 'customer' COMMENT '受众 customer/internal',
+ `Status` VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT 'draft/published/offline',
+ `Tags` VARCHAR(256) NULL COMMENT '逗号分隔标签',
+ `RelatedPath` VARCHAR(256) NULL COMMENT '站内关联 path',
+ `RelatedLabel` VARCHAR(64) NULL COMMENT '关联按钮文案',
+ `IsPinned` TINYINT NOT NULL DEFAULT 0 COMMENT '置顶:0-否,1-是',
+ `SortOrder` INT NOT NULL DEFAULT 0 COMMENT '同类排序',
+ `PublishTime` DATETIME NULL COMMENT '发布时间',
+ `ExpireTime` DATETIME NULL COMMENT '过期时间',
+ `ViewCount` 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`),
+ KEY `idx_kb_article_list` (`Status`, `Audience`, `CategoryId`, `IsPinned`, `SortOrder`),
+ KEY `idx_kb_article_publish` (`Status`, `Audience`, `PublishTime`),
+ KEY `idx_kb_article_hot` (`Status`, `Audience`, `IsPinned`, `ViewCount`)
+) COMMENT='知识库文章';
+
CREATE TABLE `t_xhs_media` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
diff --git a/sql/20260727_customer_phone_nullable.sql b/sql/20260727_customer_phone_nullable.sql
deleted file mode 100644
index 1788f35..0000000
--- a/sql/20260727_customer_phone_nullable.sql
+++ /dev/null
@@ -1,5 +0,0 @@
--- 微信注册简化:客户手机号改为可空(空值请用 NULL,勿存空字符串)
--- 执行环境:生产库先备份;与 docs/微信注册简化与联系方式补全方案.md 一致
-
-ALTER TABLE `t_customer`
- MODIFY COLUMN `Phone` VARCHAR(16) NULL COMMENT '手机号,用于联系;可空,唯一(NULL 可多条)';
diff --git a/sql/20260728_auto_trigger_merge_forecast_to_order_create.sql b/sql/20260728_auto_trigger_merge_forecast_to_order_create.sql
deleted file mode 100644
index c3532bf..0000000
--- a/sql/20260728_auto_trigger_merge_forecast_to_order_create.sql
+++ /dev/null
@@ -1,6 +0,0 @@
--- 自动触发时机:预报 并入 下单
-UPDATE t_auto_trigger
-SET TriggerTiming = N'下单'
-WHERE TriggerTiming IN (N'预报', N'forecast', N'order_create', N'OrderCreate')
- OR TriggerTiming LIKE N'%预报%'
- OR LOWER(TriggerTiming) LIKE N'%forecast%';
diff --git a/sql/20260728_order_downstream_service_no.sql b/sql/20260728_order_downstream_service_no.sql
deleted file mode 100644
index 691807f..0000000
--- a/sql/20260728_order_downstream_service_no.sql
+++ /dev/null
@@ -1,5 +0,0 @@
--- Add DownstreamServiceNo to t_order (provider service no from createOrderOne Data.serviceNo)
--- Backup production DB before running.
-
-ALTER TABLE `t_order`
- ADD COLUMN `DownstreamServiceNo` VARCHAR(64) NULL COMMENT 'Downstream provider service no' AFTER `TrackNo`;
diff --git a/sql/20260728_order_file.sql b/sql/20260728_order_file.sql
deleted file mode 100644
index 1e94b5f..0000000
--- a/sql/20260728_order_file.sql
+++ /dev/null
@@ -1,50 +0,0 @@
--- 订单附件表;将原 LabelUrl 迁移为 systemLabel 后删除订单旧面单字段。
--- 在 MySQL 执行前请先备份。
-
-CREATE TABLE IF NOT EXISTS `t_order_file` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
- `OrderId` INT NOT NULL COMMENT '订单Id',
- `FileType` VARCHAR(32) NOT NULL COMMENT '附件类型:tradeProof交易证明/systemLabel系统面单/downstreamLabel下游面单/lastMileLabel末端面单/infraredImage红外图片',
- `FileName` VARCHAR(255) NULL COMMENT '原始文件名',
- `FileUrl` VARCHAR(512) NOT NULL COMMENT '文件地址(相对路径或外链)',
- `ContentType` VARCHAR(128) NULL COMMENT '文件MIME类型',
- `FileSize` BIGINT NULL COMMENT '文件大小(字节)',
- `Sort` INT NOT NULL DEFAULT 0 COMMENT '同类型内排序',
- `Source` VARCHAR(32) NOT NULL DEFAULT 'upload' COMMENT '来源:upload上传/systemGenerate系统生成/downstream下游回传/migrate迁移',
- `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`),
- KEY `idx_ord_file_order_type` (`OrderId`, `FileType`, `IsDeleted`)
-) COMMENT='订单附件表';
-
--- 迁移已有系统面单地址(若 LabelUrl 列已删除可跳过本段)
-INSERT INTO `t_order_file` (`OrderId`, `FileType`, `FileName`, `FileUrl`, `ContentType`, `Sort`, `Source`, `CreateUserId`, `CreateTime`)
-SELECT
- `Id`,
- 'systemLabel',
- SUBSTRING_INDEX(`LabelUrl`, '/', -1),
- `LabelUrl`,
- 'application/pdf',
- 0,
- 'migrate',
- 0,
- NOW()
-FROM `t_order`
-WHERE `LabelUrl` IS NOT NULL
- AND TRIM(`LabelUrl`) <> ''
- AND NOT EXISTS (
- SELECT 1 FROM `t_order_file` f
- WHERE f.`OrderId` = `t_order`.`Id`
- AND f.`FileType` = 'systemLabel'
- AND f.`IsDeleted` = 0
- );
-
-ALTER TABLE `t_order`
- DROP COLUMN `LabelUrl`,
- DROP COLUMN `LabelGenerateStatus`,
- DROP COLUMN `LabelGenerateError`;
diff --git a/sql/20260728_order_file_comments.sql b/sql/20260728_order_file_comments.sql
deleted file mode 100644
index 1934c3c..0000000
--- a/sql/20260728_order_file_comments.sql
+++ /dev/null
@@ -1,20 +0,0 @@
--- 若 t_order_file 已按英文注释建表,执行本脚本改为中文注释(不改结构)。
-
-ALTER TABLE `t_order_file`
- MODIFY COLUMN `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
- MODIFY COLUMN `OrderId` INT NOT NULL COMMENT '订单Id',
- MODIFY COLUMN `FileType` VARCHAR(32) NOT NULL COMMENT '附件类型:tradeProof交易证明/systemLabel系统面单/downstreamLabel下游面单/lastMileLabel末端面单/infraredImage红外图片',
- MODIFY COLUMN `FileName` VARCHAR(255) NULL COMMENT '原始文件名',
- MODIFY COLUMN `FileUrl` VARCHAR(512) NOT NULL COMMENT '文件地址(相对路径或外链)',
- MODIFY COLUMN `ContentType` VARCHAR(128) NULL COMMENT '文件MIME类型',
- MODIFY COLUMN `FileSize` BIGINT NULL COMMENT '文件大小(字节)',
- MODIFY COLUMN `Sort` INT NOT NULL DEFAULT 0 COMMENT '同类型内排序',
- MODIFY COLUMN `Source` VARCHAR(32) NOT NULL DEFAULT 'upload' COMMENT '来源:upload上传/systemGenerate系统生成/downstream下游回传/migrate迁移',
- MODIFY COLUMN `Remark` VARCHAR(512) NULL COMMENT '备注',
- MODIFY COLUMN `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- MODIFY COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
- MODIFY COLUMN `CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
- MODIFY COLUMN `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
- MODIFY COLUMN `UpdateUserId` INT NULL COMMENT '更新人',
- MODIFY COLUMN `UpdateTime` DATETIME NULL COMMENT '更新时间',
- COMMENT='订单附件表';
diff --git a/sql/20260729_fix_user_empty_email.sql b/sql/20260729_fix_user_empty_email.sql
deleted file mode 100644
index 3485f95..0000000
--- a/sql/20260729_fix_user_empty_email.sql
+++ /dev/null
@@ -1,12 +0,0 @@
--- 修复:微信注册无邮箱时曾写入 user.Email='',撞 uk_user_email 导致后续注册提示「邮箱已被占用」
--- 将空邮箱改为「客户编号@noemail.local」占位(与 CustomerContactHelper.ResolveRbacEmailOrPlaceholder 一致)
-
-UPDATE `user` u
-INNER JOIN `t_customer` c ON c.`UserId` = u.`userid`
-SET u.`Email` = CONCAT(LOWER(TRIM(c.`CustomerCode`)), '@noemail.local')
-WHERE u.`Email` IS NULL OR TRIM(u.`Email`) = '';
-
--- 无客户关联的残留空邮箱
-UPDATE `user`
-SET `Email` = CONCAT('u', `userid`, '@noemail.local')
-WHERE `Email` IS NULL OR TRIM(`Email`) = '';
diff --git a/sql/20260729_mcp_tool.sql b/sql/20260729_mcp_tool.sql
deleted file mode 100644
index ebb0a69..0000000
--- a/sql/20260729_mcp_tool.sql
+++ /dev/null
@@ -1,32 +0,0 @@
--- MCP 工具配置(启用/描述覆盖),与代码内置目录合并
--- 对齐 t_system_other_config / t_order_file 等配置表结构习惯
-
-CREATE TABLE IF NOT EXISTS `t_mcp_tool` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
- `ToolKey` VARCHAR(64) NOT NULL COMMENT '工具编码,如 oms.price_check',
- `DisplayName` VARCHAR(128) NOT NULL COMMENT '显示名称',
- `Description` VARCHAR(1000) NOT NULL COMMENT '给 AI 的工具描述',
- `Enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用:0-否,1-是',
- `SortOrder` INT NOT NULL DEFAULT 0 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_mcp_tool_key` (`ToolKey`),
- KEY `idx_mcp_tool_enabled` (`Enabled`, `SortOrder`, `Id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MCP 工具配置表';
-
-INSERT INTO `t_mcp_tool` (`ToolKey`, `DisplayName`, `Description`, `Enabled`, `SortOrder`, `Remark`)
-VALUES
- ('oms.price_check', '查价格', '根据目的国、重量等查询运费报价,返回可用渠道与价格摘要。', 1, 10, '内置:封装 /order/price-check'),
- ('oms.channel_guide', '查渠道对客说明', '按销售产品代码/名称查询对客说明(禁运、可寄品名等),判断客户品名是否可承运。', 1, 20, '内置:读销售产品 CustomerGuideMarkdown'),
- ('oms.track_query', '查轨迹', '根据运单号/客户单号查询物流轨迹时间轴摘要。', 1, 30, '内置:轨迹中心 GetDetailTimeline')
-ON DUPLICATE KEY UPDATE
- `DisplayName` = VALUES(`DisplayName`),
- `Description` = VALUES(`Description`),
- `SortOrder` = VALUES(`SortOrder`),
- `Remark` = VALUES(`Remark`);
diff --git a/sql/20260729_mcp_tool_alter_align.sql b/sql/20260729_mcp_tool_alter_align.sql
deleted file mode 100644
index 501ee94..0000000
--- a/sql/20260729_mcp_tool_alter_align.sql
+++ /dev/null
@@ -1,38 +0,0 @@
--- 若已按旧版建过 t_mcp_tool,执行本脚本补齐字段(幂等)
-
-ALTER TABLE `t_mcp_tool`
- ADD COLUMN IF NOT EXISTS `Remark` VARCHAR(512) NULL COMMENT '备注' AFTER `SortOrder`;
-
--- MySQL 8.0.12 前无 IF NOT EXISTS 时,可改用下面手工判断;8.0.29+ 支持 ADD COLUMN IF NOT EXISTS
--- 并发戳:已存在则跳过
-SET @col_exists := (
- SELECT COUNT(*) FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_mcp_tool'
- AND COLUMN_NAME = 'ConcurrencyStamp'
-);
-SET @sql := IF(
- @col_exists = 0,
- 'ALTER TABLE `t_mcp_tool` ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT ''并发戳'' AFTER `IsDeleted`',
- 'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @idx_exists := (
- SELECT COUNT(*) FROM information_schema.STATISTICS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_mcp_tool'
- AND INDEX_NAME = 'idx_mcp_tool_enabled'
-);
-SET @sql := IF(
- @idx_exists = 0,
- 'ALTER TABLE `t_mcp_tool` ADD KEY `idx_mcp_tool_enabled` (`Enabled`, `SortOrder`, `Id`)',
- 'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-ALTER TABLE `t_mcp_tool` COMMENT = 'MCP 工具配置表';
diff --git a/sql/20260730_customer_price_tier_key.sql b/sql/20260730_customer_price_tier_key.sql
deleted file mode 100644
index cbc9b9f..0000000
--- a/sql/20260730_customer_price_tier_key.sql
+++ /dev/null
@@ -1,46 +0,0 @@
--- 价区键迁到客户:与会员等级解耦
--- 新注册默认价区键/会员等级均为「普通会员」;计价时空键回落「普通客户」
-
--- 1) 客户表增加价区键
-ALTER TABLE `t_customer`
- ADD COLUMN `PriceTierKey` VARCHAR(64) NULL COMMENT '价区键(卖价 CustomerGroupValues JSON 键)' AFTER `MemberLevelId`;
-
--- 2) 从原会员等级价区键回填(依赖本脚本执行前 t_member_level 仍有 PriceTierKey)
-UPDATE `t_customer` c
-INNER JOIN `t_member_level` ml ON ml.`Id` = c.`MemberLevelId` AND ml.`IsDeleted` = 0
-SET c.`PriceTierKey` = NULLIF(TRIM(ml.`PriceTierKey`), '')
-WHERE c.`IsDeleted` = 0
- AND (c.`PriceTierKey` IS NULL OR TRIM(c.`PriceTierKey`) = '')
- AND ml.`PriceTierKey` IS NOT NULL
- AND TRIM(ml.`PriceTierKey`) <> '';
-
--- 3) 仍为空的主客户:默认「普通会员」(与新注册一致)
-UPDATE `t_customer`
-SET `PriceTierKey` = '普通会员'
-WHERE `IsDeleted` = 0
- AND (`ParentCustomerId` IS NULL OR `ParentCustomerId` = 0)
- AND (`PriceTierKey` IS NULL OR TRIM(`PriceTierKey`) = '');
-
--- 4) 子客户跟随主客户价区
-UPDATE `t_customer` sub
-INNER JOIN `t_customer` main ON main.`Id` = sub.`ParentCustomerId` AND main.`IsDeleted` = 0
-SET sub.`PriceTierKey` = main.`PriceTierKey`
-WHERE sub.`IsDeleted` = 0
- AND sub.`ParentCustomerId` IS NOT NULL
- AND sub.`ParentCustomerId` <> 0;
-
--- 5) 删除会员等级上的价区键列(须在插入默认等级前执行,避免 NOT NULL 约束)
-ALTER TABLE `t_member_level` DROP COLUMN `PriceTierKey`;
-
--- 6) 确保存在启用的「普通会员」等级(供新注册默认挂靠)
-INSERT INTO `t_member_level` (
- `LevelCode`, `LevelName`, `MinPoints`, `ExtraDiscountRate`, `Sort`,
- `Status`, `IsDeleted`, `CreateTime`
-)
-SELECT '普通会员', '普通会员', 0, 0, 0, 2, 0, NOW()
-FROM DUAL
-WHERE NOT EXISTS (
- SELECT 1 FROM `t_member_level`
- WHERE `IsDeleted` = 0
- AND (`LevelName` = '普通会员' OR `LevelCode` = '普通会员')
-);
diff --git a/sql/20260730_sales_product_trade_terms.sql b/sql/20260730_sales_product_trade_terms.sql
deleted file mode 100644
index 9817317..0000000
--- a/sql/20260730_sales_product_trade_terms.sql
+++ /dev/null
@@ -1,3 +0,0 @@
--- 销售产品:贸易条款 DDP / DDU(查价线路返回并展示于价卡)
-ALTER TABLE `t_sales_product`
- ADD COLUMN `TradeTerms` VARCHAR(16) NULL COMMENT '贸易条款:DDP/DDU' AFTER `MaxTimeliness`;
diff --git a/sql/20260801_ai_skill.sql b/sql/20260801_ai_skill.sql
deleted file mode 100644
index 1ea238a..0000000
--- a/sql/20260801_ai_skill.sql
+++ /dev/null
@@ -1,26 +0,0 @@
--- 平台级 AI Skill 表(全局一份,系统页维护)
-CREATE TABLE IF NOT EXISTS `t_ai_skill` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
- `SkillKey` VARCHAR(64) NOT NULL COMMENT '稳定键',
- `Scene` VARCHAR(32) NOT NULL COMMENT '场景 pricePublish/autoTriggerFormula/receiverAddressParse/itfxPrefixScript',
- `Name` VARCHAR(128) NOT NULL COMMENT '展示名',
- `Description` VARCHAR(512) NULL COMMENT '简介',
- `Content` LONGTEXT NOT NULL COMMENT '发给模型的正文',
- `SortOrder` INT NOT NULL DEFAULT 0 COMMENT '排序',
- `Enabled` TINYINT NOT NULL DEFAULT 1 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`),
- UNIQUE KEY `uk_ai_skill_key` (`SkillKey`),
- KEY `idx_ai_skill_scene` (`Scene`, `Enabled`, `SortOrder`)
-) COMMENT='平台级 AI Skill(提示词/规范)';
-
--- 若表已按旧脚本建好(无 ConcurrencyStamp),执行:
--- ALTER TABLE `t_ai_skill`
--- ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳' AFTER `IsDeleted`;
-
--- 种子数据由应用首次调用 /ai/skill/list|get 时幂等写入(避免 LONGTEXT 转义问题)。
diff --git a/sql/20260801_billing_additional_services.sql b/sql/20260801_billing_additional_services.sql
deleted file mode 100644
index 4076bc9..0000000
--- a/sql/20260801_billing_additional_services.sql
+++ /dev/null
@@ -1,11 +0,0 @@
--- 附加服务 / 渠道偏远分区
--- 字典种子由前端 dict-batch-import 同步;AI Skill 由应用首次 list/get 幂等写入。
-
-ALTER TABLE `t_sales_product`
- ADD COLUMN `AdditionalServices` VARCHAR(512) NULL COMMENT '可选附加服务字典code JSON数组' AFTER `TradeTerms`;
-
-ALTER TABLE `t_order`
- ADD COLUMN `AdditionalServices` VARCHAR(512) NULL COMMENT '客户勾选附加服务字典code JSON数组' AFTER `IsRemote`;
-
-ALTER TABLE `t_service_channel`
- ADD COLUMN `RemoteAreaId` INT NULL COMMENT '偏远分区KPI AreaId' AFTER `Description`;
diff --git a/sql/20260801_billing_phase2.sql b/sql/20260801_billing_phase2.sql
deleted file mode 100644
index ae7b2d9..0000000
--- a/sql/20260801_billing_phase2.sql
+++ /dev/null
@@ -1,5 +0,0 @@
--- Phase-2:预报应收/应付快照(预报→入库差额对比)
-
-ALTER TABLE `t_order`
- ADD COLUMN `ForecastReceivableAmount` DECIMAL(18,4) NULL COMMENT '预报应收快照(创建预报后固化,入库不覆盖)' AFTER `ReceivableSubtotal`,
- ADD COLUMN `ForecastPayableAmount` DECIMAL(18,4) NULL COMMENT '预报应付快照(创建预报后固化,入库不覆盖)' AFTER `ForecastReceivableAmount`;
diff --git a/sql/20260801_global_ai_provider.sql b/sql/20260801_global_ai_provider.sql
deleted file mode 100644
index 33788ab..0000000
--- a/sql/20260801_global_ai_provider.sql
+++ /dev/null
@@ -1,16 +0,0 @@
--- 全局 AI 提供商:从小红书域表迁出(未上线环境可直接改名)
--- 若表尚不存在则跳过;若已是 t_ai_provider 则无需执行。
-
-RENAME TABLE `t_xhs_ai_provider` TO `t_ai_provider`;
-
-ALTER TABLE `t_ai_provider`
- COMMENT = '全局 AI 提供商配置表(CustomerId=0 表示平台级)';
-
--- 索引名顺带规范化(可选,失败可忽略)
-ALTER TABLE `t_ai_provider`
- DROP INDEX `uk_xhs_ai_provider`,
- ADD UNIQUE KEY `uk_ai_provider` (`CustomerId`, `ProviderKey`);
-
-ALTER TABLE `t_ai_provider`
- DROP INDEX `idx_xhs_ai_customer`,
- ADD KEY `idx_ai_customer` (`CustomerId`, `Enabled`);
diff --git a/sql/20260801_order_allocation_trace.sql b/sql/20260801_order_allocation_trace.sql
deleted file mode 100644
index 2f89baf..0000000
--- a/sql/20260801_order_allocation_trace.sql
+++ /dev/null
@@ -1,6 +0,0 @@
--- 订单排货过程快照(方案 + 候选指标,供详情「查看排货过程」)
-
-ALTER TABLE `t_order`
- ADD COLUMN `AllocationScheme` VARCHAR(32) NULL COMMENT '最近一次排货方案 costLowest/timeFastest/overallBest/designated' AFTER `AllocationPendingReason`,
- ADD COLUMN `AllocationTraceJson` JSON NULL COMMENT '最近一次排货过程快照 JSON' AFTER `AllocationScheme`,
- ADD COLUMN `AllocationTraceTime` DATETIME NULL COMMENT '排货快照写入时间' AFTER `AllocationTraceJson`;
diff --git a/sql/20260801_sales_product_publish_ai_report.sql b/sql/20260801_sales_product_publish_ai_report.sql
deleted file mode 100644
index d2fd354..0000000
--- a/sql/20260801_sales_product_publish_ai_report.sql
+++ /dev/null
@@ -1,3 +0,0 @@
--- 销售产品价格发布记录:保存 AI 风险分析报告
-ALTER TABLE `t_sales_product_publish_record`
- ADD COLUMN `AiAnalysisReport` MEDIUMTEXT NULL COMMENT '价格发布AI风险分析报告' AFTER `Description`;
diff --git a/sql/20260803_pickup_order.sql b/sql/20260803_pickup_order.sql
deleted file mode 100644
index 62d1cbe..0000000
--- a/sql/20260803_pickup_order.sql
+++ /dev/null
@@ -1,95 +0,0 @@
--- 揽收单(独立履约/结算)+ 与物流单 1:N 关联;物流单冗余到仓方式与揽收 FK。
--- 对齐现表公共字段:ConcurrencyStamp / OrganizationId / SecretLevel;发件快照对齐 t_order_sender。
--- 文档:前端 docs/揽收单与物流单串联方案.md
--- 执行前请备份。
--- 若表已按旧版脚本建好,请改跑 sql/20260803_pickup_order_align_fields.sql
-
-CREATE TABLE IF NOT EXISTS `t_pickup_order` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
- `PickupNo` VARCHAR(32) NOT NULL COMMENT '揽收单号',
- `RequestId` VARCHAR(64) NULL COMMENT '请求幂等ID',
- `CustomerId` INT NOT NULL COMMENT '客户Id',
- `OrganizationId` CHAR(36) NULL COMMENT '数据归属组织',
- `SecretLevel` TINYINT NOT NULL DEFAULT 2 COMMENT '数据密级 1-4',
- `SenderAddressId` INT NOT NULL COMMENT '发件地址簿Id',
- `SenderName` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '取件联系人快照',
- `SenderCompany` VARCHAR(255) NULL COMMENT '公司快照',
- `SenderCountry` INT NULL COMMENT '国家 t_country.Id 快照',
- `SenderCountryCode` VARCHAR(8) NULL COMMENT '国家码快照',
- `SenderProvince` VARCHAR(50) NULL COMMENT '省快照',
- `SenderCity` VARCHAR(50) NULL COMMENT '市快照',
- `SenderZipCode` VARCHAR(50) NULL COMMENT '邮编快照',
- `SenderStreetAddress1` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '地址1快照',
- `SenderStreetAddress2` VARCHAR(500) NULL COMMENT '地址2快照',
- `SenderStreetAddress3` VARCHAR(500) NULL COMMENT '地址3快照',
- `SenderHouseNumber` VARCHAR(50) NULL COMMENT '门牌号快照',
- `SenderPhone` VARCHAR(50) NULL COMMENT '手机快照',
- `SenderTelePhone` VARCHAR(50) NULL COMMENT '电话快照',
- `SenderEmail` VARCHAR(60) NULL COMMENT '邮箱快照',
- `WarehouseId` INT NOT NULL COMMENT '送到仓库Id',
- `CarrierCode` VARCHAR(64) NULL COMMENT '承运商编码(draft可空)',
- `CarrierService` VARCHAR(64) NULL COMMENT '承运服务(draft可空)',
- `CarrierWaybillNo` VARCHAR(64) NULL COMMENT '承运商回执单号',
- `ExpectPickupTime` DATETIME NOT NULL COMMENT '期望揽收时间',
- `PickupWindowStart` DATETIME NULL COMMENT '时间窗起',
- `PickupWindowEnd` DATETIME NULL COMMENT '时间窗止',
- `ActualPickupTime` DATETIME NULL COMMENT '实际取件时间',
- `Status` VARCHAR(32) NOT NULL DEFAULT 'draft' COMMENT 'draft/scheduled/dispatched/picked/inbound/cancelled/failed',
- `ParcelCount` INT NOT NULL DEFAULT 0 COMMENT '关联票数',
- `TotalActualWeight` DECIMAL(18,3) NULL COMMENT '汇总实重',
- `ChargeableWeight` DECIMAL(18,3) NULL COMMENT '计费重',
- `Currency` VARCHAR(8) NOT NULL DEFAULT 'CNY' COMMENT '币种',
- `FreightAmount` DECIMAL(18,2) NULL COMMENT '对客揽收运费',
- `OtherFeeAmount` DECIMAL(18,2) NULL COMMENT '对客其他费',
- `ReceivableAmount` DECIMAL(18,2) NULL COMMENT '对客应收合计',
- `PayStatus` VARCHAR(16) NOT NULL DEFAULT 'unpaid' COMMENT 'unpaid/paid',
- `PayTime` DATETIME NULL COMMENT '支付时间',
- `PayMode` VARCHAR(16) NOT NULL DEFAULT 'prepaid' COMMENT 'prepaid/collect',
- `CarrierPayableAmount` DECIMAL(18,2) NULL COMMENT '应付承运商',
- `SettlementStatus` VARCHAR(16) NOT NULL DEFAULT 'none' COMMENT 'none/pending/settled',
- `SettlementBatchNo` VARCHAR(64) NULL COMMENT '结算批次号',
- `SettledAt` DATETIME NULL COMMENT '结算时间',
- `Remark` VARCHAR(512) NULL COMMENT '备注',
- `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
- -- CREATE 可用 DEFAULT (UUID());若环境同样禁非确定默认值,可去掉 DEFAULT,由应用写入
- `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_pickup_no` (`PickupNo`),
- UNIQUE KEY `uk_pickup_request_id` (`RequestId`),
- KEY `idx_pickup_customer_status` (`CustomerId`, `Status`, `CreateTime`),
- KEY `idx_pickup_warehouse_time` (`WarehouseId`, `ExpectPickupTime`),
- KEY `idx_pickup_pay` (`PayStatus`),
- KEY `idx_pickup_settle` (`SettlementStatus`),
- KEY `idx_pickup_org_secret_ctime` (`OrganizationId`, `SecretLevel`, `CreateTime`)
-) COMMENT='揽收单(上门取件履约+对客收款+承运结算)';
-
-CREATE TABLE IF NOT EXISTS `t_pickup_order_line` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
- `PickupOrderId` INT NOT NULL COMMENT '揽收单Id',
- `OrderId` INT NOT NULL COMMENT '物流订单Id',
- `ServiceNo` VARCHAR(64) NULL COMMENT '运单号快照(便于列表)',
- `ClientNo` VARCHAR(64) NULL COMMENT '客户单号快照',
- `SortNo` 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_pickup_line_order` (`OrderId`),
- UNIQUE KEY `uk_pickup_line_pair` (`PickupOrderId`, `OrderId`),
- KEY `idx_pickup_line_header` (`PickupOrderId`, `IsDeleted`)
-) COMMENT='揽收单关联物流订单(1揽收:N物流)';
-
-ALTER TABLE `t_order`
- ADD COLUMN `InboundMethod` VARCHAR(16) NULL COMMENT '到仓方式 selfShip/doorPickup' AFTER `CustomerSenderAddressId`,
- ADD COLUMN `PickupOrderId` INT NULL COMMENT '关联揽收单Id(冗余)' AFTER `InboundMethod`;
-
-ALTER TABLE `t_order`
- ADD KEY `idx_order_pickup` (`PickupOrderId`),
- ADD KEY `idx_order_inbound_method` (`InboundMethod`);
diff --git a/sql/20260803_pickup_order_align_fields.sql b/sql/20260803_pickup_order_align_fields.sql
deleted file mode 100644
index 638fce1..0000000
--- a/sql/20260803_pickup_order_align_fields.sql
+++ /dev/null
@@ -1,53 +0,0 @@
--- 对齐已创建的 t_pickup_order / t_pickup_order_line 与现表公共字段。
--- 适用于已执行旧版 20260803_pickup_order.sql 的环境;列已存在时对应语句会报错,可跳过。
--- 执行前请备份。
---
--- 注意:ConcurrencyStamp 勿写 DEFAULT (UUID()),在开启复制/GTID 时 ALTER 会报 1674。
--- 正确做法:先可空列 → UPDATE 回填 → 再改为 NOT NULL。
-
--- ===== t_pickup_order =====
-ALTER TABLE `t_pickup_order`
- ADD COLUMN `RequestId` VARCHAR(64) NULL COMMENT '请求幂等ID' AFTER `PickupNo`,
- ADD COLUMN `OrganizationId` CHAR(36) NULL COMMENT '数据归属组织' AFTER `CustomerId`,
- ADD COLUMN `SecretLevel` TINYINT NOT NULL DEFAULT 2 COMMENT '数据密级 1-4' AFTER `OrganizationId`;
-
-ALTER TABLE `t_pickup_order`
- ADD COLUMN `SenderCountry` INT NULL COMMENT '国家 t_country.Id 快照' AFTER `SenderCompany`,
- ADD COLUMN `SenderStreetAddress3` VARCHAR(500) NULL COMMENT '地址3快照' AFTER `SenderStreetAddress2`,
- ADD COLUMN `SenderHouseNumber` VARCHAR(50) NULL COMMENT '门牌号快照' AFTER `SenderStreetAddress3`,
- ADD COLUMN `SenderTelePhone` VARCHAR(50) NULL COMMENT '电话快照' AFTER `SenderPhone`,
- ADD COLUMN `SenderEmail` VARCHAR(60) NULL COMMENT '邮箱快照' AFTER `SenderTelePhone`;
-
--- 手机字段长度与现表对齐(若已是 50 可忽略报错)
-ALTER TABLE `t_pickup_order`
- MODIFY COLUMN `SenderPhone` VARCHAR(50) NULL COMMENT '手机快照';
-
--- ConcurrencyStamp(复制安全写法)
-ALTER TABLE `t_pickup_order`
- ADD COLUMN `ConcurrencyStamp` CHAR(36) NULL COMMENT '并发戳' AFTER `IsDeleted`;
-
-UPDATE `t_pickup_order`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL OR `ConcurrencyStamp` = '';
-
-ALTER TABLE `t_pickup_order`
- MODIFY COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL COMMENT '并发戳';
-
-ALTER TABLE `t_pickup_order`
- ADD UNIQUE KEY `uk_pickup_request_id` (`RequestId`),
- ADD KEY `idx_pickup_org_secret_ctime` (`OrganizationId`, `SecretLevel`, `CreateTime`);
-
--- ===== t_pickup_order_line =====
-ALTER TABLE `t_pickup_order_line`
- ADD COLUMN `ServiceNo` VARCHAR(64) NULL COMMENT '运单号快照(便于列表)' AFTER `OrderId`,
- ADD COLUMN `ClientNo` VARCHAR(64) NULL COMMENT '客户单号快照' AFTER `ServiceNo`;
-
-ALTER TABLE `t_pickup_order_line`
- ADD COLUMN `ConcurrencyStamp` CHAR(36) NULL COMMENT '并发戳' AFTER `IsDeleted`;
-
-UPDATE `t_pickup_order_line`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL OR `ConcurrencyStamp` = '';
-
-ALTER TABLE `t_pickup_order_line`
- MODIFY COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL COMMENT '并发戳';
diff --git a/sql/20260803_pickup_order_concurrency_stamp.sql b/sql/20260803_pickup_order_concurrency_stamp.sql
deleted file mode 100644
index 06e2d44..0000000
--- a/sql/20260803_pickup_order_concurrency_stamp.sql
+++ /dev/null
@@ -1,53 +0,0 @@
--- 幂等补 ConcurrencyStamp:已存在则跳过 ADD,只做回填/NOT NULL。
--- 执行前请备份。
-
--- 先看现状(可选)
-SELECT TABLE_NAME, COLUMN_NAME, IS_NULLABLE, COLUMN_TYPE
-FROM information_schema.COLUMNS
-WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME IN ('t_pickup_order', 't_pickup_order_line')
- AND COLUMN_NAME = 'ConcurrencyStamp';
-
--- ===== t_pickup_order =====
-SET @sql := (
- SELECT IF(
- EXISTS(
- SELECT 1 FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_pickup_order'
- AND COLUMN_NAME = 'ConcurrencyStamp'
- ),
- 'SELECT ''t_pickup_order.ConcurrencyStamp already exists'' AS info',
- 'ALTER TABLE `t_pickup_order` ADD COLUMN `ConcurrencyStamp` CHAR(36) NULL COMMENT ''并发戳'' AFTER `IsDeleted`'
- )
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-UPDATE `t_pickup_order`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL OR `ConcurrencyStamp` = '';
-
-ALTER TABLE `t_pickup_order`
- MODIFY COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL COMMENT '并发戳';
-
--- ===== t_pickup_order_line =====
-SET @sql := (
- SELECT IF(
- EXISTS(
- SELECT 1 FROM information_schema.COLUMNS
- WHERE TABLE_SCHEMA = DATABASE()
- AND TABLE_NAME = 't_pickup_order_line'
- AND COLUMN_NAME = 'ConcurrencyStamp'
- ),
- 'SELECT ''t_pickup_order_line.ConcurrencyStamp already exists'' AS info',
- 'ALTER TABLE `t_pickup_order_line` ADD COLUMN `ConcurrencyStamp` CHAR(36) NULL COMMENT ''并发戳'' AFTER `IsDeleted`'
- )
-);
-PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-
-UPDATE `t_pickup_order_line`
-SET `ConcurrencyStamp` = UUID()
-WHERE `ConcurrencyStamp` IS NULL OR `ConcurrencyStamp` = '';
-
-ALTER TABLE `t_pickup_order_line`
- MODIFY COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL COMMENT '并发戳';
diff --git a/sql/20260804_issue_template_handler.sql b/sql/20260804_issue_template_handler.sql
deleted file mode 100644
index 624bf3a..0000000
--- a/sql/20260804_issue_template_handler.sql
+++ /dev/null
@@ -1,9 +0,0 @@
--- 问题模板:处理人类型 + 指定用户
-ALTER TABLE `t_issue_template`
- ADD COLUMN `HandlerType` VARCHAR(16) NULL COMMENT '处理人类型:customer=订单所属客户 user=指定用户' AFTER `NotifyMethod`,
- ADD COLUMN `HandlerUserId` INT NULL COMMENT '指定处理人用户Id(HandlerType=user 时必填)' AFTER `HandlerType`;
-
--- 问题事件:处理人快照(运行时解析)
-ALTER TABLE `t_order_exception_event`
- ADD COLUMN `HandlerType` VARCHAR(16) NULL COMMENT '处理人类型' AFTER `HandlerNames`,
- ADD COLUMN `HandlerUserId` INT NULL COMMENT '处理人用户Id(customer 时为订单客户账号)' AFTER `HandlerType`;
diff --git a/sql/20260804_kb_knowledge.sql b/sql/20260804_kb_knowledge.sql
deleted file mode 100644
index 2077eca..0000000
--- a/sql/20260804_kb_knowledge.sql
+++ /dev/null
@@ -1,144 +0,0 @@
--- 物流业务知识库 M1:分类 + 文章
--- 执行库:OMS 业务库
-
-CREATE TABLE IF NOT EXISTS `t_kb_category` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
- `Code` VARCHAR(64) NOT NULL COMMENT '稳定键,如 pricing',
- `Name` VARCHAR(128) NOT NULL COMMENT '展示名(中文)',
- `SortOrder` INT NOT NULL DEFAULT 0 COMMENT '排序,越小越前',
- `Enabled` TINYINT NOT NULL DEFAULT 1 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`),
- UNIQUE KEY `uk_kb_category_code` (`Code`),
- KEY `idx_kb_category_enabled_sort` (`Enabled`, `SortOrder`)
-) COMMENT='知识库分类';
-
-CREATE TABLE IF NOT EXISTS `t_kb_article` (
- `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
- `CategoryId` INT NOT NULL COMMENT '分类 Id',
- `Title` VARCHAR(200) NOT NULL COMMENT '标题(中文)',
- `Summary` VARCHAR(500) NULL COMMENT '列表摘要',
- `Content` LONGTEXT NOT NULL COMMENT 'Markdown 正文(中文)',
- `Audience` VARCHAR(16) NOT NULL DEFAULT 'customer' COMMENT '受众 customer/internal',
- `Status` VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT 'draft/published/offline',
- `Tags` VARCHAR(256) NULL COMMENT '逗号分隔标签',
- `RelatedPath` VARCHAR(256) NULL COMMENT '站内关联 path',
- `RelatedLabel` VARCHAR(64) NULL COMMENT '关联按钮文案',
- `IsPinned` TINYINT NOT NULL DEFAULT 0 COMMENT '置顶:0-否,1-是',
- `SortOrder` INT NOT NULL DEFAULT 0 COMMENT '同类排序',
- `PublishTime` DATETIME NULL COMMENT '发布时间',
- `ExpireTime` DATETIME NULL COMMENT '过期时间',
- `ViewCount` 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`),
- KEY `idx_kb_article_list` (`Status`, `Audience`, `CategoryId`, `IsPinned`, `SortOrder`),
- KEY `idx_kb_article_publish` (`Status`, `Audience`, `PublishTime`),
- KEY `idx_kb_article_hot` (`Status`, `Audience`, `IsPinned`, `ViewCount`)
-) COMMENT='知识库文章';
-
--- 种子分类(幂等:Code 唯一)
-INSERT INTO `t_kb_category` (`Code`, `Name`, `SortOrder`, `Enabled`)
-SELECT 'pricing', '查价与计费', 10, 1 FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_kb_category` WHERE `Code` = 'pricing' AND `IsDeleted` = 0);
-
-INSERT INTO `t_kb_category` (`Code`, `Name`, `SortOrder`, `Enabled`)
-SELECT 'order', '下单与轨迹', 20, 1 FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_kb_category` WHERE `Code` = 'order' AND `IsDeleted` = 0);
-
-INSERT INTO `t_kb_category` (`Code`, `Name`, `SortOrder`, `Enabled`)
-SELECT 'exception', '问题件与售后', 30, 1 FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_kb_category` WHERE `Code` = 'exception' AND `IsDeleted` = 0);
-
-INSERT INTO `t_kb_category` (`Code`, `Name`, `SortOrder`, `Enabled`)
-SELECT 'customs', '禁限运与清关', 40, 1 FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_kb_category` WHERE `Code` = 'customs' AND `IsDeleted` = 0);
-
-INSERT INTO `t_kb_category` (`Code`, `Name`, `SortOrder`, `Enabled`)
-SELECT 'account', '账户与充值', 50, 1 FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_kb_category` WHERE `Code` = 'account' AND `IsDeleted` = 0);
-
-INSERT INTO `t_kb_category` (`Code`, `Name`, `SortOrder`, `Enabled`)
-SELECT 'dropship', '代发与店铺', 60, 1 FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `t_kb_category` WHERE `Code` = 'dropship' AND `IsDeleted` = 0);
-
--- 种子 FAQ(幂等:按 Title + Category Code)
-INSERT INTO `t_kb_article`
-(`CategoryId`, `Title`, `Summary`, `Content`, `Audience`, `Status`, `Tags`, `RelatedPath`, `RelatedLabel`, `IsPinned`, `SortOrder`, `PublishTime`, `ViewCount`)
-SELECT c.`Id`,
- '如何查价?计费重量怎么算?',
- '说明计费重、体积重与卖价取整规则。',
- '## 查价入口\n\n工作台或菜单进入「查价」,填写目的国、重量与尺寸即可预估运费。\n\n## 计费重量\n\n系统按 **实重** 与 **体积重** 取较大者作为计费重。体积重公式以销售产品配置为准。\n\n## 提示\n\n查价结果为预估,实际以出库计费为准。',
- 'customer', 'published', '查价,计费', '/order/priceCheck', '去查价', 1, 10, NOW(), 0
-FROM `t_kb_category` c
-WHERE c.`Code` = 'pricing' AND c.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_kb_article` a
- WHERE a.`Title` = '如何查价?计费重量怎么算?' AND a.`CategoryId` = c.`Id` AND a.`IsDeleted` = 0
- );
-
-INSERT INTO `t_kb_article`
-(`CategoryId`, `Title`, `Summary`, `Content`, `Audience`, `Status`, `Tags`, `RelatedPath`, `RelatedLabel`, `IsPinned`, `SortOrder`, `PublishTime`, `ViewCount`)
-SELECT c.`Id`,
- '下单后如何查看轨迹?',
- '订单列表与轨迹查询入口说明。',
- '## 查看轨迹\n\n1. 进入「我的订单」,找到目标运单。\n2. 点击轨迹图标或进入详情查看最新节点。\n\n上网后才会出现承运商轨迹;未上网前可能仅有内部操作节点。',
- 'customer', 'published', '轨迹,订单', NULL, NULL, 1, 10, NOW(), 0
-FROM `t_kb_category` c
-WHERE c.`Code` = 'order' AND c.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_kb_article` a
- WHERE a.`Title` = '下单后如何查看轨迹?' AND a.`CategoryId` = c.`Id` AND a.`IsDeleted` = 0
- );
-
-INSERT INTO `t_kb_article`
-(`CategoryId`, `Title`, `Summary`, `Content`, `Audience`, `Status`, `Tags`, `RelatedPath`, `RelatedLabel`, `IsPinned`, `SortOrder`, `PublishTime`, `ViewCount`)
-SELECT c.`Id`,
- '什么是问题件?如何处理?',
- '问题件常见原因与处理路径。',
- '## 什么是问题件\n\n因地址不全、禁限运、欠费、清关资料缺失等原因,包裹无法继续流转时会标记为问题件。\n\n## 怎么处理\n\n在订单列表筛选「问题件」,按提示补全资料或联系客服。处理完成后会重新放行。',
- 'customer', 'published', '问题件,售后', NULL, NULL, 0, 20, NOW(), 0
-FROM `t_kb_category` c
-WHERE c.`Code` = 'exception' AND c.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_kb_article` a
- WHERE a.`Title` = '什么是问题件?如何处理?' AND a.`CategoryId` = c.`Id` AND a.`IsDeleted` = 0
- );
-
-INSERT INTO `t_kb_article`
-(`CategoryId`, `Title`, `Summary`, `Content`, `Audience`, `Status`, `Tags`, `RelatedPath`, `RelatedLabel`, `IsPinned`, `SortOrder`, `PublishTime`, `ViewCount`)
-SELECT c.`Id`,
- '账户余额不足怎么办?',
- '充值入口与余额扣费说明。',
- '## 充值\n\n工作台余额卡片或财务菜单可发起充值。到账后余额可用于下单扣费。\n\n## 注意\n\n子账号余额归属主客户;扣费失败时订单可能无法提交或出库。',
- 'customer', 'published', '充值,余额', NULL, NULL, 0, 10, NOW(), 0
-FROM `t_kb_category` c
-WHERE c.`Code` = 'account' AND c.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_kb_article` a
- WHERE a.`Title` = '账户余额不足怎么办?' AND a.`CategoryId` = c.`Id` AND a.`IsDeleted` = 0
- );
-
-INSERT INTO `t_kb_article`
-(`CategoryId`, `Title`, `Summary`, `Content`, `Audience`, `Status`, `Tags`, `RelatedPath`, `RelatedLabel`, `IsPinned`, `SortOrder`, `PublishTime`, `ViewCount`)
-SELECT c.`Id`,
- '禁限运物品有哪些?',
- '常见禁限运与申报注意点。',
- '## 常见禁限运\n\n电池、液体、粉末、管制刀具、仿牌等通常受限或禁运,以承运商与目的国法规为准。\n\n## 申报建议\n\n如实填写品名与货值,避免笼统描述(如 gifts)。不确定时可先咨询客服。',
- 'customer', 'published', '禁运,清关', NULL, NULL, 0, 10, NOW(), 0
-FROM `t_kb_category` c
-WHERE c.`Code` = 'customs' AND c.`IsDeleted` = 0
- AND NOT EXISTS (
- SELECT 1 FROM `t_kb_article` a
- WHERE a.`Title` = '禁限运物品有哪些?' AND a.`CategoryId` = c.`Id` AND a.`IsDeleted` = 0
- );
-
diff --git a/sql/20260804_kb_menu_notes.sql b/sql/20260804_kb_menu_notes.sql
deleted file mode 100644
index 64e6747..0000000
--- a/sql/20260804_kb_menu_notes.sql
+++ /dev/null
@@ -1,8 +0,0 @@
--- 知识库 M1 菜单挂载说明
--- 一级:知识库 route=/kb permissionCode=Knowledge
--- 在菜单管理对该一级点「同步子菜单及按钮」,将自动创建:
--- 分类管理 /kb/category permissionCode=Knowledge.Category
--- 三级:Knowledge.Category.Query / Knowledge.Category.Edit
--- 文章管理 /kb/article permissionCode=Knowledge.Article
--- 三级:Knowledge.Article.Query / Knowledge.Article.Edit / Knowledge.Article.Publish
--- Admin 角色启动时可自动合并上述权限(见 XhsRolePermissionSeedContributor.AdminKbPermissions)
diff --git a/sql/20260804_order_exception_event_handler.sql b/sql/20260804_order_exception_event_handler.sql
deleted file mode 100644
index 48ee74a..0000000
--- a/sql/20260804_order_exception_event_handler.sql
+++ /dev/null
@@ -1,3 +0,0 @@
--- 问题处理:事件级处理人快照(订单可有多条问题记录)
-ALTER TABLE `t_order_exception_event`
- ADD COLUMN `HandlerNames` VARCHAR(256) NULL COMMENT '处理人快照' AFTER `NotifyMethod`;
diff --git a/sql/20260804_order_status_drop_received.sql b/sql/20260804_order_status_drop_received.sql
deleted file mode 100644
index 4b875b3..0000000
--- a/sql/20260804_order_status_drop_received.sql
+++ /dev/null
@@ -1,14 +0,0 @@
--- 废弃订单状态 received(已收货):入库后直接进 pendingAllocation / pendingPayment,不再停留 received
--- 历史数据:已入库的归待排货;若已有应付且未支付则归待支付
-
-UPDATE `t_order`
-SET
- `OrderStatus` = CASE
- WHEN IFNULL(`IsPaid`, 0) > 0 THEN 'pendingShip'
- WHEN IFNULL(`PayableAmount`, 0) > 0
- AND (`AllocationPendingReason` IS NULL OR TRIM(`AllocationPendingReason`) = '')
- THEN 'pendingPayment'
- ELSE 'pendingAllocation'
- END,
- `UpdateTime` = NOW()
-WHERE `OrderStatus` = 'received';
diff --git a/src/Oms.Application/Dtos/Orders/OrderWorkplaceStatsOutput.cs b/src/Oms.Application/Dtos/Orders/OrderWorkplaceStatsOutput.cs
index 1d345af..014da04 100644
--- a/src/Oms.Application/Dtos/Orders/OrderWorkplaceStatsOutput.cs
+++ b/src/Oms.Application/Dtos/Orders/OrderWorkplaceStatsOutput.cs
@@ -41,9 +41,9 @@ public class OrderWorkplaceStatsOutput
public int Shipped { get; set; }
///
- /// 待上网数量。
+ /// 待支付数量。
///
- public int PendingOnline { get; set; }
+ public int PendingPayment { get; set; }
///
/// 问题件数量。
diff --git a/src/Oms.Application/Services/Orders/OrderService.Workplace.cs b/src/Oms.Application/Services/Orders/OrderService.Workplace.cs
index 191ba62..66ec360 100644
--- a/src/Oms.Application/Services/Orders/OrderService.Workplace.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.Workplace.cs
@@ -74,7 +74,7 @@ public partial class OrderService
DayOverDayGrowthPercent = growth,
PendingShip = GetCount(OrderStatusCodes.PendingShip),
Shipped = shipped,
- PendingOnline = GetCount(OrderStatusCodes.PendingOnline),
+ PendingPayment = GetCount(OrderStatusCodes.PendingPayment),
Problematic = GetCount(OrderStatusCodes.Problematic),
StoreCount = storeCount,
StoreOrderPending = storeOrderPending,
diff --git a/tools/SwaggerDiag/Program.cs b/tools/SwaggerDiag/Program.cs
new file mode 100644
index 0000000..539c73d
--- /dev/null
+++ b/tools/SwaggerDiag/Program.cs
@@ -0,0 +1,47 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.OpenApi.Models;
+using Oms.Application.Dtos.Orders;
+using Swashbuckle.AspNetCore.SwaggerGen;
+using System.Reflection;
+
+var services = new ServiceCollection();
+services.AddSwaggerGen(c =>
+{
+ c.SwaggerDoc("OMS-Order", new OpenApiInfo { Title = "OMS-Order", Version = "v1" });
+ c.CustomSchemaIds(t => t.FullName?.Replace("+", ".") ?? t.Name);
+});
+var sp = services.BuildServiceProvider();
+var gen = sp.GetRequiredService();
+var repo = new SchemaRepository("OMS-Order");
+
+void Try(string name, Type t)
+{
+ try
+ {
+ gen.GenerateSchema(t, repo);
+ Console.WriteLine($"OK {name}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"FAIL {name}: {ex.GetType().Name}: {ex.Message}");
+ if (ex.InnerException != null) Console.WriteLine($" inner: {ex.InnerException.Message}");
+ }
+}
+
+Try(nameof(OrderParcelBatchCreateInput), typeof(OrderParcelBatchCreateInput));
+Try(nameof(OrderParcelCreateInput), typeof(OrderParcelCreateInput));
+Try(nameof(OrderPriceCheckResultOutput), typeof(OrderPriceCheckResultOutput));
+Try(nameof(OrderPriceCheckOutput), typeof(OrderPriceCheckOutput));
+Try(nameof(OrderUploadInput), typeof(OrderUploadInput));
+Try(nameof(OrderTemplateCustomDetailOutput), typeof(OrderTemplateCustomDetailOutput));
+Try(nameof(OrderOutput), typeof(OrderOutput));
+Try(nameof(OrderPaginatedOutput), typeof(OrderPaginatedOutput));
+
+// Also generate for all public types in Orders Dtos
+var asm = typeof(OrderOutput).Assembly;
+foreach (var t in asm.GetTypes().Where(x => x.IsPublic && x.Namespace == "Oms.Application.Dtos.Orders").OrderBy(x => x.Name))
+{
+ Try(t.Name, t);
+}
+
+Console.WriteLine($"Schemas generated: {repo.Schemas.Count}");
diff --git a/tools/SwaggerDiag/SwaggerDiag.csproj b/tools/SwaggerDiag/SwaggerDiag.csproj
new file mode 100644
index 0000000..6617412
--- /dev/null
+++ b/tools/SwaggerDiag/SwaggerDiag.csproj
@@ -0,0 +1,13 @@
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/tools/_chk.py b/tools/_chk.py
new file mode 100644
index 0000000..18c6313
--- /dev/null
+++ b/tools/_chk.py
@@ -0,0 +1,10 @@
+from pathlib import Path
+db = Path(r"c:\Users\wilso\Desktop\oms0414-back\db.sql").read_text(encoding="utf-8")
+names = [
+ "t_member_level", "t_mcp_tool", "t_pickup_order", "t_coupon_template",
+ "MemberLevelId", "PriceTierKey", "PayableAmount", "ReceivableSubtotal",
+ "TradeTerms", "AdditionalServices", "AiAnalysisReport", "HandlerNames",
+]
+for n in names:
+ needle = f"`{n}`" if not n.startswith("t_") else f"CREATE TABLE `{n}`"
+ print(n, needle in db or f"`{n}`" in db)
diff --git a/tools/_cmp_sql_db.ps1 b/tools/_cmp_sql_db.ps1
new file mode 100644
index 0000000..8066c15
--- /dev/null
+++ b/tools/_cmp_sql_db.ps1
@@ -0,0 +1,79 @@
+# Compare sql/*.sql migrations against db.sql
+$dbPath = "c:\Users\wilso\Desktop\oms0414-back\db.sql"
+$sqlDir = "c:\Users\wilso\Desktop\oms0414-back\sql"
+$db = [IO.File]::ReadAllText($dbPath)
+
+function HasCol([string]$name) {
+ return $db.Contains("`$name`".Replace('$name', $name)) -or $db.Contains("``$name``")
+}
+
+# simpler: look for `ColName`
+function ColInDb([string]$name) {
+ return $db.IndexOf("`" + $name + "`" ) -ge 0 -or $db.IndexOf("``$name``") -ge 0
+}
+
+function ColInDb2([string]$name) {
+ $needle = [char]96 + $name + [char]96 # backtick Col backtick
+ return $db.Contains($needle)
+}
+
+function TableInDb([string]$name) {
+ $needle = "CREATE TABLE " + [char]96 + $name + [char]96
+ return $db.Contains($needle)
+}
+
+$files = Get-ChildItem "$sqlDir\*.sql" | Where-Object { $_.Name -notmatch 'menu_notes' } | Sort-Object Name
+$missing = @()
+
+foreach ($f in $files) {
+ $content = [IO.File]::ReadAllText($f.FullName)
+ $createMatches = [regex]::Matches($content, 'CREATE TABLE(?: IF NOT EXISTS)?\s+`([^`]+)`', 'IgnoreCase')
+ $addMatches = [regex]::Matches($content, 'ADD COLUMN(?: IF NOT EXISTS)?\s+`([^`]+)`', 'IgnoreCase')
+ $dropMatches = [regex]::Matches($content, 'DROP COLUMN\s+`([^`]+)`', 'IgnoreCase')
+ $modMatches = [regex]::Matches($content, 'MODIFY COLUMN\s+`([^`]+)`', 'IgnoreCase')
+
+ $section = @()
+ foreach ($m in $createMatches) {
+ $t = $m.Groups[1].Value
+ if (-not (TableInDb $t)) {
+ $section += "MISSING TABLE: $t"
+ $missing += "$($f.Name) -> TABLE $t"
+ } else {
+ $section += "OK TABLE: $t"
+ }
+ }
+ foreach ($m in $addMatches) {
+ $c = $m.Groups[1].Value
+ if (-not (ColInDb2 $c)) {
+ $section += "MISSING COL (ADD): $c"
+ $missing += "$($f.Name) -> ADD $c"
+ } else {
+ $section += "OK COL (ADD): $c"
+ }
+ }
+ foreach ($m in $dropMatches) {
+ $c = $m.Groups[1].Value
+ if (ColInDb2 $c) {
+ $section += "STILL IN db (DROP intended): $c"
+ $missing += "$($f.Name) -> DROP not applied in db.sql: $c"
+ } else {
+ $section += "OK DROPPED: $c"
+ }
+ }
+ foreach ($m in $modMatches) {
+ $c = $m.Groups[1].Value
+ if (-not (ColInDb2 $c)) {
+ $section += "MISSING COL (MODIFY): $c"
+ $missing += "$($f.Name) -> MODIFY $c (col absent)"
+ }
+ }
+
+ if ($section.Count -gt 0) {
+ Write-Output "==== $($f.Name) ===="
+ $section | ForEach-Object { Write-Output " $_" }
+ }
+}
+
+Write-Output ""
+Write-Output "==== SUMMARY MISSING ===="
+if ($missing.Count -eq 0) { Write-Output "(none)" } else { $missing | ForEach-Object { Write-Output $_ } }
diff --git a/tools/_cmp_sql_db.py b/tools/_cmp_sql_db.py
new file mode 100644
index 0000000..a2beae0
--- /dev/null
+++ b/tools/_cmp_sql_db.py
@@ -0,0 +1,75 @@
+import re
+from pathlib import Path
+
+db = Path(r"c:\Users\wilso\Desktop\oms0414-back\db.sql").read_text(encoding="utf-8")
+sql_dir = Path(r"c:\Users\wilso\Desktop\oms0414-back\sql")
+missing = []
+
+# Extract CREATE TABLE blocks from db.sql for per-table column checks
+table_cols = {}
+for m in re.finditer(r"CREATE TABLE `([^`]+)`\s*\((.*?)\)\s*(?:ENGINE|COMMENT|=|;)", db, re.S | re.I):
+ name = m.group(1)
+ body = m.group(2)
+ cols = re.findall(r"`([^`]+)`", body)
+ # filter index-only mentions roughly: keep all backtick names in body
+ table_cols[name] = set(cols)
+
+for f in sorted(sql_dir.glob("*.sql")):
+ if "menu_notes" in f.name:
+ continue
+ text = f.read_text(encoding="utf-8")
+ creates = re.findall(r"CREATE TABLE(?: IF NOT EXISTS)?\s+`([^`]+)`", text, re.I)
+ # ALTER TABLE `x` ... ADD COLUMN `c`
+ alter_adds = re.findall(
+ r"ALTER TABLE\s+`([^`]+)`[\s\S]*?(?=ALTER TABLE|CREATE TABLE|\Z)",
+ text,
+ re.I,
+ )
+ # Better: find each ADD COLUMN with preceding table via scanning
+ lines_out = []
+ for t in creates:
+ ok = f"CREATE TABLE `{t}`" in db
+ lines_out.append(("OK" if ok else "MISS", "TABLE", t, None))
+ if not ok:
+ missing.append(f"{f.name}: TABLE `{t}`")
+
+ # Parse ADD COLUMN with associated table
+ pos = 0
+ current_table = None
+ for m in re.finditer(
+ r"ALTER TABLE\s+`([^`]+)`|ADD COLUMN(?: IF NOT EXISTS)?\s+`([^`]+)`|DROP COLUMN\s+`([^`]+)`|MODIFY COLUMN\s+`([^`]+)`",
+ text,
+ re.I,
+ ):
+ if m.group(1):
+ current_table = m.group(1)
+ elif m.group(2):
+ col = m.group(2)
+ in_db = f"`{col}`" in db
+ in_table = current_table and col in table_cols.get(current_table, set())
+ ok = bool(in_table) if current_table in table_cols else in_db
+ lines_out.append(("OK" if ok else "MISS", "ADD", col, current_table))
+ if not ok:
+ missing.append(f"{f.name}: ADD `{current_table}`.`{col}`")
+ elif m.group(3):
+ col = m.group(3)
+ still = current_table and col in table_cols.get(current_table, set())
+ lines_out.append(("STILL" if still else "OK", "DROP", col, current_table))
+ if still:
+ missing.append(f"{f.name}: DROP `{current_table}`.`{col}` still in db.sql")
+ elif m.group(4):
+ col = m.group(4)
+ ok = current_table and col in table_cols.get(current_table, set())
+ # For MODIFY we just check presence; nullability needs manual review
+ lines_out.append(("OK" if ok else "MISS", "MODIFY", col, current_table))
+ if not ok:
+ missing.append(f"{f.name}: MODIFY `{current_table}`.`{col}` absent")
+
+ if lines_out:
+ print(f"==== {f.name} ====")
+ for st, kind, name, tbl in lines_out:
+ loc = f"{tbl}." if tbl else ""
+ print(f" [{st}] {kind} {loc}{name}")
+
+print("\n==== SUMMARY (needs db.sql sync) ====")
+print("\n".join(missing) if missing else "(none)")