3641 lines
225 KiB
SQL
3641 lines
225 KiB
SQL
-- 柏悦头程一期、二期数据库统一增量脚本
|
||
-- 固定发布入口:后续数据库变更只在本文件末尾按日期追加,不再新增部署入口脚本。
|
||
-- 适用:MySQL 8.0+;支持空库初始化和存量库幂等补齐。
|
||
-- 涉及:baiyue_auth、baiyue_iam、baiyue_order、baiyue_warehouse、baiyue_firstleg、baiyue_file、baiyue_audit、baiyue_event_bridge。
|
||
-- 安全边界:不清表、不删业务数据、不创建固定密码账号、不写入演示仓库或演示订单。权限资源属于系统配置,会幂等写入。
|
||
-- MySQL DDL 会隐式提交,跨库脚本不能整体回滚;执行账号必须具有上述数据库的 CREATE/ALTER/INDEX/INSERT/UPDATE 权限。
|
||
-- 使用 MySQL Client、Workbench、DataGrip 或 Navicat 的“运行脚本”完整执行,客户端必须支持 DELIMITER。
|
||
SET NAMES utf8mb4;
|
||
SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
|
||
SELECT VERSION() AS mysql_version, 'START' AS unified_migration_status;
|
||
|
||
-- ============================================================================
|
||
-- 来源:audit-service\src\main\resources\db\audit.sql
|
||
-- ============================================================================
|
||
CREATE DATABASE IF NOT EXISTS baiyue_audit
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_audit;
|
||
|
||
CREATE TABLE IF NOT EXISTS sys_audit_log (
|
||
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '审计日志自增ID',
|
||
event_type VARCHAR(64) NOT NULL COMMENT '审计事件编码',
|
||
resource_type VARCHAR(64) NOT NULL COMMENT '被操作资源类型',
|
||
resource_id VARCHAR(128) DEFAULT NULL COMMENT '被操作资源ID',
|
||
description VARCHAR(255) DEFAULT NULL COMMENT '操作说明',
|
||
request_id VARCHAR(128) DEFAULT NULL COMMENT '请求ID,用于单次请求追踪',
|
||
trace_id VARCHAR(128) DEFAULT NULL COMMENT '分布式链路追踪ID',
|
||
tenant_id BIGINT DEFAULT NULL COMMENT '业务数据所属租户ID',
|
||
operator_tenant_id BIGINT DEFAULT NULL COMMENT '操作主体所属租户ID',
|
||
user_id BIGINT DEFAULT NULL COMMENT '操作用户ID',
|
||
username VARCHAR(128) DEFAULT NULL COMMENT '操作用户名快照',
|
||
app_code VARCHAR(64) DEFAULT NULL COMMENT '操作来源应用端',
|
||
client_type VARCHAR(32) DEFAULT NULL COMMENT '客户端类型',
|
||
http_method VARCHAR(16) DEFAULT NULL COMMENT 'HTTP请求方法',
|
||
request_uri VARCHAR(512) DEFAULT NULL COMMENT '请求URI',
|
||
client_ip VARCHAR(64) DEFAULT NULL COMMENT '客户端IP',
|
||
duration_ms BIGINT NOT NULL DEFAULT 0 COMMENT '请求耗时(毫秒)',
|
||
success TINYINT NOT NULL DEFAULT 0 COMMENT '操作是否成功',
|
||
error_code VARCHAR(64) DEFAULT NULL COMMENT '失败时的错误码',
|
||
error_message VARCHAR(512) DEFAULT NULL COMMENT '脱敏后的失败信息',
|
||
before_data JSON DEFAULT NULL COMMENT '变更前数据快照(已脱敏)',
|
||
after_data JSON DEFAULT NULL COMMENT '变更后数据快照(已脱敏)',
|
||
service_name VARCHAR(64) DEFAULT NULL COMMENT '产生日志的服务名',
|
||
occurred_at DATETIME(3) NOT NULL COMMENT '业务操作发生时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '审计服务落库时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_audit_tenant_time (tenant_id, occurred_at),
|
||
KEY idx_audit_event_time (event_type, occurred_at),
|
||
KEY idx_audit_user_time (user_id, occurred_at),
|
||
KEY idx_audit_request (request_id)
|
||
) ENGINE=InnoDB COMMENT='统一业务审计日志表:追加记录敏感操作的主体、租户、资源、结果及前后快照;不同于消息Outbox和消费幂等表';
|
||
|
||
-- ============================================================================
|
||
-- 来源:event-bridge-service\src\main\resources\db\event-bridge.sql
|
||
-- ============================================================================
|
||
CREATE DATABASE IF NOT EXISTS baiyue_event_bridge DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
USE baiyue_event_bridge;
|
||
|
||
CREATE TABLE IF NOT EXISTS bridge_outbox (
|
||
event_id VARCHAR(128) NOT NULL COMMENT '事件全局标识',
|
||
idempotency_key VARCHAR(191) NOT NULL COMMENT '发送幂等键',
|
||
event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
|
||
event_version INT NOT NULL COMMENT '事件契约版本',
|
||
source_region VARCHAR(32) NOT NULL COMMENT '来源区域',
|
||
target_region VARCHAR(32) NOT NULL COMMENT '目标区域',
|
||
tenant_id VARCHAR(128) NOT NULL COMMENT '租户标识',
|
||
aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型',
|
||
aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合标识',
|
||
aggregate_version BIGINT NOT NULL COMMENT '聚合版本',
|
||
handover_version BIGINT NULL COMMENT '跨区交接版本',
|
||
trace_id VARCHAR(128) NOT NULL COMMENT '链路标识',
|
||
correlation_id VARCHAR(128) NOT NULL COMMENT '业务关联标识',
|
||
causation_id VARCHAR(128) NULL COMMENT '上游事件标识',
|
||
occurred_at DATETIME(3) NOT NULL COMMENT '业务事实发生时间',
|
||
payload_hash VARCHAR(71) NOT NULL COMMENT '规范化负载摘要',
|
||
payload_json JSON NOT NULL COMMENT '事件负载',
|
||
status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '投递状态',
|
||
retry_count INT NOT NULL DEFAULT 0 COMMENT '已重试次数',
|
||
next_retry_at DATETIME(3) NULL COMMENT '下次重试时间',
|
||
lease_owner VARCHAR(128) NULL COMMENT '租约持有者',
|
||
lease_until DATETIME(3) NULL COMMENT '租约截止时间',
|
||
last_error VARCHAR(1000) NULL COMMENT '最后错误',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
delivered_at DATETIME(3) NULL COMMENT '投递成功时间',
|
||
PRIMARY KEY (event_id),
|
||
UNIQUE KEY uk_bridge_outbox_idempotency (idempotency_key),
|
||
KEY idx_bridge_outbox_schedule (target_region, status, next_retry_at, lease_until)
|
||
) ENGINE=InnoDB COMMENT='跨区域事件待投递箱';
|
||
|
||
CREATE TABLE IF NOT EXISTS bridge_inbox (
|
||
event_id VARCHAR(128) NOT NULL COMMENT '事件全局标识',
|
||
idempotency_key VARCHAR(191) NOT NULL COMMENT '接收幂等键',
|
||
event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
|
||
event_version INT NOT NULL COMMENT '事件契约版本',
|
||
source_region VARCHAR(32) NOT NULL COMMENT '来源区域',
|
||
target_region VARCHAR(32) NOT NULL COMMENT '目标区域',
|
||
tenant_id VARCHAR(128) NOT NULL COMMENT '租户标识',
|
||
aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型',
|
||
aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合标识',
|
||
aggregate_version BIGINT NOT NULL COMMENT '聚合版本',
|
||
handover_version BIGINT NULL COMMENT '跨区交接版本',
|
||
trace_id VARCHAR(128) NOT NULL COMMENT '链路标识',
|
||
correlation_id VARCHAR(128) NOT NULL COMMENT '业务关联标识',
|
||
causation_id VARCHAR(128) NULL COMMENT '上游事件标识',
|
||
occurred_at DATETIME(3) NOT NULL COMMENT '业务事实发生时间',
|
||
payload_hash VARCHAR(71) NOT NULL COMMENT '规范化负载摘要',
|
||
payload_json JSON NOT NULL COMMENT '事件负载',
|
||
status VARCHAR(32) NOT NULL DEFAULT 'RECEIVED' COMMENT '消费状态',
|
||
lease_owner VARCHAR(128) NULL COMMENT '消费租约持有者',
|
||
lease_until DATETIME(3) NULL COMMENT '消费租约截止时间',
|
||
retry_count INT NOT NULL DEFAULT 0 COMMENT '消费重试次数',
|
||
next_retry_at DATETIME(3) NULL COMMENT '下次消费时间',
|
||
last_error VARCHAR(1000) NULL COMMENT '最后错误',
|
||
received_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '接收时间',
|
||
processed_at DATETIME(3) NULL COMMENT '消费完成时间',
|
||
PRIMARY KEY (event_id),
|
||
UNIQUE KEY uk_bridge_inbox_idempotency (idempotency_key),
|
||
KEY idx_bridge_inbox_consume (status, next_retry_at, lease_until)
|
||
) ENGINE=InnoDB COMMENT='跨区域事件已接收箱';
|
||
|
||
CREATE TABLE IF NOT EXISTS bridge_delivery_attempt (
|
||
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||
event_id VARCHAR(128) NOT NULL COMMENT '事件全局标识',
|
||
source_region VARCHAR(32) NOT NULL COMMENT '来源区域',
|
||
target_region VARCHAR(32) NOT NULL COMMENT '目标区域',
|
||
attempt_no INT NOT NULL COMMENT '投递序号',
|
||
status VARCHAR(32) NOT NULL COMMENT '投递结果',
|
||
response_code VARCHAR(64) NULL COMMENT '对端响应码',
|
||
error_message VARCHAR(1000) NULL COMMENT '错误信息',
|
||
started_at DATETIME(3) NOT NULL COMMENT '开始时间',
|
||
finished_at DATETIME(3) NULL COMMENT '完成时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_bridge_attempt (event_id, attempt_no),
|
||
KEY idx_bridge_attempt_event (event_id, started_at)
|
||
) ENGINE=InnoDB COMMENT='跨区域事件投递尝试记录';
|
||
|
||
-- ============================================================================
|
||
-- 来源:auth\src\main\resources\db\auth.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
CREATE DATABASE IF NOT EXISTS baiyue_auth
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_auth;
|
||
|
||
CREATE TABLE IF NOT EXISTS auth_account (
|
||
id BIGINT NOT NULL COMMENT '统一登录账号ID(雪花ID)',
|
||
username VARCHAR(64) NOT NULL COMMENT '全局唯一登录名',
|
||
password_hash VARCHAR(255) NOT NULL COMMENT 'BCrypt密码哈希,禁止保存明文密码',
|
||
display_name VARCHAR(64) NOT NULL COMMENT '登录后展示名称',
|
||
account_status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '账号状态:ACTIVE、DISABLED、LOCKED',
|
||
failed_login_count INT NOT NULL DEFAULT 0 COMMENT '连续登录失败次数',
|
||
locked_until DATETIME(3) DEFAULT NULL COMMENT '临时锁定截止时间',
|
||
token_version INT NOT NULL DEFAULT 1 COMMENT '令牌版本,递增后可使历史令牌失效',
|
||
default_tenant_id BIGINT NOT NULL COMMENT '默认业务租户ID',
|
||
operator_tenant_id BIGINT NOT NULL COMMENT '操作主体租户ID,平台端与商户端身份隔离',
|
||
default_membership_id BIGINT DEFAULT NULL COMMENT '默认租户成员关系ID',
|
||
default_app_code VARCHAR(20) NOT NULL COMMENT '默认应用端:MERCHANT或PLATFORM',
|
||
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
last_login_at DATETIME(3) DEFAULT NULL COMMENT '最近一次成功登录时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_auth_account_username (username),
|
||
KEY idx_auth_account_status (account_status, locked_until)
|
||
) ENGINE=InnoDB COMMENT='统一登录账号表:保存平台端和商户端共用的认证凭据及账号安全状态';
|
||
|
||
CREATE TABLE IF NOT EXISTS auth_refresh_token (
|
||
id BIGINT NOT NULL COMMENT '刷新令牌记录ID(雪花ID)',
|
||
token_hash CHAR(64) NOT NULL COMMENT '刷新令牌SHA-256摘要,不保存令牌明文',
|
||
user_id BIGINT NOT NULL COMMENT '认证账号ID',
|
||
tenant_id BIGINT NOT NULL COMMENT '令牌当前业务租户ID',
|
||
operator_tenant_id BIGINT NOT NULL COMMENT '令牌操作主体租户ID',
|
||
app_code VARCHAR(20) NOT NULL COMMENT '令牌所属应用端',
|
||
expires_at DATETIME(3) NOT NULL COMMENT '到期时间',
|
||
revoked_at DATETIME(3) DEFAULT NULL COMMENT '吊销时间,非空表示不可继续使用',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '签发时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_auth_refresh_hash (token_hash),
|
||
KEY idx_auth_refresh_user (user_id, revoked_at, expires_at),
|
||
KEY idx_auth_refresh_expire (expires_at, revoked_at)
|
||
) ENGINE=InnoDB COMMENT='刷新令牌表:保存令牌摘要、租户上下文、有效期和轮换/吊销状态';
|
||
|
||
-- 初始管理员密码必须由部署脚本生成 BCrypt 哈希后显式写入,仓库内禁止提供默认密码。
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\iam.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
-- IAM 服务独占数据库:负责租户、成员、双端角色、菜单/页面/按钮/API权限和数据范围。
|
||
|
||
CREATE DATABASE IF NOT EXISTS baiyue_iam
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_iam;
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_tenant (
|
||
id BIGINT NOT NULL COMMENT '租户ID(雪花ID)',
|
||
tenant_code VARCHAR(64) NOT NULL COMMENT '全局唯一租户编码',
|
||
tenant_name VARCHAR(128) NOT NULL COMMENT '租户名称',
|
||
tenant_type VARCHAR(20) NOT NULL DEFAULT 'MERCHANT' COMMENT '租户类型',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'PROFILE_REQUIRED' COMMENT '租户状态:PROFILE_REQUIRED、PENDING、ACTIVE、REJECTED、DISABLED',
|
||
legal_name VARCHAR(128) NULL COMMENT '企业法定名称',
|
||
legal_representative VARCHAR(64) NULL COMMENT '法定代表人',
|
||
unified_social_credit_code VARCHAR(32) NULL COMMENT '统一社会信用代码',
|
||
contact_name VARCHAR(64) NULL COMMENT '企业联系人',
|
||
contact_phone VARCHAR(32) NULL COMMENT '联系电话',
|
||
contact_email VARCHAR(128) NULL COMMENT '联系邮箱',
|
||
service_package VARCHAR(64) NOT NULL DEFAULT '基础版' COMMENT '客户服务套餐',
|
||
contact_wechat VARCHAR(64) NULL COMMENT '联系微信',
|
||
sales_owner_name VARCHAR(64) NULL COMMENT '销售负责人姓名',
|
||
payment_term_days SMALLINT UNSIGNED NULL COMMENT '账期天数',
|
||
enterprise_type VARCHAR(64) NULL COMMENT '企业类型',
|
||
established_date DATE NULL COMMENT '成立日期',
|
||
registered_capital DECIMAL(18,2) NULL COMMENT '注册资本',
|
||
registered_capital_currency CHAR(3) NULL COMMENT '注册资本币种 ISO 4217',
|
||
registered_address VARCHAR(500) NULL COMMENT '注册地址文本',
|
||
internal_remark VARCHAR(1000) NULL COMMENT '平台内部备注',
|
||
approved_at DATETIME(3) NULL COMMENT '审核通过时间',
|
||
approved_by BIGINT NULL COMMENT '审核人ID',
|
||
reject_reason VARCHAR(500) NULL COMMENT '驳回原因',
|
||
created_by BIGINT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_iam_tenant_code (tenant_code),
|
||
UNIQUE KEY uk_iam_tenant_credit (unified_social_credit_code),
|
||
KEY idx_iam_tenant_status (status, created_at)
|
||
) ENGINE=InnoDB COMMENT='企业租户主表:作为SaaS数据隔离边界,保存商户企业资料、审核结果和启停状态';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_tenant_review (
|
||
id BIGINT NOT NULL COMMENT '审核记录ID',
|
||
tenant_id BIGINT NOT NULL COMMENT '被审核租户ID',
|
||
review_type VARCHAR(20) NOT NULL DEFAULT 'REGISTER' COMMENT '审核类型',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '审核状态',
|
||
reviewer_id BIGINT NULL COMMENT '审核人ID',
|
||
review_comment VARCHAR(500) NULL COMMENT '审核意见',
|
||
reviewed_at DATETIME(3) NULL COMMENT '审核完成时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '进入审核队列时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_review_queue (status, created_at),
|
||
KEY idx_review_tenant (tenant_id)
|
||
) ENGINE=InnoDB COMMENT='租户审核记录表:保存企业注册、资料变更等审核过程和审核意见';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_tenant_address (
|
||
id BIGINT NOT NULL COMMENT '租户地址ID',
|
||
tenant_id BIGINT NOT NULL COMMENT '所属租户ID',
|
||
address_type VARCHAR(20) NOT NULL COMMENT '地址类型',
|
||
country_code CHAR(2) NOT NULL DEFAULT 'CN' COMMENT '国家二字码',
|
||
province VARCHAR(64) NULL COMMENT '省/州',
|
||
city VARCHAR(64) NULL COMMENT '城市',
|
||
district VARCHAR(64) NULL COMMENT '区县',
|
||
detail VARCHAR(255) NOT NULL COMMENT '详细地址',
|
||
postal_code VARCHAR(16) NULL COMMENT '邮政编码',
|
||
is_default TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认地址',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
PRIMARY KEY (id),
|
||
KEY idx_address_tenant (tenant_id, address_type)
|
||
) ENGINE=InnoDB COMMENT='租户地址表:保存企业注册地址、办公地址等租户级资料';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_tenant_qualification (
|
||
id BIGINT NOT NULL COMMENT '资质记录ID',
|
||
tenant_id BIGINT NOT NULL COMMENT '所属租户ID',
|
||
qualification_type VARCHAR(32) NOT NULL COMMENT '资质类型',
|
||
certificate_no VARCHAR(128) NULL COMMENT '证书编号',
|
||
document_url VARCHAR(500) NULL COMMENT '资质文件存储地址',
|
||
valid_from DATE NULL COMMENT '有效期开始日期',
|
||
valid_to DATE NULL COMMENT '有效期结束日期',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '资质审核状态',
|
||
review_comment VARCHAR(500) NULL COMMENT '审核意见',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
PRIMARY KEY (id),
|
||
KEY idx_qualification_tenant (tenant_id, status)
|
||
) ENGINE=InnoDB COMMENT='租户资质表:保存企业证照、有效期、文件地址和审核状态';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_user (
|
||
id BIGINT NOT NULL COMMENT 'IAM用户资料ID',
|
||
auth_user_id BIGINT NOT NULL COMMENT '认证服务账号逻辑ID',
|
||
user_type VARCHAR(20) NOT NULL DEFAULT 'ENTERPRISE' COMMENT '用户类型',
|
||
display_name VARCHAR(64) NOT NULL COMMENT '用户展示名称',
|
||
phone VARCHAR(32) NULL COMMENT '手机号',
|
||
email VARCHAR(128) NULL COMMENT '邮箱',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '用户资料状态',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_iam_user_auth (auth_user_id),
|
||
KEY idx_iam_user_status (status)
|
||
) ENGINE=InnoDB COMMENT='IAM用户资料表:连接统一认证账号与业务身份资料,不保存密码';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_membership (
|
||
id BIGINT NOT NULL COMMENT '租户成员关系ID',
|
||
tenant_id BIGINT NOT NULL COMMENT '所属租户ID',
|
||
user_id BIGINT NOT NULL COMMENT 'IAM用户资料ID',
|
||
member_type VARCHAR(20) NOT NULL DEFAULT 'EMPLOYEE' COMMENT '成员类型',
|
||
member_no VARCHAR(64) NULL COMMENT '租户内部成员编号',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '成员状态',
|
||
joined_at DATETIME(3) NULL COMMENT '加入租户时间',
|
||
left_at DATETIME(3) NULL COMMENT '离开租户时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_membership_tenant_user (tenant_id, user_id),
|
||
UNIQUE KEY uk_membership_tenant_no (tenant_id, member_no),
|
||
KEY idx_membership_user (user_id, status),
|
||
KEY idx_membership_tenant (tenant_id, status)
|
||
) ENGINE=InnoDB COMMENT='租户成员关系表:表示一个用户在某个企业租户中的成员身份,是分配商户端角色的主体';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_role (
|
||
id BIGINT NOT NULL COMMENT '角色ID',
|
||
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '角色所属租户;0表示平台预置角色',
|
||
app_code VARCHAR(20) NOT NULL COMMENT '应用端:MERCHANT或PLATFORM',
|
||
role_code VARCHAR(64) NOT NULL COMMENT '作用域内唯一角色编码',
|
||
role_name VARCHAR(128) NOT NULL COMMENT '角色名称',
|
||
role_type VARCHAR(20) NOT NULL DEFAULT 'CUSTOM' COMMENT '角色类型:SYSTEM或CUSTOM',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '角色状态',
|
||
description VARCHAR(255) NULL COMMENT '角色用途说明',
|
||
created_by BIGINT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT NULL COMMENT '更新人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_role_scope_code (tenant_id, app_code, role_code),
|
||
KEY idx_role_tenant (tenant_id, app_code, status)
|
||
) ENGINE=InnoDB COMMENT='角色表:按租户和应用端隔离商户端、平台后台两套角色体系';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_membership_role (
|
||
membership_id BIGINT NOT NULL COMMENT '租户成员关系ID',
|
||
role_id BIGINT NOT NULL COMMENT '角色ID',
|
||
tenant_id BIGINT NOT NULL COMMENT '冗余租户ID,用于租户隔离校验和查询',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '授权时间',
|
||
PRIMARY KEY (membership_id, role_id),
|
||
KEY idx_mr_tenant (tenant_id)
|
||
) ENGINE=InnoDB COMMENT='成员角色关联表:将租户成员分配到对应应用端的一个或多个角色';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_permission (
|
||
id BIGINT NOT NULL COMMENT '权限资源ID',
|
||
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '权限所属租户;0表示平台预置权限',
|
||
app_code VARCHAR(20) NOT NULL COMMENT '所属应用端:MERCHANT或PLATFORM',
|
||
permission_type VARCHAR(20) NOT NULL COMMENT '权限类型:MENU、PAGE、BUTTON或API',
|
||
parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父权限ID,用于构造菜单和页面树',
|
||
permission_code VARCHAR(128) NOT NULL COMMENT '鉴权使用的唯一权限码',
|
||
permission_name VARCHAR(128) NOT NULL COMMENT '权限名称',
|
||
route_path VARCHAR(255) NULL COMMENT '前端路由或API路径',
|
||
http_method VARCHAR(16) NULL COMMENT 'API权限对应的HTTP方法',
|
||
sort_no INT NOT NULL DEFAULT 0 COMMENT '同级显示顺序',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '权限状态',
|
||
built_in TINYINT NOT NULL DEFAULT 0 COMMENT '是否为系统预置权限;预置权限不可通过管理接口修改',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_permission_scope_code (tenant_id, app_code, permission_code),
|
||
KEY idx_permission_parent (parent_id),
|
||
KEY idx_permission_api (http_method, route_path)
|
||
) ENGINE=InnoDB COMMENT='统一权限资源表:支持商户端和平台后台两套菜单、页面、按钮及API权限,权限最细可控制到按钮';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_role_permission (
|
||
role_id BIGINT NOT NULL COMMENT '角色ID',
|
||
permission_id BIGINT NOT NULL COMMENT '权限资源ID',
|
||
tenant_id BIGINT NOT NULL COMMENT '冗余租户ID,用于隔离校验和查询',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '授权时间',
|
||
PRIMARY KEY (role_id, permission_id),
|
||
KEY idx_rp_tenant (tenant_id)
|
||
) ENGINE=InnoDB COMMENT='角色权限关联表:定义角色可访问的菜单、页面、按钮和API资源';
|
||
|
||
CREATE TABLE IF NOT EXISTS iam_data_scope (
|
||
id BIGINT NOT NULL COMMENT '数据范围规则ID',
|
||
role_id BIGINT NOT NULL COMMENT '角色ID',
|
||
tenant_id BIGINT NOT NULL COMMENT '规则所属租户ID',
|
||
scope_type VARCHAR(20) NOT NULL DEFAULT 'SELF' COMMENT '范围类型:SELF、DEPARTMENT、TENANT或CUSTOM',
|
||
scope_expression JSON NULL COMMENT '自定义数据范围表达式',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_scope_role (role_id)
|
||
) ENGINE=InnoDB COMMENT='角色数据范围表:在功能权限之外限制角色可查看和操作的租户内数据集合';
|
||
|
||
-- 存量数据库重复执行初始化脚本时,不重复创建审核状态索引。
|
||
SET @review_status_index_sql = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'iam_tenant_review'
|
||
AND index_name = 'idx_tenant_review_status'),
|
||
'SELECT 1',
|
||
'CREATE INDEX idx_tenant_review_status ON iam_tenant_review (tenant_id, status)'
|
||
);
|
||
PREPARE review_status_index_stmt FROM @review_status_index_sql;
|
||
EXECUTE review_status_index_stmt;
|
||
DEALLOCATE PREPARE review_status_index_stmt;
|
||
|
||
-- ============================================================================
|
||
-- 来源:order\src\main\resources\db\order.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
-- 订单服务独占数据库。其他服务只能通过 OpenAPI 或领域事件获取订单数据。
|
||
|
||
CREATE DATABASE IF NOT EXISTS baiyue_order
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_order;
|
||
|
||
CREATE TABLE IF NOT EXISTS ord_order (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '订单ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
order_no VARCHAR(32) NOT NULL COMMENT '租户内唯一订单号',
|
||
customer_id BIGINT UNSIGNED NULL COMMENT '客户逻辑ID',
|
||
customer_name VARCHAR(128) NOT NULL COMMENT '下单时客户名称快照',
|
||
status VARCHAR(24) NOT NULL DEFAULT 'DRAFT' COMMENT '订单业务状态',
|
||
transport_mode VARCHAR(16) NOT NULL COMMENT '运输方式',
|
||
trade_term VARCHAR(16) NULL COMMENT '贸易条款',
|
||
destination_country_code CHAR(2) NOT NULL COMMENT '目的国家二字码',
|
||
destination_warehouse_id BIGINT UNSIGNED NULL COMMENT '目的仓逻辑ID',
|
||
destination_warehouse_name VARCHAR(128) NOT NULL COMMENT '目的仓名称快照',
|
||
expected_ship_date DATE NULL COMMENT '预计发运日期',
|
||
customer_remark VARCHAR(1000) NULL COMMENT '客户可见备注',
|
||
pickup_method VARCHAR(24) NULL COMMENT '取货方式',
|
||
receiving_warehouse_id BIGINT UNSIGNED NULL COMMENT '国内收货仓ID',
|
||
receiving_warehouse_name VARCHAR(128) NULL COMMENT '国内收货仓快照',
|
||
receiving_warehouse_address VARCHAR(512) NULL COMMENT '国内收货仓完整地址快照',
|
||
receiving_time VARCHAR(128) NULL COMMENT '国内收货仓收货时间快照',
|
||
channel_code VARCHAR(64) NULL COMMENT '渠道编码',
|
||
channel_name VARCHAR(128) NULL COMMENT '渠道名称快照',
|
||
carrier_id BIGINT UNSIGNED NULL COMMENT '船司逻辑ID快照',
|
||
carrier_name VARCHAR(128) NULL COMMENT '船司名称快照',
|
||
tax_mode VARCHAR(24) NULL COMMENT '买单或退税',
|
||
container_mode VARCHAR(24) NULL COMMENT '整柜或散货',
|
||
customs_inspection TINYINT(1) NULL COMMENT '是否商检',
|
||
destination_type VARCHAR(24) NULL COMMENT 'FBA/OVERSEAS/PRIVATE',
|
||
amazon_warehouse_code VARCHAR(32) NULL COMMENT '亚马逊仓库编码',
|
||
shipment_id VARCHAR(64) NULL COMMENT 'Amazon Shipment ID',
|
||
reference_id VARCHAR(64) NULL COMMENT 'Amazon Reference ID',
|
||
express_company VARCHAR(64) NULL COMMENT '履约快递公司名称快照',
|
||
express_tracking_no VARCHAR(128) NULL COMMENT '履约快递单号',
|
||
submitted_at DATETIME(3) NULL COMMENT '提交时间',
|
||
completed_at DATETIME(3) NULL COMMENT '完成时间',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_order_tenant_no (tenant_id, order_no),
|
||
KEY idx_order_tenant_status_time (tenant_id, status, created_at),
|
||
KEY idx_order_tenant_customer (tenant_id, customer_id),
|
||
KEY idx_order_tenant_warehouse (tenant_id, destination_warehouse_id)
|
||
) ENGINE=InnoDB COMMENT='头程订单主表:保存商户委托、目的仓、运输方式和订单当前状态';
|
||
|
||
CREATE TABLE IF NOT EXISTS ord_order_party (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '参与方快照ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
order_id BIGINT UNSIGNED NOT NULL COMMENT '所属订单ID',
|
||
party_type VARCHAR(16) NOT NULL COMMENT '参与方类型:SHIPPER或CONSIGNEE',
|
||
company_name VARCHAR(128) NOT NULL COMMENT '公司名称快照',
|
||
contact_name VARCHAR(64) NOT NULL COMMENT '联系人快照',
|
||
phone VARCHAR(32) NOT NULL COMMENT '联系电话快照',
|
||
email VARCHAR(128) NULL COMMENT '联系邮箱快照',
|
||
country_code CHAR(2) NOT NULL COMMENT '国家二字码',
|
||
province VARCHAR(64) NULL COMMENT '省/州',
|
||
city VARCHAR(64) NOT NULL COMMENT '城市',
|
||
district VARCHAR(64) NULL COMMENT '区县',
|
||
address_line VARCHAR(255) NOT NULL COMMENT '详细地址',
|
||
postal_code VARCHAR(20) NULL COMMENT '邮政编码',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_party_order_type (tenant_id, order_id, party_type),
|
||
CONSTRAINT fk_party_order FOREIGN KEY (order_id) REFERENCES ord_order (id)
|
||
) ENGINE=InnoDB COMMENT='订单收发货方快照表:固化下单时发货人和收货人信息,避免主数据变化影响历史订单';
|
||
|
||
CREATE TABLE IF NOT EXISTS ord_order_cargo (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '货物明细ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
order_id BIGINT UNSIGNED NOT NULL COMMENT '所属订单ID',
|
||
item_no INT NOT NULL COMMENT '订单内明细序号',
|
||
cargo_name VARCHAR(128) NOT NULL COMMENT '货物名称',
|
||
hs_code VARCHAR(20) NULL COMMENT '海关商品编码',
|
||
package_type VARCHAR(32) NOT NULL COMMENT '包装类型',
|
||
package_count INT UNSIGNED NOT NULL COMMENT '包装件数',
|
||
gross_weight_kg DECIMAL(18,3) NOT NULL COMMENT '毛重(千克)',
|
||
volume_cbm DECIMAL(18,4) NOT NULL COMMENT '体积(立方米)',
|
||
length_cm DECIMAL(12,2) NULL COMMENT '单件长度(厘米)',
|
||
width_cm DECIMAL(12,2) NULL COMMENT '单件宽度(厘米)',
|
||
height_cm DECIMAL(12,2) NULL COMMENT '单件高度(厘米)',
|
||
declared_value DECIMAL(18,2) NULL COMMENT '申报价值',
|
||
currency CHAR(3) NULL COMMENT '币种三字码',
|
||
dangerous_goods TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否危险品',
|
||
cargo_remark VARCHAR(500) NULL COMMENT '货物备注',
|
||
sku_no VARCHAR(64) NULL COMMENT 'SKU',
|
||
upc_no VARCHAR(64) NULL COMMENT 'UPC',
|
||
cargo_name_en VARCHAR(128) NULL COMMENT '英文品名',
|
||
customs_hs_code VARCHAR(20) NULL COMMENT '目的国清关HS CODE',
|
||
units_per_package INT UNSIGNED NULL COMMENT '每箱件数',
|
||
total_quantity INT UNSIGNED NULL COMMENT '总件数',
|
||
net_weight_kg DECIMAL(18,3) NULL COMMENT '净重kg',
|
||
unit_declared_value DECIMAL(18,2) NULL COMMENT '单件申报价值',
|
||
material VARCHAR(128) NULL COMMENT '材质',
|
||
product_usage VARCHAR(128) NULL COMMENT '用途',
|
||
model VARCHAR(64) NULL COMMENT '型号',
|
||
brand VARCHAR(64) NULL COMMENT '品牌',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_cargo_item (tenant_id, order_id, item_no),
|
||
KEY idx_cargo_order (tenant_id, order_id),
|
||
CONSTRAINT fk_cargo_order FOREIGN KEY (order_id) REFERENCES ord_order (id)
|
||
) ENGINE=InnoDB COMMENT='订单货物明细表:记录件数、重量、体积、申报价值和危险品属性';
|
||
|
||
CREATE TABLE IF NOT EXISTS ord_order_internal_note (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '内部备注ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
order_id BIGINT UNSIGNED NOT NULL COMMENT '所属订单ID',
|
||
content VARCHAR(2000) NOT NULL COMMENT '仅内部人员可见的备注内容',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
KEY idx_note_order_time (tenant_id, order_id, created_at),
|
||
CONSTRAINT fk_note_order FOREIGN KEY (order_id) REFERENCES ord_order (id)
|
||
) ENGINE=InnoDB COMMENT='订单内部备注表:保存平台运营或履约人员的内部协作记录,不向商户客户展示';
|
||
|
||
CREATE TABLE IF NOT EXISTS ord_order_status_history (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '状态历史ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
order_id BIGINT UNSIGNED NOT NULL COMMENT '所属订单ID',
|
||
from_status VARCHAR(24) NULL COMMENT '变更前状态,首次创建可为空',
|
||
to_status VARCHAR(24) NOT NULL COMMENT '变更后状态',
|
||
action VARCHAR(24) NOT NULL COMMENT '触发状态变化的业务动作',
|
||
reason VARCHAR(500) NULL COMMENT '变更原因',
|
||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
||
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
||
occurred_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '状态变化时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_history_order_time (tenant_id, order_id, occurred_at),
|
||
CONSTRAINT fk_history_order FOREIGN KEY (order_id) REFERENCES ord_order (id)
|
||
) ENGINE=InnoDB COMMENT='订单状态不可变历史表:按时间记录每次状态迁移、动作、原因和操作人';
|
||
|
||
CREATE TABLE IF NOT EXISTS ord_outbox_event (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '领域事件全局ID,同时作为消费幂等键',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '事件所属租户ID',
|
||
aggregate_type VARCHAR(32) NOT NULL COMMENT '聚合类型,例如 ORDER',
|
||
aggregate_id BIGINT UNSIGNED NOT NULL COMMENT '发生变更的聚合根ID,例如订单ID',
|
||
event_type VARCHAR(64) NOT NULL COMMENT '领域事件类型,例如 ORDER_SUBMITTED',
|
||
payload_json JSON NOT NULL COMMENT '供下游消费的事件负载快照',
|
||
publish_status VARCHAR(16) NOT NULL DEFAULT 'PENDING' COMMENT '发布状态:PENDING、PUBLISHED或FAILED',
|
||
retry_count INT NOT NULL DEFAULT 0 COMMENT '投递失败后的累计重试次数',
|
||
next_retry_at DATETIME(3) NULL COMMENT '允许再次投递的最早时间',
|
||
published_at DATETIME(3) NULL COMMENT '成功发布到消息中间件的时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '事件在本地事务中的创建时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_outbox_publish (publish_status, next_retry_at, created_at)
|
||
) ENGINE=InnoDB COMMENT='订单事务Outbox表:与订单业务变更在同一本地事务写入,供后台发布器可靠投递RocketMQ,保证数据库状态与领域事件最终一致;不是普通操作日志';
|
||
|
||
CREATE TABLE IF NOT EXISTS ord_idempotency_record (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '幂等记录ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '租户ID',
|
||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作者ID',
|
||
operation VARCHAR(32) NOT NULL COMMENT '幂等操作类型',
|
||
resource_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '资源ID,创建草稿时为0',
|
||
idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键',
|
||
request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256摘要',
|
||
status VARCHAR(16) NOT NULL COMMENT '处理状态:PROCESSING或COMPLETED',
|
||
result_order_id BIGINT UNSIGNED NULL COMMENT '成功结果订单ID',
|
||
completed_at DATETIME(3) NULL COMMENT '处理完成时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_order_idempotency_scope (tenant_id, operator_id, operation, idempotency_key),
|
||
KEY idx_order_idempotency_created (created_at)
|
||
) ENGINE=InnoDB COMMENT='订单写接口持久化幂等记录:唯一键保证同租户同操作者并发请求只执行一次';
|
||
|
||
-- ============================================================================
|
||
-- 来源:warehouse\src\main\resources\db\warehouse.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
CREATE DATABASE IF NOT EXISTS baiyue_warehouse
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_warehouse;
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_warehouse (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '仓库ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '仓库所属租户ID',
|
||
warehouse_code VARCHAR(50) NOT NULL COMMENT '租户内唯一仓库编码',
|
||
warehouse_name VARCHAR(120) NOT NULL COMMENT '仓库名称',
|
||
warehouse_type VARCHAR(32) NOT NULL DEFAULT 'DOMESTIC' COMMENT '公共仓库类型:DOMESTIC、FBA、OVERSEAS',
|
||
country_code CHAR(2) NOT NULL COMMENT '所在国家二字码',
|
||
timezone VARCHAR(64) NOT NULL COMMENT '仓库所在地IANA时区',
|
||
contact_name VARCHAR(64) DEFAULT NULL COMMENT '仓库联系人',
|
||
contact_phone VARCHAR(32) DEFAULT NULL COMMENT '联系电话',
|
||
contact_email VARCHAR(128) DEFAULT NULL COMMENT '联系邮箱',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '仓库状态',
|
||
remark VARCHAR(500) DEFAULT NULL COMMENT '仓库备注',
|
||
created_by BIGINT UNSIGNED DEFAULT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED DEFAULT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_wh_tenant_code (tenant_id, warehouse_code, deleted),
|
||
KEY idx_wh_tenant_status (tenant_id, status, deleted),
|
||
KEY idx_wh_tenant_type_status (tenant_id, warehouse_type, status, deleted),
|
||
KEY idx_wh_country (tenant_id, country_code, deleted)
|
||
) ENGINE=InnoDB COMMENT='仓库主数据表:以租户为边界维护仓库编码、名称、国家、时区和启停状态';
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_warehouse_address (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '仓库地址ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
|
||
address_type VARCHAR(20) NOT NULL DEFAULT 'OPERATING' COMMENT '地址类型,例如OPERATING或RETURN',
|
||
country_code CHAR(2) NOT NULL COMMENT '国家二字码',
|
||
state_province VARCHAR(100) DEFAULT NULL COMMENT '省或州',
|
||
city VARCHAR(100) NOT NULL COMMENT '城市',
|
||
district VARCHAR(100) DEFAULT NULL COMMENT '区县',
|
||
postal_code VARCHAR(20) DEFAULT NULL COMMENT '邮政编码',
|
||
address_line1 VARCHAR(255) NOT NULL COMMENT '主地址行',
|
||
address_line2 VARCHAR(255) DEFAULT NULL COMMENT '补充地址行',
|
||
latitude DECIMAL(10,7) DEFAULT NULL COMMENT '纬度',
|
||
longitude DECIMAL(10,7) DEFAULT NULL COMMENT '经度',
|
||
created_by BIGINT UNSIGNED DEFAULT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED DEFAULT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_address_type (tenant_id, warehouse_id, address_type, deleted),
|
||
KEY idx_address_warehouse (tenant_id, warehouse_id, deleted)
|
||
) ENGINE=InnoDB COMMENT='仓库地址表:保存运营、退货等不同用途的地址及可选经纬度';
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_service_capability (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '服务能力ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
|
||
capability_code VARCHAR(50) NOT NULL COMMENT '能力编码:RECEIVING、STORAGE、PICK_PACK、RETURN等',
|
||
capability_name VARCHAR(100) NOT NULL COMMENT '能力名称',
|
||
enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
|
||
cutoff_time TIME DEFAULT NULL COMMENT '当日作业截单时间',
|
||
description VARCHAR(500) DEFAULT NULL COMMENT '能力说明',
|
||
created_by BIGINT UNSIGNED DEFAULT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED DEFAULT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_capability (tenant_id, warehouse_id, capability_code, deleted),
|
||
KEY idx_capability_query (tenant_id, warehouse_id, enabled, deleted)
|
||
) ENGINE=InnoDB COMMENT='仓库服务能力表:声明仓库可提供的收货、仓储、拣包、退货等能力及截单时间';
|
||
|
||
-- 不使用跨服务数据库外键;仓库聚合内的归属由服务代码通过 tenant_id 与 warehouse_id 共同校验。
|
||
|
||
-- ============================================================================
|
||
-- 来源:warehouse\src\main\resources\db\warehouse-partner.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_warehouse;
|
||
CREATE TABLE IF NOT EXISTS wh_partner (
|
||
id BIGINT UNSIGNED NOT NULL, tenant_id BIGINT UNSIGNED NOT NULL,
|
||
data_scope_id BIGINT UNSIGNED NOT NULL COMMENT '所属业务数据范围',
|
||
partner_code VARCHAR(50) NOT NULL, partner_name VARCHAR(128) NOT NULL,
|
||
partner_type VARCHAR(20) NOT NULL COMMENT 'CUSTOMER、SUPPLIER或BOTH',
|
||
contact_name VARCHAR(64) NOT NULL, contact_phone VARCHAR(32) NOT NULL,
|
||
contact_email VARCHAR(128) NULL, country_code CHAR(2) NOT NULL,
|
||
province VARCHAR(64) NULL, city VARCHAR(64) NOT NULL, district VARCHAR(64) NULL,
|
||
address_line VARCHAR(255) NOT NULL, postal_code VARCHAR(20) NULL,
|
||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', remark VARCHAR(500) NULL,
|
||
created_by BIGINT UNSIGNED NULL,
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_by BIGINT UNSIGNED NULL,
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0, version INT NOT NULL DEFAULT 0,
|
||
PRIMARY KEY(id), UNIQUE KEY uk_wh_partner_tenant_code(tenant_id,partner_code,deleted),
|
||
KEY idx_wh_partner_tenant_status(tenant_id,status,deleted)
|
||
) ENGINE=InnoDB COMMENT='仓储域内的租户往来单位配置';
|
||
CREATE TABLE IF NOT EXISTS wh_partner_type (
|
||
partner_id BIGINT UNSIGNED NOT NULL, tenant_id BIGINT UNSIGNED NOT NULL,
|
||
data_scope_id BIGINT UNSIGNED NOT NULL, partner_type VARCHAR(32) NOT NULL,
|
||
PRIMARY KEY(partner_id,partner_type),
|
||
KEY idx_wh_partner_type_scope(tenant_id,data_scope_id,partner_type,partner_id)
|
||
) ENGINE=InnoDB COMMENT='往来单位稳定业务类型';
|
||
INSERT INTO wh_partner(id,tenant_id,data_scope_id,partner_code,partner_name,partner_type,contact_name,contact_phone,contact_email,country_code,province,city,district,address_line,postal_code,status)
|
||
VALUES(191000000000000001,10001,10001,'CUS-001','深圳示例贸易有限公司','CUSTOMER','张三','13800138000','contact@example.com','CN','广东省','深圳市','宝安区','航城街道示例路1号','518000','ACTIVE')
|
||
ON DUPLICATE KEY UPDATE partner_name=VALUES(partner_name),status='ACTIVE';
|
||
INSERT INTO wh_partner_type(partner_id,tenant_id,data_scope_id,partner_type)
|
||
VALUES
|
||
(191000000000000001,10001,10001,'CUSTOMER'),
|
||
(191000000000000001,10001,10001,'SHIPPER')
|
||
ON DUPLICATE KEY UPDATE tenant_id=VALUES(tenant_id),data_scope_id=VALUES(data_scope_id);
|
||
|
||
-- ============================================================================
|
||
-- 来源:warehouse\src\main\resources\db\warehouse-express-company.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_warehouse;
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_express_company (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '快递公司记录ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '所属租户ID',
|
||
company_code VARCHAR(50) NOT NULL COMMENT '租户内唯一快递公司编码',
|
||
company_name VARCHAR(128) NOT NULL COMMENT '快递公司名称',
|
||
service_phone VARCHAR(32) DEFAULT NULL COMMENT '客服电话',
|
||
website VARCHAR(255) DEFAULT NULL COMMENT '官方网站',
|
||
tracking_url_template VARCHAR(500) DEFAULT NULL COMMENT '轨迹查询地址模板,可包含{trackingNo}',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '快递公司状态',
|
||
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||
created_by BIGINT UNSIGNED DEFAULT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED DEFAULT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_wh_express_tenant_code (tenant_id, company_code, deleted),
|
||
UNIQUE KEY uk_wh_express_tenant_name (tenant_id, company_name, deleted),
|
||
KEY idx_wh_express_tenant_status (tenant_id, status, deleted)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='租户维度快递公司主数据';
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\firstleg.sql
|
||
-- ============================================================================
|
||
-- 头程履约服务独占数据库。
|
||
CREATE DATABASE IF NOT EXISTS baiyue_firstleg
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_firstleg;
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_fulfillment_task (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '履约任务ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
order_id BIGINT UNSIGNED NOT NULL COMMENT '订单服务中的订单逻辑ID,不建立跨库外键',
|
||
order_no VARCHAR(32) NOT NULL COMMENT '订单号快照',
|
||
order_snapshot_json JSON NOT NULL COMMENT '创建履约任务时所需的订单业务快照',
|
||
status VARCHAR(24) NOT NULL DEFAULT 'PENDING_ASSIGNMENT' COMMENT '履约任务当前状态',
|
||
assignee_id BIGINT UNSIGNED NULL COMMENT '当前负责人ID',
|
||
assignee_name VARCHAR(64) NULL COMMENT '当前负责人名称快照',
|
||
assigned_at DATETIME(3) NULL COMMENT '最近指派时间',
|
||
started_at DATETIME(3) NULL COMMENT '开始履约时间',
|
||
completed_at DATETIME(3) NULL COMMENT '履约完成时间',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人或系统主体ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_task_tenant_order (tenant_id, order_id),
|
||
KEY idx_task_tenant_created (tenant_id, created_at),
|
||
KEY idx_task_assignee_status (tenant_id, assignee_id, status, created_at)
|
||
) ENGINE=InnoDB COMMENT='头程履约任务表:接收订单事件后形成独立履约任务,管理指派、执行和完成状态';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_assignment_history (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '指派历史ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
task_id BIGINT UNSIGNED NOT NULL COMMENT '所属履约任务ID',
|
||
previous_assignee_id BIGINT UNSIGNED NULL COMMENT '原负责人ID',
|
||
assignee_id BIGINT UNSIGNED NOT NULL COMMENT '新负责人ID',
|
||
assignee_name VARCHAR(64) NOT NULL COMMENT '新负责人名称快照',
|
||
reason VARCHAR(500) NULL COMMENT '指派或改派原因',
|
||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '执行指派的操作人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '指派发生时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_assignment_task_time (tenant_id, task_id, created_at),
|
||
CONSTRAINT fk_assignment_task FOREIGN KEY (task_id) REFERENCES fl_fulfillment_task (id)
|
||
) ENGINE=InnoDB COMMENT='头程任务指派历史表:不可变记录每次负责人变更及原因,用于追踪和审计';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_consumed_event (
|
||
event_id BIGINT UNSIGNED NOT NULL COMMENT '已消费领域事件ID,与生产端Outbox事件ID一致',
|
||
event_type VARCHAR(64) NOT NULL COMMENT '已消费事件类型',
|
||
consumed_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '首次成功消费时间',
|
||
PRIMARY KEY (event_id)
|
||
) ENGINE=InnoDB COMMENT='头程消息消费幂等表:记录已处理事件并按事件ID去重,防止RocketMQ重复投递造成重复建单;不是消息发布表';
|
||
|
||
-- ============================================================================
|
||
-- 来源:file\src\main\resources\db\file.sql
|
||
-- ============================================================================
|
||
-- 文件中心独占数据库,其他服务只保存文件逻辑ID。
|
||
CREATE DATABASE IF NOT EXISTS baiyue_file
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_file;
|
||
|
||
CREATE TABLE IF NOT EXISTS file_object (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '文件ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
business_type VARCHAR(32) NULL COMMENT '关联业务类型',
|
||
business_id VARCHAR(64) NULL COMMENT '关联业务逻辑ID',
|
||
original_name VARCHAR(255) NOT NULL COMMENT '原始文件名',
|
||
object_key VARCHAR(512) NOT NULL COMMENT '对象存储键',
|
||
storage_provider VARCHAR(32) NOT NULL COMMENT '存储提供方',
|
||
bucket_name VARCHAR(128) NOT NULL COMMENT '存储桶名称',
|
||
content_type VARCHAR(128) NOT NULL COMMENT '文件内容类型',
|
||
size_bytes BIGINT UNSIGNED NOT NULL COMMENT '文件字节数',
|
||
sha256 CHAR(64) NULL COMMENT '文件SHA-256摘要',
|
||
status VARCHAR(24) NOT NULL DEFAULT 'ACTIVE' COMMENT '文件状态',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_file_tenant_object (tenant_id, object_key),
|
||
KEY idx_file_tenant_business (tenant_id, business_type, business_id),
|
||
KEY idx_file_tenant_created (tenant_id, created_at)
|
||
) ENGINE=InnoDB COMMENT='文件元数据表';
|
||
|
||
CREATE TABLE IF NOT EXISTS file_download_token (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '下载令牌ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
file_id BIGINT UNSIGNED NOT NULL COMMENT '文件逻辑ID',
|
||
token_hash CHAR(64) NOT NULL COMMENT '下载令牌SHA-256摘要',
|
||
expires_at DATETIME(3) NOT NULL COMMENT '过期时间',
|
||
max_downloads INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '最大下载次数',
|
||
download_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '已下载次数',
|
||
revoked_at DATETIME(3) NULL COMMENT '撤销时间',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_download_token_hash (token_hash),
|
||
KEY idx_download_file (tenant_id, file_id),
|
||
KEY idx_download_expiry (expires_at)
|
||
) ENGINE=InnoDB COMMENT='临时下载授权令牌表';
|
||
|
||
CREATE TABLE IF NOT EXISTS file_download_log (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '下载日志ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
file_id BIGINT UNSIGNED NOT NULL COMMENT '文件逻辑ID',
|
||
user_id BIGINT UNSIGNED NULL COMMENT '下载用户ID',
|
||
request_id VARCHAR(64) NULL COMMENT '请求ID',
|
||
client_ip VARCHAR(64) NULL COMMENT '客户端IP',
|
||
result VARCHAR(16) NOT NULL COMMENT '下载结果',
|
||
failure_reason VARCHAR(500) NULL COMMENT '失败原因',
|
||
downloaded_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '下载时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_download_log_file (tenant_id, file_id, downloaded_at),
|
||
KEY idx_download_log_user (tenant_id, user_id, downloaded_at)
|
||
) ENGINE=InnoDB COMMENT='文件下载审计日志表';
|
||
|
||
CREATE TABLE IF NOT EXISTS file_export_task (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '导出任务ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '申请人所属租户ID,平台任务为0',
|
||
app_code VARCHAR(24) NOT NULL COMMENT '申请端:PLATFORM或MERCHANT',
|
||
task_no VARCHAR(40) NOT NULL COMMENT '导出任务编号',
|
||
export_type VARCHAR(64) NOT NULL COMMENT '导出类型',
|
||
format VARCHAR(16) NOT NULL DEFAULT 'XLSX' COMMENT '导出格式',
|
||
task_name VARCHAR(128) NOT NULL COMMENT '任务名称',
|
||
parameters_json JSON NOT NULL COMMENT '筛选条件快照',
|
||
status VARCHAR(24) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/RUNNING/SUCCEEDED/FAILED/EXPIRED',
|
||
total_rows BIGINT UNSIGNED NULL COMMENT '预计总行数',
|
||
processed_rows BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '已处理行数',
|
||
file_name VARCHAR(255) NULL COMMENT '下载文件名',
|
||
object_key VARCHAR(512) NULL COMMENT '存储对象键',
|
||
content_type VARCHAR(128) NULL COMMENT '文件类型',
|
||
size_bytes BIGINT UNSIGNED NULL COMMENT '文件字节数',
|
||
failure_message VARCHAR(1000) NULL COMMENT '失败原因',
|
||
dispatch_version INT NOT NULL DEFAULT 1 COMMENT '派发版本,仅执行重试时递增',
|
||
attempt_count INT NOT NULL DEFAULT 0 COMMENT '已执行尝试次数',
|
||
max_attempts INT NOT NULL DEFAULT 3 COMMENT '自动重试上限',
|
||
next_retry_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '允许执行的最早时间',
|
||
lease_owner VARCHAR(128) NULL COMMENT '当前执行实例标识',
|
||
lease_until DATETIME(3) NULL COMMENT '执行租约截止时间',
|
||
last_heartbeat_at DATETIME(3) NULL COMMENT '最后心跳时间',
|
||
execution_deadline_at DATETIME(3) NULL COMMENT '本次执行截止时间',
|
||
requested_by BIGINT UNSIGNED NOT NULL COMMENT '申请用户ID',
|
||
requested_username VARCHAR(128) NULL COMMENT '申请账号快照',
|
||
requested_at DATETIME(3) NOT NULL COMMENT '申请时间',
|
||
started_at DATETIME(3) NULL COMMENT '开始时间',
|
||
completed_at DATETIME(3) NULL COMMENT '完成时间',
|
||
expires_at DATETIME(3) NULL COMMENT '文件过期时间',
|
||
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_file_export_task_no (task_no),
|
||
KEY idx_file_export_owner (tenant_id, app_code, requested_by, requested_at),
|
||
KEY idx_file_export_status (status, requested_at),
|
||
KEY idx_file_export_dispatch (status, next_retry_at, id),
|
||
KEY idx_file_export_lease (status, lease_until),
|
||
KEY idx_file_export_expiry (status, expires_at)
|
||
) ENGINE=InnoDB COMMENT='公共异步导出任务表';
|
||
|
||
CREATE TABLE IF NOT EXISTS file_export_task_guard (
|
||
guard_key VARCHAR(64) NOT NULL COMMENT '任务创建串行化锁键',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||
PRIMARY KEY (guard_key)
|
||
) ENGINE=InnoDB COMMENT='导出任务创建并发保护表:低频创建入口使用单行锁保证重复提交及活动上限';
|
||
|
||
INSERT IGNORE INTO file_export_task_guard (guard_key) VALUES ('GLOBAL_CREATE');
|
||
|
||
CREATE TABLE IF NOT EXISTS file_export_outbox (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT 'Outbox记录ID',
|
||
event_id VARCHAR(64) NOT NULL COMMENT '投递意图唯一标识',
|
||
task_id BIGINT UNSIGNED NOT NULL COMMENT '关联导出任务ID',
|
||
dispatch_version INT NOT NULL COMMENT '任务派发版本',
|
||
topic VARCHAR(128) NOT NULL COMMENT '目标Topic',
|
||
tag VARCHAR(64) NOT NULL COMMENT '消息Tag',
|
||
message_key VARCHAR(64) NOT NULL COMMENT '消息Key',
|
||
payload_json JSON NOT NULL COMMENT '命令消息体',
|
||
status VARCHAR(24) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/CLAIMED/SENT/QUARANTINED',
|
||
attempt_count INT NOT NULL DEFAULT 0 COMMENT '累计发送尝试次数',
|
||
next_retry_at DATETIME(3) NOT NULL COMMENT '允许发送的最早时间',
|
||
lease_owner VARCHAR(128) NULL COMMENT '领取实例标识',
|
||
lease_until DATETIME(3) NULL COMMENT '领取租约截止时间',
|
||
sent_at DATETIME(3) NULL COMMENT '发送成功时间',
|
||
last_error VARCHAR(1000) NULL COMMENT '最后发送错误',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_file_export_outbox_event (event_id),
|
||
UNIQUE KEY uk_file_export_outbox_task_version (task_id, dispatch_version),
|
||
KEY idx_file_export_outbox_publish (status, next_retry_at, id),
|
||
KEY idx_file_export_outbox_task (task_id, dispatch_version, status, sent_at)
|
||
) ENGINE=InnoDB COMMENT='导出命令事务Outbox表';
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase1-admin-rbac.sql
|
||
-- ============================================================================
|
||
-- Phase-one administrator identities and RBAC seed data.
|
||
-- Scope is intentionally limited to first-level menus, second-level menus and buttons.
|
||
-- PAGE and API permission resources are not part of phase one.
|
||
USE baiyue_iam;
|
||
SET NAMES utf8mb4;
|
||
|
||
-- Keep the role table aligned with the shared BaseEntity audit fields.
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'iam_role' AND column_name = 'created_by'),
|
||
'SELECT 1',
|
||
'ALTER TABLE iam_role ADD COLUMN created_by BIGINT NULL AFTER description'
|
||
);
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'iam_role' AND column_name = 'updated_by'),
|
||
'SELECT 1',
|
||
'ALTER TABLE iam_role ADD COLUMN updated_by BIGINT NULL AFTER created_at'
|
||
);
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
INSERT INTO iam_tenant (
|
||
id, tenant_code, tenant_name, tenant_type, status, legal_name,
|
||
unified_social_credit_code, contact_name, contact_phone, contact_email,
|
||
approved_at, approved_by, created_by, deleted, version
|
||
) VALUES
|
||
(0, 'PLATFORM', '虫虫出海平台', 'PLATFORM', 'ACTIVE', '虫虫出海平台',
|
||
NULL, '平台管理员', NULL, NULL, NOW(3), 1000001, 1000001, 0, 0),
|
||
(10001, 'PHASE1_DEMO', '一期演示企业', 'MERCHANT', 'ACTIVE', '一期演示企业有限公司',
|
||
'91310000PHASE10001', '企业管理员', '13800000000', 'merchant@example.com',
|
||
NOW(3), 1000001, 1000001, 0, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
tenant_name = VALUES(tenant_name), tenant_type = VALUES(tenant_type),
|
||
status = 'ACTIVE', legal_name = VALUES(legal_name),
|
||
contact_name = VALUES(contact_name), contact_phone = VALUES(contact_phone),
|
||
contact_email = VALUES(contact_email), approved_at = COALESCE(approved_at, NOW(3)),
|
||
approved_by = VALUES(approved_by), deleted = 0;
|
||
|
||
INSERT INTO iam_user (
|
||
id, auth_user_id, user_type, display_name, phone, email, status, deleted, version
|
||
) VALUES
|
||
(2000001, 1000001, 'INTERNAL', '平台管理员', NULL, NULL, 'ACTIVE', 0, 0),
|
||
(2000002, 1000002, 'ENTERPRISE', '一期演示企业管理员', '13800000000',
|
||
'merchant@example.com', 'ACTIVE', 0, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
display_name = VALUES(display_name), phone = VALUES(phone), email = VALUES(email),
|
||
status = 'ACTIVE', deleted = 0;
|
||
|
||
INSERT INTO iam_membership (
|
||
id, tenant_id, user_id, member_type, member_no, status, joined_at, deleted, version
|
||
) VALUES
|
||
(3000001, 0, 2000001, 'EMPLOYEE', 'PLATFORM-ADMIN-001', 'ACTIVE', NOW(3), 0, 0),
|
||
(3000002, 10001, 2000002, 'OWNER', 'MERCHANT-OWNER-001', 'ACTIVE', NOW(3), 0, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
member_type = VALUES(member_type), member_no = VALUES(member_no),
|
||
status = 'ACTIVE', joined_at = COALESCE(joined_at, NOW(3)), left_at = NULL, deleted = 0;
|
||
|
||
INSERT INTO iam_role (
|
||
id, tenant_id, app_code, role_code, role_name, role_type, status, description, deleted, version
|
||
) VALUES
|
||
(4000001, 0, 'PLATFORM', 'PLATFORM_ADMIN', '平台超级管理员', 'SYSTEM', 'ACTIVE', '一期平台全部菜单和按钮', 0, 0),
|
||
(4000002, 0, 'PLATFORM', 'CUSTOMER_REVIEWER', '企业审核员', 'SYSTEM', 'ACTIVE', '企业资料与入驻审核', 0, 0),
|
||
(4000003, 0, 'PLATFORM', 'ORDER_OPERATOR', '平台订单运营', 'SYSTEM', 'ACTIVE', '头程订单审核与履约处理', 0, 0),
|
||
(4000101, 10001, 'MERCHANT', 'MERCHANT_OWNER', '企业管理员', 'SYSTEM', 'ACTIVE', '本企业一期全部菜单和按钮', 0, 0),
|
||
(4000102, 10001, 'MERCHANT', 'MERCHANT_ORDER_MANAGER', '企业订单管理员', 'SYSTEM', 'ACTIVE', '本企业头程订单操作', 0, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
role_name = VALUES(role_name), role_type = VALUES(role_type), status = 'ACTIVE',
|
||
description = VALUES(description), deleted = 0;
|
||
|
||
-- Platform: level-one menus.
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name, route_path, http_method, sort_no, status, deleted)
|
||
VALUES
|
||
(5100000, 0, 'PLATFORM', 'MENU', 0, 'platform:customer', '客户管理', '/customers', NULL, 10, 'ACTIVE', 0),
|
||
(5101000, 0, 'PLATFORM', 'MENU', 0, 'platform:system', '系统管理', '/system', NULL, 20, 'ACTIVE', 0),
|
||
(5102000, 0, 'PLATFORM', 'MENU', 0, 'platform:order', '头程订单', '/first-leg-orders', NULL, 30, 'ACTIVE', 0),
|
||
(5103000, 0, 'PLATFORM', 'MENU', 0, 'platform:master-data', '基础资料', '/master-data', NULL, 40, 'ACTIVE', 0),
|
||
(5104000, 0, 'PLATFORM', 'MENU', 0, 'platform:audit', '审计管理', '/audit', NULL, 50, 'ACTIVE', 0),
|
||
-- Platform: level-two menus.
|
||
(5100010, 0, 'PLATFORM', 'MENU', 5100000, 'platform:customer:list', '企业客户', '/customers/list', NULL, 10, 'ACTIVE', 0),
|
||
(5101010, 0, 'PLATFORM', 'MENU', 5101000, 'platform:user:list', '内部用户', '/system/users', NULL, 10, 'ACTIVE', 0),
|
||
(5101020, 0, 'PLATFORM', 'MENU', 5101000, 'platform:role:list', '角色管理', '/system/roles', NULL, 20, 'ACTIVE', 0),
|
||
(5101030, 0, 'PLATFORM', 'MENU', 5101000, 'platform:permission:list', '菜单按钮', '/system/permissions', NULL, 30, 'ACTIVE', 0),
|
||
(5102010, 0, 'PLATFORM', 'MENU', 5102000, 'platform:order:list', '订单列表', '/first-leg-orders/list', NULL, 10, 'ACTIVE', 0),
|
||
(5102020, 0, 'PLATFORM', 'MENU', 5102000, 'platform:firstleg:task:list', '履约任务', '/first-leg-tasks/list', NULL, 20, 'ACTIVE', 0),
|
||
(5103010, 0, 'PLATFORM', 'MENU', 5103000, 'platform:warehouse:list', '国内仓/FBA仓', '/master-data/warehouses', NULL, 10, 'ACTIVE', 0),
|
||
(5103020, 0, 'PLATFORM', 'MENU', 5103000, 'platform:express:list', '快递公司', '/master-data/express', NULL, 20, 'ACTIVE', 0),
|
||
(5103030, 0, 'PLATFORM', 'MENU', 5103000, 'platform:counterparty:list', '往来单位', '/master-data/counterparties', NULL, 30, 'ACTIVE', 0),
|
||
(5103040, 0, 'PLATFORM', 'MENU', 5103000, 'platform:download:list', '下载中心', '/downloads', NULL, 40, 'ACTIVE', 0),
|
||
(5104010, 0, 'PLATFORM', 'MENU', 5104000, 'platform:audit:list', '操作日志', '/audit/logs', NULL, 10, 'ACTIVE', 0),
|
||
-- Platform: buttons.
|
||
(5100020, 0, 'PLATFORM', 'BUTTON', 5100010, 'platform:customer:review', '客户审核', NULL, NULL, 50, 'ACTIVE', 0),
|
||
(5100021, 0, 'PLATFORM', 'BUTTON', 5100020, 'platform:customer:approve', '审核通过', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5100022, 0, 'PLATFORM', 'BUTTON', 5100020, 'platform:customer:reject', '审核驳回', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5100015, 0, 'PLATFORM', 'BUTTON', 5100010, 'platform:customer:export', '导出企业客户', NULL, NULL, 40, 'ACTIVE', 0),
|
||
(5103041, 0, 'PLATFORM', 'BUTTON', 5103040, 'platform:download:all', '查看全部下载任务', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5101011, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:create', '新增用户', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5101012, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:edit', '编辑用户', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5101013, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:status', '启停用户', NULL, NULL, 30, 'ACTIVE', 0),
|
||
(5101014, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:reset-password', '重置密码', NULL, NULL, 40, 'ACTIVE', 0),
|
||
(5101015, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:grant-role', '分配用户角色', NULL, NULL, 50, 'ACTIVE', 0),
|
||
(5101021, 0, 'PLATFORM', 'BUTTON', 5101020, 'platform:role:create', '新增角色', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5101022, 0, 'PLATFORM', 'BUTTON', 5101020, 'platform:role:grant', '角色授权', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5101031, 0, 'PLATFORM', 'BUTTON', 5101030, 'platform:permission:create', '新增菜单按钮', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5102011, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:approve', '订单审核通过', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5102012, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:reject', '订单驳回', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5102013, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:accept', '订单受理', NULL, NULL, 30, 'ACTIVE', 0),
|
||
(5102014, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:process', '开始处理', NULL, NULL, 40, 'ACTIVE', 0),
|
||
(5102015, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:complete', '完成订单', NULL, NULL, 50, 'ACTIVE', 0),
|
||
(5102016, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:cancel', '取消订单', NULL, NULL, 60, 'ACTIVE', 0),
|
||
(5102017, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:note', '内部备注', NULL, NULL, 70, 'ACTIVE', 0),
|
||
(5102018, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:fulfillment', '登记履约快递', NULL, NULL, 80, 'ACTIVE', 0),
|
||
(5102021, 0, 'PLATFORM', 'BUTTON', 5102020, 'platform:firstleg:task:view', '查看履约任务', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5102022, 0, 'PLATFORM', 'BUTTON', 5102020, 'platform:firstleg:assignment:history', '查看分配历史', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5102023, 0, 'PLATFORM', 'BUTTON', 5102020, 'platform:firstleg:assignment:assign', '分配履约任务', NULL, NULL, 30, 'ACTIVE', 0),
|
||
(5103011, 0, 'PLATFORM', 'BUTTON', 5103010, 'platform:warehouse:create', '新增仓库', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5103012, 0, 'PLATFORM', 'BUTTON', 5103010, 'platform:warehouse:edit', '编辑仓库', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5103013, 0, 'PLATFORM', 'BUTTON', 5103010, 'platform:warehouse:status', '启用停用', NULL, NULL, 30, 'ACTIVE', 0),
|
||
(5103021, 0, 'PLATFORM', 'BUTTON', 5103020, 'platform:express:create', '新增快递公司', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5103022, 0, 'PLATFORM', 'BUTTON', 5103020, 'platform:express:edit', '编辑快递公司', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5103023, 0, 'PLATFORM', 'BUTTON', 5103020, 'platform:express:status', '启用停用快递公司', NULL, NULL, 30, 'ACTIVE', 0),
|
||
(5103024, 0, 'PLATFORM', 'BUTTON', 5103020, 'platform:express:import', '批量导入快递公司', NULL, NULL, 40, 'ACTIVE', 0),
|
||
(5103031, 0, 'PLATFORM', 'BUTTON', 5103030, 'platform:counterparty:create', '新增往来单位', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5103032, 0, 'PLATFORM', 'BUTTON', 5103030, 'platform:counterparty:edit', '编辑往来单位', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5103033, 0, 'PLATFORM', 'BUTTON', 5103030, 'platform:counterparty:status', '启用停用往来单位', NULL, NULL, 30, 'ACTIVE', 0),
|
||
(5103034, 0, 'PLATFORM', 'BUTTON', 5103030, 'platform:counterparty:import', '批量导入往来单位', NULL, NULL, 40, 'ACTIVE', 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||
http_method = NULL, sort_no = VALUES(sort_no), status = 'ACTIVE', deleted = 0;
|
||
|
||
-- 平台代客创建、编辑草稿权限;可重复执行并纳入已有平台管理员和订单运营角色授权。
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name, route_path, http_method, sort_no, status, deleted)
|
||
VALUES
|
||
(5102019, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:create', '平台代客创建订单', NULL, NULL, 90, 'ACTIVE', 0),
|
||
(5102024, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:edit', '平台编辑订单草稿', NULL, NULL, 100, 'ACTIVE', 0),
|
||
(5102025, 0, 'PLATFORM', 'BUTTON', 5102010, 'platform:order:submit', '平台代客提交订单', NULL, NULL, 110, 'ACTIVE', 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_name = VALUES(permission_name), parent_id = VALUES(parent_id), status = 'ACTIVE', deleted = 0;
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0 FROM iam_permission
|
||
WHERE id IN (5102019, 5102024, 5102025)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000003, id, 0 FROM iam_permission
|
||
WHERE id IN (5102019, 5102024, 5102025)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- Merchant: level-one menus, level-two menus and buttons.
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name, route_path, http_method, sort_no, status, deleted)
|
||
VALUES
|
||
(5200000, 10001, 'MERCHANT', 'MENU', 0, 'merchant:enterprise', '企业管理', '/enterprise', NULL, 10, 'ACTIVE', 0),
|
||
(5201000, 10001, 'MERCHANT', 'MENU', 0, 'merchant:order', '头程订单', '/first-leg-orders', NULL, 20, 'ACTIVE', 0),
|
||
(5202000, 10001, 'MERCHANT', 'MENU', 0, 'merchant:master-data', '基础资料', '/master-data', NULL, 30, 'ACTIVE', 0),
|
||
(5200010, 10001, 'MERCHANT', 'MENU', 5200000, 'merchant:profile:view', '企业资料', '/enterprise/profile', NULL, 10, 'ACTIVE', 0),
|
||
(5200020, 10001, 'MERCHANT', 'MENU', 5200000, 'merchant:member:list', '企业成员', '/enterprise/members', NULL, 20, 'ACTIVE', 0),
|
||
(5200030, 10001, 'MERCHANT', 'MENU', 5200000, 'merchant:role:list', '角色管理', '/enterprise/roles', NULL, 30, 'ACTIVE', 0),
|
||
(5201010, 10001, 'MERCHANT', 'MENU', 5201000, 'merchant:order:list', '我的订单', '/first-leg-orders/list', NULL, 10, 'ACTIVE', 0),
|
||
(5201020, 10001, 'MERCHANT', 'MENU', 5201000, 'merchant:order:create-page', '新建订单', '/first-leg-orders/create', NULL, 20, 'ACTIVE', 0),
|
||
(5202010, 10001, 'MERCHANT', 'MENU', 5202000, 'merchant:warehouse:list', '收货仓选择', '/master-data/warehouses', NULL, 10, 'ACTIVE', 0),
|
||
(5202020, 10001, 'MERCHANT', 'MENU', 5202000, 'merchant:counterparty:list', '往来单位', '/master-data/counterparties', NULL, 20, 'ACTIVE', 0),
|
||
(5200011, 10001, 'MERCHANT', 'BUTTON', 5200010, 'merchant:profile:edit', '编辑企业资料', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5200012, 10001, 'MERCHANT', 'BUTTON', 5200010, 'merchant:qualification:upload', '上传企业资质', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5200021, 10001, 'MERCHANT', 'BUTTON', 5200020, 'merchant:member:create', '新增成员', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5200022, 10001, 'MERCHANT', 'BUTTON', 5200020, 'merchant:member:grant-role', '分配角色', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5200031, 10001, 'MERCHANT', 'BUTTON', 5200030, 'merchant:role:create', '新增角色', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5200032, 10001, 'MERCHANT', 'BUTTON', 5200030, 'merchant:role:grant', '角色授权', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5201011, 10001, 'MERCHANT', 'BUTTON', 5201010, 'merchant:order:view', '查看订单', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5201012, 10001, 'MERCHANT', 'BUTTON', 5201010, 'merchant:order:cancel', '取消订单', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5201021, 10001, 'MERCHANT', 'BUTTON', 5201020, 'merchant:order:create', '创建草稿', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5201022, 10001, 'MERCHANT', 'BUTTON', 5201020, 'merchant:order:edit', '编辑草稿', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5201023, 10001, 'MERCHANT', 'BUTTON', 5201020, 'merchant:order:submit', '提交订单', NULL, NULL, 30, 'ACTIVE', 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||
http_method = NULL, sort_no = VALUES(sort_no), status = 'ACTIVE', deleted = 0;
|
||
|
||
INSERT INTO iam_membership_role (membership_id, role_id, tenant_id) VALUES
|
||
(3000001, 4000001, 0),
|
||
(3000002, 4000101, 10001)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- Full administrator roles receive all phase-one permissions in their application scope.
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0 FROM iam_permission
|
||
WHERE app_code = 'PLATFORM' AND tenant_id = 0 AND permission_type IN ('MENU', 'BUTTON')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000101, id, 10001 FROM iam_permission
|
||
WHERE app_code = 'MERCHANT' AND tenant_id = 10001 AND permission_type IN ('MENU', 'BUTTON')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- Limited platform and merchant operational roles.
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000002, id, 0 FROM iam_permission
|
||
WHERE permission_code IN (
|
||
'platform:customer', 'platform:customer:list', 'platform:customer:review',
|
||
'platform:customer:approve', 'platform:customer:reject', 'platform:customer:export',
|
||
'platform:master-data', 'platform:download:list'
|
||
)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000003, id, 0 FROM iam_permission
|
||
WHERE permission_code LIKE 'platform:order%' OR permission_code LIKE 'platform:firstleg%'
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000102, id, 10001 FROM iam_permission
|
||
WHERE permission_code LIKE 'merchant:order%' OR permission_code IN ('merchant:master-data', 'merchant:warehouse:list')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_data_scope (id, role_id, tenant_id, scope_type, scope_expression) VALUES
|
||
(6000001, 4000001, 0, 'TENANT', NULL),
|
||
(6000002, 4000002, 0, 'TENANT', NULL),
|
||
(6000003, 4000003, 0, 'TENANT', NULL),
|
||
(6000101, 4000101, 10001, 'TENANT', NULL),
|
||
(6000102, 4000102, 10001, 'TENANT', NULL)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id), scope_type = VALUES(scope_type), scope_expression = NULL;
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase1-onboarding.sql
|
||
-- ============================================================================
|
||
-- Phase-one merchant onboarding state migration.
|
||
USE baiyue_iam;
|
||
SET NAMES utf8mb4;
|
||
|
||
ALTER TABLE iam_tenant MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'PROFILE_REQUIRED'
|
||
COMMENT 'PROFILE_REQUIRED, PENDING, ACTIVE, REJECTED or DISABLED';
|
||
DROP PROCEDURE IF EXISTS phase1_iam_add_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE phase1_iam_add_column(
|
||
IN p_table_name VARCHAR(64), IN p_column_name VARCHAR(64), IN p_definition VARCHAR(1000)
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = p_table_name AND COLUMN_NAME = p_column_name
|
||
) THEN
|
||
SET @phase1_iam_sql = CONCAT('ALTER TABLE `', p_table_name, '` ADD COLUMN `',
|
||
p_column_name, '` ', p_definition);
|
||
PREPARE phase1_iam_stmt FROM @phase1_iam_sql;
|
||
EXECUTE phase1_iam_stmt;
|
||
DEALLOCATE PREPARE phase1_iam_stmt;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL phase1_iam_add_column('iam_tenant', 'approved_at', "DATETIME(3) NULL COMMENT 'Approval time'");
|
||
CALL phase1_iam_add_column('iam_tenant', 'approved_by', "BIGINT NULL COMMENT 'Reviewer ID'");
|
||
CALL phase1_iam_add_column('iam_tenant', 'reject_reason', "VARCHAR(500) NULL COMMENT 'Rejection reason'");
|
||
CALL phase1_iam_add_column('iam_tenant', 'legal_representative', "VARCHAR(64) NULL COMMENT '法定代表人' AFTER legal_name");
|
||
CALL phase1_iam_add_column('iam_tenant_qualification', 'review_comment', "VARCHAR(500) NULL COMMENT 'Review comment'");
|
||
CALL phase1_iam_add_column('iam_membership', 'created_by', "BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Creator ID'");
|
||
CALL phase1_iam_add_column('iam_membership', 'updated_by', "BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Updater ID'");
|
||
DROP PROCEDURE phase1_iam_add_column;
|
||
|
||
-- A global merchant owner template is assigned to newly registered enterprises.
|
||
INSERT INTO iam_role (
|
||
id, tenant_id, app_code, role_code, role_name, role_type, status,
|
||
description, created_by, updated_by, deleted, version
|
||
) VALUES (
|
||
4000100, 0, 'MERCHANT', 'MERCHANT_OWNER', '企业管理员', 'SYSTEM', 'ACTIVE',
|
||
'一期企业全部菜单和操作按钮模板', 1000001, 1000001, 0, 0
|
||
)
|
||
ON DUPLICATE KEY UPDATE status='ACTIVE', deleted=0;
|
||
|
||
-- Clone the一期 merchant menu/button template into the global scope.
|
||
INSERT INTO iam_permission (
|
||
id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||
permission_name, route_path, http_method, sort_no, status, deleted
|
||
)
|
||
SELECT id + 100000, 0, app_code, permission_type,
|
||
CASE WHEN parent_id = 0 THEN 0 ELSE parent_id + 100000 END,
|
||
permission_code, permission_name, route_path, NULL, sort_no, 'ACTIVE', 0
|
||
FROM iam_permission
|
||
WHERE tenant_id = 10001 AND app_code = 'MERCHANT'
|
||
AND permission_type IN ('MENU', 'BUTTON')
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_name=VALUES(permission_name), route_path=VALUES(route_path),
|
||
parent_id=VALUES(parent_id), sort_no=VALUES(sort_no), status='ACTIVE', deleted=0;
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT owner_role.id, permission.id, 0
|
||
FROM iam_role owner_role
|
||
JOIN iam_permission permission
|
||
ON permission.app_code='MERCHANT' AND permission.tenant_id=0
|
||
AND permission.permission_type IN ('MENU','BUTTON')
|
||
AND permission.status='ACTIVE' AND permission.deleted=0
|
||
WHERE owner_role.tenant_id=0 AND owner_role.app_code='MERCHANT'
|
||
AND owner_role.role_code='MERCHANT_OWNER'
|
||
AND owner_role.status='ACTIVE' AND owner_role.deleted=0
|
||
ON DUPLICATE KEY UPDATE tenant_id=VALUES(tenant_id);
|
||
|
||
-- 不再写入伪造的资质 URL。资质必须先由 File 服务保存真实图片,再由 IAM 记录文件地址和审核结果。
|
||
-- 已部署环境中的 /phase1-seed/ 历史记录按 docs/企业资质文件迁移说明.md 处理,本脚本不得将其改成不存在的 UUID。
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase1-member-permissions.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
-- 企业成员管理按钮权限增量;部署后应将权限按需授予企业管理员角色。
|
||
USE baiyue_iam;
|
||
|
||
-- 为存量数据库补齐企业内成员编号唯一约束,防止并发重复创建。
|
||
SET @member_no_index_sql = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'iam_membership'
|
||
AND index_name = 'uk_membership_tenant_no'),
|
||
'SELECT 1',
|
||
'ALTER TABLE iam_membership ADD UNIQUE KEY uk_membership_tenant_no (tenant_id, member_no)'
|
||
);
|
||
PREPARE member_no_index_stmt FROM @member_no_index_sql;
|
||
EXECUTE member_no_index_stmt;
|
||
DEALLOCATE PREPARE member_no_index_stmt;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name, sort_no, status, deleted)
|
||
VALUES
|
||
(5200023, 10001, 'MERCHANT', 'BUTTON', 5200020, 'merchant:member:edit', '编辑成员', 30, 'ACTIVE', 0),
|
||
(5200024, 10001, 'MERCHANT', 'BUTTON', 5200020, 'merchant:member:status', '启停成员', 40, 'ACTIVE', 0),
|
||
(5200025, 10001, 'MERCHANT', 'BUTTON', 5200020, 'merchant:member:reset-password', '重置成员密码', 50, 'ACTIVE', 0),
|
||
(5300023, 0, 'MERCHANT', 'BUTTON', 5300020, 'merchant:member:edit', '编辑成员', 30, 'ACTIVE', 0),
|
||
(5300024, 0, 'MERCHANT', 'BUTTON', 5300020, 'merchant:member:status', '启停成员', 40, 'ACTIVE', 0),
|
||
(5300025, 0, 'MERCHANT', 'BUTTON', 5300020, 'merchant:member:reset-password', '重置成员密码', 50, 'ACTIVE', 0)
|
||
ON DUPLICATE KEY UPDATE permission_name = VALUES(permission_name), status = VALUES(status), deleted = 0;
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000101, id, 10001 FROM iam_permission
|
||
WHERE tenant_id = 10001 AND permission_code IN
|
||
('merchant:member:edit', 'merchant:member:status', 'merchant:member:reset-password')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000100, id, 0 FROM iam_permission
|
||
WHERE tenant_id = 0 AND permission_code IN
|
||
('merchant:member:edit', 'merchant:member:status', 'merchant:member:reset-password')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\rbac-role-management-v2.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
-- 角色管理闭环权限迁移,可重复执行。
|
||
USE baiyue_iam;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||
permission_name, sort_no, status, deleted)
|
||
VALUES
|
||
(5100011, 0, 'PLATFORM', 'BUTTON', 5100010, 'platform:customer:create', '新增企业客户', 10, 'ACTIVE', 0),
|
||
(5101023, 0, 'PLATFORM', 'BUTTON', 5101020, 'platform:role:edit', '编辑角色', 30, 'ACTIVE', 0),
|
||
(5101024, 0, 'PLATFORM', 'BUTTON', 5101020, 'platform:role:status', '启停角色', 40, 'ACTIVE', 0),
|
||
(5101025, 0, 'PLATFORM', 'BUTTON', 5101020, 'platform:role:delete', '删除角色', 50, 'ACTIVE', 0),
|
||
(5101040, 0, 'PLATFORM', 'MENU', 5101000, 'platform:member:list', '平台成员', 40, 'ACTIVE', 0),
|
||
(5101041, 0, 'PLATFORM', 'BUTTON', 5101040, 'platform:member:grant-role', '分配成员角色', 10, 'ACTIVE', 0),
|
||
(5101012, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:edit', '编辑用户', 20, 'ACTIVE', 0),
|
||
(5101013, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:status', '启停用户', 30, 'ACTIVE', 0),
|
||
(5101014, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:reset-password', '重置密码', 40, 'ACTIVE', 0),
|
||
(5101015, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:grant-role', '分配内部用户角色', 50, 'ACTIVE', 0),
|
||
(5200033, 10001, 'MERCHANT', 'BUTTON', 5200030, 'merchant:role:edit', '编辑角色', 30, 'ACTIVE', 0),
|
||
(5200034, 10001, 'MERCHANT', 'BUTTON', 5200030, 'merchant:role:status', '启停角色', 40, 'ACTIVE', 0),
|
||
(5200035, 10001, 'MERCHANT', 'BUTTON', 5200030, 'merchant:role:delete', '删除角色', 50, 'ACTIVE', 0),
|
||
(5300033, 0, 'MERCHANT', 'BUTTON', 5300030, 'merchant:role:edit', '编辑角色', 30, 'ACTIVE', 0),
|
||
(5300034, 0, 'MERCHANT', 'BUTTON', 5300030, 'merchant:role:status', '启停角色', 40, 'ACTIVE', 0),
|
||
(5300035, 0, 'MERCHANT', 'BUTTON', 5300030, 'merchant:role:delete', '删除角色', 50, 'ACTIVE', 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||
permission_name = VALUES(permission_name), sort_no = VALUES(sort_no),
|
||
status = 'ACTIVE', deleted = 0;
|
||
|
||
-- 示例管理员获得新增权限;其他角色仍由管理员按需授权。
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0 FROM iam_permission
|
||
WHERE tenant_id = 0 AND app_code = 'PLATFORM'
|
||
AND permission_code IN ('platform:role:edit', 'platform:role:status', 'platform:role:delete',
|
||
'platform:member:list', 'platform:member:grant-role', 'platform:customer:create',
|
||
'platform:user:edit', 'platform:user:status', 'platform:user:reset-password',
|
||
'platform:user:grant-role')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000101, id, 10001 FROM iam_permission
|
||
WHERE tenant_id = 10001 AND app_code = 'MERCHANT'
|
||
AND permission_code IN ('merchant:role:edit', 'merchant:role:status', 'merchant:role:delete')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000100, id, 0 FROM iam_permission
|
||
WHERE tenant_id = 0 AND app_code = 'MERCHANT'
|
||
AND permission_code IN ('merchant:role:edit', 'merchant:role:status', 'merchant:role:delete')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase1-platform-master-data-and-permission-management.sql
|
||
-- ============================================================================
|
||
-- 权限资源维护与平台主数据权限迁移。
|
||
-- 在 phase1-admin-rbac.sql、rbac-role-management-v2.sql 之后执行,可重复执行。
|
||
USE baiyue_iam;
|
||
|
||
-- 兼容不支持 ADD COLUMN IF NOT EXISTS 的 MySQL 版本,通过元数据判断后执行。
|
||
SET @iam_permission_built_in_sql = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'iam_permission' AND column_name = 'built_in'),
|
||
'SELECT 1',
|
||
"ALTER TABLE iam_permission ADD COLUMN built_in TINYINT NOT NULL DEFAULT 0 COMMENT '是否为系统预置权限;预置资源不可通过管理接口修改' AFTER status"
|
||
);
|
||
PREPARE iam_permission_built_in_stmt FROM @iam_permission_built_in_sql;
|
||
EXECUTE iam_permission_built_in_stmt;
|
||
DEALLOCATE PREPARE iam_permission_built_in_stmt;
|
||
|
||
-- 一期固定编号范围内的资源均为种子资源,运行期生成的雪花编号不作预置标记。
|
||
UPDATE iam_permission
|
||
SET built_in = 1
|
||
WHERE id BETWEEN 5000000 AND 5399999 AND built_in = 0;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name,
|
||
route_path, sort_no, status, built_in, deleted)
|
||
VALUES
|
||
(5103040, 0, 'PLATFORM', 'MENU', 5103000, 'platform:download:list', '下载中心',
|
||
'/downloads', 40, 'ACTIVE', 1, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path), sort_no = VALUES(sort_no),
|
||
status = 'ACTIVE', built_in = 1, deleted = 0;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name,
|
||
sort_no, status, built_in, deleted)
|
||
VALUES
|
||
(5100014, 0, 'PLATFORM', 'BUTTON', 5100010, 'platform:customer:view', '查看企业客户档案', 15, 'ACTIVE', 1, 0),
|
||
(5100012, 0, 'PLATFORM', 'BUTTON', 5100010, 'platform:customer:edit', '编辑企业客户', 20, 'ACTIVE', 1, 0),
|
||
(5100013, 0, 'PLATFORM', 'BUTTON', 5100010, 'platform:customer:status', '启停企业客户', 30, 'ACTIVE', 1, 0),
|
||
(5100015, 0, 'PLATFORM', 'BUTTON', 5100010, 'platform:customer:export', '导出企业客户', 40, 'ACTIVE', 1, 0),
|
||
(5101015, 0, 'PLATFORM', 'BUTTON', 5101010, 'platform:user:grant-role', '分配内部用户角色', 50, 'ACTIVE', 1, 0),
|
||
(5101032, 0, 'PLATFORM', 'BUTTON', 5101030, 'platform:permission:edit', '编辑权限资源', 20, 'ACTIVE', 1, 0),
|
||
(5101033, 0, 'PLATFORM', 'BUTTON', 5101030, 'platform:permission:status', '启停权限资源', 30, 'ACTIVE', 1, 0),
|
||
(5101034, 0, 'PLATFORM', 'BUTTON', 5101030, 'platform:permission:delete', '删除权限资源', 40, 'ACTIVE', 1, 0),
|
||
(5103021, 0, 'PLATFORM', 'BUTTON', 5103020, 'platform:express:create', '新增快递公司', 10, 'ACTIVE', 1, 0),
|
||
(5103022, 0, 'PLATFORM', 'BUTTON', 5103020, 'platform:express:edit', '编辑快递公司', 20, 'ACTIVE', 1, 0),
|
||
(5103023, 0, 'PLATFORM', 'BUTTON', 5103020, 'platform:express:status', '启停快递公司', 30, 'ACTIVE', 1, 0),
|
||
(5103024, 0, 'PLATFORM', 'BUTTON', 5103020, 'platform:express:import', '批量导入快递公司', 40, 'ACTIVE', 1, 0),
|
||
(5103031, 0, 'PLATFORM', 'BUTTON', 5103030, 'platform:counterparty:create', '新增往来单位', 10, 'ACTIVE', 1, 0),
|
||
(5103032, 0, 'PLATFORM', 'BUTTON', 5103030, 'platform:counterparty:edit', '编辑往来单位', 20, 'ACTIVE', 1, 0),
|
||
(5103033, 0, 'PLATFORM', 'BUTTON', 5103030, 'platform:counterparty:status', '启停往来单位', 30, 'ACTIVE', 1, 0),
|
||
(5103041, 0, 'PLATFORM', 'BUTTON', 5103040, 'platform:download:all', '查看全部下载任务', 10, 'ACTIVE', 1, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_name = VALUES(permission_name), sort_no = VALUES(sort_no), status = 'ACTIVE',
|
||
built_in = 1, deleted = 0;
|
||
|
||
-- 新增平台操作权限默认只授予系统管理员。
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0
|
||
FROM iam_permission
|
||
WHERE tenant_id = 0 AND app_code = 'PLATFORM'
|
||
AND permission_code IN (
|
||
'platform:customer:edit', 'platform:customer:status', 'platform:user:grant-role',
|
||
'platform:permission:edit', 'platform:permission:status', 'platform:permission:delete',
|
||
'platform:express:list', 'platform:express:create', 'platform:express:edit', 'platform:express:status', 'platform:express:import',
|
||
'platform:counterparty:list', 'platform:counterparty:create', 'platform:counterparty:edit', 'platform:counterparty:status',
|
||
'platform:customer:export', 'platform:download:list', 'platform:download:all'
|
||
)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- 已有客户运营角色继续具备客户导出与本人下载任务查询能力,但不授予查看全部任务。
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT DISTINCT existing_grant.role_id, added_permission.id, existing_grant.tenant_id
|
||
FROM iam_role_permission existing_grant
|
||
JOIN iam_permission existing_permission ON existing_permission.id = existing_grant.permission_id
|
||
JOIN iam_permission added_permission
|
||
ON added_permission.tenant_id = 0 AND added_permission.app_code = 'PLATFORM'
|
||
AND added_permission.permission_code IN ('platform:customer:export', 'platform:download:list')
|
||
WHERE existing_permission.tenant_id = 0
|
||
AND existing_permission.app_code = 'PLATFORM'
|
||
AND existing_permission.permission_code IN ('platform:customer:list', 'platform:customer:review')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- 详情查看从列表和审核权限中拆分;升级时保留既有运营角色的查询能力。
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT DISTINCT existing_grant.role_id, view_permission.id, existing_grant.tenant_id
|
||
FROM iam_role_permission existing_grant
|
||
JOIN iam_permission existing_permission
|
||
ON existing_permission.id = existing_grant.permission_id
|
||
JOIN iam_permission view_permission
|
||
ON view_permission.tenant_id = 0
|
||
AND view_permission.app_code = 'PLATFORM'
|
||
AND view_permission.permission_code = 'platform:customer:view'
|
||
WHERE existing_permission.tenant_id = 0
|
||
AND existing_permission.app_code = 'PLATFORM'
|
||
AND existing_permission.permission_code IN ('platform:customer:list', 'platform:customer:review')
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase1-customer-profile.sql
|
||
-- ============================================================================
|
||
-- 一期平台客户档案字段增量迁移。可在同一数据库重复执行。
|
||
USE baiyue_iam;
|
||
SET NAMES utf8mb4;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'contact_wechat'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN contact_wechat VARCHAR(64) NULL COMMENT ''联系微信'' AFTER contact_email');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'sales_owner_name'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN sales_owner_name VARCHAR(64) NULL COMMENT ''销售负责人姓名'' AFTER contact_wechat');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'payment_term_days'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN payment_term_days SMALLINT UNSIGNED NULL COMMENT ''账期天数'' AFTER sales_owner_name');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'enterprise_type'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN enterprise_type VARCHAR(64) NULL COMMENT ''企业类型'' AFTER payment_term_days');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'established_date'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN established_date DATE NULL COMMENT ''成立日期'' AFTER enterprise_type');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'registered_capital'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN registered_capital DECIMAL(18,2) NULL COMMENT ''注册资本'' AFTER established_date');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'registered_capital_currency'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN registered_capital_currency CHAR(3) NULL COMMENT ''注册资本币种 ISO 4217'' AFTER registered_capital');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'registered_address'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN registered_address VARCHAR(500) NULL COMMENT ''注册地址文本'' AFTER registered_capital_currency');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'iam_tenant' AND column_name = 'internal_remark'),
|
||
'SELECT 1', 'ALTER TABLE iam_tenant ADD COLUMN internal_remark VARCHAR(1000) NULL COMMENT ''平台内部备注'' AFTER registered_address');
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
-- ============================================================================
|
||
-- 来源:order\src\main\resources\db\phase1-order-extension.sql
|
||
-- ============================================================================
|
||
-- Phase-one first-leg order fields. Safe to run repeatedly on MySQL 8.
|
||
USE baiyue_order;
|
||
SET NAMES utf8mb4;
|
||
|
||
DROP PROCEDURE IF EXISTS phase1_add_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE phase1_add_column(
|
||
IN p_table_name VARCHAR(64),
|
||
IN p_column_name VARCHAR(64),
|
||
IN p_definition VARCHAR(1000)
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = p_table_name
|
||
AND COLUMN_NAME = p_column_name
|
||
) THEN
|
||
SET @phase1_sql = CONCAT('ALTER TABLE `', p_table_name, '` ADD COLUMN `',
|
||
p_column_name, '` ', p_definition);
|
||
PREPARE phase1_stmt FROM @phase1_sql;
|
||
EXECUTE phase1_stmt;
|
||
DEALLOCATE PREPARE phase1_stmt;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL phase1_add_column('ord_order', 'pickup_method', "VARCHAR(24) NULL COMMENT 'Pickup method'");
|
||
CALL phase1_add_column('ord_order', 'receiving_warehouse_id', "BIGINT UNSIGNED NULL COMMENT 'Domestic receiving warehouse ID'");
|
||
CALL phase1_add_column('ord_order', 'receiving_warehouse_name', "VARCHAR(128) NULL COMMENT 'Domestic receiving warehouse snapshot'");
|
||
CALL phase1_add_column('ord_order', 'receiving_warehouse_address', "VARCHAR(512) NULL COMMENT '国内收货仓完整地址快照'");
|
||
CALL phase1_add_column('ord_order', 'receiving_time', "VARCHAR(128) NULL COMMENT '国内收货仓收货时间快照'");
|
||
CALL phase1_add_column('ord_order', 'channel_code', "VARCHAR(64) NULL COMMENT 'Shipping channel code'");
|
||
CALL phase1_add_column('ord_order', 'channel_name', "VARCHAR(128) NULL COMMENT 'Shipping channel snapshot'");
|
||
CALL phase1_add_column('ord_order', 'tax_mode', "VARCHAR(24) NULL COMMENT 'BUY_DECLARATION or TAX_REFUND'");
|
||
CALL phase1_add_column('ord_order', 'container_mode', "VARCHAR(24) NULL COMMENT 'FULL_CONTAINER or LCL'");
|
||
CALL phase1_add_column('ord_order', 'customs_inspection', "TINYINT(1) NULL COMMENT 'Whether customs inspection is required'");
|
||
CALL phase1_add_column('ord_order', 'destination_type', "VARCHAR(24) NULL COMMENT 'FBA, OVERSEAS or PRIVATE'");
|
||
CALL phase1_add_column('ord_order', 'amazon_warehouse_code', "VARCHAR(32) NULL COMMENT 'Amazon warehouse code'");
|
||
CALL phase1_add_column('ord_order', 'shipment_id', "VARCHAR(64) NULL COMMENT 'Amazon Shipment ID'");
|
||
CALL phase1_add_column('ord_order', 'reference_id', "VARCHAR(64) NULL COMMENT 'Amazon Reference ID'");
|
||
CALL phase1_add_column('ord_order', 'express_company', "VARCHAR(64) NULL COMMENT '履约快递公司名称快照'");
|
||
CALL phase1_add_column('ord_order', 'express_tracking_no', "VARCHAR(128) NULL COMMENT '履约快递单号'");
|
||
|
||
CALL phase1_add_column('ord_order_cargo', 'sku_no', "VARCHAR(64) NULL COMMENT 'SKU number'");
|
||
CALL phase1_add_column('ord_order_cargo', 'upc_no', "VARCHAR(64) NULL COMMENT 'UPC number'");
|
||
CALL phase1_add_column('ord_order_cargo', 'cargo_name_en', "VARCHAR(128) NULL COMMENT 'English cargo name'");
|
||
CALL phase1_add_column('ord_order_cargo', 'customs_hs_code', "VARCHAR(20) NULL COMMENT 'Destination customs HS code'");
|
||
CALL phase1_add_column('ord_order_cargo', 'units_per_package', "INT UNSIGNED NULL COMMENT 'Units per carton'");
|
||
CALL phase1_add_column('ord_order_cargo', 'total_quantity', "INT UNSIGNED NULL COMMENT 'Total units'");
|
||
CALL phase1_add_column('ord_order_cargo', 'net_weight_kg', "DECIMAL(18,3) NULL COMMENT 'Net weight in kilograms'");
|
||
CALL phase1_add_column('ord_order_cargo', 'unit_declared_value', "DECIMAL(18,2) NULL COMMENT 'Declared value per unit'");
|
||
CALL phase1_add_column('ord_order_cargo', 'material', "VARCHAR(128) NULL COMMENT 'Material'");
|
||
CALL phase1_add_column('ord_order_cargo', 'product_usage', "VARCHAR(128) NULL COMMENT 'Usage'");
|
||
CALL phase1_add_column('ord_order_cargo', 'model', "VARCHAR(64) NULL COMMENT 'Model'");
|
||
CALL phase1_add_column('ord_order_cargo', 'brand', "VARCHAR(64) NULL COMMENT 'Brand'");
|
||
|
||
DROP PROCEDURE phase1_add_column;
|
||
|
||
-- 已有订单库的幂等记录迁移,和订单写入处于同一个本地事务。
|
||
CREATE TABLE IF NOT EXISTS ord_idempotency_record (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '幂等记录 ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '租户 ID',
|
||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人 ID',
|
||
operation VARCHAR(32) NOT NULL COMMENT '操作类型',
|
||
resource_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '资源 ID',
|
||
idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键',
|
||
request_hash CHAR(64) NOT NULL COMMENT '请求内容摘要',
|
||
status VARCHAR(16) NOT NULL COMMENT '处理状态',
|
||
result_order_id BIGINT UNSIGNED NULL COMMENT '重放结果订单 ID',
|
||
completed_at DATETIME(3) NULL COMMENT '完成时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_order_idempotency_scope (tenant_id, operator_id, operation, idempotency_key),
|
||
KEY idx_order_idempotency_created (created_at)
|
||
) ENGINE=InnoDB COMMENT='订单写接口持久化幂等记录';
|
||
|
||
-- ============================================================================
|
||
-- 来源:order\src\main\resources\db\phase1-masterdata-extension.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_order;
|
||
-- MySQL 8 可重复执行的订单快照及履约字段迁移。
|
||
SET @schema_name = DATABASE();
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@schema_name AND TABLE_NAME='ord_order' AND COLUMN_NAME='receiving_warehouse_address')=0,
|
||
'ALTER TABLE ord_order ADD COLUMN receiving_warehouse_address VARCHAR(600) NULL COMMENT ''收货仓地址历史快照'' AFTER receiving_warehouse_name','SELECT 1');
|
||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@schema_name AND TABLE_NAME='ord_order' AND COLUMN_NAME='receiving_time')=0,
|
||
'ALTER TABLE ord_order ADD COLUMN receiving_time VARCHAR(100) NULL COMMENT ''收货时间历史快照'' AFTER receiving_warehouse_address','SELECT 1');
|
||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@schema_name AND TABLE_NAME='ord_order' AND COLUMN_NAME='express_company')=0,
|
||
'ALTER TABLE ord_order ADD COLUMN express_company VARCHAR(64) NULL COMMENT ''履约快递公司'' AFTER reference_id','SELECT 1');
|
||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@schema_name AND TABLE_NAME='ord_order' AND COLUMN_NAME='express_tracking_no')=0,
|
||
'ALTER TABLE ord_order ADD COLUMN express_tracking_no VARCHAR(128) NULL COMMENT ''履约快递单号'' AFTER express_company','SELECT 1');
|
||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||
|
||
-- ============================================================================
|
||
-- 来源:warehouse\src\main\resources\db\phase1-warehouse-schema-migration.sql
|
||
-- ============================================================================
|
||
-- 既有 baiyue_warehouse 的一期增量迁移(只增不删,可重复执行)。
|
||
-- 执行顺序:warehouse.sql、warehouse-partner.sql、warehouse-express-company.sql、
|
||
-- 本文件、warehouse-seed.sql。应用不会在启动时自动执行这些脚本,必须由发布流程执行。
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_warehouse;
|
||
|
||
-- MySQL 5.7/8.0 各小版本对条件补列语法的支持不一致。
|
||
-- 统一先查 information_schema,再通过动态 SQL 补列,确保脚本可重复执行。
|
||
DROP PROCEDURE IF EXISTS add_column_if_missing;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE add_column_if_missing(
|
||
IN p_table_name VARCHAR(64),
|
||
IN p_column_name VARCHAR(64),
|
||
IN p_column_definition TEXT
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1
|
||
FROM information_schema.columns
|
||
WHERE table_schema = DATABASE()
|
||
AND table_name = p_table_name
|
||
AND column_name = p_column_name
|
||
) THEN
|
||
SET @add_column_sql = CONCAT(
|
||
'ALTER TABLE `', REPLACE(p_table_name, '`', '``'),
|
||
'` ADD COLUMN `', REPLACE(p_column_name, '`', '``'),
|
||
'` ', p_column_definition
|
||
);
|
||
PREPARE add_column_statement FROM @add_column_sql;
|
||
EXECUTE add_column_statement;
|
||
DEALLOCATE PREPARE add_column_statement;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
-- 早期 wh_warehouse 缺少的业务与审计字段。
|
||
CALL add_column_if_missing('wh_warehouse', 'warehouse_type', 'VARCHAR(32) NOT NULL DEFAULT ''DOMESTIC'' COMMENT ''仓库类型'' AFTER warehouse_name');
|
||
CALL add_column_if_missing('wh_warehouse', 'country_code', 'CHAR(2) NOT NULL DEFAULT ''CN'' COMMENT ''所在国家二字码'' AFTER warehouse_type');
|
||
CALL add_column_if_missing('wh_warehouse', 'timezone', 'VARCHAR(64) NOT NULL DEFAULT ''Asia/Shanghai'' COMMENT ''IANA时区'' AFTER country_code');
|
||
CALL add_column_if_missing('wh_warehouse', 'contact_name', 'VARCHAR(64) NULL AFTER timezone');
|
||
CALL add_column_if_missing('wh_warehouse', 'contact_phone', 'VARCHAR(32) NULL AFTER contact_name');
|
||
CALL add_column_if_missing('wh_warehouse', 'contact_email', 'VARCHAR(128) NULL AFTER contact_phone');
|
||
CALL add_column_if_missing('wh_warehouse', 'status', 'VARCHAR(20) NOT NULL DEFAULT ''ACTIVE'' AFTER contact_email');
|
||
CALL add_column_if_missing('wh_warehouse', 'remark', 'VARCHAR(500) NULL AFTER status');
|
||
CALL add_column_if_missing('wh_warehouse', 'created_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_warehouse', 'created_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_warehouse', 'updated_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_warehouse', 'updated_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_warehouse', 'deleted', 'TINYINT(1) NOT NULL DEFAULT 0');
|
||
CALL add_column_if_missing('wh_warehouse', 'version', 'INT NOT NULL DEFAULT 0');
|
||
|
||
CALL add_column_if_missing('wh_warehouse_address', 'tenant_id', 'BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER id');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'warehouse_id', 'BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER tenant_id');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'address_type', 'VARCHAR(20) NOT NULL DEFAULT ''OPERATING'' AFTER warehouse_id');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'country_code', 'CHAR(2) NOT NULL DEFAULT ''CN'' AFTER address_type');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'state_province', 'VARCHAR(100) NULL');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'city', 'VARCHAR(100) NOT NULL DEFAULT '''' AFTER state_province');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'district', 'VARCHAR(100) NULL');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'postal_code', 'VARCHAR(20) NULL');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'address_line1', 'VARCHAR(255) NOT NULL DEFAULT '''' AFTER postal_code');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'address_line2', 'VARCHAR(255) NULL');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'latitude', 'DECIMAL(10,7) NULL');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'longitude', 'DECIMAL(10,7) NULL');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'created_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'created_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'updated_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'updated_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'deleted', 'TINYINT(1) NOT NULL DEFAULT 0');
|
||
CALL add_column_if_missing('wh_warehouse_address', 'version', 'INT NOT NULL DEFAULT 0');
|
||
|
||
CALL add_column_if_missing('wh_service_capability', 'tenant_id', 'BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER id');
|
||
CALL add_column_if_missing('wh_service_capability', 'warehouse_id', 'BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER tenant_id');
|
||
CALL add_column_if_missing('wh_service_capability', 'capability_code', 'VARCHAR(50) NOT NULL DEFAULT '''' AFTER warehouse_id');
|
||
CALL add_column_if_missing('wh_service_capability', 'capability_name', 'VARCHAR(100) NOT NULL DEFAULT '''' AFTER capability_code');
|
||
CALL add_column_if_missing('wh_service_capability', 'enabled', 'TINYINT(1) NOT NULL DEFAULT 1');
|
||
CALL add_column_if_missing('wh_service_capability', 'cutoff_time', 'TIME NULL');
|
||
CALL add_column_if_missing('wh_service_capability', 'description', 'VARCHAR(500) NULL');
|
||
CALL add_column_if_missing('wh_service_capability', 'created_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_service_capability', 'created_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_service_capability', 'updated_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_service_capability', 'updated_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_service_capability', 'deleted', 'TINYINT(1) NOT NULL DEFAULT 0');
|
||
CALL add_column_if_missing('wh_service_capability', 'version', 'INT NOT NULL DEFAULT 0');
|
||
|
||
CALL add_column_if_missing('wh_partner', 'tenant_id', 'BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER id');
|
||
CALL add_column_if_missing('wh_partner', 'partner_code', 'VARCHAR(50) NOT NULL DEFAULT '''' AFTER tenant_id');
|
||
CALL add_column_if_missing('wh_partner', 'partner_name', 'VARCHAR(128) NOT NULL DEFAULT '''' AFTER partner_code');
|
||
CALL add_column_if_missing('wh_partner', 'partner_type', 'VARCHAR(20) NOT NULL DEFAULT ''CUSTOMER'' AFTER partner_name');
|
||
CALL add_column_if_missing('wh_partner', 'contact_name', 'VARCHAR(64) NOT NULL DEFAULT '''' AFTER partner_type');
|
||
CALL add_column_if_missing('wh_partner', 'contact_phone', 'VARCHAR(32) NOT NULL DEFAULT '''' AFTER contact_name');
|
||
CALL add_column_if_missing('wh_partner', 'contact_email', 'VARCHAR(128) NULL');
|
||
CALL add_column_if_missing('wh_partner', 'country_code', 'CHAR(2) NOT NULL DEFAULT ''CN'' AFTER contact_email');
|
||
CALL add_column_if_missing('wh_partner', 'province', 'VARCHAR(64) NULL');
|
||
CALL add_column_if_missing('wh_partner', 'city', 'VARCHAR(64) NOT NULL DEFAULT '''' AFTER province');
|
||
CALL add_column_if_missing('wh_partner', 'district', 'VARCHAR(64) NULL');
|
||
CALL add_column_if_missing('wh_partner', 'address_line', 'VARCHAR(255) NOT NULL DEFAULT '''' AFTER district');
|
||
CALL add_column_if_missing('wh_partner', 'postal_code', 'VARCHAR(20) NULL');
|
||
CALL add_column_if_missing('wh_partner', 'status', 'VARCHAR(20) NOT NULL DEFAULT ''ACTIVE'' AFTER postal_code');
|
||
CALL add_column_if_missing('wh_partner', 'created_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_partner', 'created_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_partner', 'updated_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_partner', 'updated_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_partner', 'deleted', 'TINYINT(1) NOT NULL DEFAULT 0');
|
||
CALL add_column_if_missing('wh_partner', 'version', 'INT NOT NULL DEFAULT 0');
|
||
|
||
-- 该表在旧库中不存在时先由 warehouse-express-company.sql 建表;此段补齐早期部署缺列。
|
||
CALL add_column_if_missing('wh_express_company', 'tenant_id', 'BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER id');
|
||
CALL add_column_if_missing('wh_express_company', 'company_code', 'VARCHAR(50) NOT NULL DEFAULT '''' AFTER tenant_id');
|
||
CALL add_column_if_missing('wh_express_company', 'company_name', 'VARCHAR(128) NOT NULL DEFAULT '''' AFTER company_code');
|
||
CALL add_column_if_missing('wh_express_company', 'service_phone', 'VARCHAR(32) NULL');
|
||
CALL add_column_if_missing('wh_express_company', 'website', 'VARCHAR(255) NULL');
|
||
CALL add_column_if_missing('wh_express_company', 'tracking_url_template', 'VARCHAR(500) NULL');
|
||
CALL add_column_if_missing('wh_express_company', 'status', 'VARCHAR(20) NOT NULL DEFAULT ''ACTIVE'' AFTER tracking_url_template');
|
||
CALL add_column_if_missing('wh_express_company', 'remark', 'VARCHAR(500) NULL');
|
||
CALL add_column_if_missing('wh_express_company', 'created_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_express_company', 'created_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_express_company', 'updated_by', 'BIGINT UNSIGNED NULL');
|
||
CALL add_column_if_missing('wh_express_company', 'updated_at', 'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)');
|
||
CALL add_column_if_missing('wh_express_company', 'deleted', 'TINYINT(1) NOT NULL DEFAULT 0');
|
||
CALL add_column_if_missing('wh_express_company', 'version', 'INT NOT NULL DEFAULT 0');
|
||
|
||
DROP PROCEDURE IF EXISTS add_column_if_missing;
|
||
|
||
-- MySQL 8 的 ALTER ADD INDEX 不在所有小版本都支持 IF NOT EXISTS,使用元数据判断以保证重复执行安全。
|
||
SET @schema_name = DATABASE();
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_warehouse' AND index_name = 'idx_wh_tenant_status') = 0,
|
||
'ALTER TABLE wh_warehouse ADD KEY idx_wh_tenant_status (tenant_id, status, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_warehouse' AND index_name = 'idx_wh_tenant_type_status') = 0,
|
||
'ALTER TABLE wh_warehouse ADD KEY idx_wh_tenant_type_status (tenant_id, warehouse_type, status, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_warehouse_address' AND index_name = 'idx_address_warehouse') = 0,
|
||
'ALTER TABLE wh_warehouse_address ADD KEY idx_address_warehouse (tenant_id, warehouse_id, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_service_capability' AND index_name = 'idx_capability_query') = 0,
|
||
'ALTER TABLE wh_service_capability ADD KEY idx_capability_query (tenant_id, warehouse_id, enabled, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_partner' AND index_name = 'idx_wh_partner_tenant_status') = 0,
|
||
'ALTER TABLE wh_partner ADD KEY idx_wh_partner_tenant_status (tenant_id, status, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_express_company' AND index_name = 'idx_wh_express_tenant_status') = 0,
|
||
'ALTER TABLE wh_express_company ADD KEY idx_wh_express_tenant_status (tenant_id, status, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_partner' AND index_name = 'uk_wh_partner_tenant_code') = 0,
|
||
'ALTER TABLE wh_partner ADD UNIQUE KEY uk_wh_partner_tenant_code (tenant_id, partner_code, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_express_company' AND index_name = 'uk_wh_express_tenant_code') = 0,
|
||
'ALTER TABLE wh_express_company ADD UNIQUE KEY uk_wh_express_tenant_code (tenant_id, company_code, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_express_company' AND index_name = 'uk_wh_express_tenant_name') = 0,
|
||
'ALTER TABLE wh_express_company ADD UNIQUE KEY uk_wh_express_tenant_name (tenant_id, company_name, deleted)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\phase1-firstleg-task-list-index.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_firstleg;
|
||
|
||
-- 既有履约任务表补充分页查询索引;重复执行时不重复创建。
|
||
SET @firstleg_task_list_index_sql = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'fl_fulfillment_task'
|
||
AND index_name = 'idx_task_tenant_created'),
|
||
'SELECT 1',
|
||
'CREATE INDEX idx_task_tenant_created ON fl_fulfillment_task (tenant_id, created_at)'
|
||
);
|
||
PREPARE firstleg_task_list_index_stmt FROM @firstleg_task_list_index_sql;
|
||
EXECUTE firstleg_task_list_index_stmt;
|
||
DEALLOCATE PREPARE firstleg_task_list_index_stmt;
|
||
|
||
-- ============================================================================
|
||
-- 来源:warehouse\src\main\resources\db\phase2-pallet-location-schema.sql
|
||
-- ============================================================================
|
||
-- 二期托盘、库位、预占与占用表结构。
|
||
-- 本脚本只新增表、字段、索引和约束,不包含业务数据及流程实现。
|
||
-- 可在 warehouse.sql 和一期增量脚本之后执行;所有建表均可重复执行。
|
||
SET NAMES utf8mb4;
|
||
|
||
CREATE DATABASE IF NOT EXISTS baiyue_warehouse
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_warehouse;
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_pallet (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '托盘ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
|
||
pallet_code VARCHAR(50) NOT NULL COMMENT '租户仓库内唯一托盘编码',
|
||
pallet_type VARCHAR(32) NOT NULL COMMENT '托盘类型',
|
||
pallet_name VARCHAR(100) NULL COMMENT '托盘名称',
|
||
capacity_cbm DECIMAL(18,6) NOT NULL COMMENT '托盘可用容积CBM',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'AVAILABLE' COMMENT '内部状态:AVAILABLE、RESERVED或OCCUPIED',
|
||
remark VARCHAR(500) NULL COMMENT '备注',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_pallet_tenant_warehouse_code (tenant_id, warehouse_id, pallet_code),
|
||
KEY idx_pallet_available (tenant_id, warehouse_id, status, deleted),
|
||
KEY idx_pallet_type (tenant_id, warehouse_id, pallet_type, status, deleted),
|
||
CONSTRAINT fk_pallet_warehouse FOREIGN KEY (warehouse_id) REFERENCES wh_warehouse (id),
|
||
CONSTRAINT ck_pallet_capacity CHECK (capacity_cbm > 0)
|
||
) ENGINE=InnoDB COMMENT='二期托盘基础资料和物理托盘实例';
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_location (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
|
||
zone_code VARCHAR(50) NULL COMMENT '库区编码',
|
||
zone_name VARCHAR(100) NULL COMMENT '库区名称',
|
||
location_code VARCHAR(50) NOT NULL COMMENT '租户仓库内唯一库位编码',
|
||
location_name VARCHAR(100) NULL COMMENT '库位名称',
|
||
location_type VARCHAR(32) NOT NULL DEFAULT 'PALLET' COMMENT '库位类型,二期为PALLET',
|
||
max_weight_kg DECIMAL(18,3) NULL COMMENT '最大承重展示值,二期不作容量拦截',
|
||
shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否为系统共享溢出位A0',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'AVAILABLE' COMMENT 'AVAILABLE、RESERVED、OCCUPIED或DISABLED',
|
||
remark VARCHAR(500) NULL COMMENT '备注',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_location_tenant_warehouse_code (tenant_id, warehouse_id, location_code),
|
||
KEY idx_location_available (tenant_id, warehouse_id, status, deleted),
|
||
KEY idx_location_zone (tenant_id, warehouse_id, zone_code, status, deleted),
|
||
CONSTRAINT fk_location_warehouse FOREIGN KEY (warehouse_id) REFERENCES wh_warehouse (id),
|
||
CONSTRAINT ck_location_max_weight CHECK (max_weight_kg IS NULL OR max_weight_kg > 0)
|
||
) ENGINE=InnoDB COMMENT='二期库位基础资料,默认一托盘对应一个库位且不作容量校验';
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_location_reservation (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '库位预占ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
reservation_no VARCHAR(40) NOT NULL COMMENT '租户内唯一预占业务号',
|
||
idempotency_key VARCHAR(128) NOT NULL COMMENT '调用方幂等键',
|
||
source_service VARCHAR(40) NOT NULL DEFAULT 'FIRSTLEG' COMMENT '来源服务',
|
||
business_id BIGINT UNSIGNED NOT NULL COMMENT '来源服务入库单ID',
|
||
inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '仓库ID',
|
||
pallet_id BIGINT UNSIGNED NOT NULL COMMENT '托盘ID',
|
||
pallet_code VARCHAR(50) NOT NULL COMMENT '托盘编码快照',
|
||
location_id BIGINT UNSIGNED NOT NULL COMMENT '库位ID',
|
||
location_code VARCHAR(50) NOT NULL COMMENT '库位编码快照',
|
||
shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否使用共享溢出位A0',
|
||
reservation_status VARCHAR(20) NOT NULL DEFAULT 'RESERVED' COMMENT 'RESERVED、CONFIRMED、RELEASED或EXPIRED',
|
||
expires_at DATETIME(3) NOT NULL COMMENT '预占过期时间',
|
||
confirmed_at DATETIME(3) NULL COMMENT '确认占用时间',
|
||
released_at DATETIME(3) NULL COMMENT '释放时间',
|
||
release_reason VARCHAR(500) NULL COMMENT '释放或过期原因',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人或系统主体ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
active_reservation TINYINT GENERATED ALWAYS AS (CASE WHEN reservation_status = 'RESERVED' AND shared_overflow = 0 THEN 1 ELSE NULL END) STORED COMMENT '普通库位活动预占唯一标记',
|
||
active_pallet_reservation TINYINT GENERATED ALWAYS AS (CASE WHEN reservation_status = 'RESERVED' THEN 1 ELSE NULL END) STORED COMMENT '托盘活动预占唯一标记(包含A0)',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_location_reservation_no (tenant_id, reservation_no),
|
||
UNIQUE KEY uk_location_reservation_idempotency (tenant_id, source_service, idempotency_key),
|
||
UNIQUE KEY uk_location_active_reservation (tenant_id, location_id, active_reservation),
|
||
UNIQUE KEY uk_pallet_active_reservation (tenant_id, pallet_id, active_pallet_reservation),
|
||
KEY idx_location_reservation_business (tenant_id, source_service, business_id, reservation_status),
|
||
KEY idx_location_reservation_expire (reservation_status, expires_at),
|
||
KEY idx_location_reservation_target (tenant_id, warehouse_id, location_id, reservation_status),
|
||
CONSTRAINT fk_reservation_warehouse FOREIGN KEY (warehouse_id) REFERENCES wh_warehouse (id),
|
||
CONSTRAINT fk_reservation_pallet FOREIGN KEY (pallet_id) REFERENCES wh_pallet (id),
|
||
CONSTRAINT fk_reservation_location FOREIGN KEY (location_id) REFERENCES wh_location (id)
|
||
) ENGINE=InnoDB COMMENT='跨服务入库Saga的托盘和库位临时预占';
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_location_occupancy (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '库位占用ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
occupancy_no VARCHAR(40) NOT NULL COMMENT '租户内唯一占用业务号',
|
||
reservation_id BIGINT UNSIGNED NOT NULL COMMENT '来源预占ID',
|
||
source_service VARCHAR(40) NOT NULL DEFAULT 'FIRSTLEG' COMMENT '来源服务',
|
||
business_id BIGINT UNSIGNED NOT NULL COMMENT '来源服务入库单ID',
|
||
inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '仓库ID',
|
||
pallet_id BIGINT UNSIGNED NOT NULL COMMENT '托盘ID',
|
||
pallet_code VARCHAR(50) NOT NULL COMMENT '托盘编码快照',
|
||
location_id BIGINT UNSIGNED NOT NULL COMMENT '库位ID',
|
||
location_code VARCHAR(50) NOT NULL COMMENT '库位编码快照',
|
||
shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否使用共享溢出位A0',
|
||
allocated_volume_cbm DECIMAL(18,6) NOT NULL COMMENT '本托盘分配体积CBM',
|
||
allocated_package_count INT UNSIGNED NULL COMMENT '本托盘分配箱数',
|
||
occupancy_status VARCHAR(20) NOT NULL DEFAULT 'OCCUPIED' COMMENT 'OCCUPIED或RELEASED',
|
||
occupied_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '占用开始时间',
|
||
released_at DATETIME(3) NULL COMMENT '释放时间',
|
||
release_reason VARCHAR(500) NULL COMMENT '释放原因',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人或系统主体ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
active_location_occupancy TINYINT GENERATED ALWAYS AS (CASE WHEN occupancy_status = 'OCCUPIED' AND shared_overflow = 0 THEN 1 ELSE NULL END) STORED COMMENT '普通库位活动占用唯一标记',
|
||
active_pallet_occupancy TINYINT GENERATED ALWAYS AS (CASE WHEN occupancy_status = 'OCCUPIED' THEN 1 ELSE NULL END) STORED COMMENT '托盘活动占用唯一标记(包含A0)',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_location_occupancy_no (tenant_id, occupancy_no),
|
||
UNIQUE KEY uk_occupancy_reservation (tenant_id, reservation_id),
|
||
UNIQUE KEY uk_location_active_occupancy (tenant_id, location_id, active_location_occupancy),
|
||
UNIQUE KEY uk_pallet_active_occupancy (tenant_id, pallet_id, active_pallet_occupancy),
|
||
KEY idx_occupancy_business (tenant_id, source_service, business_id, occupancy_status),
|
||
KEY idx_occupancy_warehouse (tenant_id, warehouse_id, occupancy_status, occupied_at),
|
||
CONSTRAINT fk_occupancy_reservation FOREIGN KEY (reservation_id) REFERENCES wh_location_reservation (id),
|
||
CONSTRAINT fk_occupancy_warehouse FOREIGN KEY (warehouse_id) REFERENCES wh_warehouse (id),
|
||
CONSTRAINT fk_occupancy_pallet FOREIGN KEY (pallet_id) REFERENCES wh_pallet (id),
|
||
CONSTRAINT fk_occupancy_location FOREIGN KEY (location_id) REFERENCES wh_location (id),
|
||
CONSTRAINT ck_occupancy_volume CHECK (allocated_volume_cbm > 0)
|
||
) ENGINE=InnoDB COMMENT='已确认的一托一库位占用事实记录';
|
||
|
||
-- 头程入库单属于其他数据库,不建立跨库外键。
|
||
|
||
-- ============================================================================
|
||
-- 来源:warehouse\src\main\resources\db\phase2-location-overflow-migration.sql
|
||
-- ============================================================================
|
||
-- 二期库位共享溢出位 A0 增量迁移。
|
||
-- 执行顺序:phase2-pallet-location-schema.sql、本文件。
|
||
-- 普通库位仍保持一托一位;同一租户仓库只有一个 A0,且 A0 可承载多个活动资源。
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_warehouse;
|
||
|
||
DROP PROCEDURE IF EXISTS add_location_overflow_column_if_missing;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE add_location_overflow_column_if_missing(
|
||
IN p_table_name VARCHAR(64),
|
||
IN p_column_name VARCHAR(64),
|
||
IN p_column_definition TEXT
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE()
|
||
AND table_name = p_table_name
|
||
AND column_name = p_column_name
|
||
) THEN
|
||
SET @column_sql = CONCAT(
|
||
'ALTER TABLE `', REPLACE(p_table_name, '`', '``'),
|
||
'` ADD COLUMN `', REPLACE(p_column_name, '`', '``'), '` ', p_column_definition
|
||
);
|
||
PREPARE column_statement FROM @column_sql;
|
||
EXECUTE column_statement;
|
||
DEALLOCATE PREPARE column_statement;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL add_location_overflow_column_if_missing(
|
||
'wh_location', 'shared_overflow',
|
||
'TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否为系统共享溢出位 A0'' AFTER max_weight_kg'
|
||
);
|
||
CALL add_location_overflow_column_if_missing(
|
||
'wh_location_reservation', 'shared_overflow',
|
||
'TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否使用共享溢出位 A0'' AFTER location_code'
|
||
);
|
||
CALL add_location_overflow_column_if_missing(
|
||
'wh_location_occupancy', 'shared_overflow',
|
||
'TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否使用共享溢出位 A0'' AFTER location_code'
|
||
);
|
||
|
||
-- 兼容迁移前人工或旧流程已创建的 A0,并将资源快照回填一致。
|
||
UPDATE wh_location
|
||
SET shared_overflow = 1,
|
||
status = 'AVAILABLE'
|
||
WHERE location_code = 'A0' AND deleted = 0;
|
||
|
||
UPDATE wh_location_reservation r
|
||
JOIN wh_location l
|
||
ON l.tenant_id = r.tenant_id AND l.id = r.location_id
|
||
SET r.shared_overflow = l.shared_overflow;
|
||
|
||
UPDATE wh_location_occupancy o
|
||
JOIN wh_location l
|
||
ON l.tenant_id = o.tenant_id AND l.id = o.location_id
|
||
SET o.shared_overflow = l.shared_overflow;
|
||
|
||
DROP PROCEDURE IF EXISTS add_location_overflow_column_if_missing;
|
||
|
||
-- 仅旧生成列需要移除并重建唯一索引;已经是最终定义时必须跳过,避免重复部署产生约束空窗。
|
||
SET @schema_name = DATABASE();
|
||
SET @reservation_needs_upgrade = IFNULL((
|
||
SELECT IF(LOCATE('shared_overflow', generation_expression) = 0, 1, 0)
|
||
FROM information_schema.columns
|
||
WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation'
|
||
AND column_name = 'active_reservation'
|
||
), 1);
|
||
SET @sql = IF(@reservation_needs_upgrade = 1 AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND index_name = 'uk_location_active_reservation') > 0,
|
||
'ALTER TABLE wh_location_reservation DROP INDEX uk_location_active_reservation', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF(@reservation_needs_upgrade = 1 AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND index_name = 'uk_pallet_active_reservation') > 0,
|
||
'ALTER TABLE wh_location_reservation DROP INDEX uk_pallet_active_reservation', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
SET @sql = IF(@reservation_needs_upgrade = 1,
|
||
'ALTER TABLE wh_location_reservation MODIFY COLUMN active_reservation TINYINT GENERATED ALWAYS AS (CASE WHEN reservation_status = ''RESERVED'' AND shared_overflow = 0 THEN 1 ELSE NULL END) STORED COMMENT ''普通库位活动预占唯一标记,A0 返回 NULL''',
|
||
'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND index_name = 'uk_location_active_reservation') = 0,
|
||
'ALTER TABLE wh_location_reservation ADD UNIQUE KEY uk_location_active_reservation (tenant_id, location_id, active_reservation)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
SET @occupancy_needs_upgrade = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy'
|
||
AND column_name = 'active_location_occupancy'
|
||
AND LOCATE('shared_overflow', generation_expression) > 0)
|
||
AND EXISTS(SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy'
|
||
AND column_name = 'active_pallet_occupancy'),
|
||
0, 1);
|
||
SET @sql = IF(@occupancy_needs_upgrade = 1 AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_location_active_occupancy') > 0,
|
||
'ALTER TABLE wh_location_occupancy DROP INDEX uk_location_active_occupancy', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF(@occupancy_needs_upgrade = 1 AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_pallet_active_occupancy') > 0,
|
||
'ALTER TABLE wh_location_occupancy DROP INDEX uk_pallet_active_occupancy', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
DROP PROCEDURE IF EXISTS add_location_overflow_column_if_missing;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE add_location_overflow_column_if_missing(
|
||
IN p_table_name VARCHAR(64),
|
||
IN p_column_name VARCHAR(64),
|
||
IN p_column_definition TEXT
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE()
|
||
AND table_name = p_table_name
|
||
AND column_name = p_column_name
|
||
) THEN
|
||
SET @column_sql = CONCAT(
|
||
'ALTER TABLE `', REPLACE(p_table_name, '`', '``'),
|
||
'` ADD COLUMN `', REPLACE(p_column_name, '`', '``'), '` ', p_column_definition
|
||
);
|
||
PREPARE column_statement FROM @column_sql;
|
||
EXECUTE column_statement;
|
||
DEALLOCATE PREPARE column_statement;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL add_location_overflow_column_if_missing(
|
||
'wh_location_reservation', 'active_pallet_reservation',
|
||
'TINYINT GENERATED ALWAYS AS (CASE WHEN reservation_status = ''RESERVED'' THEN 1 ELSE NULL END) STORED COMMENT ''托盘活动预占唯一标记(包含 A0)'''
|
||
);
|
||
CALL add_location_overflow_column_if_missing(
|
||
'wh_location_occupancy', 'active_location_occupancy',
|
||
'TINYINT GENERATED ALWAYS AS (CASE WHEN occupancy_status = ''OCCUPIED'' AND shared_overflow = 0 THEN 1 ELSE NULL END) STORED COMMENT ''普通库位活动占用唯一标记'''
|
||
);
|
||
CALL add_location_overflow_column_if_missing(
|
||
'wh_location_occupancy', 'active_pallet_occupancy',
|
||
'TINYINT GENERATED ALWAYS AS (CASE WHEN occupancy_status = ''OCCUPIED'' THEN 1 ELSE NULL END) STORED COMMENT ''托盘活动占用唯一标记(包含 A0)'''
|
||
);
|
||
DROP PROCEDURE IF EXISTS add_location_overflow_column_if_missing;
|
||
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND index_name = 'uk_pallet_active_reservation') = 0,
|
||
'ALTER TABLE wh_location_reservation ADD UNIQUE KEY uk_pallet_active_reservation (tenant_id, pallet_id, active_pallet_reservation)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_location_active_occupancy') = 0,
|
||
'ALTER TABLE wh_location_occupancy ADD UNIQUE KEY uk_location_active_occupancy (tenant_id, location_id, active_location_occupancy)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_pallet_active_occupancy') = 0,
|
||
'ALTER TABLE wh_location_occupancy ADD UNIQUE KEY uk_pallet_active_occupancy (tenant_id, pallet_id, active_pallet_occupancy)', 'SELECT 1');
|
||
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
-- ============================================================================
|
||
-- 来源:order\src\main\resources\db\phase2-order-carrier-migration.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_order;
|
||
|
||
SET @carrier_id_exists := (
|
||
SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'ord_order' AND column_name = 'carrier_id'
|
||
);
|
||
SET @carrier_id_sql := IF(@carrier_id_exists = 0,
|
||
'ALTER TABLE ord_order ADD COLUMN carrier_id BIGINT UNSIGNED NULL COMMENT ''船司逻辑ID快照'' AFTER channel_name',
|
||
'SELECT 1');
|
||
PREPARE carrier_id_statement FROM @carrier_id_sql;
|
||
EXECUTE carrier_id_statement;
|
||
DEALLOCATE PREPARE carrier_id_statement;
|
||
|
||
SET @carrier_name_exists := (
|
||
SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'ord_order' AND column_name = 'carrier_name'
|
||
);
|
||
SET @carrier_name_sql := IF(@carrier_name_exists = 0,
|
||
'ALTER TABLE ord_order ADD COLUMN carrier_name VARCHAR(128) NULL COMMENT ''船司名称快照'' AFTER carrier_id',
|
||
'SELECT 1');
|
||
PREPARE carrier_name_statement FROM @carrier_name_sql;
|
||
EXECUTE carrier_name_statement;
|
||
DEALLOCATE PREPARE carrier_name_statement;
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\phase2-inbound-schema.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
|
||
CREATE DATABASE IF NOT EXISTS baiyue_firstleg
|
||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||
USE baiyue_firstleg;
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_order (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
task_id BIGINT UNSIGNED NULL COMMENT '头程履约任务ID',
|
||
order_id BIGINT UNSIGNED NOT NULL COMMENT '订单服务订单ID,不建立跨库外键',
|
||
order_no VARCHAR(32) NOT NULL COMMENT '订单号快照',
|
||
inbound_code VARCHAR(40) NOT NULL COMMENT '租户内唯一入仓码',
|
||
process_status VARCHAR(24) NOT NULL DEFAULT 'WAIT_MEASURE' COMMENT '入库流程状态',
|
||
order_status_snapshot VARCHAR(24) NOT NULL COMMENT '订单状态快照',
|
||
measure_review_status VARCHAR(24) NOT NULL DEFAULT 'NOT_SUBMITTED' COMMENT '测量数据审核状态',
|
||
fee_status VARCHAR(24) NOT NULL DEFAULT 'UNPRICED' COMMENT '费用业务状态',
|
||
fee_review_status VARCHAR(24) NOT NULL DEFAULT 'NOT_SUBMITTED' COMMENT '费用审核状态',
|
||
notification_status VARCHAR(24) NOT NULL DEFAULT 'NOT_CREATED' COMMENT '客户通知状态',
|
||
expected_arrival_at DATETIME(3) NULL COMMENT '预计到达时间',
|
||
customer_id BIGINT UNSIGNED NULL COMMENT '客户逻辑ID',
|
||
customer_name VARCHAR(128) NOT NULL COMMENT '客户名称快照',
|
||
company_id BIGINT UNSIGNED NULL COMMENT '运营公司逻辑ID',
|
||
company_name VARCHAR(128) NULL COMMENT '运营公司名称快照',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '实际作业仓库ID',
|
||
warehouse_name VARCHAR(128) NOT NULL COMMENT '实际作业仓库名称快照',
|
||
delivery_warehouse_id BIGINT UNSIGNED NULL COMMENT '交货仓逻辑ID',
|
||
delivery_warehouse_name VARCHAR(128) NULL COMMENT '交货仓名称快照',
|
||
business_type VARCHAR(32) NOT NULL COMMENT '业务类型',
|
||
channel_code VARCHAR(64) NULL COMMENT '渠道编码',
|
||
channel_name VARCHAR(128) NULL COMMENT '渠道名称快照',
|
||
carrier_id BIGINT UNSIGNED NULL COMMENT '计费船司逻辑ID',
|
||
carrier_name VARCHAR(128) NULL COMMENT '计费船司名称快照',
|
||
tax_mode VARCHAR(24) NULL COMMENT '买单或退税模式',
|
||
container_mode VARCHAR(24) NULL COMMENT '整柜或散货模式',
|
||
customs_inspection TINYINT(1) NULL COMMENT '是否商检',
|
||
destination_type VARCHAR(24) NULL COMMENT '目的仓类型',
|
||
destination_warehouse_id BIGINT UNSIGNED NULL COMMENT '目的仓逻辑ID',
|
||
destination_code VARCHAR(32) NULL COMMENT '目的仓编码,例如FBA仓编码',
|
||
destination_name VARCHAR(128) NULL COMMENT '目的仓名称快照',
|
||
hold_flag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '当前是否扣货',
|
||
current_hold_reason VARCHAR(500) NULL COMMENT '当前扣货理由快照',
|
||
total_package_count INT UNSIGNED NULL COMMENT '确认后的总箱数',
|
||
actual_gross_weight_kg DECIMAL(18,3) NULL COMMENT '确认后的实际总毛重kg',
|
||
chargeable_weight_kg DECIMAL(18,3) NULL COMMENT '当前费用快照的计费重量kg',
|
||
actual_volume_cbm DECIMAL(18,4) NULL COMMENT '确认后的实际总体积m3',
|
||
chargeable_volume_cbm DECIMAL(18,4) NULL COMMENT '当前费用快照的计费体积m3',
|
||
pallet_count INT UNSIGNED NULL COMMENT '已分配总托盘数快照',
|
||
volume_weight_kg DECIMAL(18,3) NULL COMMENT '总材积重kg',
|
||
actual_net_weight_kg DECIMAL(18,3) NULL COMMENT '总净重kg',
|
||
measure_completed_at DATETIME(3) NULL COMMENT '测量完成时间',
|
||
inbounded_at DATETIME(3) NULL COMMENT '入库完成时间',
|
||
express_company_code VARCHAR(64) NULL COMMENT '快递公司编码快照',
|
||
express_company_name VARCHAR(128) NULL COMMENT '快递公司名称快照',
|
||
express_tracking_no VARCHAR(128) NULL COMMENT '快递单号快照',
|
||
public_remark VARCHAR(1000) NULL COMMENT '客户可见备注',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_inbound_tenant_code (tenant_id, inbound_code),
|
||
UNIQUE KEY uk_inbound_tenant_order (tenant_id, order_id),
|
||
KEY idx_inbound_process_time (tenant_id, process_status, created_at, id),
|
||
KEY idx_inbound_measure_time (tenant_id, measure_review_status, created_at, id),
|
||
KEY idx_inbound_fee_time (tenant_id, fee_review_status, created_at, id),
|
||
KEY idx_inbound_warehouse_status (tenant_id, warehouse_id, process_status, created_at),
|
||
KEY idx_inbound_customer_time (tenant_id, customer_id, created_at),
|
||
KEY idx_inbound_company_time (tenant_id, company_id, created_at),
|
||
KEY idx_inbound_arrival (tenant_id, expected_arrival_at),
|
||
KEY idx_inbound_destination (tenant_id, destination_code, created_at),
|
||
KEY idx_inbound_channel (tenant_id, channel_code, created_at),
|
||
CONSTRAINT fk_inbound_task FOREIGN KEY (task_id) REFERENCES fl_fulfillment_task (id)
|
||
) ENGINE=InnoDB COMMENT='二期头程入库单聚合根和列表查询快照';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_pickup_snapshot (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '提货信息快照ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
pickup_method VARCHAR(24) NULL COMMENT '提货方式',
|
||
pickup_at DATETIME(3) NULL COMMENT '提货时间',
|
||
contact_name VARCHAR(64) NULL COMMENT '提货联系人',
|
||
contact_phone VARCHAR(32) NULL COMMENT '提货联系人电话',
|
||
contact_email VARCHAR(128) NULL COMMENT '提货联系人邮箱',
|
||
country_code CHAR(2) NULL COMMENT '国家二字码',
|
||
province VARCHAR(64) NULL COMMENT '省或州',
|
||
city VARCHAR(64) NULL COMMENT '城市',
|
||
district VARCHAR(64) NULL COMMENT '区县',
|
||
address_line VARCHAR(512) NULL COMMENT '提货详细地址',
|
||
postal_code VARCHAR(20) NULL COMMENT '提货邮编',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_pickup_inbound (tenant_id, inbound_id),
|
||
CONSTRAINT fk_pickup_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='入库单提货信息不可变快照';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_destination_snapshot (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '目的仓地址快照ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
destination_type VARCHAR(24) NULL COMMENT '目的仓类型',
|
||
destination_code VARCHAR(32) NULL COMMENT '目的仓编码',
|
||
destination_name VARCHAR(128) NULL COMMENT '目的仓名称',
|
||
country_code CHAR(2) NULL COMMENT '国家二字码',
|
||
state_province VARCHAR(100) NULL COMMENT '省或州',
|
||
city VARCHAR(100) NULL COMMENT '城市',
|
||
address_line VARCHAR(512) NULL COMMENT '详细地址',
|
||
postal_code VARCHAR(20) NULL COMMENT '邮编',
|
||
contact_name VARCHAR(64) NULL COMMENT '联系人',
|
||
contact_phone VARCHAR(32) NULL COMMENT '联系人电话',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_destination_inbound (tenant_id, inbound_id),
|
||
CONSTRAINT fk_destination_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='入库单目的仓地址和联系人快照';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_transport_snapshot (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '运输信息快照ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
loading_status VARCHAR(24) NULL COMMENT '配载状态快照',
|
||
container_no VARCHAR(64) NULL COMMENT '集装箱号',
|
||
cabinet_no VARCHAR(64) NULL COMMENT '柜号或内部柜单号',
|
||
vessel_name VARCHAR(128) NULL COMMENT '船名',
|
||
voyage_no VARCHAR(64) NULL COMMENT '航次',
|
||
sailing_at DATETIME(3) NULL COMMENT '开船时间',
|
||
port_arrival_at DATETIME(3) NULL COMMENT '到港时间',
|
||
source_updated_at DATETIME(3) NULL COMMENT '上游数据更新时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_transport_inbound (tenant_id, inbound_id),
|
||
KEY idx_transport_container (tenant_id, container_no),
|
||
KEY idx_transport_cabinet (tenant_id, cabinet_no),
|
||
KEY idx_transport_loading (tenant_id, loading_status, sailing_at),
|
||
CONSTRAINT fk_transport_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='入库单关联运输信息只读快照';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_measurement (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '测量批次ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
source_type VARCHAR(24) NOT NULL COMMENT '数据来源:THIRD_PARTY或MANUAL',
|
||
source_code VARCHAR(64) NULL COMMENT '第三方应用或来源编码',
|
||
external_event_no VARCHAR(128) NULL COMMENT '第三方事件号',
|
||
external_request_hash CHAR(64) NULL COMMENT '第三方data原文和图片内容联合请求哈希',
|
||
device_code VARCHAR(64) NULL COMMENT '测量设备编码',
|
||
warehouse_code VARCHAR(50) NULL COMMENT '第三方回传仓库编码',
|
||
measured_at DATETIME(3) NULL COMMENT '设备测量时间',
|
||
status VARCHAR(24) NOT NULL DEFAULT 'RECEIVED' COMMENT '测量批次状态',
|
||
raw_payload_json JSON NULL COMMENT '第三方原始报文',
|
||
original_document_no VARCHAR(64) NULL COMMENT '原单据号码快照',
|
||
original_gross_weight_kg DECIMAL(18,3) NULL COMMENT '原单据毛重kg',
|
||
original_volume_cbm DECIMAL(18,4) NULL COMMENT '原单据体积或材积m3',
|
||
actual_goods_name VARCHAR(255) NULL COMMENT '实际品名',
|
||
total_package_count INT UNSIGNED NULL COMMENT '本批次总箱数',
|
||
total_volume_raw_cbm DECIMAL(18,6) NULL COMMENT '本批次原始总体积m3',
|
||
total_volume_cbm DECIMAL(18,4) NULL COMMENT '本批次业务总体积m3',
|
||
volume_weight_kg DECIMAL(18,3) NULL COMMENT '本批次总材积重kg',
|
||
created_by BIGINT UNSIGNED NULL COMMENT '创建人或系统主体ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_measure_external_event (tenant_id, source_code, external_event_no),
|
||
KEY idx_measure_inbound_time (tenant_id, inbound_id, created_at),
|
||
CONSTRAINT fk_measure_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='入库长宽高测量批次和第三方原始数据';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_measurement_item (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '测量明细ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
measurement_id BIGINT UNSIGNED NOT NULL COMMENT '测量批次ID',
|
||
inbound_detail_id BIGINT UNSIGNED NULL COMMENT '绑定的订单货物明细ID,平台手工明细可为空',
|
||
external_detail_no VARCHAR(128) NULL COMMENT '第三方测量明细唯一号,平台手工明细可为空',
|
||
item_no VARCHAR(32) NOT NULL COMMENT '批次内明细号',
|
||
box_specification VARCHAR(64) NOT NULL COMMENT '箱规标识',
|
||
package_count INT UNSIGNED NOT NULL COMMENT '相同箱规箱数',
|
||
length_cm DECIMAL(12,3) NOT NULL COMMENT '原始长度cm',
|
||
width_cm DECIMAL(12,3) NOT NULL COMMENT '原始宽度cm',
|
||
height_cm DECIMAL(12,3) NOT NULL COMMENT '原始高度cm',
|
||
girth_cm DECIMAL(12,3) NOT NULL COMMENT '周长cm,规则为长+2*(宽+高)',
|
||
unit_weight_kg DECIMAL(18,3) NULL COMMENT '单箱重量kg,第三方仅回传尺寸时可为空',
|
||
unit_volume_cbm DECIMAL(18,4) NOT NULL COMMENT '单箱业务体积m3',
|
||
volume_raw_cbm DECIMAL(18,6) NOT NULL COMMENT '原始体积m3',
|
||
volume_cbm DECIMAL(18,4) NOT NULL COMMENT '业务体积m3',
|
||
total_weight_kg DECIMAL(18,3) NULL COMMENT '本箱规总重量kg',
|
||
total_volume_cbm DECIMAL(18,4) NOT NULL COMMENT '本箱规总体积m3',
|
||
volume_weight_kg DECIMAL(18,3) NOT NULL COMMENT '本箱规材积重kg',
|
||
calculation_rule_version VARCHAR(32) NOT NULL COMMENT '体积计算和舍入规则版本',
|
||
source_image_file_id BIGINT UNSIGNED NULL COMMENT '测量设备图片文件ID',
|
||
over_limit_warning VARCHAR(500) NULL COMMENT '超线提醒快照',
|
||
outer_length_cm DECIMAL(12,3) NULL COMMENT '外箱规长度cm',
|
||
outer_width_cm DECIMAL(12,3) NULL COMMENT '外箱规宽度cm',
|
||
outer_height_cm DECIMAL(12,3) NULL COMMENT '外箱规高度cm',
|
||
remark VARCHAR(500) NULL COMMENT '测量明细备注',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_measure_item_no (tenant_id, measurement_id, item_no),
|
||
UNIQUE KEY uk_measure_external_detail (tenant_id, inbound_detail_id, external_detail_no),
|
||
CONSTRAINT fk_measure_item_batch FOREIGN KEY (measurement_id) REFERENCES fl_inbound_measurement (id)
|
||
) ENGINE=InnoDB COMMENT='入库长宽高和箱数测量明细';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_weight_result (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT 'OCR重量结果ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
file_id BIGINT UNSIGNED NOT NULL COMMENT '称重图片文件ID',
|
||
ocr_provider VARCHAR(64) NULL COMMENT 'OCR服务商编码',
|
||
ocr_raw_text VARCHAR(1000) NULL COMMENT 'OCR原始文本',
|
||
ocr_weight_value DECIMAL(18,3) NULL COMMENT 'OCR识别原始重量值',
|
||
ocr_weight_unit VARCHAR(8) NULL COMMENT 'OCR识别原始单位',
|
||
confidence DECIMAL(6,5) NULL COMMENT '识别置信度',
|
||
adjusted_weight_value DECIMAL(18,3) NULL COMMENT '人工修正后的原单位重量',
|
||
adjusted_weight_unit VARCHAR(8) NULL COMMENT '人工修正后的单位',
|
||
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认并统一换算后的重量kg',
|
||
recognition_status VARCHAR(24) NOT NULL DEFAULT 'PENDING' COMMENT '识别和确认状态',
|
||
adjustment_reason VARCHAR(500) NULL COMMENT '人工修正原因',
|
||
adjusted_by BIGINT UNSIGNED NULL COMMENT '修正人ID',
|
||
adjusted_at DATETIME(3) NULL COMMENT '修正时间',
|
||
confirmed_by BIGINT UNSIGNED NULL COMMENT '确认人ID',
|
||
confirmed_at DATETIME(3) NULL COMMENT '确认时间',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_weight_inbound_file (tenant_id, inbound_id, file_id),
|
||
KEY idx_weight_inbound_status (tenant_id, inbound_id, recognition_status),
|
||
CONSTRAINT fk_weight_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='称重图片OCR原值、人工修正值和确认重量';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT 'OCR重量修订记录ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
weight_result_id BIGINT UNSIGNED NOT NULL COMMENT 'OCR重量结果ID',
|
||
revision_no INT UNSIGNED NOT NULL COMMENT '结果版本号,与乐观锁版本一致',
|
||
action VARCHAR(24) NOT NULL COMMENT '动作:CORRECT或CONFIRM',
|
||
before_weight_value DECIMAL(18,3) NULL COMMENT '变更前原单位重量',
|
||
before_weight_unit VARCHAR(8) NULL COMMENT '变更前单位',
|
||
after_weight_value DECIMAL(18,3) NULL COMMENT '变更后原单位重量',
|
||
after_weight_unit VARCHAR(8) NULL COMMENT '变更后单位',
|
||
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的重量kg',
|
||
reason VARCHAR(500) NULL COMMENT '人工修正原因',
|
||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
||
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
||
operated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_weight_revision_no (tenant_id, weight_result_id, revision_no),
|
||
KEY idx_weight_revision_time (tenant_id, inbound_id, operated_at),
|
||
CONSTRAINT fk_weight_revision_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id),
|
||
CONSTRAINT fk_weight_revision_result FOREIGN KEY (weight_result_id) REFERENCES fl_inbound_weight_result (id)
|
||
) ENGINE=InnoDB COMMENT='OCR重量人工修正和确认的不可变版本历史';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_measure_review_record (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '测量审核记录ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
measurement_id BIGINT UNSIGNED NULL COMMENT '被审核的测量批次ID',
|
||
review_result VARCHAR(24) NOT NULL COMMENT '审核结果',
|
||
review_reason VARCHAR(1000) NULL COMMENT '审核或驳回原因',
|
||
exception_release TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否异常放行',
|
||
release_reason VARCHAR(1000) NULL COMMENT '异常放行原因',
|
||
allow_rejected_config TINYINT(1) NOT NULL DEFAULT 0 COMMENT '操作时Nacos异常放行开关值',
|
||
reviewer_id BIGINT UNSIGNED NOT NULL COMMENT '审核人ID',
|
||
reviewer_name VARCHAR(64) NULL COMMENT '审核人名称快照',
|
||
reviewed_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '审核时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_review_inbound_time (tenant_id, inbound_id, reviewed_at),
|
||
KEY idx_review_exception_release (tenant_id, inbound_id, exception_release, reviewed_at),
|
||
CONSTRAINT fk_review_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id),
|
||
CONSTRAINT fk_review_measurement FOREIGN KEY (measurement_id) REFERENCES fl_inbound_measurement (id)
|
||
) ENGINE=InnoDB COMMENT='测量审核、驳回和异常放行不可变记录';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_customer_charge_rule (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '客户计费规则ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
rule_code VARCHAR(50) NOT NULL COMMENT '租户内规则编码',
|
||
rule_version INT UNSIGNED NOT NULL COMMENT '规则版本号',
|
||
customer_id BIGINT UNSIGNED NOT NULL COMMENT '客户逻辑ID',
|
||
customer_name VARCHAR(128) NOT NULL COMMENT '客户名称快照',
|
||
business_type VARCHAR(32) NOT NULL COMMENT '业务类型',
|
||
charge_mode VARCHAR(16) NOT NULL COMMENT '计费口径:KG或CBM',
|
||
tax_mode VARCHAR(24) NULL COMMENT '包税或不包税类型',
|
||
conversion_factor DECIMAL(18,6) NOT NULL COMMENT '重量体积换算系数',
|
||
rounding_scale TINYINT UNSIGNED NOT NULL DEFAULT 3 COMMENT '结果保留小数位数',
|
||
rounding_mode VARCHAR(24) NOT NULL DEFAULT 'CEILING' COMMENT '舍入方式',
|
||
currency CHAR(3) NOT NULL COMMENT '默认币种',
|
||
effective_from DATETIME(3) NOT NULL COMMENT '生效开始时间',
|
||
effective_to DATETIME(3) NULL COMMENT '生效结束时间',
|
||
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '规则状态',
|
||
remark VARCHAR(500) NULL COMMENT '规则备注',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_charge_rule_version (tenant_id, rule_code, rule_version),
|
||
KEY idx_charge_rule_match (tenant_id, customer_id, business_type, status, effective_from, effective_to)
|
||
) ENGINE=InnoDB COMMENT='客户头程计费规则版本';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_carrier_fba_rate (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '船司FBA价格ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
rate_code VARCHAR(50) NOT NULL COMMENT '租户内价格编码',
|
||
rate_version INT UNSIGNED NOT NULL COMMENT '价格版本号',
|
||
origin_warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '起运仓逻辑ID',
|
||
origin_warehouse_name VARCHAR(128) NOT NULL COMMENT '起运仓名称快照',
|
||
business_type VARCHAR(32) NOT NULL COMMENT '业务或计费类型',
|
||
channel_code VARCHAR(64) NULL COMMENT '渠道编码',
|
||
carrier_id BIGINT UNSIGNED NULL COMMENT '船司逻辑ID',
|
||
carrier_name VARCHAR(128) NOT NULL COMMENT '船司名称快照',
|
||
destination_code VARCHAR(32) NOT NULL COMMENT 'FBA目的仓编码',
|
||
charge_unit VARCHAR(16) NOT NULL COMMENT '计费单位:KG或CBM',
|
||
unit_price DECIMAL(18,6) NOT NULL COMMENT '基础单价',
|
||
currency CHAR(3) NOT NULL COMMENT '币种',
|
||
additional_fee DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '固定附加费',
|
||
effective_from DATETIME(3) NOT NULL COMMENT '生效开始时间',
|
||
effective_to DATETIME(3) NULL COMMENT '生效结束时间',
|
||
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '价格状态',
|
||
remark VARCHAR(500) NULL COMMENT '价格备注',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_fba_rate_version (tenant_id, rate_code, rate_version),
|
||
KEY idx_fba_rate_match (tenant_id, origin_warehouse_id, business_type, channel_code, carrier_id, destination_code, charge_unit, status, effective_from, effective_to)
|
||
) ENGINE=InnoDB COMMENT='船司FBA目的仓价格版本';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_fee (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '入库费用ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
fee_no VARCHAR(40) NOT NULL COMMENT '租户内唯一费用单号',
|
||
fee_version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '费用快照版本',
|
||
charge_rule_id BIGINT UNSIGNED NOT NULL COMMENT '客户计费规则ID',
|
||
charge_rule_version INT UNSIGNED NOT NULL COMMENT '客户规则版本快照',
|
||
carrier_rate_id BIGINT UNSIGNED NOT NULL COMMENT '船司FBA价格ID',
|
||
carrier_rate_version INT UNSIGNED NOT NULL COMMENT '船司价格版本快照',
|
||
rule_code VARCHAR(50) NOT NULL COMMENT '客户规则编码快照',
|
||
customer_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID快照',
|
||
customer_name VARCHAR(128) NOT NULL COMMENT '客户名称快照',
|
||
business_type VARCHAR(32) NOT NULL COMMENT '业务类型快照',
|
||
tax_mode VARCHAR(24) NULL COMMENT '包税模式快照',
|
||
rounding_scale TINYINT UNSIGNED NOT NULL COMMENT '计费量保留位数快照',
|
||
rounding_mode VARCHAR(24) NOT NULL COMMENT '舍入方式快照',
|
||
rule_effective_from DATETIME(3) NOT NULL COMMENT '客户规则生效开始快照',
|
||
rule_effective_to DATETIME(3) NULL COMMENT '客户规则生效结束快照',
|
||
rate_code VARCHAR(50) NOT NULL COMMENT '船司价格编码快照',
|
||
origin_warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '起运仓ID快照',
|
||
origin_warehouse_name VARCHAR(128) NOT NULL COMMENT '起运仓名称快照',
|
||
channel_code VARCHAR(64) NOT NULL COMMENT '渠道编码快照',
|
||
carrier_id BIGINT UNSIGNED NOT NULL COMMENT '船司ID快照',
|
||
carrier_name VARCHAR(128) NOT NULL COMMENT '船司名称快照',
|
||
destination_code VARCHAR(32) NOT NULL COMMENT 'FBA仓编码快照',
|
||
rate_effective_from DATETIME(3) NOT NULL COMMENT '价格生效开始快照',
|
||
rate_effective_to DATETIME(3) NULL COMMENT '价格生效结束快照',
|
||
charge_mode VARCHAR(16) NOT NULL COMMENT '计费口径:KG或CBM',
|
||
conversion_factor DECIMAL(18,6) NOT NULL COMMENT '使用的换算系数快照',
|
||
actual_weight_kg DECIMAL(18,3) NOT NULL COMMENT '试算时实际重量kg',
|
||
actual_volume_cbm DECIMAL(18,4) NOT NULL COMMENT '试算时实际体积m3',
|
||
converted_quantity DECIMAL(18,4) NOT NULL COMMENT '换算后的重量或体积',
|
||
chargeable_quantity DECIMAL(18,4) NOT NULL COMMENT '最终计费量',
|
||
charge_unit VARCHAR(16) NOT NULL COMMENT '计费单位',
|
||
currency CHAR(3) NOT NULL COMMENT '币种',
|
||
subtotal_amount DECIMAL(18,2) NOT NULL COMMENT '基础费用金额',
|
||
additional_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '附加费金额',
|
||
total_amount DECIMAL(18,2) NOT NULL COMMENT '总金额',
|
||
fee_status VARCHAR(24) NOT NULL DEFAULT 'CALCULATED' COMMENT '费用状态',
|
||
review_status VARCHAR(24) NOT NULL DEFAULT 'NOT_SUBMITTED' COMMENT '费用审核状态',
|
||
exception_release TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否基于测量异常放行生成',
|
||
calculated_by BIGINT UNSIGNED NOT NULL COMMENT '试算人ID',
|
||
calculated_at DATETIME(3) NOT NULL COMMENT '试算时间',
|
||
confirmed_by BIGINT UNSIGNED NULL COMMENT '确认人ID',
|
||
confirmed_at DATETIME(3) NULL COMMENT '确认时间',
|
||
sent_by BIGINT UNSIGNED NULL COMMENT '发送人ID',
|
||
sent_at DATETIME(3) NULL COMMENT '发送客户时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_inbound_fee_no (tenant_id, fee_no),
|
||
UNIQUE KEY uk_inbound_fee_version (tenant_id, inbound_id, fee_version),
|
||
KEY idx_inbound_fee_status (tenant_id, inbound_id, fee_status, review_status),
|
||
CONSTRAINT fk_fee_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id),
|
||
CONSTRAINT fk_fee_charge_rule FOREIGN KEY (charge_rule_id) REFERENCES fl_customer_charge_rule (id),
|
||
CONSTRAINT fk_fee_carrier_rate FOREIGN KEY (carrier_rate_id) REFERENCES fl_carrier_fba_rate (id)
|
||
) ENGINE=InnoDB COMMENT='入库头程费用计算和确认快照';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_fee_item (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '费用明细ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
fee_id BIGINT UNSIGNED NOT NULL COMMENT '费用头ID',
|
||
item_no INT UNSIGNED NOT NULL COMMENT '费用单内序号',
|
||
fee_code VARCHAR(50) NOT NULL COMMENT '费用项目编码',
|
||
fee_name VARCHAR(128) NOT NULL COMMENT '费用项目名称快照',
|
||
quantity DECIMAL(18,4) NOT NULL COMMENT '计费数量',
|
||
unit VARCHAR(16) NOT NULL COMMENT '计费单位',
|
||
unit_price DECIMAL(18,6) NOT NULL COMMENT '单价',
|
||
amount DECIMAL(18,2) NOT NULL COMMENT '金额',
|
||
currency CHAR(3) NOT NULL COMMENT '币种',
|
||
automatic_flag TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否自动计算',
|
||
remark VARCHAR(500) NULL COMMENT '费用备注',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_fee_item_no (tenant_id, fee_id, item_no),
|
||
CONSTRAINT fk_fee_item_header FOREIGN KEY (fee_id) REFERENCES fl_inbound_fee (id)
|
||
) ENGINE=InnoDB COMMENT='入库头程费用项目明细';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_pallet_allocation (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '头程托盘分配引用ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
allocation_no INT UNSIGNED NOT NULL COMMENT '入库单内分配序号',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '仓库服务仓库ID',
|
||
warehouse_resource_tenant_id BIGINT UNSIGNED NOT NULL COMMENT '仓储资源所属租户ID',
|
||
pallet_id BIGINT UNSIGNED NOT NULL COMMENT '仓库服务托盘ID',
|
||
pallet_code VARCHAR(50) NOT NULL COMMENT '托盘编码快照',
|
||
pallet_capacity_cbm DECIMAL(18,4) NOT NULL COMMENT '托盘可用容积快照',
|
||
allocated_volume_cbm DECIMAL(18,4) NOT NULL COMMENT '本托盘分配体积',
|
||
allocated_package_count INT UNSIGNED NULL COMMENT '本托盘分配箱数',
|
||
location_id BIGINT UNSIGNED NOT NULL COMMENT '仓库服务库位ID',
|
||
location_code VARCHAR(50) NOT NULL COMMENT '库位编码快照',
|
||
reservation_no VARCHAR(64) NOT NULL COMMENT '仓库库位预占单号',
|
||
allocation_status VARCHAR(24) NOT NULL DEFAULT 'RESERVED' COMMENT '分配状态',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_pallet_allocation_no (tenant_id, inbound_id, allocation_no),
|
||
UNIQUE KEY uk_pallet_allocation_pallet (tenant_id, inbound_id, pallet_id),
|
||
KEY idx_allocation_location (tenant_id, warehouse_id, location_id, allocation_status),
|
||
CONSTRAINT fk_allocation_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='头程侧托盘、库位和仓库预占结果引用';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_file (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '入库单文件关系ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
file_id BIGINT UNSIGNED NOT NULL COMMENT '文件服务文件ID',
|
||
file_type VARCHAR(24) NOT NULL COMMENT '文件类型:RELATED、MARK、PC_ORDER、MEASURE或WEIGHT',
|
||
file_name_snapshot VARCHAR(255) NOT NULL COMMENT '文件名快照',
|
||
visibility VARCHAR(16) NOT NULL DEFAULT 'INTERNAL' COMMENT '可见范围',
|
||
file_version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '业务文件版本',
|
||
uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '上传人ID',
|
||
uploaded_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '上传时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_inbound_file_relation (tenant_id, inbound_id, file_id, file_type),
|
||
KEY idx_inbound_file_type (tenant_id, inbound_id, file_type, deleted),
|
||
CONSTRAINT fk_file_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='入库单与文件中心对象的分类关系';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_hold_record (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '扣货记录ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
hold_action VARCHAR(16) NOT NULL COMMENT '动作:HOLD或RELEASE',
|
||
reason VARCHAR(1000) NOT NULL COMMENT '扣货或解除原因',
|
||
evidence_file_id BIGINT UNSIGNED NULL COMMENT '证据文件ID',
|
||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
||
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
||
operated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_hold_inbound_time (tenant_id, inbound_id, operated_at),
|
||
CONSTRAINT fk_hold_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='入库单扣货和解除扣货不可变历史';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_internal_note (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '客服内部备注ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
content VARCHAR(2000) NOT NULL COMMENT '仅内部可见备注',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_internal_note_time (tenant_id, inbound_id, created_at),
|
||
CONSTRAINT fk_internal_note_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='入库单客服内部备注历史';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_status_history (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '入库状态历史ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
from_status VARCHAR(24) NULL COMMENT '变更前状态',
|
||
to_status VARCHAR(24) NOT NULL COMMENT '变更后状态',
|
||
action VARCHAR(32) NOT NULL COMMENT '触发动作',
|
||
reason VARCHAR(1000) NULL COMMENT '变更原因',
|
||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
||
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
||
occurred_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '发生时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_inbound_history_time (tenant_id, inbound_id, occurred_at),
|
||
CONSTRAINT fk_history_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='入库单流程状态不可变历史';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_outbox (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '领域事件全局ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '事件所属租户ID',
|
||
aggregate_type VARCHAR(32) NOT NULL DEFAULT 'INBOUND' COMMENT '聚合类型',
|
||
aggregate_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
|
||
payload_json JSON NOT NULL COMMENT '事件负载快照',
|
||
publish_status VARCHAR(16) NOT NULL DEFAULT 'PENDING' COMMENT '发布状态',
|
||
retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数',
|
||
next_retry_at DATETIME(3) NULL COMMENT '下次重试时间',
|
||
published_at DATETIME(3) NULL COMMENT '发布时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_inbound_outbox_publish (publish_status, next_retry_at, created_at)
|
||
) ENGINE=InnoDB COMMENT='入库事务Outbox事件表';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_idempotency (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '入库写操作幂等记录ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '租户ID',
|
||
operation VARCHAR(40) NOT NULL COMMENT '操作类型',
|
||
operator_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '操作者或外部应用ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '入库单ID,创建前可为0',
|
||
idempotency_key VARCHAR(128) NOT NULL COMMENT '幂等键',
|
||
request_hash CHAR(64) NOT NULL COMMENT '请求内容摘要',
|
||
status VARCHAR(16) NOT NULL COMMENT '处理状态',
|
||
result_json JSON NULL COMMENT '成功结果摘要',
|
||
result_resource_id BIGINT UNSIGNED NULL COMMENT '成功结果资源ID',
|
||
completed_at DATETIME(3) NULL COMMENT '完成时间',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_inbound_idempotency (tenant_id, operation, operator_id, idempotency_key),
|
||
KEY idx_inbound_idempotency_created (created_at)
|
||
) ENGINE=InnoDB COMMENT='第三方测量、审核、费用发送和入库写操作幂等记录';
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\phase2-inbound-measurement-maintenance.sql
|
||
-- ============================================================================
|
||
-- 二期入库测量与 OCR 维护增量(只增不删,可重复执行)。
|
||
-- 执行顺序:phase2-inbound-schema.sql 后执行本文件;已有二期库只需执行本文件。
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_firstleg;
|
||
|
||
DROP PROCEDURE IF EXISTS phase2_measure_add_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE phase2_measure_add_column(
|
||
IN p_table_name VARCHAR(64),
|
||
IN p_column_name VARCHAR(64),
|
||
IN p_column_definition TEXT
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE()
|
||
AND table_name = p_table_name
|
||
AND column_name = p_column_name
|
||
) THEN
|
||
SET @phase2_measure_sql = CONCAT(
|
||
'ALTER TABLE `', REPLACE(p_table_name, '`', '``'),
|
||
'` ADD COLUMN `', REPLACE(p_column_name, '`', '``'), '` ', p_column_definition
|
||
);
|
||
PREPARE phase2_measure_statement FROM @phase2_measure_sql;
|
||
EXECUTE phase2_measure_statement;
|
||
DEALLOCATE PREPARE phase2_measure_statement;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL phase2_measure_add_column('fl_inbound_measurement', 'original_document_no',
|
||
'VARCHAR(64) NULL COMMENT ''原单据号码快照'' AFTER raw_payload_json');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement', 'original_gross_weight_kg',
|
||
'DECIMAL(18,3) NULL COMMENT ''原单据毛重kg'' AFTER original_document_no');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement', 'original_volume_cbm',
|
||
'DECIMAL(18,4) NULL COMMENT ''原单据体积或材积m3'' AFTER original_gross_weight_kg');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement', 'actual_goods_name',
|
||
'VARCHAR(255) NULL COMMENT ''实际品名'' AFTER original_volume_cbm');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement', 'volume_weight_kg',
|
||
'DECIMAL(18,3) NULL COMMENT ''本批次总材积重kg'' AFTER total_volume_cbm');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement', 'version',
|
||
'INT NOT NULL DEFAULT 0 COMMENT ''乐观锁版本号'' AFTER updated_at');
|
||
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'box_specification',
|
||
'VARCHAR(64) NOT NULL DEFAULT '''' COMMENT ''箱规标识'' AFTER item_no');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'girth_cm',
|
||
'DECIMAL(12,3) NOT NULL DEFAULT 0 COMMENT ''周长cm,规则为长+2*(宽+高)'' AFTER height_cm');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'unit_weight_kg',
|
||
'DECIMAL(18,3) NULL COMMENT ''单箱重量kg'' AFTER girth_cm');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'unit_volume_cbm',
|
||
'DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''单箱业务体积m3'' AFTER unit_weight_kg');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'total_weight_kg',
|
||
'DECIMAL(18,3) NULL COMMENT ''本箱规总重量kg'' AFTER volume_cbm');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'total_volume_cbm',
|
||
'DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''本箱规总体积m3'' AFTER total_weight_kg');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'volume_weight_kg',
|
||
'DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT ''本箱规材积重kg'' AFTER total_volume_cbm');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'over_limit_warning',
|
||
'VARCHAR(500) NULL COMMENT ''超线提醒快照'' AFTER source_image_file_id');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'outer_length_cm',
|
||
'DECIMAL(12,3) NULL COMMENT ''外箱规长度cm'' AFTER over_limit_warning');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'outer_width_cm',
|
||
'DECIMAL(12,3) NULL COMMENT ''外箱规宽度cm'' AFTER outer_length_cm');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'outer_height_cm',
|
||
'DECIMAL(12,3) NULL COMMENT ''外箱规高度cm'' AFTER outer_width_cm');
|
||
|
||
DROP PROCEDURE IF EXISTS phase2_measure_add_column;
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT 'OCR重量修订记录ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
weight_result_id BIGINT UNSIGNED NOT NULL COMMENT 'OCR重量结果ID',
|
||
revision_no INT UNSIGNED NOT NULL COMMENT '结果版本号,与乐观锁版本一致',
|
||
action VARCHAR(24) NOT NULL COMMENT '动作:CORRECT或CONFIRM',
|
||
before_weight_value DECIMAL(18,3) NULL COMMENT '变更前原单位重量',
|
||
before_weight_unit VARCHAR(8) NULL COMMENT '变更前单位',
|
||
after_weight_value DECIMAL(18,3) NULL COMMENT '变更后原单位重量',
|
||
after_weight_unit VARCHAR(8) NULL COMMENT '变更后单位',
|
||
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的重量kg',
|
||
reason VARCHAR(500) NULL COMMENT '人工修正原因',
|
||
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
||
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
||
operated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_weight_revision_no (tenant_id, weight_result_id, revision_no),
|
||
KEY idx_weight_revision_time (tenant_id, inbound_id, operated_at),
|
||
CONSTRAINT fk_weight_revision_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id),
|
||
CONSTRAINT fk_weight_revision_result FOREIGN KEY (weight_result_id) REFERENCES fl_inbound_weight_result (id)
|
||
) ENGINE=InnoDB COMMENT='OCR重量人工修正和确认的不可变版本历史';
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\phase2-inbound-weight-audit-migration.sql
|
||
-- ============================================================================
|
||
-- 二期称重结果审计字段增量迁移(可重复执行)。
|
||
-- InboundWeightResultEntity 继承 BaseEntity,持久化需要 created_by、updated_by 两个审计字段。
|
||
SET @has_created_by := (
|
||
SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_weight_result' AND column_name = 'created_by'
|
||
);
|
||
SET @created_by_sql := IF(@has_created_by = 0,
|
||
'ALTER TABLE fl_inbound_weight_result ADD COLUMN created_by BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''创建人ID'' AFTER confirmed_at',
|
||
'SELECT 1');
|
||
PREPARE created_by_stmt FROM @created_by_sql;
|
||
EXECUTE created_by_stmt;
|
||
DEALLOCATE PREPARE created_by_stmt;
|
||
|
||
SET @has_updated_by := (
|
||
SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_weight_result' AND column_name = 'updated_by'
|
||
);
|
||
SET @updated_by_sql := IF(@has_updated_by = 0,
|
||
'ALTER TABLE fl_inbound_weight_result ADD COLUMN updated_by BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''最后修改人ID'' AFTER created_at',
|
||
'SELECT 1');
|
||
PREPARE updated_by_stmt FROM @updated_by_sql;
|
||
EXECUTE updated_by_stmt;
|
||
DEALLOCATE PREPARE updated_by_stmt;
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\phase2-inbound-workflow-migration.sql
|
||
-- ============================================================================
|
||
-- 业务块4增量迁移:既有二期库补齐异常放行关口查询索引。
|
||
-- 可重复执行;新库仍先执行 phase2-inbound-schema.sql。
|
||
USE baiyue_firstleg;
|
||
SET NAMES utf8mb4;
|
||
|
||
SET @ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'fl_measure_review_record'
|
||
AND index_name = 'idx_review_exception_release'),
|
||
'SELECT 1',
|
||
'ALTER TABLE fl_measure_review_record ADD INDEX idx_review_exception_release (tenant_id, inbound_id, exception_release, reviewed_at)'
|
||
);
|
||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\phase2-measurement-openapi.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_firstleg;
|
||
|
||
-- 既有二期数据库增量:先确保 phase2-inbound-schema.sql 中的测量和幂等表已存在。
|
||
CREATE TABLE IF NOT EXISTS fl_third_party_call_log (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '第三方调用日志ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '识别出的租户ID,未知应用为0',
|
||
app_key VARCHAR(128) NULL COMMENT '第三方应用标识',
|
||
signature_subject VARCHAR(128) NULL COMMENT '签名主体快照',
|
||
request_method VARCHAR(8) NOT NULL COMMENT 'HTTP方法',
|
||
request_path VARCHAR(255) NOT NULL COMMENT '签名使用的规范路径',
|
||
request_timestamp VARCHAR(32) NULL COMMENT '请求头Unix毫秒时间戳原值',
|
||
nonce VARCHAR(128) NULL COMMENT '请求Nonce',
|
||
idempotency_key VARCHAR(128) NULL COMMENT 'HTTP幂等键,查询接口为空',
|
||
idempotency_anchor TINYINT UNSIGNED NULL COMMENT '签名通过后首个请求为1,重复调用为空',
|
||
signature_value VARCHAR(128) NULL COMMENT '第三方签名原值',
|
||
request_hash CHAR(64) NOT NULL COMMENT '原始请求体SHA-256小写十六进制',
|
||
raw_payload LONGTEXT NOT NULL COMMENT '未经重新序列化的UTF-8原始请求体',
|
||
processing_status VARCHAR(16) NOT NULL COMMENT 'PROCESSING、ACCEPTED或REJECTED',
|
||
result_code VARCHAR(32) NULL COMMENT '统一响应业务码',
|
||
result_message VARCHAR(1000) NULL COMMENT '处理结果或失败原因',
|
||
result_json JSON NULL COMMENT '首次成功结果快照',
|
||
requested_at DATETIME(3) NOT NULL COMMENT '服务端接收时间',
|
||
processed_at DATETIME(3) NULL COMMENT '处理完成时间',
|
||
PRIMARY KEY (id),
|
||
KEY idx_third_call_app_time (tenant_id, app_key, requested_at),
|
||
KEY idx_third_call_idempotency (tenant_id, app_key, idempotency_key),
|
||
KEY idx_third_call_nonce (tenant_id, app_key, nonce),
|
||
UNIQUE KEY uk_third_call_idempotency_owner (tenant_id, app_key, idempotency_key, idempotency_anchor)
|
||
) ENGINE=InnoDB COMMENT='第三方测量开放接口原始请求、签名主体和处理结果留档';
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\phase2-third-party-single-measurement-migration.sql
|
||
-- ============================================================================
|
||
-- 二期第三方单条箱规 + 单张图片绑定增量;可重复执行。
|
||
USE baiyue_firstleg;
|
||
|
||
DROP PROCEDURE IF EXISTS phase2_add_measurement_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE phase2_add_measurement_column(
|
||
IN p_table VARCHAR(64), IN p_column VARCHAR(64), IN p_definition TEXT)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = p_table AND COLUMN_NAME = p_column
|
||
) THEN
|
||
SET @ddl = CONCAT('ALTER TABLE `', p_table, '` ADD COLUMN `', p_column, '` ', p_definition);
|
||
PREPARE statement FROM @ddl;
|
||
EXECUTE statement;
|
||
DEALLOCATE PREPARE statement;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL phase2_add_measurement_column(
|
||
'fl_inbound_measurement', 'external_request_hash',
|
||
'CHAR(64) NULL COMMENT ''第三方data原文和图片内容联合请求哈希'' AFTER external_event_no');
|
||
CALL phase2_add_measurement_column(
|
||
'fl_inbound_measurement_item', 'inbound_detail_id',
|
||
'BIGINT UNSIGNED NULL COMMENT ''绑定的订单货物明细ID,平台手工明细可为空'' AFTER measurement_id');
|
||
CALL phase2_add_measurement_column(
|
||
'fl_inbound_measurement_item', 'external_detail_no',
|
||
'VARCHAR(128) NULL COMMENT ''第三方测量明细唯一号,平台手工明细可为空'' AFTER inbound_detail_id');
|
||
|
||
DROP PROCEDURE IF EXISTS phase2_add_measurement_column;
|
||
|
||
SET @has_index = (
|
||
SELECT COUNT(*) FROM information_schema.STATISTICS
|
||
WHERE TABLE_SCHEMA = DATABASE()
|
||
AND TABLE_NAME = 'fl_inbound_measurement_item'
|
||
AND INDEX_NAME = 'uk_measure_external_detail'
|
||
);
|
||
SET @ddl = IF(
|
||
@has_index = 0,
|
||
'ALTER TABLE fl_inbound_measurement_item ADD UNIQUE KEY uk_measure_external_detail (tenant_id, inbound_detail_id, external_detail_no)',
|
||
'SELECT 1'
|
||
);
|
||
PREPARE statement FROM @ddl;
|
||
EXECUTE statement;
|
||
DEALLOCATE PREPARE statement;
|
||
|
||
-- ============================================================================
|
||
-- 来源:firstleg\src\main\resources\db\phase2-fba-pricing-migration.sql
|
||
-- ============================================================================
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_firstleg;
|
||
|
||
-- 二期 FBA 计费增量迁移。通过 information_schema 判断,允许重复部署。
|
||
DROP PROCEDURE IF EXISTS phase2_fba_add_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE phase2_fba_add_column(IN p_table VARCHAR(64), IN p_column VARCHAR(64), IN p_definition TEXT)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = p_table AND COLUMN_NAME = p_column
|
||
) THEN
|
||
SET @sql = CONCAT('ALTER TABLE `', p_table, '` ADD COLUMN `', p_column, '` ', p_definition);
|
||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL phase2_fba_add_column('fl_inbound_order', 'carrier_id', "BIGINT UNSIGNED NULL COMMENT '计费船司逻辑ID' AFTER channel_name");
|
||
CALL phase2_fba_add_column('fl_inbound_order', 'carrier_name', "VARCHAR(128) NULL COMMENT '计费船司名称快照' AFTER carrier_id");
|
||
CALL phase2_fba_add_column('fl_carrier_fba_rate', 'business_type', "VARCHAR(32) NOT NULL DEFAULT 'FBA' COMMENT '业务或计费类型' AFTER origin_warehouse_name");
|
||
CALL phase2_fba_add_column('fl_customer_charge_rule', 'version', "INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号' AFTER deleted");
|
||
CALL phase2_fba_add_column('fl_carrier_fba_rate', 'version', "INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号' AFTER deleted");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'rule_code', "VARCHAR(50) NOT NULL DEFAULT '' COMMENT '客户规则编码快照' AFTER carrier_rate_version");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'customer_id', "BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '客户ID快照' AFTER rule_code");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'customer_name', "VARCHAR(128) NOT NULL DEFAULT '' COMMENT '客户名称快照' AFTER customer_id");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'business_type', "VARCHAR(32) NOT NULL DEFAULT '' COMMENT '业务类型快照' AFTER customer_name");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'tax_mode', "VARCHAR(24) NULL COMMENT '包税模式快照' AFTER business_type");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'rounding_scale', "TINYINT UNSIGNED NOT NULL DEFAULT 3 COMMENT '计费量保留位数快照' AFTER tax_mode");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'rounding_mode', "VARCHAR(24) NOT NULL DEFAULT 'CEILING' COMMENT '舍入方式快照' AFTER rounding_scale");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'rule_effective_from', "DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '客户规则生效开始快照' AFTER rounding_mode");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'rule_effective_to', "DATETIME(3) NULL COMMENT '客户规则生效结束快照' AFTER rule_effective_from");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'rate_code', "VARCHAR(50) NOT NULL DEFAULT '' COMMENT '船司价格编码快照' AFTER rule_effective_to");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'origin_warehouse_id', "BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '起运仓ID快照' AFTER rate_code");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'origin_warehouse_name', "VARCHAR(128) NOT NULL DEFAULT '' COMMENT '起运仓名称快照' AFTER origin_warehouse_id");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'channel_code', "VARCHAR(64) NOT NULL DEFAULT '' COMMENT '渠道编码快照' AFTER origin_warehouse_name");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'carrier_id', "BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '船司ID快照' AFTER channel_code");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'carrier_name', "VARCHAR(128) NOT NULL DEFAULT '' COMMENT '船司名称快照' AFTER carrier_id");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'destination_code', "VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'FBA仓编码快照' AFTER carrier_name");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'rate_effective_from', "DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '价格生效开始快照' AFTER destination_code");
|
||
CALL phase2_fba_add_column('fl_inbound_fee', 'rate_effective_to', "DATETIME(3) NULL COMMENT '价格生效结束快照' AFTER rate_effective_from");
|
||
CALL phase2_fba_add_column('fl_inbound_idempotency', 'result_resource_id', "BIGINT UNSIGNED NULL COMMENT '成功结果资源ID' AFTER result_json");
|
||
CALL phase2_fba_add_column('fl_inbound_pallet_allocation', 'warehouse_resource_tenant_id',
|
||
"BIGINT UNSIGNED NULL COMMENT '仓储资源所属租户ID' AFTER warehouse_id");
|
||
|
||
-- 旧分配记录创建于共享仓储资源租户拆分前,按原业务租户回填后再收口非空约束。
|
||
UPDATE fl_inbound_pallet_allocation
|
||
SET warehouse_resource_tenant_id = tenant_id
|
||
WHERE warehouse_resource_tenant_id IS NULL OR warehouse_resource_tenant_id = 0;
|
||
SET @resource_tenant_nullable = (SELECT IS_NULLABLE FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_inbound_pallet_allocation'
|
||
AND COLUMN_NAME = 'warehouse_resource_tenant_id');
|
||
SET @sql = IF(@resource_tenant_nullable = 'YES',
|
||
"ALTER TABLE fl_inbound_pallet_allocation MODIFY COLUMN warehouse_resource_tenant_id BIGINT UNSIGNED NOT NULL COMMENT '仓储资源所属租户ID'",
|
||
'SELECT 1');
|
||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
DROP PROCEDURE IF EXISTS phase2_fba_add_column;
|
||
|
||
-- 旧索引可能缺少业务类型、船司和结束时间;用新索引名并存,避免破坏线上依赖。
|
||
SET @idx_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_carrier_fba_rate' AND INDEX_NAME = 'idx_fba_rate_unique_match');
|
||
SET @sql = IF(@idx_exists = 0,
|
||
'ALTER TABLE fl_carrier_fba_rate ADD INDEX idx_fba_rate_unique_match (tenant_id, origin_warehouse_id, business_type, channel_code, carrier_id, destination_code, charge_unit, status, effective_from, effective_to)',
|
||
'SELECT 1');
|
||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase2-inbound-query-permissions.sql
|
||
-- ============================================================================
|
||
-- 二期入库单列表和详情只读权限,可在一期 RBAC 脚本后重复执行。
|
||
USE baiyue_iam;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||
permission_name, route_path, http_method, sort_no, status, built_in, deleted)
|
||
VALUES
|
||
(5102030, 0, 'PLATFORM', 'MENU', 5102000, 'platform:firstleg:inbound:list',
|
||
'入库单', '/inbounds', 'GET', 30, 'ACTIVE', 1, 0),
|
||
(5102031, 0, 'PLATFORM', 'BUTTON', 5102030, 'platform:firstleg:inbound:view',
|
||
'查看入库单详情', NULL, 'GET', 10, 'ACTIVE', 1, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_name = VALUES(permission_name), parent_id = VALUES(parent_id),
|
||
route_path = VALUES(route_path), http_method = VALUES(http_method),
|
||
status = 'ACTIVE', built_in = 1, deleted = 0;
|
||
|
||
INSERT IGNORE INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT role.id, permission.id, role.tenant_id
|
||
FROM iam_role role
|
||
JOIN iam_permission permission
|
||
ON permission.tenant_id = 0
|
||
AND permission.permission_code IN (
|
||
'platform:firstleg:inbound:list', 'platform:firstleg:inbound:view')
|
||
WHERE role.tenant_id = 0
|
||
AND role.role_code IN ('PLATFORM_ADMIN', 'ORDER_OPERATOR');
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase2-inbound-measurement-permissions.sql
|
||
-- ============================================================================
|
||
-- 二期入库测量平台菜单和按钮权限,可重复执行。
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_iam;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name,
|
||
route_path, http_method, sort_no, status, deleted)
|
||
VALUES
|
||
(5102041, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:measure:view', '查看入库测量', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5102042, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:measure:edit', '保存测量草稿', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5102043, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:measure:submit', '确认并提交测量', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5102044, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:weight:edit', '维护OCR重量', NULL, NULL, 30, 'ACTIVE', 0),
|
||
(5102045, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:weight:confirm', '确认OCR重量', NULL, NULL, 40, 'ACTIVE', 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||
http_method = NULL, sort_no = VALUES(sort_no), status = 'ACTIVE', deleted = 0;
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0 FROM iam_permission
|
||
WHERE id IN (5102041, 5102042, 5102043, 5102044, 5102045)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000003, id, 0 FROM iam_permission
|
||
WHERE id IN (5102041, 5102042, 5102043, 5102044, 5102045)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase2-inbound-permissions.sql
|
||
-- ============================================================================
|
||
-- 二期入库审核与异常放行按钮权限,可重复部署。
|
||
USE baiyue_iam;
|
||
SET NAMES utf8mb4;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||
permission_name, route_path, http_method, sort_no, status, deleted)
|
||
VALUES
|
||
(5102051, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:inbound:measurement-review',
|
||
'测量审核', NULL, NULL, 10, 'ACTIVE', 0),
|
||
(5102052, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:inbound:measurement-review-history',
|
||
'查看测量审核历史', NULL, NULL, 20, 'ACTIVE', 0),
|
||
(5102053, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:inbound:exception-release',
|
||
'测量异常放行', NULL, NULL, 30, 'ACTIVE', 0),
|
||
(5102054, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:inbound:send-fee',
|
||
'发送费用并入库', NULL, NULL, 40, 'ACTIVE', 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_name = VALUES(permission_name), parent_id = VALUES(parent_id),
|
||
status = 'ACTIVE', deleted = 0;
|
||
|
||
-- 仅给平台超级管理员补齐默认权限;业务角色由 IAM 页面按职责授权。
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, p.id, 0
|
||
FROM iam_permission p
|
||
WHERE p.id BETWEEN 5102051 AND 5102054
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- 客服(订单运营)负责测量审核;费用发送由审核通过后的服务端编排自动执行。
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000003, p.id, 0
|
||
FROM iam_permission p
|
||
WHERE p.id IN (5102051, 5102052)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase2-fba-pricing-permissions.sql
|
||
-- ============================================================================
|
||
-- 二期 FBA 计费权限;在入库查询、测量和审核权限脚本后执行,可重复部署。
|
||
USE baiyue_iam;
|
||
SET NAMES utf8mb4;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||
permission_name, route_path, http_method, sort_no, status, built_in, deleted)
|
||
VALUES
|
||
(5102061, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:fba-pricing:rule:view', '查看客户计费规则', NULL, NULL, 10, 'ACTIVE', 1, 0),
|
||
(5102062, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:fba-pricing:rule:edit', '维护客户计费规则', NULL, NULL, 20, 'ACTIVE', 1, 0),
|
||
(5102063, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:fba-pricing:rate:view', '查看承运商价格', NULL, NULL, 30, 'ACTIVE', 1, 0),
|
||
(5102064, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:fba-pricing:rate:edit', '维护承运商价格', NULL, NULL, 40, 'ACTIVE', 1, 0),
|
||
(5102065, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:fba-pricing:calculate', '计算入库费用', NULL, NULL, 50, 'ACTIVE', 1, 0),
|
||
(5102066, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:fba-pricing:confirm', '内部确认入库费用', NULL, NULL, 60, 'ACTIVE', 1, 0),
|
||
(5102067, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:fba-pricing:view', '查看入库费用', NULL, NULL, 70, 'ACTIVE', 1, 0),
|
||
(5102068, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:fba-pricing:adjust', '调整已发布费用', NULL, NULL, 80, 'ACTIVE', 1, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_name = VALUES(permission_name), parent_id = VALUES(parent_id),
|
||
status = 'ACTIVE', built_in = 1, deleted = 0;
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0 FROM iam_permission
|
||
WHERE id BETWEEN 5102061 AND 5102068
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000003, id, 0 FROM iam_permission
|
||
WHERE id IN (5102061, 5102063, 5102065, 5102066, 5102067, 5102068)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase2-location-permissions.sql
|
||
-- ============================================================================
|
||
-- 二期库位管理菜单和按钮权限。
|
||
-- 在 phase1-admin-rbac.sql、phase1-platform-master-data-and-permission-management.sql 之后执行,可重复执行。
|
||
USE baiyue_iam;
|
||
SET NAMES utf8mb4;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name,
|
||
route_path, http_method, sort_no, status, built_in, deleted)
|
||
VALUES
|
||
(5103040, 0, 'PLATFORM', 'MENU', 5103000, 'platform:location:list', '库位管理',
|
||
'/master-data/locations', NULL, 40, 'ACTIVE', 1, 0),
|
||
(5103041, 0, 'PLATFORM', 'BUTTON', 5103040, 'platform:location:create', '新增库位',
|
||
NULL, NULL, 10, 'ACTIVE', 1, 0),
|
||
(5103042, 0, 'PLATFORM', 'BUTTON', 5103040, 'platform:location:edit', '编辑库位',
|
||
NULL, NULL, 20, 'ACTIVE', 1, 0),
|
||
(5103043, 0, 'PLATFORM', 'BUTTON', 5103040, 'platform:location:status', '启停库位',
|
||
NULL, NULL, 30, 'ACTIVE', 1, 0),
|
||
(5103044, 0, 'PLATFORM', 'BUTTON', 5103040, 'platform:location:delete', '删除库位',
|
||
NULL, NULL, 40, 'ACTIVE', 1, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||
sort_no = VALUES(sort_no), status = 'ACTIVE', built_in = 1, deleted = 0;
|
||
|
||
-- 二期新增库位权限默认只授予平台系统管理员。
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0
|
||
FROM iam_permission
|
||
WHERE tenant_id = 0 AND app_code = 'PLATFORM'
|
||
AND permission_code IN (
|
||
'platform:location:list', 'platform:location:create', 'platform:location:edit',
|
||
'platform:location:status', 'platform:location:delete'
|
||
)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- ============================================================================
|
||
-- 来源:iam\src\main\resources\db\phase2-pallet-permissions.sql
|
||
-- ============================================================================
|
||
-- 二期托盘管理菜单和按钮权限。
|
||
-- 在 phase1-admin-rbac.sql、phase1-platform-master-data-and-permission-management.sql 之后执行,可重复执行。
|
||
USE baiyue_iam;
|
||
SET NAMES utf8mb4;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code, permission_name,
|
||
route_path, http_method, sort_no, status, built_in, deleted)
|
||
VALUES
|
||
(5103050, 0, 'PLATFORM', 'MENU', 5103000, 'platform:pallet:list', '托盘管理',
|
||
'/master-data/pallets', NULL, 50, 'ACTIVE', 1, 0),
|
||
(5103051, 0, 'PLATFORM', 'BUTTON', 5103050, 'platform:pallet:create', '新增托盘',
|
||
NULL, NULL, 10, 'ACTIVE', 1, 0),
|
||
(5103052, 0, 'PLATFORM', 'BUTTON', 5103050, 'platform:pallet:edit', '编辑托盘',
|
||
NULL, NULL, 20, 'ACTIVE', 1, 0),
|
||
(5103054, 0, 'PLATFORM', 'BUTTON', 5103050, 'platform:pallet:delete', '删除托盘',
|
||
NULL, NULL, 30, 'ACTIVE', 1, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||
sort_no = VALUES(sort_no), status = 'ACTIVE', built_in = 1, deleted = 0;
|
||
|
||
-- 二期新增托盘权限默认只授予平台系统管理员。
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0
|
||
FROM iam_permission
|
||
WHERE tenant_id = 0 AND app_code = 'PLATFORM'
|
||
AND permission_code IN (
|
||
'platform:pallet:list', 'platform:pallet:create', 'platform:pallet:edit', 'platform:pallet:delete'
|
||
)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- 兼容已经试运行过旧脚本的环境:移除人工启停权限。
|
||
DELETE rp FROM iam_role_permission rp
|
||
JOIN iam_permission p ON p.id = rp.permission_id
|
||
WHERE p.tenant_id = 0 AND p.app_code = 'PLATFORM' AND p.permission_code = 'platform:pallet:status';
|
||
UPDATE iam_permission
|
||
SET status = 'INACTIVE', deleted = 1
|
||
WHERE tenant_id = 0 AND app_code = 'PLATFORM' AND permission_code = 'platform:pallet:status';
|
||
|
||
-- ============================================================================
|
||
-- 存量 File 导出中心安全升级
|
||
-- ============================================================================
|
||
USE baiyue_file;
|
||
DROP PROCEDURE IF EXISTS unified_file_add_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_file_add_column(
|
||
IN p_column_name VARCHAR(64), IN p_definition TEXT
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE()
|
||
AND table_name = 'file_export_task'
|
||
AND column_name = p_column_name
|
||
) THEN
|
||
SET @unified_ddl = CONCAT(
|
||
'ALTER TABLE file_export_task ADD COLUMN `',
|
||
REPLACE(p_column_name, '`', '``'), '` ', p_definition
|
||
);
|
||
PREPARE unified_stmt FROM @unified_ddl;
|
||
EXECUTE unified_stmt;
|
||
DEALLOCATE PREPARE unified_stmt;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL unified_file_add_column('dispatch_version',
|
||
'INT NOT NULL DEFAULT 1 COMMENT ''派发版本,仅执行重试时递增'' AFTER failure_message');
|
||
CALL unified_file_add_column('attempt_count',
|
||
'INT NOT NULL DEFAULT 0 COMMENT ''已执行尝试次数'' AFTER dispatch_version');
|
||
CALL unified_file_add_column('max_attempts',
|
||
'INT NOT NULL DEFAULT 3 COMMENT ''自动重试上限'' AFTER attempt_count');
|
||
CALL unified_file_add_column('next_retry_at',
|
||
'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT ''允许执行的最早时间'' AFTER max_attempts');
|
||
CALL unified_file_add_column('lease_owner',
|
||
'VARCHAR(128) NULL COMMENT ''当前执行实例标识'' AFTER next_retry_at');
|
||
CALL unified_file_add_column('lease_until',
|
||
'DATETIME(3) NULL COMMENT ''执行租约截止时间'' AFTER lease_owner');
|
||
CALL unified_file_add_column('last_heartbeat_at',
|
||
'DATETIME(3) NULL COMMENT ''最后心跳时间'' AFTER lease_until');
|
||
CALL unified_file_add_column('execution_deadline_at',
|
||
'DATETIME(3) NULL COMMENT ''本次执行截止时间'' AFTER last_heartbeat_at');
|
||
DROP PROCEDURE IF EXISTS unified_file_add_column;
|
||
|
||
SET @unified_ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'file_export_task'
|
||
AND index_name = 'idx_file_export_dispatch'),
|
||
'SELECT 1',
|
||
'ALTER TABLE file_export_task ADD INDEX idx_file_export_dispatch (status, next_retry_at, id)'
|
||
);
|
||
PREPARE unified_stmt FROM @unified_ddl; EXECUTE unified_stmt; DEALLOCATE PREPARE unified_stmt;
|
||
|
||
SET @unified_ddl = IF(
|
||
EXISTS(SELECT 1 FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'file_export_task'
|
||
AND index_name = 'idx_file_export_lease'),
|
||
'SELECT 1',
|
||
'ALTER TABLE file_export_task ADD INDEX idx_file_export_lease (status, lease_until)'
|
||
);
|
||
PREPARE unified_stmt FROM @unified_ddl; EXECUTE unified_stmt; DEALLOCATE PREPARE unified_stmt;
|
||
|
||
-- ============================================================================
|
||
-- 一期订单快照字段规格统一
|
||
-- ============================================================================
|
||
USE baiyue_order;
|
||
SET @unified_ddl = IF(
|
||
COALESCE((SELECT character_maximum_length FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'ord_order'
|
||
AND column_name = 'receiving_warehouse_address'), 0) < 600,
|
||
'ALTER TABLE ord_order MODIFY COLUMN receiving_warehouse_address VARCHAR(600) NULL COMMENT ''收货仓地址历史快照''',
|
||
'SELECT 1'
|
||
);
|
||
PREPARE unified_stmt FROM @unified_ddl; EXECUTE unified_stmt; DEALLOCATE PREPARE unified_stmt;
|
||
|
||
SET @unified_ddl = IF(
|
||
COALESCE((SELECT character_maximum_length FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'ord_order'
|
||
AND column_name = 'receiving_time'), 0) < 128,
|
||
'ALTER TABLE ord_order MODIFY COLUMN receiving_time VARCHAR(128) NULL COMMENT ''收货时间历史快照''',
|
||
'SELECT 1'
|
||
);
|
||
PREPARE unified_stmt FROM @unified_ddl; EXECUTE unified_stmt; DEALLOCATE PREPARE unified_stmt;
|
||
|
||
-- ============================================================================
|
||
-- 重新同步一期商户管理员全局模板,包含一期后续追加的菜单和按钮
|
||
-- ============================================================================
|
||
USE baiyue_iam;
|
||
INSERT INTO iam_permission (
|
||
id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||
permission_name, route_path, http_method, sort_no, status, deleted
|
||
)
|
||
SELECT id + 100000, 0, app_code, permission_type,
|
||
CASE WHEN parent_id = 0 THEN 0 ELSE parent_id + 100000 END,
|
||
permission_code, permission_name, route_path, NULL, sort_no, 'ACTIVE', 0
|
||
FROM iam_permission
|
||
WHERE tenant_id = 10001 AND app_code = 'MERCHANT'
|
||
AND permission_type IN ('MENU', 'BUTTON')
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||
parent_id = VALUES(parent_id), sort_no = VALUES(sort_no), status = 'ACTIVE', deleted = 0;
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT owner_role.id, permission.id, 0
|
||
FROM iam_role owner_role
|
||
JOIN iam_permission permission
|
||
ON permission.app_code = 'MERCHANT' AND permission.tenant_id = 0
|
||
AND permission.permission_type IN ('MENU', 'BUTTON')
|
||
AND permission.status = 'ACTIVE' AND permission.deleted = 0
|
||
WHERE owner_role.tenant_id = 0 AND owner_role.app_code = 'MERCHANT'
|
||
AND owner_role.role_code = 'MERCHANT_OWNER'
|
||
AND owner_role.status = 'ACTIVE' AND owner_role.deleted = 0
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- ============================================================================
|
||
-- 统一执行结果强校验:任一关键结构缺失立即终止,不输出虚假 PASS
|
||
-- ============================================================================
|
||
DROP PROCEDURE IF EXISTS unified_assert_table;
|
||
DROP PROCEDURE IF EXISTS unified_assert_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_assert_table(IN p_schema VARCHAR(64), IN p_table VARCHAR(64))
|
||
BEGIN
|
||
DECLARE v_count INT DEFAULT 0;
|
||
DECLARE v_message VARCHAR(255);
|
||
SELECT COUNT(*) INTO v_count FROM information_schema.tables
|
||
WHERE table_schema = p_schema AND table_name = p_table;
|
||
IF v_count <> 1 THEN
|
||
SET v_message = CONCAT('统一迁移失败,缺少表:', p_schema, '.', p_table);
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = v_message;
|
||
END IF;
|
||
END$$
|
||
|
||
CREATE PROCEDURE unified_assert_column(
|
||
IN p_schema VARCHAR(64), IN p_table VARCHAR(64), IN p_column VARCHAR(64)
|
||
)
|
||
BEGIN
|
||
DECLARE v_count INT DEFAULT 0;
|
||
DECLARE v_message VARCHAR(255);
|
||
SELECT COUNT(*) INTO v_count FROM information_schema.columns
|
||
WHERE table_schema = p_schema AND table_name = p_table AND column_name = p_column;
|
||
IF v_count <> 1 THEN
|
||
SET v_message = CONCAT('统一迁移失败,缺少字段:', p_schema, '.', p_table, '.', p_column);
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = v_message;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL unified_assert_table('baiyue_auth', 'auth_account');
|
||
CALL unified_assert_table('baiyue_iam', 'iam_permission');
|
||
CALL unified_assert_table('baiyue_order', 'ord_order');
|
||
CALL unified_assert_table('baiyue_warehouse', 'wh_warehouse');
|
||
CALL unified_assert_table('baiyue_warehouse', 'wh_pallet');
|
||
CALL unified_assert_table('baiyue_warehouse', 'wh_location');
|
||
CALL unified_assert_table('baiyue_firstleg', 'fl_fulfillment_task');
|
||
CALL unified_assert_table('baiyue_firstleg', 'fl_inbound_order');
|
||
CALL unified_assert_table('baiyue_firstleg', 'fl_third_party_call_log');
|
||
CALL unified_assert_table('baiyue_file', 'file_export_task_guard');
|
||
CALL unified_assert_table('baiyue_file', 'file_export_outbox');
|
||
CALL unified_assert_table('baiyue_audit', 'sys_audit_log');
|
||
CALL unified_assert_table('baiyue_event_bridge', 'bridge_inbox');
|
||
CALL unified_assert_column('baiyue_order', 'ord_order', 'carrier_id');
|
||
CALL unified_assert_column('baiyue_order', 'ord_order', 'carrier_name');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_inbound_pallet_allocation', 'warehouse_resource_tenant_id');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_inbound_measurement_item', 'external_detail_no');
|
||
CALL unified_assert_column('baiyue_file', 'file_export_task', 'execution_deadline_at');
|
||
|
||
DROP PROCEDURE IF EXISTS unified_assert_table;
|
||
DROP PROCEDURE IF EXISTS unified_assert_column;
|
||
|
||
SET @phase2_permission_count = (
|
||
SELECT COUNT(DISTINCT permission_code)
|
||
FROM iam_permission
|
||
WHERE tenant_id = 0 AND deleted = 0
|
||
AND permission_code IN (
|
||
'platform:firstleg:inbound:list', 'platform:firstleg:inbound:view',
|
||
'platform:firstleg:inbound:measure:view', 'platform:firstleg:inbound:measure:edit',
|
||
'platform:firstleg:inbound:measure:submit', 'platform:firstleg:inbound:weight:edit',
|
||
'platform:firstleg:inbound:weight:confirm', 'firstleg:inbound:measurement-review',
|
||
'firstleg:inbound:measurement-review-history', 'firstleg:inbound:exception-release',
|
||
'firstleg:inbound:send-fee', 'firstleg:fba-pricing:rule:view',
|
||
'firstleg:fba-pricing:rule:edit', 'firstleg:fba-pricing:rate:view',
|
||
'firstleg:fba-pricing:rate:edit', 'firstleg:fba-pricing:calculate',
|
||
'firstleg:fba-pricing:confirm', 'firstleg:fba-pricing:view',
|
||
'firstleg:fba-pricing:adjust', 'platform:location:list',
|
||
'platform:location:create', 'platform:location:edit', 'platform:location:status',
|
||
'platform:location:delete', 'platform:pallet:list', 'platform:pallet:create',
|
||
'platform:pallet:edit', 'platform:pallet:delete'
|
||
)
|
||
);
|
||
|
||
DROP PROCEDURE IF EXISTS unified_assert_permission_count;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_assert_permission_count()
|
||
BEGIN
|
||
IF @phase2_permission_count <> 28 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:二期 IAM 权限资源未达到 28 项';
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL unified_assert_permission_count();
|
||
DROP PROCEDURE IF EXISTS unified_assert_permission_count;
|
||
|
||
-- ============================================================================
|
||
-- 2026-08-05:海外仓阶梯费用基础资料 CRUD 增量
|
||
-- ============================================================================
|
||
USE baiyue_warehouse;
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_overseas_storage_fee_rule (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '海外仓阶梯费用规则ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户账号ID,沿用tenant_id物理字段',
|
||
customer_name VARCHAR(128) NOT NULL COMMENT '客户公司名称快照',
|
||
currency CHAR(3) NOT NULL COMMENT 'ISO 4217币种三字码',
|
||
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
|
||
ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
active_customer_id BIGINT UNSIGNED
|
||
GENERATED ALWAYS AS (CASE WHEN deleted = 0 THEN tenant_id ELSE NULL END) STORED
|
||
COMMENT '未删除规则的客户唯一键',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_overseas_fee_active_customer (active_customer_id),
|
||
KEY idx_overseas_fee_page (deleted, updated_at, id),
|
||
KEY idx_overseas_fee_customer_name (customer_name, deleted)
|
||
) ENGINE=InnoDB COMMENT='客户维度海外仓阶梯仓储费规则';
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_overseas_storage_fee_tier (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '海外仓阶梯费用明细ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户账号ID,沿用tenant_id物理字段',
|
||
rule_id BIGINT UNSIGNED NOT NULL COMMENT '阶梯费用规则ID',
|
||
start_day SMALLINT UNSIGNED NOT NULL COMMENT '起始天,含边界',
|
||
end_day SMALLINT UNSIGNED NOT NULL COMMENT '结束天,含边界',
|
||
unit_price DECIMAL(18,6) NOT NULL COMMENT '仓储费标准',
|
||
sort_no SMALLINT UNSIGNED NOT NULL COMMENT '阶梯排序号',
|
||
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
|
||
ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
active_start_day SMALLINT UNSIGNED
|
||
GENERATED ALWAYS AS (CASE WHEN deleted = 0 THEN start_day ELSE NULL END) STORED
|
||
COMMENT '未删除阶梯的起始天唯一键',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_overseas_fee_tier_start (rule_id, active_start_day),
|
||
KEY idx_overseas_fee_tier_rule (tenant_id, rule_id, deleted, sort_no, id),
|
||
CONSTRAINT chk_overseas_fee_tier_days CHECK (start_day >= 1 AND end_day >= start_day),
|
||
CONSTRAINT chk_overseas_fee_tier_price CHECK (unit_price > 0)
|
||
) ENGINE=InnoDB COMMENT='海外仓阶梯仓储费明细';
|
||
|
||
USE baiyue_iam;
|
||
INSERT INTO iam_permission (
|
||
id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||
permission_name, route_path, http_method, sort_no, status, built_in, deleted
|
||
)
|
||
VALUES
|
||
(5100030, 0, 'PLATFORM', 'MENU', 5100000,
|
||
'platform:overseas-storage-fee:list', '海外仓阶梯费用',
|
||
'/customers/overseas-storage-fees', 'GET', 20, 'ACTIVE', 1, 0),
|
||
(5100031, 0, 'PLATFORM', 'BUTTON', 5100030,
|
||
'platform:overseas-storage-fee:create', '新增海外仓阶梯费用',
|
||
NULL, NULL, 10, 'ACTIVE', 1, 0),
|
||
(5100032, 0, 'PLATFORM', 'BUTTON', 5100030,
|
||
'platform:overseas-storage-fee:edit', '编辑海外仓阶梯费用',
|
||
NULL, NULL, 20, 'ACTIVE', 1, 0),
|
||
(5100033, 0, 'PLATFORM', 'BUTTON', 5100030,
|
||
'platform:overseas-storage-fee:delete', '删除海外仓阶梯费用',
|
||
NULL, NULL, 30, 'ACTIVE', 1, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||
http_method = VALUES(http_method), sort_no = VALUES(sort_no),
|
||
status = 'ACTIVE', built_in = 1, deleted = 0;
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0
|
||
FROM iam_permission
|
||
WHERE tenant_id = 0 AND app_code = 'PLATFORM'
|
||
AND permission_code IN (
|
||
'platform:overseas-storage-fee:list',
|
||
'platform:overseas-storage-fee:create',
|
||
'platform:overseas-storage-fee:edit',
|
||
'platform:overseas-storage-fee:delete'
|
||
)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
DROP PROCEDURE IF EXISTS unified_assert_overseas_storage_fee;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_assert_overseas_storage_fee()
|
||
BEGIN
|
||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||
WHERE table_schema = 'baiyue_warehouse'
|
||
AND table_name IN ('wh_overseas_storage_fee_rule', 'wh_overseas_storage_fee_tier')) <> 2 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:海外仓阶梯费用表未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT index_name) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_warehouse'
|
||
AND index_name IN ('uk_overseas_fee_active_customer', 'idx_overseas_fee_page',
|
||
'idx_overseas_fee_customer_name', 'uk_overseas_fee_tier_start',
|
||
'idx_overseas_fee_tier_rule')) <> 5 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:海外仓阶梯费用索引未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT permission_code) FROM baiyue_iam.iam_permission
|
||
WHERE tenant_id = 0 AND status = 'ACTIVE' AND deleted = 0
|
||
AND permission_code IN (
|
||
'platform:overseas-storage-fee:list', 'platform:overseas-storage-fee:create',
|
||
'platform:overseas-storage-fee:edit', 'platform:overseas-storage-fee:delete')) <> 4 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:海外仓阶梯费用权限未完整创建';
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL unified_assert_overseas_storage_fee();
|
||
DROP PROCEDURE IF EXISTS unified_assert_overseas_storage_fee;
|
||
|
||
SELECT 'PASS' AS migration_status,
|
||
'统一增量执行完成,海外仓阶梯费用表、索引和权限校验通过' AS message;
|
||
|
||
-- ============================================================
|
||
-- 二期:费用项目主数据与入库单应收应付费用明细
|
||
-- ============================================================
|
||
USE baiyue_firstleg;
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_fee_item (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '费用项目ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '账号ID,沿用tenant_id字段名',
|
||
category VARCHAR(64) NOT NULL COMMENT '费用分类',
|
||
trade_scope VARCHAR(20) NOT NULL COMMENT 'DOMESTIC国内、INTERNATIONAL国际',
|
||
fee_type_name VARCHAR(128) NOT NULL COMMENT '费用类型名称',
|
||
pickup_payable TINYINT(1) NOT NULL DEFAULT 0 COMMENT '提柜应付是否参与',
|
||
pickup_receivable TINYINT(1) NOT NULL DEFAULT 0 COMMENT '提柜应收是否参与',
|
||
warehouse_payable TINYINT(1) NOT NULL DEFAULT 0 COMMENT '仓储应付是否参与',
|
||
warehouse_receivable TINYINT(1) NOT NULL DEFAULT 0 COMMENT '仓储应收是否参与',
|
||
allocation_fee TINYINT(1) NOT NULL DEFAULT 0 COMMENT '平摊费用是否参与',
|
||
description VARCHAR(500) NULL COMMENT '说明',
|
||
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT 'ACTIVE或DISABLED',
|
||
created_by BIGINT NULL,
|
||
created_by_name VARCHAR(64) NULL,
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
updated_by BIGINT NULL,
|
||
updated_by_name VARCHAR(64) NULL,
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0,
|
||
version INT NOT NULL DEFAULT 0,
|
||
PRIMARY KEY (id),
|
||
KEY idx_fee_item_query (tenant_id, trade_scope, category, status, deleted),
|
||
KEY idx_fee_item_name (tenant_id, fee_type_name, deleted)
|
||
) ENGINE=InnoDB COMMENT='费用项目主数据';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_fee_detail (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '入库费用明细ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '账号ID,沿用tenant_id字段名',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
fee_item_id BIGINT UNSIGNED NOT NULL COMMENT '绑定费用项目ID',
|
||
inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照',
|
||
direction VARCHAR(16) NOT NULL COMMENT 'RECEIVABLE应收、PAYABLE应付',
|
||
business_date DATE NOT NULL COMMENT '业务发生日',
|
||
fee_category_snapshot VARCHAR(64) NOT NULL COMMENT '费用分类快照',
|
||
trade_scope_snapshot VARCHAR(20) NOT NULL COMMENT '国内国际快照',
|
||
fee_type_name_snapshot VARCHAR(128) NOT NULL COMMENT '费用类型名称快照',
|
||
channel_code VARCHAR(64) NULL COMMENT '渠道编码快照',
|
||
channel_name VARCHAR(128) NULL COMMENT '渠道名称快照',
|
||
destination_code VARCHAR(32) NULL COMMENT '目的仓编码快照',
|
||
destination_name VARCHAR(128) NULL COMMENT '目的仓名称快照',
|
||
package_count INT NULL COMMENT '件数快照',
|
||
actual_gross_weight_kg DECIMAL(18,4) NULL COMMENT '仓库实测毛重',
|
||
actual_volume_cbm DECIMAL(18,6) NULL COMMENT '体积',
|
||
volume_weight_kg DECIMAL(18,4) NULL COMMENT '材积重',
|
||
chargeable_weight_kg DECIMAL(18,4) NULL COMMENT '计费重量',
|
||
chargeable_volume_cbm DECIMAL(18,6) NULL COMMENT '计费体积',
|
||
unit_price DECIMAL(18,4) NOT NULL COMMENT '单价',
|
||
currency CHAR(3) NOT NULL COMMENT '币种',
|
||
amount DECIMAL(18,2) NOT NULL COMMENT '金额',
|
||
remark VARCHAR(500) NULL COMMENT '备注',
|
||
review_status VARCHAR(16) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING、APPROVED、REJECTED',
|
||
reviewer_id BIGINT NULL COMMENT '审核人ID',
|
||
reviewer_name VARCHAR(64) NULL COMMENT '审核人名称快照',
|
||
reviewed_at DATETIME(3) NULL COMMENT '审核时间',
|
||
review_reason VARCHAR(500) NULL COMMENT '审核驳回原因',
|
||
created_by BIGINT NULL,
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
updated_by BIGINT NULL,
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0,
|
||
version INT NOT NULL DEFAULT 0,
|
||
PRIMARY KEY (id),
|
||
KEY idx_inbound_fee_detail (tenant_id, inbound_id, business_date, deleted),
|
||
KEY idx_inbound_fee_review (tenant_id, review_status, business_date, deleted),
|
||
KEY idx_inbound_fee_item (tenant_id, fee_item_id, deleted),
|
||
CONSTRAINT fk_inbound_fee_detail_order FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id),
|
||
CONSTRAINT fk_inbound_fee_detail_item FOREIGN KEY (fee_item_id) REFERENCES fl_fee_item (id)
|
||
) ENGINE=InnoDB COMMENT='入库单应收应付费用明细';
|
||
|
||
USE baiyue_iam;
|
||
|
||
INSERT INTO iam_permission
|
||
(id, tenant_id, app_code, permission_type, parent_id, permission_code,
|
||
permission_name, route_path, http_method, sort_no, status, built_in, deleted)
|
||
VALUES
|
||
(5102070, 0, 'PLATFORM', 'MENU', 5103000, 'firstleg:fee-item:view',
|
||
'费用项目', '/master-data/fee-items', NULL, 40, 'ACTIVE', 1, 0),
|
||
(5102071, 0, 'PLATFORM', 'BUTTON', 5102070, 'firstleg:fee-item:create',
|
||
'新增费用项目', NULL, NULL, 10, 'ACTIVE', 1, 0),
|
||
(5102072, 0, 'PLATFORM', 'BUTTON', 5102070, 'firstleg:fee-item:edit',
|
||
'编辑或停用费用项目', NULL, NULL, 20, 'ACTIVE', 1, 0),
|
||
(5102073, 0, 'PLATFORM', 'BUTTON', 5102070, 'firstleg:fee-item:delete',
|
||
'删除费用项目', NULL, NULL, 30, 'ACTIVE', 1, 0),
|
||
(5102081, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:inbound:fee-detail:view',
|
||
'查看入库费用明细', NULL, NULL, 100, 'ACTIVE', 1, 0),
|
||
(5102082, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:inbound:fee-detail:edit',
|
||
'新增编辑入库费用明细', NULL, NULL, 110, 'ACTIVE', 1, 0),
|
||
(5102083, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:inbound:fee-detail:delete',
|
||
'删除入库费用明细', NULL, NULL, 120, 'ACTIVE', 1, 0),
|
||
(5102084, 0, 'PLATFORM', 'BUTTON', 5102030, 'firstleg:inbound:fee-detail:review',
|
||
'审核入库费用明细', NULL, NULL, 130, 'ACTIVE', 1, 0)
|
||
ON DUPLICATE KEY UPDATE
|
||
permission_type = VALUES(permission_type), parent_id = VALUES(parent_id),
|
||
permission_name = VALUES(permission_name), route_path = VALUES(route_path),
|
||
sort_no = VALUES(sort_no), status = 'ACTIVE', built_in = 1, deleted = 0;
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT 4000001, id, 0
|
||
FROM iam_permission
|
||
WHERE id IN (5102070, 5102071, 5102072, 5102073, 5102081, 5102082, 5102083, 5102084)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
SELECT 'PASS' AS migration_status,
|
||
'费用项目、入库费用明细及按钮权限增量已执行' AS message;
|
||
|
||
-- ============================================================
|
||
-- 可靠审计:本地 Outbox、RocketMQ 消费幂等和死信补偿
|
||
-- ============================================================
|
||
-- 可靠审计 Outbox、消费幂等和死信补偿增量(MySQL 8)
|
||
SET NAMES utf8mb4;
|
||
USE baiyue_audit;
|
||
|
||
DROP PROCEDURE IF EXISTS create_reliable_audit_outbox;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE create_reliable_audit_outbox(IN schema_name VARCHAR(64))
|
||
BEGIN
|
||
SET @ddl = CONCAT(
|
||
'CREATE TABLE IF NOT EXISTS \`', schema_name, '\`.sys_audit_outbox (',
|
||
'event_id VARCHAR(64) NOT NULL,event_type VARCHAR(64) NOT NULL,resource_type VARCHAR(64) NOT NULL,',
|
||
'resource_id VARCHAR(128) NULL,service_name VARCHAR(64) NULL,payload_json JSON NOT NULL,',
|
||
'status VARCHAR(16) NOT NULL DEFAULT ''PENDING'',attempt_count INT NOT NULL DEFAULT 0,',
|
||
'compensation_count INT NOT NULL DEFAULT 0,next_retry_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),',
|
||
'lease_owner VARCHAR(128) NULL,lease_until DATETIME(3) NULL,last_error VARCHAR(1000) NULL,',
|
||
'dead_at DATETIME(3) NULL,sent_at DATETIME(3) NULL,created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),',
|
||
'updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),',
|
||
'PRIMARY KEY(event_id),KEY idx_audit_outbox_publish(status,next_retry_at,lease_until,created_at),',
|
||
'KEY idx_audit_outbox_retention(status,sent_at)) ENGINE=InnoDB COMMENT=''可靠审计事件本地发送箱'''
|
||
);
|
||
PREPARE stmt FROM @ddl;
|
||
EXECUTE stmt;
|
||
DEALLOCATE PREPARE stmt;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL create_reliable_audit_outbox('baiyue_auth');
|
||
CALL create_reliable_audit_outbox('baiyue_iam');
|
||
CALL create_reliable_audit_outbox('baiyue_order');
|
||
CALL create_reliable_audit_outbox('baiyue_firstleg');
|
||
CALL create_reliable_audit_outbox('baiyue_warehouse');
|
||
DROP PROCEDURE IF EXISTS create_reliable_audit_outbox;
|
||
|
||
USE baiyue_audit;
|
||
DROP PROCEDURE IF EXISTS add_audit_event_id;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE add_audit_event_id()
|
||
BEGIN
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA='baiyue_audit' AND TABLE_NAME='sys_audit_log' AND COLUMN_NAME='event_id') THEN
|
||
ALTER TABLE sys_audit_log ADD COLUMN event_id VARCHAR(64) NULL COMMENT '审计事件全局唯一ID' AFTER id;
|
||
END IF;
|
||
IF NOT EXISTS (SELECT 1 FROM information_schema.STATISTICS
|
||
WHERE TABLE_SCHEMA='baiyue_audit' AND TABLE_NAME='sys_audit_log' AND INDEX_NAME='uk_audit_event_id') THEN
|
||
ALTER TABLE sys_audit_log ADD UNIQUE KEY uk_audit_event_id(event_id);
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL add_audit_event_id();
|
||
DROP PROCEDURE IF EXISTS add_audit_event_id;
|
||
|
||
CREATE TABLE IF NOT EXISTS sys_audit_dead_letter (
|
||
id BIGINT NOT NULL AUTO_INCREMENT,event_id VARCHAR(64) NOT NULL,payload_text LONGTEXT NOT NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'PENDING',retry_count INT NOT NULL DEFAULT 0,
|
||
next_retry_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),lease_owner VARCHAR(128) NULL,
|
||
lease_until DATETIME(3) NULL,last_error VARCHAR(1000) NULL,
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),processed_at DATETIME(3) NULL,
|
||
PRIMARY KEY(id),UNIQUE KEY uk_audit_dead_event(event_id),
|
||
KEY idx_audit_dead_retry(status,next_retry_at,lease_until)
|
||
) ENGINE=InnoDB COMMENT='审计消息死信补偿表';
|
||
|
||
SELECT 'PASS' AS migration_status,'可靠审计Outbox、幂等和死信补偿表已就绪' AS message;
|