5584 lines
342 KiB
SQL
5584 lines
342 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 '租户内唯一订单号',
|
||
inbound_code VARCHAR(40) 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 '买单或退税',
|
||
pricing_tax_mode VARCHAR(16) NULL COMMENT '报价包税维度:TAX_INCLUDED或TAX_EXCLUDED;独立于tax_mode',
|
||
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),
|
||
UNIQUE KEY uk_order_tenant_inbound_code (tenant_id, inbound_code),
|
||
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 '品牌',
|
||
product_length_cm DECIMAL(12,2) NULL COMMENT '产品长度(厘米)',
|
||
product_width_cm DECIMAL(12,2) NULL COMMENT '产品宽度(厘米)',
|
||
product_height_cm DECIMAL(12,2) NULL COMMENT '产品高度(厘米)',
|
||
shipment_id VARCHAR(64) NULL COMMENT '货物级 Amazon Shipment ID',
|
||
reference_id VARCHAR(64) NULL COMMENT '货物级 Amazon Reference ID',
|
||
product_image_file_id BIGINT UNSIGNED NULL COMMENT '文件中心产品图片逻辑ID',
|
||
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 '平台公共仓库固定使用 tenant_id=0',
|
||
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='平台公共仓库主数据表:统一归属平台作用域 tenant_id=0';
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_warehouse_address (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '仓库地址ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '平台公共仓库地址固定使用 tenant_id=0',
|
||
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 '平台公共仓库服务能力固定使用 tenant_id=0',
|
||
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,0,0,'CUS-001','深圳示例贸易有限公司','CUSTOMER','张三','13800138000','contact@example.com','CN','广东省','深圳市','宝安区','航城街道示例路1号','518000','ACTIVE')
|
||
ON DUPLICATE KEY UPDATE tenant_id=VALUES(tenant_id),data_scope_id=VALUES(data_scope_id),partner_name=VALUES(partner_name),status='ACTIVE';
|
||
INSERT INTO wh_partner_type(partner_id,tenant_id,data_scope_id,partner_type)
|
||
VALUES
|
||
(191000000000000001,0,0,'CUSTOMER'),
|
||
(191000000000000001,0,0,'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 '平台公共快递公司固定使用 tenant_id=0',
|
||
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='平台公共快递公司主数据,固定归属 tenant_id=0';
|
||
|
||
-- ============================================================================
|
||
-- 来源: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'");
|
||
CALL phase1_add_column('ord_order_cargo', 'product_length_cm', "DECIMAL(12,2) NULL COMMENT 'Product length in centimeters'");
|
||
CALL phase1_add_column('ord_order_cargo', 'product_width_cm', "DECIMAL(12,2) NULL COMMENT 'Product width in centimeters'");
|
||
CALL phase1_add_column('ord_order_cargo', 'product_height_cm', "DECIMAL(12,2) NULL COMMENT 'Product height in centimeters'");
|
||
CALL phase1_add_column('ord_order_cargo', 'shipment_id', "VARCHAR(64) NULL COMMENT 'Cargo Amazon Shipment ID'");
|
||
CALL phase1_add_column('ord_order_cargo', 'reference_id', "VARCHAR(64) NULL COMMENT 'Cargo Amazon Reference ID'");
|
||
CALL phase1_add_column('ord_order_cargo', 'product_image_file_id', "BIGINT UNSIGNED NULL COMMENT 'Product image logical file ID'");
|
||
|
||
UPDATE ord_order_cargo cargo
|
||
JOIN ord_order orders ON orders.id = cargo.order_id AND orders.tenant_id = cargo.tenant_id
|
||
SET cargo.shipment_id = COALESCE(NULLIF(cargo.shipment_id, ''), orders.shipment_id),
|
||
cargo.reference_id = COALESCE(NULLIF(cargo.reference_id, ''), orders.reference_id)
|
||
WHERE orders.destination_type = 'FBA'
|
||
AND ((cargo.shipment_id IS NULL OR cargo.shipment_id = '')
|
||
OR (cargo.reference_id IS NULL OR cargo.reference_id = ''));
|
||
|
||
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');
|
||
|
||
-- 平台公共仓储主数据和平台往来单位统一归平台作用域 0;订单自身仍按客户 tenant_id 隔离。
|
||
UPDATE wh_warehouse SET tenant_id = 0 WHERE tenant_id <> 0;
|
||
UPDATE wh_warehouse_address a
|
||
JOIN wh_warehouse w ON w.id = a.warehouse_id
|
||
SET a.tenant_id = w.tenant_id
|
||
WHERE a.tenant_id <> w.tenant_id;
|
||
UPDATE wh_service_capability c
|
||
JOIN wh_warehouse w ON w.id = c.warehouse_id
|
||
SET c.tenant_id = w.tenant_id
|
||
WHERE c.tenant_id <> w.tenant_id;
|
||
UPDATE wh_warehouse_address SET tenant_id = 0 WHERE tenant_id <> 0;
|
||
UPDATE wh_service_capability SET tenant_id = 0 WHERE tenant_id <> 0;
|
||
UPDATE wh_express_company SET tenant_id = 0 WHERE tenant_id <> 0;
|
||
UPDATE wh_partner SET tenant_id = 0, data_scope_id = 0
|
||
WHERE tenant_id <> 0 OR data_scope_id <> 0;
|
||
UPDATE wh_partner_type SET tenant_id = 0, data_scope_id = 0
|
||
WHERE tenant_id <> 0 OR data_scope_id <> 0;
|
||
|
||
DROP PROCEDURE IF EXISTS assert_platform_public_resource_scope;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE assert_platform_public_resource_scope()
|
||
BEGIN
|
||
IF (SELECT COUNT(*) FROM wh_warehouse WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM wh_warehouse_address WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM wh_service_capability WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM wh_express_company WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM wh_partner WHERE tenant_id <> 0 OR data_scope_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM wh_partner_type WHERE tenant_id <> 0 OR data_scope_id <> 0) > 0 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = 'Warehouse 迁移失败:平台公共仓储或往来单位仍有非0作用域';
|
||
END IF;
|
||
IF EXISTS (
|
||
SELECT 1 FROM wh_warehouse_address a
|
||
JOIN wh_warehouse w ON w.id = a.warehouse_id
|
||
WHERE a.tenant_id <> w.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM wh_service_capability c
|
||
JOIN wh_warehouse w ON w.id = c.warehouse_id
|
||
WHERE c.tenant_id <> w.tenant_id
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = 'Warehouse 迁移失败:仓库子表与父仓库平台归属不一致';
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL assert_platform_public_resource_scope();
|
||
DROP PROCEDURE IF EXISTS assert_platform_public_resource_scope;
|
||
|
||
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 '平台公共托盘固定使用 tenant_id=0',
|
||
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',
|
||
weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '托盘重量kg',
|
||
color VARCHAR(32) NOT NULL DEFAULT '' COMMENT '托盘颜色',
|
||
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_code (tenant_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='二期托盘基础资料和物理托盘实例';
|
||
|
||
-- 存量库补齐托盘重量、颜色字段(可重复执行)。
|
||
SET @pallet_weight_sql = IF((SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND column_name = 'weight_kg') = 0,
|
||
'ALTER TABLE wh_pallet ADD COLUMN weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT ''托盘重量kg'' AFTER capacity_cbm', 'SELECT 1');
|
||
PREPARE pallet_weight_stmt FROM @pallet_weight_sql; EXECUTE pallet_weight_stmt; DEALLOCATE PREPARE pallet_weight_stmt;
|
||
SET @pallet_color_sql = IF((SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND column_name = 'color') = 0,
|
||
'ALTER TABLE wh_pallet ADD COLUMN color VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''托盘颜色'' AFTER weight_kg', 'SELECT 1');
|
||
PREPARE pallet_color_stmt FROM @pallet_color_sql; EXECUTE pallet_color_stmt; DEALLOCATE PREPARE pallet_color_stmt;
|
||
|
||
CREATE TABLE IF NOT EXISTS wh_location (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '平台公共库位固定使用 tenant_id=0',
|
||
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 '平台公共库位预占固定使用 tenant_id=0',
|
||
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 '平台公共库位占用固定使用 tenant_id=0',
|
||
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;
|
||
|
||
-- 托盘、库位、预占和占用均为平台公共仓储资源,存量测试数据统一迁移到平台作用域 0。
|
||
UPDATE wh_pallet SET tenant_id = 0 WHERE tenant_id <> 0;
|
||
UPDATE wh_location SET tenant_id = 0 WHERE tenant_id <> 0;
|
||
UPDATE wh_location_reservation SET tenant_id = 0 WHERE tenant_id <> 0;
|
||
UPDATE wh_location_occupancy SET tenant_id = 0 WHERE tenant_id <> 0;
|
||
|
||
-- 托盘编码在平台公共作用域全局唯一;包含逻辑删除记录,编码不复用。
|
||
DROP PROCEDURE IF EXISTS assert_pallet_code_globally_unique;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE assert_pallet_code_globally_unique()
|
||
BEGIN
|
||
IF EXISTS (SELECT 1 FROM wh_pallet GROUP BY tenant_id, pallet_code HAVING COUNT(*) > 1) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '托盘编码迁移失败:不同仓库存在重复编码,请先清理';
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL assert_pallet_code_globally_unique();
|
||
DROP PROCEDURE IF EXISTS assert_pallet_code_globally_unique;
|
||
SET @pallet_code_index_sql = IF((SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND index_name = 'uk_pallet_tenant_warehouse_code') > 0,
|
||
'ALTER TABLE wh_pallet DROP INDEX uk_pallet_tenant_warehouse_code', 'SELECT 1');
|
||
PREPARE pallet_code_index_stmt FROM @pallet_code_index_sql; EXECUTE pallet_code_index_stmt; DEALLOCATE PREPARE pallet_code_index_stmt;
|
||
SET @pallet_code_index_sql = IF((SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND index_name = 'uk_pallet_tenant_code') = 0,
|
||
'ALTER TABLE wh_pallet ADD UNIQUE KEY uk_pallet_tenant_code (tenant_id, pallet_code)', 'SELECT 1');
|
||
PREPARE pallet_code_index_stmt FROM @pallet_code_index_sql; EXECUTE pallet_code_index_stmt; DEALLOCATE PREPARE pallet_code_index_stmt;
|
||
|
||
DROP PROCEDURE IF EXISTS assert_phase2_public_resource_scope;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE assert_phase2_public_resource_scope()
|
||
BEGIN
|
||
IF (SELECT COUNT(*) FROM wh_pallet WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM wh_location WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM wh_location_reservation WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM wh_location_occupancy WHERE tenant_id <> 0) > 0 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = 'Warehouse 二期迁移失败:托盘、库位、预占或占用仍有 tenant_id<>0';
|
||
END IF;
|
||
IF EXISTS (
|
||
SELECT 1 FROM wh_pallet p JOIN wh_warehouse w ON w.id = p.warehouse_id
|
||
WHERE p.tenant_id <> w.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM wh_location l JOIN wh_warehouse w ON w.id = l.warehouse_id
|
||
WHERE l.tenant_id <> w.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM wh_location_reservation r
|
||
JOIN wh_warehouse w ON w.id = r.warehouse_id
|
||
JOIN wh_pallet p ON p.id = r.pallet_id
|
||
JOIN wh_location l ON l.id = r.location_id
|
||
WHERE r.tenant_id <> w.tenant_id OR r.tenant_id <> p.tenant_id OR r.tenant_id <> l.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM wh_location_occupancy o
|
||
JOIN wh_warehouse w ON w.id = o.warehouse_id
|
||
JOIN wh_pallet p ON p.id = o.pallet_id
|
||
JOIN wh_location l ON l.id = o.location_id
|
||
JOIN wh_location_reservation r ON r.id = o.reservation_id
|
||
WHERE o.tenant_id <> w.tenant_id OR o.tenant_id <> p.tenant_id
|
||
OR o.tenant_id <> l.tenant_id OR o.tenant_id <> r.tenant_id
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = 'Warehouse 二期迁移失败:公共仓储资源父子归属不一致';
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL assert_phase2_public_resource_scope();
|
||
DROP PROCEDURE IF EXISTS assert_phase2_public_resource_scope;
|
||
|
||
-- ============================================================================
|
||
-- 来源: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;
|
||
|
||
-- 客户提交时由 Order 固定入仓码;审核通过后 Firstleg 沿用该码创建正式入库单。
|
||
SET @inbound_code_exists := (
|
||
SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'ord_order' AND column_name = 'inbound_code'
|
||
);
|
||
SET @inbound_code_sql := IF(@inbound_code_exists = 0,
|
||
'ALTER TABLE ord_order ADD COLUMN inbound_code VARCHAR(40) NULL COMMENT ''客户提交后生成的入仓码,草稿为空'' AFTER order_no',
|
||
'SELECT 1');
|
||
PREPARE inbound_code_statement FROM @inbound_code_sql;
|
||
EXECUTE inbound_code_statement;
|
||
DEALLOCATE PREPARE inbound_code_statement;
|
||
|
||
SET @inbound_code_index_exists := (
|
||
SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = 'ord_order'
|
||
AND index_name = 'uk_order_tenant_inbound_code'
|
||
);
|
||
SET @inbound_code_index_sql := IF(@inbound_code_index_exists = 0,
|
||
'ALTER TABLE ord_order ADD UNIQUE KEY uk_order_tenant_inbound_code (tenant_id, inbound_code)',
|
||
'SELECT 1');
|
||
PREPARE inbound_code_index_statement FROM @inbound_code_index_sql;
|
||
EXECUTE inbound_code_index_statement;
|
||
DEALLOCATE PREPARE inbound_code_index_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 '买单或退税模式',
|
||
pricing_tax_mode VARCHAR(16) NULL COMMENT '报价包税维度:TAX_INCLUDED/TAX_EXCLUDED',
|
||
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='二期头程入库单聚合根和列表查询快照';
|
||
|
||
UPDATE baiyue_order.ord_order o
|
||
LEFT JOIN baiyue_firstleg.fl_inbound_order i
|
||
ON i.tenant_id = o.tenant_id AND i.order_id = o.id AND i.deleted = 0
|
||
SET o.inbound_code = COALESCE(i.inbound_code, CONCAT('RK-', o.id))
|
||
WHERE o.deleted = 0
|
||
AND o.status <> 'DRAFT'
|
||
AND (o.submitted_at IS NOT NULL
|
||
OR o.status IN ('SUBMITTED', 'APPROVED', 'ACCEPTED', 'PROCESSING', 'COMPLETED'))
|
||
AND o.inbound_code IS NULL;
|
||
|
||
-- 从未提交的草稿或由草稿直接取消的订单不应拥有入仓码。
|
||
UPDATE baiyue_order.ord_order
|
||
SET inbound_code = NULL
|
||
WHERE deleted = 0
|
||
AND inbound_code IS NOT NULL
|
||
AND (status = 'DRAFT'
|
||
OR (status IN ('REJECTED', 'CANCELLED') AND submitted_at IS NULL));
|
||
|
||
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 '第三方测量明细唯一号,平台手工明细可为空',
|
||
box_code 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',
|
||
machine_no VARCHAR(64) NULL COMMENT '本次测量设备编号',
|
||
device_measured_at DATETIME(3) NULL COMMENT '本次设备测量时间',
|
||
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 '创建时间',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE 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),
|
||
UNIQUE KEY uk_measure_box_code (tenant_id, box_code),
|
||
CONSTRAINT fk_measure_item_batch FOREIGN KEY (measurement_id) REFERENCES fl_inbound_measurement (id)
|
||
) ENGINE=InnoDB COMMENT='入库长宽高和箱数测量明细';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_inbound_carton_label (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '实际箱唛头映射ID(雪花ID)',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '当前客户隔离ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
|
||
order_id BIGINT UNSIGNED NOT NULL COMMENT '订单服务订单ID快照',
|
||
inbound_detail_id BIGINT UNSIGNED NOT NULL COMMENT '订单货物明细ID,不建立跨库外键',
|
||
cargo_item_no INT UNSIGNED NOT NULL COMMENT '订单货物明细序号快照',
|
||
cargo_name VARCHAR(255) NULL COMMENT '货物名称快照',
|
||
detail_package_count INT UNSIGNED NOT NULL COMMENT '该订单货物明细箱数快照',
|
||
inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照',
|
||
box_code VARCHAR(80) NOT NULL COMMENT '固定二维码内容:入仓码#总箱数-箱下标',
|
||
total_carton_count INT UNSIGNED NOT NULL COMMENT '首次分配时整单总箱数',
|
||
carton_index INT UNSIGNED NOT NULL COMMENT '整单从1开始的稳定箱下标',
|
||
box_specification VARCHAR(255) NOT NULL COMMENT '订单箱规或货物明细描述快照',
|
||
length_cm DECIMAL(12,3) NULL COMMENT '下单箱规长度cm快照',
|
||
width_cm DECIMAL(12,3) NULL COMMENT '下单箱规宽度cm快照',
|
||
height_cm DECIMAL(12,3) NULL COMMENT '下单箱规高度cm快照',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '首次分配时间',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_carton_label_box_code (tenant_id, box_code),
|
||
UNIQUE KEY uk_carton_label_index (tenant_id, inbound_id, carton_index),
|
||
KEY idx_carton_label_detail (tenant_id, inbound_id, inbound_detail_id),
|
||
CONSTRAINT fk_carton_label_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (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,船司价格固定为0',
|
||
price_book_version_id BIGINT UNSIGNED NULL COMMENT '整表价格版本ID;历史兼容价格可为空',
|
||
rate_code VARCHAR(50) NOT NULL COMMENT '平台公共价格编码',
|
||
rate_version INT UNSIGNED NOT NULL COMMENT '价格版本号',
|
||
origin_warehouse_id BIGINT UNSIGNED NULL COMMENT '确认前可为空;确认后绑定平台公共起运仓逻辑ID',
|
||
origin_warehouse_code VARCHAR(64) NULL COMMENT '起运仓稳定编码',
|
||
origin_warehouse_name VARCHAR(128) NOT NULL COMMENT '起运仓名称快照',
|
||
business_type VARCHAR(32) NOT NULL COMMENT '业务或计费类型',
|
||
channel_code VARCHAR(64) NULL COMMENT '渠道编码',
|
||
price_model VARCHAR(32) NOT NULL DEFAULT 'FBA_WAREHOUSE_RATE' COMMENT '价格模型',
|
||
carrier_id BIGINT UNSIGNED NULL COMMENT '船司逻辑ID',
|
||
carrier_name VARCHAR(128) NULL COMMENT '历史承运商名称;渠道价格可为空',
|
||
destination_type VARCHAR(16) NULL COMMENT '目的地类型:FBA或OVERSEAS;REGION_WEIGHT_TIER区域阶梯行为空',
|
||
destination_code VARCHAR(32) NULL COMMENT 'FBA目的仓编码;区域阶梯模型为空',
|
||
destination_warehouse_id BIGINT UNSIGNED NULL COMMENT '平台海外仓稳定ID;不存环境专属ID',
|
||
destination_name VARCHAR(128) NULL COMMENT '目的仓名称快照',
|
||
region_code VARCHAR(16) NULL COMMENT '区域阶梯模型区域编码',
|
||
pricing_tax_mode VARCHAR(16) NULL COMMENT '报价包税维度;独立于订单tax_mode',
|
||
weight_from_kg DECIMAL(18,6) NULL COMMENT '区域阶梯起始计费重量KG',
|
||
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 '固定附加费',
|
||
source_sheet_name VARCHAR(128) NULL COMMENT '原始Excel Sheet',
|
||
source_row_number INT UNSIGNED NULL COMMENT '原始Excel行号',
|
||
source_destination_text VARCHAR(1000) NULL COMMENT '原始组合仓库或区域文本',
|
||
effective_from DATETIME(3) NOT NULL COMMENT '生效开始时间',
|
||
effective_to DATETIME(3) NULL COMMENT '生效结束时间',
|
||
status VARCHAR(24) NOT NULL DEFAULT 'ACTIVE' COMMENT '价格状态:PENDING_CONFIRMATION、ACTIVE或SUPERSEDED',
|
||
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_type, destination_code, destination_warehouse_id, charge_unit, status, effective_from, effective_to),
|
||
KEY idx_fba_rate_book (price_book_version_id, channel_code, origin_warehouse_id, price_model, status),
|
||
KEY idx_fba_rate_destination (price_book_version_id, channel_code, origin_warehouse_id, destination_type, destination_warehouse_id, destination_code),
|
||
KEY idx_fba_rate_region (price_book_version_id, channel_code, origin_warehouse_id, region_code, weight_from_kg)
|
||
) ENGINE=InnoDB COMMENT='船司FBA目的仓价格版本';
|
||
|
||
ALTER TABLE fl_carrier_fba_rate
|
||
MODIFY COLUMN status VARCHAR(24) NOT NULL DEFAULT 'ACTIVE'
|
||
COMMENT '价格状态:PENDING_CONFIRMATION、ACTIVE或SUPERSEDED';
|
||
|
||
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 NULL COMMENT '历史客户计费规则ID;渠道价格可为空',
|
||
charge_rule_version INT UNSIGNED NULL COMMENT '历史客户规则版本快照',
|
||
carrier_rate_id BIGINT UNSIGNED NOT NULL COMMENT '船司FBA价格ID',
|
||
carrier_rate_version INT UNSIGNED NOT NULL COMMENT '船司价格版本快照',
|
||
price_book_version_id BIGINT UNSIGNED NULL COMMENT '整表价格版本ID快照',
|
||
rule_code VARCHAR(50) 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 '订单买单或退税模式快照',
|
||
pricing_tax_mode VARCHAR(16) NULL COMMENT '报价包税维度快照',
|
||
rounding_scale TINYINT UNSIGNED NULL COMMENT '历史客户规则计费量保留位数快照',
|
||
rounding_mode VARCHAR(24) NULL COMMENT '历史客户规则舍入方式快照',
|
||
rule_effective_from DATETIME(3) 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 NULL COMMENT '历史承运商ID;渠道价格可为空',
|
||
carrier_name VARCHAR(128) NULL COMMENT '历史承运商名称;渠道价格可为空',
|
||
destination_type VARCHAR(16) NULL COMMENT '目的地类型快照:FBA或OVERSEAS',
|
||
destination_warehouse_id BIGINT UNSIGNED NULL COMMENT '海外仓或FBA目的仓ID快照',
|
||
destination_name VARCHAR(128) NULL COMMENT '目的仓名称快照',
|
||
destination_code VARCHAR(32) NULL COMMENT 'FBA仓编码快照;海外仓可为空',
|
||
rate_effective_from DATETIME(3) NOT NULL COMMENT '价格生效开始快照',
|
||
rate_effective_to DATETIME(3) NULL COMMENT '价格生效结束快照',
|
||
charge_mode VARCHAR(16) NULL COMMENT '计费口径:KG或CBM',
|
||
conversion_factor DECIMAL(18,6) 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 '平台公共仓储资源固定使用 0;tenant_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', 'box_code',
|
||
'VARCHAR(128) NULL COMMENT ''柏悦唛头箱号;设备单箱测量时同一客户内唯一'' AFTER external_detail_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', 'machine_no',
|
||
'VARCHAR(64) NULL COMMENT ''本次测量设备编号'' AFTER source_image_file_id');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'device_measured_at',
|
||
'DATETIME(3) NULL COMMENT ''本次设备测量时间'' AFTER machine_no');
|
||
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');
|
||
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'updated_at',
|
||
'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT ''最后更新时间'' AFTER created_at');
|
||
|
||
SET @has_measure_box_code_index = (
|
||
SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE()
|
||
AND table_name = 'fl_inbound_measurement_item'
|
||
AND index_name = 'uk_measure_box_code'
|
||
);
|
||
SET @phase2_measure_sql = IF(
|
||
@has_measure_box_code_index = 0,
|
||
'ALTER TABLE fl_inbound_measurement_item ADD UNIQUE KEY uk_measure_box_code (tenant_id, box_code)',
|
||
'SELECT 1'
|
||
);
|
||
PREPARE phase2_measure_statement FROM @phase2_measure_sql;
|
||
EXECUTE phase2_measure_statement;
|
||
DEALLOCATE PREPARE phase2_measure_statement;
|
||
|
||
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 '第三方未知/未解析主体哨兵值;不是平台客户记录或平台作用域,不得用于业务数据授权',
|
||
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='第三方测量开放接口原始请求、签名主体和处理结果留档';
|
||
|
||
-- 既有表也要同步未知主体 0 的语义,避免历史注释继续误导为真实租户。
|
||
SET @third_party_tenant_comment = '第三方未知/未解析主体哨兵值;不是平台客户记录或平台作用域,不得用于业务数据授权';
|
||
SET @ddl = IF(
|
||
(SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'fl_third_party_call_log'
|
||
AND column_name = 'tenant_id' AND column_comment = @third_party_tenant_comment) = 1,
|
||
'SELECT 1',
|
||
'ALTER TABLE fl_third_party_call_log MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''第三方未知/未解析主体哨兵值;不是平台客户记录或平台作用域,不得用于业务数据授权'''
|
||
);
|
||
PREPARE statement FROM @ddl; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
-- ============================================================================
|
||
-- 来源: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 '平台公共仓储资源固定使用 0;tenant_id 仍是客户隔离键' AFTER warehouse_id");
|
||
|
||
-- 仓储资源是平台公共主数据;存量分配快照统一迁移到平台作用域 0,再收口非空约束。
|
||
UPDATE fl_inbound_pallet_allocation
|
||
SET warehouse_resource_tenant_id = 0
|
||
WHERE warehouse_resource_tenant_id IS NULL OR warehouse_resource_tenant_id <> 0;
|
||
SET @resource_tenant_needs_modify = (SELECT COUNT(*) FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_inbound_pallet_allocation'
|
||
AND COLUMN_NAME = 'warehouse_resource_tenant_id'
|
||
AND (IS_NULLABLE = 'YES' OR COLUMN_COMMENT <> '平台公共仓储资源固定使用 0;tenant_id 仍是客户隔离键'));
|
||
SET @sql = IF(@resource_tenant_needs_modify > 0,
|
||
"ALTER TABLE fl_inbound_pallet_allocation MODIFY COLUMN warehouse_resource_tenant_id BIGINT UNSIGNED NOT NULL COMMENT '平台公共仓储资源固定使用 0;tenant_id 仍是客户隔离键'",
|
||
'SELECT 1');
|
||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||
|
||
DROP PROCEDURE IF EXISTS phase2_fba_add_column;
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_price_channel_catalog (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '渠道目录ID',
|
||
channel_code VARCHAR(64) NOT NULL COMMENT '稳定渠道编码',
|
||
display_name VARCHAR(128) NOT NULL COMMENT '平台渠道名称',
|
||
price_model VARCHAR(32) NOT NULL COMMENT '默认价格模型',
|
||
source_sheet_name VARCHAR(128) NOT NULL COMMENT '来源Sheet名称;海派为同一Sheet',
|
||
aliases_json JSON NOT NULL COMMENT '上传名称别名数组',
|
||
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' 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_price_channel_code (channel_code),
|
||
KEY idx_price_channel_status (status, price_model)
|
||
) ENGINE=InnoDB COMMENT='平台公共船期价格固定渠道目录';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_price_origin_alias (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '起运仓别名ID',
|
||
warehouse_code VARCHAR(64) NOT NULL COMMENT '平台仓库稳定编码,不存环境专属ID',
|
||
alias_name VARCHAR(128) NOT NULL COMMENT 'Excel起运仓名称别名',
|
||
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||
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_price_origin_alias (warehouse_code, alias_name),
|
||
KEY idx_price_origin_alias_name (alias_name, status)
|
||
) ENGINE=InnoDB COMMENT='价格表起运仓名称别名映射';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_price_warehouse_mapping (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '价格仓映射ID',
|
||
source_type VARCHAR(24) NOT NULL COMMENT '来源维度:ORIGIN_CODE或OVERSEAS_NAME',
|
||
source_value VARCHAR(128) NOT NULL COMMENT '解析后的来源仓编码或海外仓名称',
|
||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '固定平台公共仓库ID',
|
||
warehouse_code VARCHAR(64) NOT NULL COMMENT '平台仓库稳定编码快照',
|
||
warehouse_type VARCHAR(16) NOT NULL COMMENT 'DOMESTIC或OVERSEAS',
|
||
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||
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_price_warehouse_mapping_source (source_type, source_value),
|
||
KEY idx_price_warehouse_mapping_target (warehouse_id, status)
|
||
) ENGINE=InnoDB COMMENT='价格表来源仓与固定平台公共仓映射';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_price_book_version (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '整表价格版本ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '平台公共价格作用域固定为0',
|
||
version_no INT UNSIGNED NOT NULL COMMENT '整表版本号',
|
||
original_file_name VARCHAR(255) NOT NULL COMMENT '原始Excel文件名',
|
||
source_file_id BIGINT UNSIGNED NULL COMMENT 'File服务原始文件ID',
|
||
source_sha256 CHAR(64) NULL COMMENT '原始文件SHA-256',
|
||
status VARCHAR(24) NOT NULL DEFAULT 'PENDING_CONFIRMATION' COMMENT '待确认上传记录;ACTIVE/SUPERSEDED/FAILED',
|
||
blocking_error_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '阻断错误数',
|
||
warning_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '警告数',
|
||
parse_issues_json JSON NULL COMMENT '上传解析问题及待确认重新校验结果',
|
||
channel_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '解析渠道数',
|
||
rate_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '解析价格数',
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
published_by BIGINT UNSIGNED NULL,
|
||
published_at DATETIME(3) NULL COMMENT '确认并生效时间',
|
||
superseded_at DATETIME(3) NULL COMMENT '被下一版本替换时间',
|
||
updated_by BIGINT UNSIGNED NOT 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 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_price_book_version (tenant_id, version_no),
|
||
KEY idx_price_book_status (tenant_id, status, published_at),
|
||
KEY idx_price_book_source_hash (tenant_id, source_sha256)
|
||
) ENGINE=InnoDB COMMENT='平台公共船期价格整表版本';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_price_book_channel (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '版本渠道快照ID',
|
||
price_book_version_id BIGINT UNSIGNED NOT NULL COMMENT '整表价格版本ID',
|
||
channel_code VARCHAR(64) NOT NULL COMMENT '固定渠道编码',
|
||
channel_name VARCHAR(128) NOT NULL COMMENT '渠道名称快照',
|
||
price_model VARCHAR(32) NOT NULL COMMENT '价格模型快照',
|
||
source_sheet_name VARCHAR(128) NOT NULL COMMENT '原始Excel Sheet',
|
||
estimated_departure_date DATE NULL COMMENT '标准预计开船日期',
|
||
estimated_departure_text VARCHAR(128) NULL COMMENT '原始预计开船日期文本',
|
||
latest_warehouse_entry VARCHAR(128) NULL COMMENT '最晚进仓时间',
|
||
vessel_name VARCHAR(128) NULL COMMENT '船名',
|
||
voyage_no VARCHAR(64) NULL COMMENT '航次',
|
||
reference_transit VARCHAR(128) NULL COMMENT '参考时效',
|
||
surcharge_description VARCHAR(2000) NULL COMMENT '附加费说明,仅展示',
|
||
remark VARCHAR(2000) NULL COMMENT '渠道备注',
|
||
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
|
||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_price_book_channel (price_book_version_id, channel_code),
|
||
KEY idx_price_book_channel_code (channel_code, price_book_version_id)
|
||
|
||
) ENGINE=InnoDB COMMENT='价格版本渠道及船期快照';
|
||
|
||
INSERT INTO fl_price_channel_catalog
|
||
(id, channel_code, display_name, price_model, source_sheet_name, aliases_json, status)
|
||
VALUES
|
||
(1, 'MATSON_CLX_TRUCK', '美森正班海卡', 'FBA_WAREHOUSE_RATE', '美森正班海卡', JSON_ARRAY('美森正班海卡'), 'ACTIVE'),
|
||
(2, 'MATSON_MAX_TRUCK', '美森加班海卡', 'FBA_WAREHOUSE_RATE', '美森加班海卡', JSON_ARRAY('美森加班海卡'), 'ACTIVE'),
|
||
(3, 'EXX_TRUCK', 'EXX海卡', 'FBA_WAREHOUSE_RATE', 'EXX海卡', JSON_ARRAY('EXX海卡'), 'ACTIVE'),
|
||
(4, 'HEDE_TRUCK', '合德海卡', 'FBA_WAREHOUSE_RATE', '合德海卡', JSON_ARRAY('合德海卡'), 'ACTIVE'),
|
||
(5, 'EXX_RAIL_NY', '纽约EXX海铁', 'FBA_WAREHOUSE_RATE', '纽约EXX海铁', JSON_ARRAY('纽约EXX海铁'), 'ACTIVE'),
|
||
(6, 'OA_LA_TRUCK', '洛杉矶普船海卡', 'FBA_WAREHOUSE_RATE', '洛杉矶普船海卡', JSON_ARRAY('洛杉矶普船海卡'), 'ACTIVE'),
|
||
(7, 'OA_LA_FULL_TRUCK', '洛杉矶普船全卡', 'FBA_WAREHOUSE_RATE', '洛杉矶普船全卡', JSON_ARRAY('洛杉矶普船全卡'), 'ACTIVE'),
|
||
(8, 'OA_CHICAGO_RAIL', '芝加哥普船海铁', 'FBA_WAREHOUSE_RATE', '芝加哥普船海铁', JSON_ARRAY('芝加哥普船海铁'), 'ACTIVE'),
|
||
(9, 'OA_HOUSTON_TRUCK', '休斯顿普船海卡', 'FBA_WAREHOUSE_RATE', '休斯顿普船海卡', JSON_ARRAY('休斯顿普船海卡'), 'ACTIVE'),
|
||
(10, 'OA_NEW_YORK_TRUCK', '纽约普船海卡', 'FBA_WAREHOUSE_RATE', '纽约普船海卡', JSON_ARRAY('纽约普船海卡'), 'ACTIVE'),
|
||
(11, 'OA_SAVANNAH_TRUCK', '萨凡纳普船海卡', 'FBA_WAREHOUSE_RATE', '萨凡纳普船海卡', JSON_ARRAY('萨凡纳普船海卡'), 'ACTIVE'),
|
||
(12, 'MATSON_CLX_PARCEL', '美森正班海派', 'REGION_WEIGHT_TIER', '海派', JSON_ARRAY('美森正班海派'), 'ACTIVE'),
|
||
(13, 'MATSON_MAX_PARCEL', '美森加班海派', 'REGION_WEIGHT_TIER', '海派', JSON_ARRAY('美森加班海派'), 'ACTIVE'),
|
||
(14, 'HEDE_PARCEL', '合德海派', 'REGION_WEIGHT_TIER', '海派', JSON_ARRAY('合德海派'), 'ACTIVE'),
|
||
(15, 'OA_PARCEL', '普船海派', 'REGION_WEIGHT_TIER', '海派', JSON_ARRAY('普船海派'), 'ACTIVE')
|
||
ON DUPLICATE KEY UPDATE
|
||
display_name = VALUES(display_name), price_model = VALUES(price_model),
|
||
source_sheet_name = VALUES(source_sheet_name), aliases_json = VALUES(aliases_json), status = VALUES(status);
|
||
|
||
INSERT INTO fl_price_origin_alias (id, warehouse_code, alias_name, status)
|
||
VALUES
|
||
(1, 'CN-YIWU-01', '华东仓(义乌)', 'ACTIVE'),
|
||
(2, 'CN-YIWU-01', '义乌仓', 'ACTIVE'),
|
||
(3, 'CN-YIWU-01', '义乌', 'ACTIVE'),
|
||
(4, 'CN-DONGGUAN-01', '华南仓(深圳)', 'ACTIVE'),
|
||
(5, 'CN-DONGGUAN-01', '东莞仓', 'ACTIVE'),
|
||
(6, 'CN-DONGGUAN-01', '深圳仓', 'ACTIVE'),
|
||
(7, 'CN-DONGGUAN-01', '华南仓(深圳/东莞)', 'ACTIVE')
|
||
ON DUPLICATE KEY UPDATE status = VALUES(status);
|
||
|
||
INSERT INTO fl_price_warehouse_mapping
|
||
(id, source_type, source_value, warehouse_id, warehouse_code, warehouse_type, status)
|
||
VALUES
|
||
(1, 'ORIGIN_CODE', 'CN-YIWU-01', 193000000000200001, 'CN-YIWU-01', 'DOMESTIC', 'ACTIVE'),
|
||
(2, 'ORIGIN_CODE', 'CN-DONGGUAN-01', 193000000000200002, 'CN-DONGGUAN-01', 'DOMESTIC', 'ACTIVE'),
|
||
(3, 'OVERSEAS_NAME', '洛杉矶仓', 193000000000200003, 'US-LAX-01', 'OVERSEAS', 'ACTIVE'),
|
||
(4, 'OVERSEAS_NAME', '纽约仓', 193000000000200004, 'US-NYC-01', 'OVERSEAS', 'ACTIVE')
|
||
ON DUPLICATE KEY UPDATE
|
||
warehouse_id = VALUES(warehouse_id), warehouse_code = VALUES(warehouse_code),
|
||
warehouse_type = VALUES(warehouse_type), status = VALUES(status);
|
||
|
||
-- ============================================================================
|
||
-- 来源: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);
|
||
|
||
-- 客户尺寸计算配置权限;与 FBA 计费规则相互独立。
|
||
DROP PROCEDURE IF EXISTS unified_guard_dimension_config_permissions;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_guard_dimension_config_permissions()
|
||
BEGIN
|
||
IF EXISTS (
|
||
SELECT 1 FROM iam_permission
|
||
WHERE (id = 5102111 AND COALESCE(permission_code, '') <> 'firstleg:dimension-config:view')
|
||
OR (id = 5102112 AND COALESCE(permission_code, '') <> 'firstleg:dimension-config:edit')
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户尺寸计算配置权限固定ID已被其他权限码占用';
|
||
END IF;
|
||
IF EXISTS (
|
||
SELECT 1 FROM iam_permission
|
||
WHERE (permission_code = 'firstleg:dimension-config:view' AND id <> 5102111)
|
||
OR (permission_code = 'firstleg:dimension-config:edit' AND id <> 5102112)
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户尺寸计算配置权限码已绑定其他固定ID';
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL unified_guard_dimension_config_permissions();
|
||
DROP PROCEDURE IF EXISTS unified_guard_dimension_config_permissions;
|
||
|
||
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
|
||
(5102111, 0, 'PLATFORM', 'BUTTON', 5100010, 'firstleg:dimension-config:view',
|
||
'查看客户尺寸计算配置', NULL, NULL, 90, 'ACTIVE', 1, 0),
|
||
(5102112, 0, 'PLATFORM', 'BUTTON', 5100010, 'firstleg:dimension-config:edit',
|
||
'维护客户尺寸计算配置', NULL, NULL, 100, '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 r.id, p.id, 0
|
||
FROM iam_role r
|
||
JOIN iam_permission p
|
||
ON p.tenant_id = 0 AND p.app_code = 'PLATFORM'
|
||
AND p.permission_code IN ('firstleg:dimension-config:view', 'firstleg:dimension-config:edit')
|
||
WHERE r.tenant_id = 0 AND r.app_code = 'PLATFORM' AND r.role_code = 'PLATFORM_ADMIN'
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
INSERT INTO iam_role_permission (role_id, permission_id, tenant_id)
|
||
SELECT r.id, p.id, 0
|
||
FROM iam_role r
|
||
JOIN iam_permission p
|
||
ON p.tenant_id = 0 AND p.app_code = 'PLATFORM'
|
||
AND p.permission_code = 'firstleg:dimension-config:view'
|
||
WHERE r.tenant_id = 0 AND r.app_code = 'PLATFORM' AND r.role_code = 'ORDER_OPERATOR'
|
||
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_order', 'ord_order', 'pricing_tax_mode');
|
||
CALL unified_assert_column('baiyue_order', 'ord_order', 'inbound_code');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_inbound_pallet_allocation', 'warehouse_resource_tenant_id');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_inbound_order', 'pricing_tax_mode');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_inbound_measurement_item', 'external_detail_no');
|
||
CALL unified_assert_table('baiyue_firstleg', 'fl_price_channel_catalog');
|
||
CALL unified_assert_table('baiyue_firstleg', 'fl_price_origin_alias');
|
||
CALL unified_assert_table('baiyue_firstleg', 'fl_price_warehouse_mapping');
|
||
CALL unified_assert_table('baiyue_firstleg', 'fl_price_book_version');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_price_book_version', 'parse_issues_json');
|
||
CALL unified_assert_table('baiyue_firstleg', 'fl_price_book_channel');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_carrier_fba_rate', 'price_book_version_id');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_carrier_fba_rate', 'pricing_tax_mode');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_carrier_fba_rate', 'source_sheet_name');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_carrier_fba_rate', 'destination_type');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_carrier_fba_rate', 'destination_warehouse_id');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_carrier_fba_rate', 'destination_name');
|
||
CALL unified_assert_column('baiyue_firstleg', 'fl_inbound_fee', 'price_book_version_id');
|
||
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', 'firstleg:dimension-config:view',
|
||
'firstleg:dimension-config:edit', '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 <> 30 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:二期 IAM 权限资源未达到 30 项';
|
||
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;
|
||
|
||
-- 海外仓阶梯费用结构校验已完成;最终 PASS 统一在脚本末尾输出。
|
||
|
||
-- ============================================================
|
||
-- 二期:费用项目主数据与入库单应收应付费用明细
|
||
-- ============================================================
|
||
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='入库单应收应付费用明细';
|
||
|
||
-- 既有表同步字段注释:tenant_id 当前承载客户 ID,不是上级租户 ID。
|
||
SET @fee_tenant_comment = '当前客户ID(客户隔离键);物理字段名沿用 tenant_id,当前不表示上级租户';
|
||
SET @ddl = IF(
|
||
(SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'fl_fee_item'
|
||
AND column_name = 'tenant_id' AND column_comment = @fee_tenant_comment) = 1,
|
||
'SELECT 1',
|
||
'ALTER TABLE fl_fee_item MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL COMMENT ''当前客户ID(客户隔离键);物理字段名沿用 tenant_id,当前不表示上级租户'''
|
||
);
|
||
PREPARE statement FROM @ddl; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
SET @ddl = IF(
|
||
(SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_fee_detail'
|
||
AND column_name = 'tenant_id' AND column_comment = @fee_tenant_comment) = 1,
|
||
'SELECT 1',
|
||
'ALTER TABLE fl_inbound_fee_detail MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL COMMENT ''当前客户ID(客户隔离键);物理字段名沿用 tenant_id,当前不表示上级租户'''
|
||
);
|
||
PREPARE statement FROM @ddl; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
|
||
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);
|
||
|
||
-- 费用项目、入库费用明细及按钮权限结构校验延后至脚本末尾统一执行。
|
||
|
||
-- ============================================================
|
||
-- 可靠审计:本地 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='审计消息死信补偿表';
|
||
|
||
-- ============================================================
|
||
|
||
-- 2026-08-06 平台公共仓库正式主数据:固定作业仓 + FBA 地址库
|
||
-- 来源:warehouse/src/main/resources/db/warehouse-public-master-data.sql。必须位于最终 PASS 校验之前,可重复执行。
|
||
USE baiyue_warehouse;
|
||
|
||
-- 正式平台公共仓库主数据:固定作业仓 + FBA 地址库。
|
||
-- 来源:C:\Users\BY-OY\Downloads\FBA地址表.xls,只读清洗后生成。
|
||
-- 接受 252 条,拒绝 54 条;拒绝清单见 master-data/fba-public-addresses.rejected.csv。
|
||
-- 四个固定作业仓按通用占位地址写入;清单见 master-data/platform-fixed-warehouses.csv。
|
||
-- FBA 是目的地址主数据,不创建 RECEIVING、STORAGE、PICK_PACK、RETURN 等平台作业能力。
|
||
|
||
DROP TEMPORARY TABLE IF EXISTS tmp_wh_fixed_platform_warehouse;
|
||
CREATE TEMPORARY TABLE tmp_wh_fixed_platform_warehouse (
|
||
warehouse_id_seed BIGINT UNSIGNED NOT NULL,
|
||
address_id_seed BIGINT UNSIGNED NOT NULL,
|
||
warehouse_code VARCHAR(50) NOT NULL,
|
||
warehouse_name VARCHAR(120) NOT NULL,
|
||
warehouse_type VARCHAR(32) NOT NULL,
|
||
country_code CHAR(2) NOT NULL,
|
||
timezone VARCHAR(64) NOT NULL,
|
||
state_province VARCHAR(100) NOT NULL,
|
||
city VARCHAR(100) NOT NULL,
|
||
postal_code VARCHAR(20) NOT NULL,
|
||
address_line1 VARCHAR(255) NOT NULL,
|
||
PRIMARY KEY (warehouse_code),
|
||
UNIQUE KEY uk_tmp_fixed_warehouse_id_seed (warehouse_id_seed),
|
||
UNIQUE KEY uk_tmp_fixed_address_id_seed (address_id_seed)
|
||
) ENGINE=MEMORY DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
INSERT INTO tmp_wh_fixed_platform_warehouse
|
||
(warehouse_id_seed,address_id_seed,warehouse_code,warehouse_name,warehouse_type,country_code,timezone,state_province,city,postal_code,address_line1)
|
||
VALUES
|
||
(193000000000200001,193000000000300001,'CN-YIWU-01','义乌仓','DOMESTIC','CN','UTC+8','浙江省','义乌市','322000','义乌仓通用地址待维护'),
|
||
(193000000000200002,193000000000300002,'CN-DONGGUAN-01','东莞仓','DOMESTIC','CN','UTC+8','广东省','东莞市','523000','东莞仓通用地址待维护'),
|
||
(193000000000200003,193000000000300003,'US-LAX-01','洛杉矶仓','OVERSEAS','US','UTC-8','CA','Los Angeles','90001','Los Angeles warehouse generic address pending maintenance'),
|
||
(193000000000200004,193000000000300004,'US-NYC-01','纽约仓','OVERSEAS','US','UTC-5','NY','New York','10001','New York warehouse generic address pending maintenance');
|
||
|
||
DROP PROCEDURE IF EXISTS assert_wh_fixed_platform_warehouse_seed;
|
||
DELIMITER //
|
||
CREATE PROCEDURE assert_wh_fixed_platform_warehouse_seed()
|
||
BEGIN
|
||
IF (SELECT COUNT(*) FROM tmp_wh_fixed_platform_warehouse) <> 4 THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '固定平台仓源数量不是4';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM tmp_wh_fixed_platform_warehouse
|
||
WHERE warehouse_code <> UPPER(TRIM(warehouse_code))
|
||
OR warehouse_type NOT IN ('DOMESTIC', 'OVERSEAS')
|
||
OR country_code NOT IN ('CN', 'US')
|
||
OR TRIM(timezone) = ''
|
||
OR TRIM(city) = ''
|
||
OR TRIM(state_province) = ''
|
||
OR TRIM(address_line1) = ''
|
||
OR TRIM(postal_code) = ''
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '固定平台仓主数据存在未清洗或必填缺失记录';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM wh_warehouse existing
|
||
JOIN tmp_wh_fixed_platform_warehouse source
|
||
ON existing.id = source.warehouse_id_seed
|
||
AND (existing.tenant_id <> 0 OR existing.warehouse_code <> source.warehouse_code OR existing.deleted <> 0)
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '固定平台仓仓库种子ID与既有数据冲突';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM wh_warehouse_address existing
|
||
JOIN tmp_wh_fixed_platform_warehouse source
|
||
ON existing.id = source.address_id_seed
|
||
LEFT JOIN wh_warehouse parent
|
||
ON parent.id = existing.warehouse_id
|
||
AND parent.tenant_id = existing.tenant_id
|
||
WHERE existing.tenant_id <> 0
|
||
OR existing.deleted <> 0
|
||
OR parent.warehouse_code IS NULL
|
||
OR parent.warehouse_code <> source.warehouse_code
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '固定平台仓地址种子ID与既有数据冲突';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM wh_warehouse existing
|
||
JOIN tmp_wh_fixed_platform_warehouse source
|
||
ON existing.tenant_id = 0
|
||
AND existing.warehouse_code = source.warehouse_code
|
||
AND existing.deleted = 1
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '固定平台仓存在同编码已删除仓库,需人工确认后恢复或清理';
|
||
END IF;
|
||
END//
|
||
DELIMITER ;
|
||
CALL assert_wh_fixed_platform_warehouse_seed();
|
||
DROP PROCEDURE IF EXISTS assert_wh_fixed_platform_warehouse_seed;
|
||
|
||
INSERT INTO wh_warehouse (
|
||
id, tenant_id, warehouse_code, warehouse_name, warehouse_type, country_code, timezone,
|
||
contact_name, contact_phone, contact_email, status, remark,
|
||
created_by, created_at, updated_by, updated_at, deleted, version
|
||
)
|
||
SELECT
|
||
source.warehouse_id_seed,
|
||
0,
|
||
source.warehouse_code,
|
||
source.warehouse_name,
|
||
source.warehouse_type,
|
||
source.country_code,
|
||
source.timezone,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
'ACTIVE',
|
||
NULL,
|
||
NULL,
|
||
CURRENT_TIMESTAMP(3),
|
||
NULL,
|
||
CURRENT_TIMESTAMP(3),
|
||
0,
|
||
0
|
||
FROM tmp_wh_fixed_platform_warehouse source
|
||
ON DUPLICATE KEY UPDATE
|
||
warehouse_name = VALUES(warehouse_name),
|
||
warehouse_type = VALUES(warehouse_type),
|
||
country_code = VALUES(country_code),
|
||
timezone = VALUES(timezone),
|
||
updated_at = CURRENT_TIMESTAMP(3);
|
||
|
||
INSERT INTO wh_warehouse_address (
|
||
id, tenant_id, warehouse_id, address_type, country_code, state_province, city,
|
||
district, postal_code, address_line1, address_line2, latitude, longitude,
|
||
created_by, created_at, updated_by, updated_at, deleted, version
|
||
)
|
||
SELECT
|
||
source.address_id_seed,
|
||
0,
|
||
warehouse.id,
|
||
'OPERATING',
|
||
source.country_code,
|
||
source.state_province,
|
||
source.city,
|
||
NULL,
|
||
source.postal_code,
|
||
source.address_line1,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
CURRENT_TIMESTAMP(3),
|
||
NULL,
|
||
CURRENT_TIMESTAMP(3),
|
||
0,
|
||
0
|
||
FROM tmp_wh_fixed_platform_warehouse source
|
||
JOIN wh_warehouse warehouse
|
||
ON warehouse.tenant_id = 0
|
||
AND warehouse.warehouse_code = source.warehouse_code
|
||
AND warehouse.deleted = 0
|
||
ON DUPLICATE KEY UPDATE
|
||
tenant_id = VALUES(tenant_id);
|
||
|
||
-- 国内固定作业仓必须启用收货能力,FBA 目的地址仍不得创建作业能力。
|
||
INSERT INTO wh_service_capability (
|
||
id, tenant_id, warehouse_id, capability_code, capability_name, enabled, cutoff_time,
|
||
description, created_by, created_at, updated_by, updated_at, deleted, version
|
||
)
|
||
VALUES
|
||
(193000000000400001,0,193000000000200001,'RECEIVING','头程收货',1,'16:00:00',
|
||
'义乌仓头程订单收货能力',NULL,CURRENT_TIMESTAMP(3),NULL,CURRENT_TIMESTAMP(3),0,0),
|
||
(193000000000400002,0,193000000000200002,'RECEIVING','头程收货',1,'16:00:00',
|
||
'东莞仓头程订单收货能力',NULL,CURRENT_TIMESTAMP(3),NULL,CURRENT_TIMESTAMP(3),0,0)
|
||
ON DUPLICATE KEY UPDATE
|
||
capability_name = VALUES(capability_name),
|
||
enabled = VALUES(enabled),
|
||
cutoff_time = VALUES(cutoff_time),
|
||
description = VALUES(description),
|
||
deleted = 0,
|
||
updated_at = CURRENT_TIMESTAMP(3);
|
||
|
||
-- 平台托盘初始化主数据;内部状态仅供预占/占用,不作为平台维护字段。
|
||
INSERT INTO wh_pallet (
|
||
id, tenant_id, warehouse_id, pallet_code, pallet_type, capacity_cbm,
|
||
weight_kg, color, status, remark, created_by, updated_by
|
||
)
|
||
VALUES
|
||
(193000000000200101,0,193000000000200001,'TP-001','木托盘',1.200000,8.000,'黄色','AVAILABLE',NULL,0,0),
|
||
(193000000000200102,0,193000000000200001,'TP-002','胶托盘',2.400000,12.000,'黑色','AVAILABLE',NULL,0,0)
|
||
ON DUPLICATE KEY UPDATE
|
||
tenant_id = 0,
|
||
warehouse_id = VALUES(warehouse_id),
|
||
pallet_type = VALUES(pallet_type),
|
||
capacity_cbm = VALUES(capacity_cbm),
|
||
weight_kg = VALUES(weight_kg),
|
||
color = VALUES(color),
|
||
remark = VALUES(remark);
|
||
|
||
DROP TEMPORARY TABLE IF EXISTS tmp_wh_fba_public_master_data;
|
||
CREATE TEMPORARY TABLE tmp_wh_fba_public_master_data (
|
||
warehouse_id_seed BIGINT UNSIGNED NOT NULL,
|
||
address_id_seed BIGINT UNSIGNED NOT NULL,
|
||
warehouse_code VARCHAR(50) NOT NULL,
|
||
warehouse_name VARCHAR(120) NOT NULL,
|
||
state_province VARCHAR(100) NOT NULL,
|
||
city VARCHAR(100) NOT NULL,
|
||
postal_code VARCHAR(20) NOT NULL,
|
||
timezone VARCHAR(64) NOT NULL,
|
||
address_line1 VARCHAR(255) NOT NULL,
|
||
source_row INT NOT NULL,
|
||
PRIMARY KEY (warehouse_code),
|
||
UNIQUE KEY uk_tmp_fba_warehouse_id_seed (warehouse_id_seed),
|
||
UNIQUE KEY uk_tmp_fba_address_id_seed (address_id_seed)
|
||
) ENGINE=MEMORY DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||
|
||
INSERT INTO tmp_wh_fba_public_master_data
|
||
(warehouse_id_seed,address_id_seed,warehouse_code,warehouse_name,state_province,city,postal_code,timezone,address_line1,source_row)
|
||
VALUES
|
||
(193000000000000001,193000000000100001,'ABE2','ABE2','PA','Breinigsville','18031','UTC-5','705 Boulder Drive',238),
|
||
(193000000000000002,193000000000100002,'ABE3','ABE3','PA','Breinigsville','18031','UTC-5','650 Boulder Drive',237),
|
||
(193000000000000003,193000000000100003,'ABE4','ABE4','PA','Easton','18045','UTC-5','1610 Van Buren Road',134),
|
||
(193000000000000004,193000000000100004,'ABE5','ABE5','PA','Harrisburg','17112','UTC-5','6455 Allentown Boulevard',231),
|
||
(193000000000000005,193000000000100005,'ABE8','ABE8','NJ','Florence','08518','UTC-5','401 Independence Road 08518-2200',125),
|
||
(193000000000000006,193000000000100006,'ABQ2','ABQ2','NM','LOS LUNAS','87031','UTC-7','6251 Pioneer Trail NW',99),
|
||
(193000000000000007,193000000000100007,'ACY2','ACY2','NJ','BURLINGTON','08016','UTC-5','1101 E PEARL ST',84),
|
||
(193000000000000008,193000000000100008,'AFW1','AFW1','TX','FORT WORTH','76131','UTC-6','1851 NE LOOP 820',141),
|
||
(193000000000000009,193000000000100009,'AFW5','AFW5','TX','BALCH SPRINGS','75180-1636','UTC-6','12374 LAKE JUNE RD',27),
|
||
(193000000000000010,193000000000100010,'AKR1','AKR1','OH','Canton','44705','UTC-5','4747 Rebar Ave NE',148),
|
||
(193000000000000011,193000000000100011,'ALB1','ALB1','NY','Castleton','12033-9634','UTC-5','1835 US Route 9',174),
|
||
(193000000000000012,193000000000100012,'AMA1','AMA1','TX','Amarillo','79108','UTC-6','8590 NE 24th Avenue',129),
|
||
(193000000000000013,193000000000100013,'ATL2N','ATL2N','GA','Carrollton','30117','UTC-5','3101 N. Highway 27',31),
|
||
(193000000000000014,193000000000100014,'ATL3','ATL3','GA','Pendergrass','30567','UTC-5','445 Valentine Industrial Parkway',147),
|
||
(193000000000000015,193000000000100015,'ATL6','ATL6','GA','East Point','30344','UTC-5','4200 North Commerce',202),
|
||
(193000000000000016,193000000000100016,'AVP1','AVP1','PA','Hazle Township','18202-9361','UTC-5','550 Oak Ridge Road',233),
|
||
(193000000000000017,193000000000100017,'AVP3','AVP3','PA','GOULDSBORO','18424-9492','UTC-5','298 1ST AVE',232),
|
||
(193000000000000018,193000000000100018,'BDL1','BDL1','CT','Windsor','06095','UTC-5','801 Day Hill Rd.',289),
|
||
(193000000000000019,193000000000100019,'BFI1','BFI1','WA','Sumner','98390','UTC-8','1800 140th Avenue E.',208),
|
||
(193000000000000020,193000000000100020,'BFI3','BFI3','WA','Dupont','98327-9607','UTC-8','2700 Center Drive',207),
|
||
(193000000000000021,193000000000100021,'BFI7','BFI7','WA','Sumner','98390','UTC-8','1901 140th Ave E',206),
|
||
(193000000000000022,193000000000100022,'BJC1','BJC1','CO','AURORA','80019','UTC-7','6300 N Powhaton Road',11),
|
||
(193000000000000023,193000000000100023,'BNA1','BNA1','TN','Lebanon','37090','UTC-6','14840 Central Pike Suite 190',221),
|
||
(193000000000000024,193000000000100024,'BNA2','BNA2','TN','Lebanon','37090','UTC-6','500 Duke DR',131),
|
||
(193000000000000025,193000000000100025,'BNA3','BNA3','TN','Murfreesboro','37127','UTC-6','2020 Joe B Jackson Pkwy',140),
|
||
(193000000000000026,193000000000100026,'BNA4','BNA4','TN','Nashville','37217','UTC-6','50 airways Blvd',220),
|
||
(193000000000000027,193000000000100027,'BNA6','BNA6','TN','CLARKSVILLE','37040-5502','UTC-6','3875 GUTHRIE HWY',110),
|
||
(193000000000000028,193000000000100028,'BOS1','BOS1','NH','Nashua','03063','UTC-5','10 State St.',243),
|
||
(193000000000000029,193000000000100029,'BOS2','BOS2','MA','Drive Stoughton','02072','UTC-5','1000 Tech Centre',193),
|
||
(193000000000000030,193000000000100030,'BOS7','BOS7','MA','Fall River','02720','UTC-5','1180 Innovation Way',192),
|
||
(193000000000000031,193000000000100031,'BWI1','BWI1','VA','Sterling','20166-2058','UTC-5','45121 Global Plaza',242),
|
||
(193000000000000032,193000000000100032,'BWI2','BWI2','MD','Baltimore','21224','UTC-5','2010 Broening Hwy',241),
|
||
(193000000000000033,193000000000100033,'BWI4','BWI4','VA','CLEARBROOK','22624','UTC-5','165 Business Blvd',102),
|
||
(193000000000000034,193000000000100034,'CAE1','CAE1','SC','West Columbia','29172','UTC-5','4400 12TH STREET EXT',225),
|
||
(193000000000000035,193000000000100035,'CHA1','CHA1','TN','Chattanooga','37416','UTC-5','7200 Discovery Drive',223),
|
||
(193000000000000036,193000000000100036,'CHA2','CHA2','TN','Charleston','37310','UTC-5','225 Infinity Dr NW',222),
|
||
(193000000000000037,193000000000100037,'CHO1','CHO1','VA','FISHERSVILLE','22939','UTC-5','32 TRADER RD',75),
|
||
(193000000000000038,193000000000100038,'CLT2','CLT2','NC','Charlotte','28214-8082','UTC-5','10240 Old Dowd Rd',191),
|
||
(193000000000000039,193000000000100039,'CLT3','CLT3','NC','CONCORD','28027','UTC-5','6500 Davidson Hwy',114),
|
||
(193000000000000040,193000000000100040,'CMH2','CMH2','OH','Groveport','43125-9016','UTC-5','6050 Gateway Court',240),
|
||
(193000000000000041,193000000000100041,'CMH3','CMH3','OH','Monroe','45050-1848','UTC-5','700 GATEWAY BLVD',181),
|
||
(193000000000000042,193000000000100042,'CVG1','CVG1','KY','Hebron','41048','UTC-5','1155 Worldwide Blvd',262),
|
||
(193000000000000043,193000000000100043,'CVG2','CVG2','KY','Hebron','41048','UTC-5','1600 Worldwide Blvd',261),
|
||
(193000000000000044,193000000000100044,'CVG3','CVG3','KY','Hebron','41048','UTC-5','3680 Langley Dr.',260),
|
||
(193000000000000045,193000000000100045,'CVG5','CVG5','KY','Hebron','41048','UTC-5','2285 Litton Lane',259),
|
||
(193000000000000046,193000000000100046,'DCA6','DCA6','MD','BALTIMORE','21219','UTC-5','6001 Bethlehem Blvd',135),
|
||
(193000000000000047,193000000000100047,'DEN2','DEN2','CO','Aurora','80019','UTC-7','22205 East 19th Ave',123),
|
||
(193000000000000048,193000000000100048,'DEN8','DEN8','CO','Aurora','80018','UTC-7','21000 E 13th Ave',120),
|
||
(193000000000000049,193000000000100049,'DET1','DET1','MI','Livonia','48150-1543','UTC-5','39000 Amrhein Road',189),
|
||
(193000000000000050,193000000000100050,'DET2','DET2','MI','Shelby Township','48317-1318','UTC-5','50500 Mound Rd',182),
|
||
(193000000000000051,193000000000100051,'DFW5S','DFW5S','TX','Lancaster','75146','UTC-6','2500 E Belt Line Rd,',143),
|
||
(193000000000000052,193000000000100052,'DFW6','DFW6','TX','Coppell','75019','UTC-6','940 W Bethel Road',219),
|
||
(193000000000000053,193000000000100053,'DFW8','DFW8','TX','DFW Airport','75261','UTC-6','2700 Regent Blvd',217),
|
||
(193000000000000054,193000000000100054,'EWR4','EWR4','NJ','Robbinsville','08691','UTC-5','50 New Canton Way',256),
|
||
(193000000000000055,193000000000100055,'EWR5','EWR5','NJ','Avenel','07001','UTC-5','301 Blair Rd.',255),
|
||
(193000000000000056,193000000000100056,'EWR7','EWR7','NJ','Avenel','07001','UTC-5','301 Blair Rd.',254),
|
||
(193000000000000057,193000000000100057,'EWR9','EWR9','NJ','Carteret','07008','UTC-5','8003 Industrial Parkway',253),
|
||
(193000000000000058,193000000000100058,'FAT2','FAT2','CA','VISALIA','93291-1882','UTC-8','3315 N KELSEYST',117),
|
||
(193000000000000059,193000000000100059,'FOE1','FOE1','KS','KANSAS CITY','66109-3665','UTC-6','9400 LEAVENWORTH RD',176),
|
||
(193000000000000060,193000000000100060,'FTW1','FTW1','TX','Dallas','75241','UTC-6','33333 Lyndon B Johnson FREEWAY',212),
|
||
(193000000000000061,193000000000100061,'FTW2','FTW2','TX','Coppell','75019','UTC-6','2701 West Bethel Road',211),
|
||
(193000000000000062,193000000000100062,'FTW3','FTW3','TX','Fort Worth','76177-2517','UTC-6','15201 Heritage Pkwy',89),
|
||
(193000000000000063,193000000000100063,'FTW5','FTW5','TX','Forney','75126','UTC-6','1475 AKRON WAY',121),
|
||
(193000000000000064,193000000000100064,'FWA4','FWA4','IN','FORT WAYNE','46809-9771','UTC-5','9798 Smith Road',171),
|
||
(193000000000000065,193000000000100065,'GEG2','GEG2','WA','SPOKANE','99216','UTC-8','18007 E Garland Ave',151),
|
||
(193000000000000066,193000000000100066,'GEU2','GEU2','AZ','Glendale','85307','UTC-7','15301 West Northern Avenue',67),
|
||
(193000000000000067,193000000000100067,'GEU3','GEU3','AZ','BUCKEYE','85396','UTC-7','18900 W McDowell Road',78),
|
||
(193000000000000068,193000000000100068,'GEU5','GEU5','AZ','GOODYEAR','85395','UTC-7','4660 North Cotton Lane',68),
|
||
(193000000000000069,193000000000100069,'GSO1','GSO1','NC','KERNERSVILLE','27284','UTC-5','1656 OLD GREENSBORO RD',164),
|
||
(193000000000000070,193000000000100070,'GSP1','GSP1','SC','Spartanburg','29303','UTC-5','402 John Dodd Rd',224),
|
||
(193000000000000071,193000000000100071,'GYR2','GYR2','AZ','GOODYEAR','85395-7672','UTC-7','17341 W MINNEZONA AVE',188),
|
||
(193000000000000072,193000000000100072,'GYR3','GYR3','AZ','PHOENIX','85043-2356','UTC-7','8181 W ROOSEVELT ST',187),
|
||
(193000000000000073,193000000000100073,'HGR6','HGR6','MD','HAGERSTOWN','21740-7301','UTC-5','55 West Oak Ridge Drive',80),
|
||
(193000000000000074,193000000000100074,'HIA1','HIA1','PA','MIDDLETOWN','17057','UTC-5','3327 E Harrisburg Pik',87),
|
||
(193000000000000075,193000000000100075,'HLI2','HLI2','CA','HOLLISTER','95023','UTC-8','600 Ernie Drive',44),
|
||
(193000000000000076,193000000000100076,'HOU1','HOU1','TX','Humble','77338','UTC-6','8120 Humble Westfield Rd',216),
|
||
(193000000000000077,193000000000100077,'HOU2','HOU2','TX','Houston','77038-2324','UTC-6','10550 Ella Blvd.',215),
|
||
(193000000000000078,193000000000100078,'HOU3','HOU3','TX','Brookshire','77423','UTC-6','31555 Highway 90 E',214),
|
||
(193000000000000079,193000000000100079,'HOU8','HOU8','TX','FRESNO','77545','UTC-6','2303 Hurricane Lane',154),
|
||
(193000000000000080,193000000000100080,'HSV1','HSV1','AL','Madison','35756','UTC-6','7817 Greenbrier Road',142),
|
||
(193000000000000081,193000000000100081,'HSV2','HSV2','AL','MADISON','35756','UTC-6','28869 Fanning Dr NW',126),
|
||
(193000000000000082,193000000000100082,'IAH3','IAH3','TX','Houston','77032','UTC-6','15525 Milner Road',155),
|
||
(193000000000000083,193000000000100083,'IAZ1','IAZ1','AZ','GOODYEAR','85395-4515','UTC-7','4660 N COTTON LN 85395-4515 - GOODYEAR, AZ - United States',3),
|
||
(193000000000000084,193000000000100084,'ICT2','ICT2','KS','PARK CITY','67219','UTC-6','7130 N BROADWAY AVE',136),
|
||
(193000000000000085,193000000000100085,'IGA3','IGA3','GA','MACON','31216-6427','UTC-5','7001 Skipper Rd 31216-6427 MACON, GA - United States',2),
|
||
(193000000000000086,193000000000100086,'IGQ2','IGQ2','IL','University park','60484','UTC-6','23257 S. Central Avenue',152),
|
||
(193000000000000087,193000000000100087,'ILG1','ILG1','DE','NEW CASTLE','19720','UTC-5','780 S. DuPont Highway',119),
|
||
(193000000000000088,193000000000100088,'IMO1','IMO1','MO','LIBERTY','64068-8933','UTC-6','2361 S Withers RD',10),
|
||
(193000000000000089,193000000000100089,'IMS1','IMS1','MS','OLIVE BRANCH','38654','UTC-6','IMS1-11505 Progress Way,38654-2510,OLIVE BRANCH,MS,US',6),
|
||
(193000000000000090,193000000000100090,'INC1','INC1','NC','FAYETTEVILLE','28303-2215','UTC-5','6309 Bragg Blvd 28303-2215 - FAYETTEVILLE, NC - United States',5),
|
||
(193000000000000091,193000000000100091,'IND2','IND2','IN','Plainfield','46168-7442','UTC-5','715 Airtech Pkwy',88),
|
||
(193000000000000092,193000000000100092,'IND4','IND4','IN','Indianapolis','46231','UTC-5','710 S. Girls School Rd',276),
|
||
(193000000000000093,193000000000100093,'IND5','IND5','IN','Plainfield','46168','UTC-5','800 Perry Road',275),
|
||
(193000000000000094,193000000000100094,'IND6','IND6','IN','Jeffersonville','47130','UTC-5','1453 E 10th St',274),
|
||
(193000000000000095,193000000000100095,'IND9','IND9','IN','GREENWOOD','46143-7830','UTC-5','1151 S GRAHAM RD',173),
|
||
(193000000000000096,193000000000100096,'ITX3','ITX3','TX','AMARILLO','79108-7749','UTC-6','ITX3-8590 NE 24th Ave,79108-7749,AMARILLO,TX,US',9),
|
||
(193000000000000097,193000000000100097,'IUSF','IUSF','TX','DALLAS','75241','UTC-6','3351 Balmorhea Dr',22),
|
||
(193000000000000098,193000000000100098,'IUSJ','IUSJ','CA','BEAUMONT','92223','UTC-8','36900 West 4th Street',69),
|
||
(193000000000000099,193000000000100099,'IUSP','IUSP','CA','HESPERIA,','92344','UTC-8','8140 Caliente Rd',74),
|
||
(193000000000000100,193000000000100100,'IUSQ','IUSQ','CA','REDLANDS','92374','UTC-8','2125 W San Bernardino Ave',70),
|
||
(193000000000000101,193000000000100101,'IUSR','IUSR','SC','COWPENS','29330','UTC-5','1120 Mt Olive Rd',40),
|
||
(193000000000000102,193000000000100102,'IUST','IUST','PA','GREENCASTLE','17225','UTC-5','3PL AWD (Greencastle, PA, US) 15651 Greenmount RdGREENCASTLE, PA 17225 United States',39),
|
||
(193000000000000103,193000000000100103,'IUSW','IUSW','CA','Hesperia','92344','UTC-8','8130 Caliente Rd 92344 - Hesperia, CA - United States',33),
|
||
(193000000000000104,193000000000100104,'IUTE','IUTE','AZ','GOODYEAR','85338','UTC-7','16155 W Elwood St',21),
|
||
(193000000000000105,193000000000100105,'IUTJ','IUTJ','CA','Fontana','92335','UTC-8','9253 Dreamland Drive 92335 - Fontana, CA - United',8),
|
||
(193000000000000106,193000000000100106,'IUTL','IUTL','CA','Moreno Valley','92551','UTC-8','24405 Krameria Ave 92551 - Moreno Valley, CA - United States',7),
|
||
(193000000000000107,193000000000100107,'IWA6','IWA6','WA','PASCO','99301-6161','UTC-8','1202 S Road 40 E 99301-6161 - PASCO, WA - United States',4),
|
||
(193000000000000108,193000000000100108,'JOT1','JOT1','CA','SAN BERNARDINO','92408','UTC-8','1494 S WATERMAN AVE',72),
|
||
(193000000000000109,193000000000100109,'JVL1','JVL1','WI','BELOIT','53511','UTC-6','1255 Gateway Blvd',150),
|
||
(193000000000000110,193000000000100110,'KRB4','KRB4','CA','PERRIS','92571-9722','UTC-8','4501 PATTERSON AVE',178),
|
||
(193000000000000111,193000000000100111,'KY1','KY1','KY','Shepherdsville','40165','UTC-5','120 Velocity Way.,',161),
|
||
(193000000000000112,193000000000100112,'LAN2','LAN2','MI','LANSING','48917','UTC-5','6500 W Mt Hope Hwy',100),
|
||
(193000000000000113,193000000000100113,'LAS1','LAS1','NV','HENDERSON','89044','UTC-8','12300 Bermuda Road',247),
|
||
(193000000000000114,193000000000100114,'LAS2','LAS2','NV','Las Vegas','89030','UTC-8','3837 Bay Lake Trail, Suite 111 North',246),
|
||
(193000000000000115,193000000000100115,'LAS6','LAS6','NV','Las Vegas','89115','UTC-8','4550 Nexus Way',132),
|
||
(193000000000000116,193000000000100116,'LAX2T','LAX2T','CA','CHINO','91708','UTC-8','6730 Kimball Ave',162),
|
||
(193000000000000117,193000000000100117,'LAX9','LAX9','CA','FONTANA','92337','UTC-8','11263 Oleander Ave',183),
|
||
(193000000000000118,193000000000100118,'LBE1','LBE1','PA','Greensburg','15605','UTC-5','165 Glen Fox Road',86),
|
||
(193000000000000119,193000000000100119,'LEX1','LEX1','KY','Lexington','40511','UTC-5','1850 Mercer RD',268),
|
||
(193000000000000120,193000000000100120,'LEX2','LEX2','KY','Lexington','40511','UTC-5','172 Trade St.',267),
|
||
(193000000000000121,193000000000100121,'LFT1','LFT1','LA','CARENCRO','70520-5976','UTC-6','3550 NE EVANGELINE TRWY',107),
|
||
(193000000000000122,193000000000100122,'LGB3','LGB3','CA','Eastvale','91752','UTC-8','4950 Goodman Way',291),
|
||
(193000000000000123,193000000000100123,'LGB4','LGB4','CA','Redlands','92374','UTC-8','27517 Pioneer Avenue',292),
|
||
(193000000000000124,193000000000100124,'LGB6','LGB6','CA','Riverside','92518-1513','UTC-8','20901 Krameria Ave',293),
|
||
(193000000000000125,193000000000100125,'LGB8','LGB8','CA','Rialto','92376','UTC-8','1568 N Linden Ave',294),
|
||
(193000000000000126,193000000000100126,'LIT2','LIT2','AR','NORTH LITTLE ROCK','72117','UTC-6','13001 HIGHWAY 70',106),
|
||
(193000000000000127,193000000000100127,'MCC1','MCC1','CA','RANCHO CORDOVA','95742','UTC-8','3300 Rancho Cordova Pkwy 95742 - RANCHO CORDOVA, CA - United States',32),
|
||
(193000000000000128,193000000000100128,'MCE1','MCE1','CA','TURLOCK','95380','UTC-8','FULKERTH RD',157),
|
||
(193000000000000129,193000000000100129,'MCI1','MCI1','KS','Lenexa','66219','UTC-6','113th St & Renner Blvd.',271),
|
||
(193000000000000130,193000000000100130,'MCI4','MCI4','MO','KANSAS CITY','64163','UTC-6','MCI4 - 10501 NW 136th Street',12),
|
||
(193000000000000131,193000000000100131,'MCO2','MCO2','FL','Deltona','32725-2610','UTC-5','2600 N Normandy Blvd',115),
|
||
(193000000000000132,193000000000100132,'MDT1','MDT1','PA','Carlisle','17015','UTC-5','2Ames Drive',230),
|
||
(193000000000000133,193000000000100133,'MDT4','MDT4','PA','York','17408','UTC-5','5125 Commerce Drive',128),
|
||
(193000000000000134,193000000000100134,'MDW2','MDW2','IL','Joliet','60433-3280','UTC-6','250 Emerald Drive',200),
|
||
(193000000000000135,193000000000100135,'MDW6','MDW6','IL','ROMEOVILLE','60446-6529','UTC-6','1125 W REMINGTON BLVD ROMEOVILLE',199),
|
||
(193000000000000136,193000000000100136,'MDW7','MDW7','IL','Monee','60449','UTC-6','6605 Monee Manhattan Road',198),
|
||
(193000000000000137,193000000000100137,'MDW8','MDW8','IL','Waukegan','60085','UTC-6','1750 Bridge Drive',197),
|
||
(193000000000000138,193000000000100138,'MDW9','MDW9','IL','Aurora','60502','UTC-6','2865 Duke Parkway',196),
|
||
(193000000000000139,193000000000100139,'MEM1','MEM1','TN','Memphis','38118','UTC-6','3292 E Holmes Rd',163),
|
||
(193000000000000140,193000000000100140,'MEM6','MEM6','MS','OLIVE BRANCH','38654','UTC-6','11505 Progress Way',118),
|
||
(193000000000000141,193000000000100141,'MGE3','MGE3','GA','Jefferson','30549-2010','UTC-5','808 Hog Mountain Road',201),
|
||
(193000000000000142,193000000000100142,'MIT2','MIT2','CA','SHAFTER','93263','UTC-8','5408 Express Avenue',77),
|
||
(193000000000000143,193000000000100143,'MKC4','MKC4','KS','Edgerton','66021-9588','UTC-6','19645 Waverly Rd',270),
|
||
(193000000000000144,193000000000100144,'MKC6','MKC6','KS','Kansas City','66102','UTC-6','6925 Riverview Avenue',269),
|
||
(193000000000000145,193000000000100145,'MKE1','MKE1','WI','Kenosha','53144','UTC-6','3501 120th Ave',203),
|
||
(193000000000000146,193000000000100146,'MQJ1','MQJ1','IN','GREENFIELD','46140','UTC-5','4412 W 300 RD N',94),
|
||
(193000000000000147,193000000000100147,'MSP1','MSP1','MN','Shakopee','55379','UTC-6','2601 4th Avenue East',190),
|
||
(193000000000000148,193000000000100148,'NJ3','NJ3','NJ','Pedricktown','08067','UTC-5','3 Sorbello Way',17),
|
||
(193000000000000149,193000000000100149,'OAK3','OAK3','CA','Patterson','95363-8876','UTC-8','255 Park Center Drive',299),
|
||
(193000000000000150,193000000000100150,'OAK4','OAK4','CA','Tracy','95304-9370','UTC-8','1555 N. Chrisman Rd',300),
|
||
(193000000000000151,193000000000100151,'OKC2','OKC2','OK','OKLAHOMA CITY','73159','UTC-6','8991 S PORTLAND AVENUE',133),
|
||
(193000000000000152,193000000000100152,'OLM1','OLM1','WA','OLYMPIA','98516','UTC-8','3300 HOGUM BAY RD NE 98516-3111 - OLYMPIA, WA - United States',19),
|
||
(193000000000000153,193000000000100153,'ONT2','ONT2','CA','San Bernardino','92408','UTC-8','1910 E Central Ave',303),
|
||
(193000000000000154,193000000000100154,'ONT6','ONT6','CA','Moreno Valley','92551-9561','UTC-8','24208 San Michele Rd',302),
|
||
(193000000000000155,193000000000100155,'ONT8','ONT8','CA','Moreno Valley','92551-9534','UTC-8','24300 Nandina Ave',301),
|
||
(193000000000000156,193000000000100156,'ONT9','ONT9','CA','Redlands','92374','UTC-8','2125 W. San Bernandino Ave',298),
|
||
(193000000000000157,193000000000100157,'ORD2','ORD2','IL','CHANNAHON','60410-8758','UTC-6','23714 W Amoco Rd',103),
|
||
(193000000000000158,193000000000100158,'ORD6','ORD6','IL','Wood Dale','60191','UTC-6','1250 N Mittel Blvd',195),
|
||
(193000000000000159,193000000000100159,'ORF2','ORF2','VA','CHESAPEAKE','23321-1425','UTC-5','ORF2 - 5045 PORTSMOUTH BLVD',113),
|
||
(193000000000000160,193000000000100160,'PBI3','PBI3','FL','Jacksonville','32206','UTC-5','21 Jump Street',81),
|
||
(193000000000000161,193000000000100161,'PDX7','PDX7','OR','Salem','97317','UTC-8','4775 Depot Ct SE',127),
|
||
(193000000000000162,193000000000100162,'PHL1','PHL1','DE','New Castle','19720','UTC-5','1 Centerpoint Blvd.',288),
|
||
(193000000000000163,193000000000100163,'PHL3','PHL3','DE','New Castle','19720','UTC-5','1600 Johnson Way',287),
|
||
(193000000000000164,193000000000100164,'PHL4','PHL4','PA','Carlisle','17015','UTC-5','21 Roadway Dr',236),
|
||
(193000000000000165,193000000000100165,'PHL5','PHL5','PA','Lewisberry','17339','UTC-5','500 McCarthy Dr',235),
|
||
(193000000000000166,193000000000100166,'PHL5S','PHL5S','PA','Greencastle','17225','UTC-5','1915 Ebberts Spg Ct, Greencastle, PA 17225',20),
|
||
(193000000000000167,193000000000100167,'PHL6','PHL6','PA','Carlisle','17015','UTC-5','675 Allen Rd.',234),
|
||
(193000000000000168,193000000000100168,'PHL7','PHL7','DE','Middletown','19709','UTC-5','560 Merrimac Ave',286),
|
||
(193000000000000169,193000000000100169,'PHL8','PHL8','DE','Middletown','19709','UTC-5','727 N Broad St',285),
|
||
(193000000000000170,193000000000100170,'PHX3','PHX3','AZ','Phoenix','85043','UTC-7','6835 West Buckeye Road',307),
|
||
(193000000000000171,193000000000100171,'PHX5','PHX5','AZ','Goodyear','85338','UTC-7','16920 W Commerce Drive',306),
|
||
(193000000000000172,193000000000100172,'PHX6','PHX6','AZ','Phoenix','85043','UTC-7','4750 West Mohave St',305),
|
||
(193000000000000173,193000000000100173,'PHX7','PHX7','AZ','Phoenix','85043','UTC-7','800 N 75th Ave',304),
|
||
(193000000000000174,193000000000100174,'PIT1','PIT1','PA','Pittsburgh','15205','UTC-5','2250 Roswell Drive',229),
|
||
(193000000000000175,193000000000100175,'PIT2','PIT2','PA','IMPERIAL','15126-1002','UTC-5','1200 Westport Rd',158),
|
||
(193000000000000176,193000000000100176,'POC1','POC1','CA','FONTANA','92336-1123','UTC-8','4121 LYTLE CREEK RD',46),
|
||
(193000000000000177,193000000000100177,'POC2','POC2','CA','ONTARIO','91761','UTC-8','4000 South Hamner Avenue',38),
|
||
(193000000000000178,193000000000100178,'POC3','POC3','CA','JURUPA VALLEY','92509','UTC-8','6120 Clinker Drive',45),
|
||
(193000000000000179,193000000000100179,'PPO4','PPO4','IN','MERRILLVILLE','46410','UTC-6','9850 Mississippi Street',49),
|
||
(193000000000000180,193000000000100180,'PSC2','PSC2','WA','PASCO','99301','UTC-8','1351 S Road 40 E',93),
|
||
(193000000000000181,193000000000100181,'PSP3','PSP3','CA','DESERT HOT SPRINGS','92240','UTC-8','64165 19th AVE',28),
|
||
(193000000000000182,193000000000100182,'QXY5','QXY5','CA','STOCKTON','95215','UTC-8','4532 NEWCASTLE RD',71),
|
||
(193000000000000183,193000000000100183,'QXY8','QXY8','CA','FRESNO','93725-1962','UTC-8','3611 S NORTHPOINTE DR',35),
|
||
(193000000000000184,193000000000100184,'QZZ7','QZZ7','AZ','MESA','85212-9608','UTC-7','8560 E ELLIOT RD',14),
|
||
(193000000000000185,193000000000100185,'RDU2','RDU2','NC','Smithfield','27577','UTC-5','2150 US HWY 70 Business West',146),
|
||
(193000000000000186,193000000000100186,'RDU4','RDU4','NC','FAYETTEVILLE','28303','UTC-5','6309 Bragg Blvd',95),
|
||
(193000000000000187,193000000000100187,'RFD2','RFD2','IL','Huntley','60142','UTC-6','11500 Freeman Road',145),
|
||
(193000000000000188,193000000000100188,'RFD4','RFD4','IL','HUNTLEY','60142','UTC-6','11400 Venture Court 60142-8075 - HUNTLEY, IL - United States',16),
|
||
(193000000000000189,193000000000100189,'RIC1','RIC1','VA','Petersburg','23803','UTC-5','5000 Commerce Way',210),
|
||
(193000000000000190,193000000000100190,'RIC2','RIC2','VA','Chester','23836','UTC-5','1901 Meadowville Technology Pkwy',209),
|
||
(193000000000000191,193000000000100191,'RMN3','RMN3','VA','Fredericksburg','22406','UTC-5','220 Centreport Parkway',144),
|
||
(193000000000000192,193000000000100192,'RNO1','RNO1','NV','Fernley','89408','UTC-8','1600 East Newlands RD',248),
|
||
(193000000000000193,193000000000100193,'RNO2','RNO2','NV','Reno','85906','UTC-8','8000 North Virginia Street',245),
|
||
(193000000000000194,193000000000100194,'RNO4','RNO4','NV','Reno','89506','UTC-8','8000 North Virginia Street',244),
|
||
(193000000000000195,193000000000100195,'RYY2','RYY2','GA','White','30184','UTC-5','1250 Cassville White Road,',73),
|
||
(193000000000000196,193000000000100196,'SAT1','SAT1','TX','Schertz','78154-1461','UTC-6','6000 Enterprise Avenue',218),
|
||
(193000000000000197,193000000000100197,'SAT4','SAT4','TX','SAN ANTONIO','78245','UTC-6','10384 W US HIGHWAY 90',149),
|
||
(193000000000000198,193000000000100198,'SAT6','SAT6','TX','SAN MARCOS','78666','UTC-6','1346 Fortuna Road 78666-0001 - SAN MARCOS, TX - United States',15),
|
||
(193000000000000199,193000000000100199,'SAV3','SAV3','GA','Macon','31216-6427','UTC-5','7001 Skipper Rd',98),
|
||
(193000000000000200,193000000000100200,'SBD1','SBD1','CA','BLOOMINGTON','92316-3819','UTC-8','3388 S Cactus Ave',185),
|
||
(193000000000000201,193000000000100201,'SBD2','SBD2','CA','SAN BERNARDINO','92408-2805','UTC-8','1494 S WATERMAN AVE',179),
|
||
(193000000000000202,193000000000100202,'SCK1','SCK1','CA','STOCKTON','95215','UTC-8','4532 NEWCASTLE RD',97),
|
||
(193000000000000203,193000000000100203,'SCK3','SCK3','CA','MANTECA','95336','UTC-8','3565 N AIRPORT WAY MANTECA',60),
|
||
(193000000000000204,193000000000100204,'SCK4','SCK4','CA','STOCKTON','95215-8354','UTC-8','6001 S AUSTIN RD',186),
|
||
(193000000000000205,193000000000100205,'SCK8','SCK8','CA','OAKLEY','94561-2677','UTC-8','4700 WILBUR AVE',104),
|
||
(193000000000000206,193000000000100206,'SDF1','SDF1','KY','Campbellsville','42718','UTC-5','1050 South Columbia AVE',266),
|
||
(193000000000000207,193000000000100207,'SDF2','SDF2','KY','Watterson Park','40218','UTC-5','4360 Robards Ln',265),
|
||
(193000000000000208,193000000000100208,'SDF4','SDF4','KY','Shepherdsville','40165','UTC-5','376 Zappos.com Blvd',264),
|
||
(193000000000000209,193000000000100209,'SDF6','SDF6','KY','Shepherdsville','40165','UTC-5','271 Omega Pkwy',263),
|
||
(193000000000000210,193000000000100210,'SDF7','SDF7','KY','Shepherdsville','40165','UTC-5','300 Omicron Court',258),
|
||
(193000000000000211,193000000000100211,'SDF8','SDF8','IN','Jeffersonville','47130','UTC-5','900 Patrol Rd',273),
|
||
(193000000000000212,193000000000100212,'SDF9','SDF9','KY','Shepherdsville','40165','UTC-5','100 W. Thomas P. Echols Lane',257),
|
||
(193000000000000213,193000000000100213,'SEA6','SEA6','WA','South Seattle','98144','UTC-8','2646 Rainier Ave.',205),
|
||
(193000000000000214,193000000000100214,'SEA8','SEA8','WA','Northeast Bellevue','98005','UTC-8','1475 124th Avenue',204),
|
||
(193000000000000215,193000000000100215,'SJC7','SJC7','CA','Tracy','95377-8906','UTC-8','188 Mountain House Parkway',295),
|
||
(193000000000000216,193000000000100216,'SLC2','SLC2','UT','West Jordan','84081','UTC-7','7148 W. Old Bingham Hwy',153),
|
||
(193000000000000217,193000000000100217,'SLC3','SLC3','UT','SALT LAKE CITY','84116-4413','UTC-7','355 N JOHN GLENN RD',13),
|
||
(193000000000000218,193000000000100218,'SMF3','SMF3','CA','Stockton','95206-8202','UTC-8','3923 S B ST',184),
|
||
(193000000000000219,193000000000100219,'SMF6','SMF6','CA','SACRAMENTO','95837-9109','UTC-8','4930 ALLBAUGH DR',105),
|
||
(193000000000000220,193000000000100220,'SNA4','SNA4','CA','Rialto','92376-3009','UTC-8','2496 W Walnut Ave',296),
|
||
(193000000000000221,193000000000100221,'STL3','STL3','MO','REPUBLIC','65738-2779','UTC-6','3200 E SAWYER RD',109),
|
||
(193000000000000222,193000000000100222,'STL4','STL4','IL','Edwardsville','62025-2815','UTC-6','3050 GATEWAY COMMERCE CENTER DR S',194),
|
||
(193000000000000223,193000000000100223,'SWF1','SWF1','NY','ROCK TAVERN','12575','UTC-5','635 INTERNATIONAL BLVD',122),
|
||
(193000000000000224,193000000000100224,'SWF2','SWF2','NY','Hopewell Junction','12533','UTC-5','76 Patriot Way Hopewell Junction',76),
|
||
(193000000000000225,193000000000100225,'TCY1','TCY1','CA','STOCKTON','95206','UTC-8','2690 East Arch Airport Road',41),
|
||
(193000000000000226,193000000000100226,'TCY2','TCY2','CA','STOCKTON','95215','UTC-8','6201 Newcastle Rd',43),
|
||
(193000000000000227,193000000000100227,'TEB3','TEB3','NJ','Logan Township','08085','UTC-5','2651 Oldmans Creek Rd',250),
|
||
(193000000000000228,193000000000100228,'TEB4','TEB4','NJ','PENNS GROVE','08069','UTC-5','747 COURSES LANDING RD',130),
|
||
(193000000000000229,193000000000100229,'TEB6','TEB6','NJ','Cranbury','08512','UTC-5','22 Hightstown Cranbury State Road',249),
|
||
(193000000000000230,193000000000100230,'TEB9','TEB9','NJ','Somerset','08873','UTC-5','601 Randolph Road',156),
|
||
(193000000000000231,193000000000100231,'TMB8','TMB8','FL','HOMESTEAD','33032-8597','UTC-5','27505 SW 132nd AVE',65),
|
||
(193000000000000232,193000000000100232,'TOL3','TOL3','OH','PERRYSBURG','43551','UTC-5','9240 Fremont Pike 43551-4210 - PERRYSBURG, OH - United States',18),
|
||
(193000000000000233,193000000000100233,'TPA1','TPA1','FL','Ruskin','33570','UTC-5','3350 Laurel Ridge Ave.',284),
|
||
(193000000000000234,193000000000100234,'TPA2','TPA2','FL','Lakeland','33811','UTC-5','1760 County Line Rd',283),
|
||
(193000000000000235,193000000000100235,'TPA3','TPA3','FL','Auburndale','33823','UTC-5','676 C. Fred Jones Boulevard',124),
|
||
(193000000000000236,193000000000100236,'TUL1','TUL1','KS','Coffeyville','67337','UTC-6','2654 North Highway 169',272),
|
||
(193000000000000237,193000000000100237,'VGT2','VGT2','NV','LAS VEGAS','89115-2013','UTC-8','6401 Howdy Wells Ave',172),
|
||
(193000000000000238,193000000000100238,'VUBA','VUBA','PA','Scranton','18512','UTC-5','1000 Keystone Industrial Park',228),
|
||
(193000000000000239,193000000000100239,'VUGA','VUGA','PA','Pittston','18643','UTC-5','508 Delaware Avenue West',227),
|
||
(193000000000000240,193000000000100240,'WBW2','WBW2','PA','OLYPHANT','18447','UTC-5','1300 Corporate Way',82),
|
||
(193000000000000241,193000000000100241,'XAV3','XAV3','GA','PORT WENTWORTH','31407','UTC-5','XAV3-120Crossgate Dr 31407-Port Wentworth, GA- United States',36),
|
||
(193000000000000242,193000000000100242,'XEW5','XEW5','NJ','Cinnaminson','08077-2015','UTC-5','995 Taylors Ln 08077-2015',37),
|
||
(193000000000000243,193000000000100243,'XIN5','XIN5','IN','Avon','46123-1700','UTC-5','8838 E COUNTY ROAD 100 S',25),
|
||
(193000000000000244,193000000000100244,'XLX1','XLX1','MD','HAGERSTOWN','21740','UTC-5','1115 Wesel Blvd HAGERSTOWN,MD 21740,USA',34),
|
||
(193000000000000245,193000000000100245,'XLX6','XLX6','NC','PINEVILLE','28134','UTC-5','12220 Carolina Logistics Drive PINEVILLE,NC 28134,USA',23),
|
||
(193000000000000246,193000000000100246,'XLX7','XLX7','CA','VICTORVILLE','92394','UTC-8','18580 Gateway Dr,Victorville,CA 92394,USA',63),
|
||
(193000000000000247,193000000000100247,'XPB2','XPB2','FL','APOPKA','32712','UTC-5','XPB2 - 4661 Apopka Logistics Pkwy 32712 - Apopka, FL - United States',26),
|
||
(193000000000000248,193000000000100248,'XRI3','XRI3','VA','Richmond','23234','UTC-5','4949 Commerce Rd, Richmond, VA 23234',24),
|
||
(193000000000000249,193000000000100249,'XUSB','XUSB','TX','Fort Worth','76155','UTC-6','14900 Frye Rd.',213),
|
||
(193000000000000250,193000000000100250,'XUSC','XUSC','PA','Carlisle','17013','UTC-5','40 Logistics Drive',226),
|
||
(193000000000000251,193000000000100251,'XUSD','XUSD','CA','Stockton','95206','UTC-8','1909 Zephyr St',297),
|
||
(193000000000000252,193000000000100252,'XUSE','XUSE','IN','Whitestown','46075','UTC-5','5100 S Indianapolis Rd',280);
|
||
|
||
DROP PROCEDURE IF EXISTS assert_wh_fba_public_master_data_seed;
|
||
DELIMITER //
|
||
CREATE PROCEDURE assert_wh_fba_public_master_data_seed()
|
||
BEGIN
|
||
IF (SELECT COUNT(*) FROM tmp_wh_fba_public_master_data) <> 252 THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'FBA公共主数据源数量不是252';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM tmp_wh_fba_public_master_data
|
||
WHERE warehouse_code <> UPPER(TRIM(warehouse_code))
|
||
OR warehouse_code NOT REGEXP '^[A-Z0-9]{3,5}$'
|
||
OR TRIM(city) = ''
|
||
OR TRIM(state_province) = ''
|
||
OR TRIM(address_line1) = ''
|
||
OR TRIM(postal_code) = ''
|
||
OR TRIM(timezone) = ''
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'FBA公共主数据存在未清洗或必填缺失记录';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM wh_warehouse existing
|
||
JOIN tmp_wh_fba_public_master_data source
|
||
ON existing.id = source.warehouse_id_seed
|
||
AND (existing.tenant_id <> 0 OR existing.warehouse_code <> source.warehouse_code OR existing.deleted <> 0)
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'FBA公共主数据仓库种子ID与既有数据冲突';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM wh_warehouse_address existing
|
||
JOIN tmp_wh_fba_public_master_data source
|
||
ON existing.id = source.address_id_seed
|
||
LEFT JOIN wh_warehouse parent
|
||
ON parent.id = existing.warehouse_id
|
||
AND parent.tenant_id = existing.tenant_id
|
||
WHERE existing.tenant_id <> 0
|
||
OR existing.deleted <> 0
|
||
OR parent.warehouse_code IS NULL
|
||
OR parent.warehouse_code <> source.warehouse_code
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'FBA公共主数据地址种子ID与既有数据冲突';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM wh_warehouse existing
|
||
JOIN tmp_wh_fba_public_master_data source
|
||
ON existing.tenant_id = 0
|
||
AND existing.warehouse_code = source.warehouse_code
|
||
AND existing.deleted = 1
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'FBA公共主数据存在同编码已删除仓库,需人工确认后恢复或清理';
|
||
END IF;
|
||
END//
|
||
DELIMITER ;
|
||
CALL assert_wh_fba_public_master_data_seed();
|
||
DROP PROCEDURE IF EXISTS assert_wh_fba_public_master_data_seed;
|
||
|
||
INSERT INTO wh_warehouse (
|
||
id, tenant_id, warehouse_code, warehouse_name, warehouse_type, country_code, timezone,
|
||
contact_name, contact_phone, contact_email, status, remark,
|
||
created_by, created_at, updated_by, updated_at, deleted, version
|
||
)
|
||
SELECT
|
||
source.warehouse_id_seed,
|
||
0,
|
||
source.warehouse_code,
|
||
source.warehouse_name,
|
||
'FBA',
|
||
'US',
|
||
source.timezone,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
'ACTIVE',
|
||
NULL,
|
||
NULL,
|
||
CURRENT_TIMESTAMP(3),
|
||
NULL,
|
||
CURRENT_TIMESTAMP(3),
|
||
0,
|
||
0
|
||
FROM tmp_wh_fba_public_master_data source
|
||
ON DUPLICATE KEY UPDATE
|
||
warehouse_type = VALUES(warehouse_type),
|
||
country_code = VALUES(country_code),
|
||
timezone = VALUES(timezone),
|
||
updated_at = CURRENT_TIMESTAMP(3);
|
||
|
||
INSERT INTO wh_warehouse_address (
|
||
id, tenant_id, warehouse_id, address_type, country_code, state_province, city,
|
||
district, postal_code, address_line1, address_line2, latitude, longitude,
|
||
created_by, created_at, updated_by, updated_at, deleted, version
|
||
)
|
||
SELECT
|
||
source.address_id_seed,
|
||
0,
|
||
warehouse.id,
|
||
'OPERATING',
|
||
'US',
|
||
source.state_province,
|
||
source.city,
|
||
NULL,
|
||
source.postal_code,
|
||
source.address_line1,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
CURRENT_TIMESTAMP(3),
|
||
NULL,
|
||
CURRENT_TIMESTAMP(3),
|
||
0,
|
||
0
|
||
FROM tmp_wh_fba_public_master_data source
|
||
JOIN wh_warehouse warehouse
|
||
ON warehouse.tenant_id = 0
|
||
AND warehouse.warehouse_code = source.warehouse_code
|
||
AND warehouse.deleted = 0
|
||
ON DUPLICATE KEY UPDATE
|
||
tenant_id = VALUES(tenant_id),
|
||
country_code = VALUES(country_code),
|
||
state_province = VALUES(state_province),
|
||
city = VALUES(city),
|
||
postal_code = VALUES(postal_code),
|
||
address_line1 = VALUES(address_line1),
|
||
updated_at = CURRENT_TIMESTAMP(3);
|
||
|
||
DROP PROCEDURE IF EXISTS verify_wh_fba_public_master_data;
|
||
DELIMITER //
|
||
CREATE PROCEDURE verify_wh_fba_public_master_data()
|
||
BEGIN
|
||
IF (SELECT COUNT(*)
|
||
FROM wh_warehouse warehouse
|
||
JOIN tmp_wh_fba_public_master_data source
|
||
ON source.warehouse_code = warehouse.warehouse_code
|
||
WHERE warehouse.tenant_id = 0
|
||
AND warehouse.warehouse_type = 'FBA'
|
||
AND warehouse.country_code = 'US'
|
||
AND warehouse.deleted = 0) <> 252 THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'FBA公共仓库写入数量校验失败';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM tmp_wh_fba_public_master_data source
|
||
LEFT JOIN wh_warehouse warehouse
|
||
ON warehouse.tenant_id = 0
|
||
AND warehouse.warehouse_code = source.warehouse_code
|
||
AND warehouse.deleted = 0
|
||
LEFT JOIN wh_warehouse_address address
|
||
ON address.tenant_id = 0
|
||
AND address.warehouse_id = warehouse.id
|
||
AND address.address_type = 'OPERATING'
|
||
AND address.deleted = 0
|
||
WHERE warehouse.id IS NULL
|
||
OR address.id IS NULL
|
||
OR address.country_code <> 'US'
|
||
OR address.state_province <> source.state_province
|
||
OR address.city <> source.city
|
||
OR address.postal_code <> source.postal_code
|
||
OR address.address_line1 <> source.address_line1
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'FBA公共地址父子解析或地址字段校验失败';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM wh_service_capability capability
|
||
JOIN wh_warehouse warehouse
|
||
ON warehouse.id = capability.warehouse_id
|
||
AND warehouse.tenant_id = capability.tenant_id
|
||
WHERE warehouse.tenant_id = 0
|
||
AND warehouse.warehouse_type = 'FBA'
|
||
AND warehouse.warehouse_code IN (SELECT warehouse_code FROM tmp_wh_fba_public_master_data)
|
||
AND capability.deleted = 0
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'FBA公共地址不得创建平台作业能力';
|
||
END IF;
|
||
END//
|
||
DELIMITER ;
|
||
CALL verify_wh_fba_public_master_data();
|
||
DROP PROCEDURE IF EXISTS verify_wh_fba_public_master_data;
|
||
DROP PROCEDURE IF EXISTS verify_wh_fixed_platform_warehouse;
|
||
DELIMITER //
|
||
CREATE PROCEDURE verify_wh_fixed_platform_warehouse()
|
||
BEGIN
|
||
IF (SELECT COUNT(*)
|
||
FROM wh_warehouse warehouse
|
||
JOIN tmp_wh_fixed_platform_warehouse source
|
||
ON source.warehouse_code = warehouse.warehouse_code
|
||
WHERE warehouse.tenant_id = 0
|
||
AND warehouse.warehouse_type = source.warehouse_type
|
||
AND warehouse.country_code = source.country_code
|
||
AND warehouse.deleted = 0) <> 4 THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '固定平台仓写入数量校验失败';
|
||
END IF;
|
||
|
||
IF EXISTS (
|
||
SELECT 1
|
||
FROM tmp_wh_fixed_platform_warehouse source
|
||
LEFT JOIN wh_warehouse warehouse
|
||
ON warehouse.tenant_id = 0
|
||
AND warehouse.warehouse_code = source.warehouse_code
|
||
AND warehouse.deleted = 0
|
||
LEFT JOIN wh_warehouse_address address
|
||
ON address.tenant_id = 0
|
||
AND address.warehouse_id = warehouse.id
|
||
AND address.address_type = 'OPERATING'
|
||
AND address.deleted = 0
|
||
WHERE warehouse.id IS NULL
|
||
OR address.id IS NULL
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '固定平台仓地址父子解析失败';
|
||
END IF;
|
||
|
||
IF (SELECT COUNT(*)
|
||
FROM wh_service_capability capability
|
||
WHERE capability.tenant_id = 0
|
||
AND capability.warehouse_id IN (193000000000200001,193000000000200002)
|
||
AND capability.capability_code = 'RECEIVING'
|
||
AND capability.enabled = 1
|
||
AND capability.deleted = 0) <> 2 THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内固定作业仓收货能力写入校验失败';
|
||
END IF;
|
||
END//
|
||
DELIMITER ;
|
||
CALL verify_wh_fixed_platform_warehouse();
|
||
DROP PROCEDURE IF EXISTS verify_wh_fixed_platform_warehouse;
|
||
DROP TEMPORARY TABLE IF EXISTS tmp_wh_fba_public_master_data;
|
||
DROP TEMPORARY TABLE IF EXISTS tmp_wh_fixed_platform_warehouse;
|
||
|
||
-- 全部增量完成后的最终结构强校验;只有通过此段才输出唯一 PASS
|
||
-- ============================================================
|
||
USE baiyue_firstleg;
|
||
DROP PROCEDURE IF EXISTS unified_publish_fee_add_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_publish_fee_add_column(
|
||
IN target_table VARCHAR(64), IN target_column VARCHAR(64), IN column_definition TEXT
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = target_table AND column_name = target_column
|
||
) THEN
|
||
SET @ddl = CONCAT('ALTER TABLE `', target_table, '` ADD COLUMN `', target_column, '` ', column_definition);
|
||
PREPARE statement FROM @ddl; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL unified_publish_fee_add_column('fl_fee_item', 'fee_code',
|
||
"VARCHAR(50) NULL COMMENT '稳定费用编码;系统费用使用固定编码' AFTER trade_scope");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'source_type',
|
||
"VARCHAR(32) NOT NULL DEFAULT 'MANUAL' COMMENT 'MANUAL或FBA_PRICING' AFTER fee_item_id");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'source_fee_id',
|
||
"BIGINT UNSIGNED NULL COMMENT '来源计费快照ID' AFTER source_type");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'source_fee_version',
|
||
"INT UNSIGNED NULL COMMENT '来源计费快照版本' AFTER source_fee_id");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'source_fee_no',
|
||
"VARCHAR(40) NULL COMMENT '来源费用单号' AFTER source_fee_version");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'customer_id',
|
||
"BIGINT UNSIGNED NULL COMMENT '客户ID快照' AFTER business_date");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'customer_name',
|
||
"VARCHAR(128) NULL COMMENT '客户公司名称快照' AFTER customer_id");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'invoice_title',
|
||
"VARCHAR(256) NULL COMMENT '发票抬头快照' AFTER customer_name");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'chargeable_quantity',
|
||
"DECIMAL(18,4) NULL COMMENT '本费用最终计费量' AFTER chargeable_volume_cbm");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'charge_unit',
|
||
"VARCHAR(16) NULL COMMENT 'KG或CBM' AFTER chargeable_quantity");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'publication_status',
|
||
"VARCHAR(16) NOT NULL DEFAULT 'DRAFT' COMMENT 'DRAFT、PUBLISHED、SUPERSEDED' AFTER review_reason");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'published_by',
|
||
"BIGINT NULL COMMENT '发布人ID' AFTER publication_status");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'published_by_name',
|
||
"VARCHAR(64) NULL COMMENT '发布人名称快照' AFTER published_by");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'published_at',
|
||
"DATETIME(3) NULL COMMENT '发布时间' AFTER published_by_name");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'inbounded_at',
|
||
"DATETIME(3) NULL COMMENT '入库完成时间快照' AFTER published_at");
|
||
CALL unified_publish_fee_add_column('fl_inbound_fee_detail', 'settlement_included',
|
||
"TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否参与结算' AFTER inbounded_at");
|
||
DROP PROCEDURE IF EXISTS unified_publish_fee_add_column;
|
||
|
||
DROP PROCEDURE IF EXISTS unified_publish_fee_add_index;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_publish_fee_add_index(
|
||
IN target_table VARCHAR(64), IN target_index VARCHAR(64), IN index_definition TEXT
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE() AND table_name = target_table AND index_name = target_index
|
||
) THEN
|
||
SET @ddl = CONCAT('ALTER TABLE `', target_table, '` ADD ', index_definition);
|
||
PREPARE statement FROM @ddl; EXECUTE statement; DEALLOCATE PREPARE statement;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL unified_publish_fee_add_index('fl_fee_item', 'uk_fee_item_code',
|
||
'UNIQUE KEY `uk_fee_item_code` (`tenant_id`, `fee_code`)');
|
||
CALL unified_publish_fee_add_index('fl_inbound_fee_detail', 'uk_inbound_fee_source',
|
||
'UNIQUE KEY `uk_inbound_fee_source` (`tenant_id`, `source_type`, `source_fee_id`)');
|
||
CALL unified_publish_fee_add_index('fl_inbound_fee_detail', 'idx_inbound_fee_published',
|
||
'KEY `idx_inbound_fee_published` (`tenant_id`, `inbound_id`, `publication_status`, `source_fee_version`)');
|
||
DROP PROCEDURE IF EXISTS unified_publish_fee_add_index;
|
||
|
||
-- ============================================================================
|
||
-- 2026-08-06:三期分柜、预装、拣货、装柜和派送当前基线
|
||
-- ============================================================================
|
||
USE baiyue_firstleg;
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_preload_plan (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '预装清单ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户隔离ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单/订单ID',
|
||
status VARCHAR(16) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/CONFIRMING/CONFIRMED',
|
||
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本',
|
||
items_json JSON NOT NULL COMMENT '可编辑分柜明细快照',
|
||
remark VARCHAR(1000) NULL COMMENT '预装备注',
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
created_by_name VARCHAR(64) NULL,
|
||
updated_by BIGINT UNSIGNED NOT NULL,
|
||
updated_by_name VARCHAR(64) 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 (id),
|
||
UNIQUE KEY uk_preload_tenant_inbound (tenant_id, inbound_id),
|
||
KEY idx_preload_status (tenant_id, status, updated_at),
|
||
CONSTRAINT fk_preload_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='订单分柜预装清单';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_split_operation (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '幂等记录ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户隔离ID',
|
||
inbound_id BIGINT UNSIGNED NOT NULL,
|
||
operator_id BIGINT UNSIGNED NOT NULL,
|
||
operation VARCHAR(40) NOT NULL,
|
||
idempotency_key VARCHAR(128) NOT NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'PROCESSING' COMMENT 'PROCESSING/SUCCESS',
|
||
result_json JSON NULL,
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_split_operation (tenant_id, inbound_id, operator_id, operation, idempotency_key),
|
||
KEY idx_split_operation_time (tenant_id, inbound_id, created_at),
|
||
CONSTRAINT fk_split_operation_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='分柜操作幂等与审计索引';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_loading_evidence (
|
||
id BIGINT UNSIGNED NOT NULL,
|
||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||
inbound_id BIGINT UNSIGNED NOT NULL,
|
||
evidence_type VARCHAR(32) NOT NULL COMMENT 'PHOTO_STEP_1..4/SEAL',
|
||
file_id BIGINT UNSIGNED NULL COMMENT 'File 服务逻辑文件ID',
|
||
file_name VARCHAR(255) NULL,
|
||
seal_no VARCHAR(64) NULL,
|
||
remark VARCHAR(1000) NULL,
|
||
version INT NOT NULL DEFAULT 0,
|
||
created_by BIGINT UNSIGNED NOT NULL,
|
||
created_by_name VARCHAR(64) NULL,
|
||
updated_by BIGINT UNSIGNED NOT NULL,
|
||
updated_by_name VARCHAR(64) 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 (id),
|
||
UNIQUE KEY uk_loading_evidence_type (tenant_id, inbound_id, evidence_type),
|
||
KEY idx_loading_evidence_time (tenant_id, inbound_id, updated_at),
|
||
CONSTRAINT fk_loading_evidence_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='订单装柜四步照片和铅封证据';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_loading_operation (
|
||
id BIGINT UNSIGNED NOT NULL,
|
||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||
inbound_id BIGINT UNSIGNED NOT NULL,
|
||
operator_id BIGINT UNSIGNED NOT NULL,
|
||
operation VARCHAR(48) NOT NULL,
|
||
idempotency_key VARCHAR(128) NOT NULL,
|
||
request_hash CHAR(64) NOT NULL,
|
||
status VARCHAR(16) NOT NULL DEFAULT 'PROCESSING',
|
||
result_json JSON NULL,
|
||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
completed_at DATETIME(3) NULL,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_loading_operation (tenant_id, inbound_id, operator_id, operation, idempotency_key),
|
||
KEY idx_loading_operation_time (tenant_id, inbound_id, created_at),
|
||
CONSTRAINT fk_loading_operation_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='装柜与派送写操作幂等记录';
|
||
|
||
CREATE TABLE IF NOT EXISTS fl_loading_pick_task (
|
||
id BIGINT UNSIGNED NOT NULL,
|
||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||
inbound_id BIGINT UNSIGNED NOT NULL,
|
||
status VARCHAR(24) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/IN_PROGRESS/COMPLETED',
|
||
version INT NOT NULL DEFAULT 0,
|
||
expected_count INT UNSIGNED NULL,
|
||
picked_count INT UNSIGNED NULL,
|
||
remark VARCHAR(1000) NULL,
|
||
updated_by BIGINT UNSIGNED NOT NULL,
|
||
updated_by_name VARCHAR(64) 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 (id),
|
||
UNIQUE KEY uk_loading_pick_tenant_inbound (tenant_id, inbound_id),
|
||
KEY idx_loading_pick_status (tenant_id, status, updated_at),
|
||
CONSTRAINT fk_loading_pick_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
|
||
) ENGINE=InnoDB COMMENT='PDA拣货任务及结果';
|
||
|
||
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
|
||
(5102091, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'firstleg:inbound:split', '智能分柜', NULL, NULL, 140, 'ACTIVE', 1, 0),
|
||
(5102092, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'firstleg:inbound:preload', '编辑并确认预装清单', NULL, NULL, 150, 'ACTIVE', 1, 0),
|
||
(5102093, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'firstleg:inbound:preload-view', '查看预装清单', NULL, NULL, 160, 'ACTIVE', 1, 0),
|
||
(5102094, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:loading:edit', '维护装柜证据', NULL, NULL, 170, 'ACTIVE', 1, 0),
|
||
(5102095, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:loading:view', '查看装柜证据', NULL, NULL, 180, 'ACTIVE', 1, 0),
|
||
(5102096, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:loading:complete', '完成装柜', NULL, NULL, 190, 'ACTIVE', 1, 0),
|
||
(5102097, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:delivery:complete', '完成派送', NULL, NULL, 200, 'ACTIVE', 1, 0),
|
||
(5102098, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:picking:edit', '执行拣货', NULL, NULL, 210, 'ACTIVE', 1, 0),
|
||
(5102099, 0, 'PLATFORM', 'BUTTON', 5102030,
|
||
'platform:firstleg:inbound:picking:view', '查看拣货任务', NULL, NULL, 220, '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 (
|
||
'firstleg:inbound:split',
|
||
'firstleg:inbound:preload',
|
||
'firstleg:inbound:preload-view',
|
||
'platform:firstleg:inbound:loading:edit',
|
||
'platform:firstleg:inbound:loading:view',
|
||
'platform:firstleg:inbound:loading:complete',
|
||
'platform:firstleg:inbound:delivery:complete',
|
||
'platform:firstleg:inbound:picking:edit',
|
||
'platform:firstleg:inbound:picking:view'
|
||
)
|
||
ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id);
|
||
|
||
-- 兼容已经执行过旧单行配置模型的开发/测试库。仅精确识别旧结构时丢弃旧值并重建;
|
||
-- 已是四箱规结构时不做 DDL,避免破坏 Admin 已编辑的数据。
|
||
DROP PROCEDURE IF EXISTS unified_upgrade_legacy_customer_dimension_config;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_upgrade_legacy_customer_dimension_config()
|
||
BEGIN
|
||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_customer_dimension_config') = 1
|
||
AND (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_customer_dimension_config'
|
||
AND column_name = 'box_type') = 0 THEN
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_customer_dimension_config'
|
||
AND column_name IN ('id', 'tenant_id', 'edge_addition_cm', 'remark', 'initialization_key',
|
||
'created_by', 'created_at', 'updated_by', 'updated_at', 'deleted', 'version')) <> 11
|
||
OR (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_customer_dimension_config') <> 11
|
||
OR (SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_customer_dimension_config'
|
||
AND index_name = 'uk_customer_dimension_config_tenant'
|
||
AND non_unique = 0 AND seq_in_index = 1 AND column_name = 'tenant_id') <> 1 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户尺寸配置表不是可识别的旧单行结构';
|
||
END IF;
|
||
DROP TABLE baiyue_firstleg.fl_customer_dimension_config;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL unified_upgrade_legacy_customer_dimension_config();
|
||
DROP PROCEDURE IF EXISTS unified_upgrade_legacy_customer_dimension_config;
|
||
|
||
CREATE TABLE IF NOT EXISTS baiyue_firstleg.fl_customer_dimension_config (
|
||
id BIGINT UNSIGNED NOT NULL COMMENT '配置ID',
|
||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户隔离ID',
|
||
box_type VARCHAR(24) NOT NULL COMMENT '固定箱规类型:SMALL/MEDIUM/LARGE/EXTRA_LARGE',
|
||
inner_length_cm DECIMAL(9,3) NOT NULL COMMENT '箱规内长(厘米)',
|
||
inner_width_cm DECIMAL(9,3) NOT NULL COMMENT '箱规内宽(厘米)',
|
||
inner_height_cm DECIMAL(9,3) NOT NULL COMMENT '箱规内高(厘米)',
|
||
edge_addition_cm DECIMAL(6,3) NOT NULL DEFAULT 2.000 COMMENT '每个尺寸方向的单侧加宽厘米数',
|
||
remark VARCHAR(500) NULL COMMENT '备注',
|
||
initialization_key VARCHAR(128) 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),
|
||
UNIQUE KEY uk_customer_dimension_config_tenant_box (tenant_id, box_type),
|
||
KEY idx_customer_dimension_config_initialization (tenant_id, initialization_key),
|
||
CONSTRAINT chk_customer_dimension_box_type
|
||
CHECK (box_type IN ('SMALL', 'MEDIUM', 'LARGE', 'EXTRA_LARGE')),
|
||
CONSTRAINT chk_customer_dimension_inner_size
|
||
CHECK (inner_length_cm >= 0.001 AND inner_width_cm >= 0.001 AND inner_height_cm >= 0.001),
|
||
CONSTRAINT chk_customer_dimension_edge_addition
|
||
CHECK (edge_addition_cm >= 0.001 AND edge_addition_cm <= 100.000)
|
||
) ENGINE=InnoDB COMMENT='客户固定四箱规尺寸配置';
|
||
|
||
-- 新结构首次部署或旧结构受控重建后,为所有现有企业客户补齐缺失箱规。
|
||
-- 复跑命中 (tenant_id, box_type) 唯一键时只做空更新,不覆盖尺寸、备注、版本或审计字段。
|
||
INSERT INTO baiyue_firstleg.fl_customer_dimension_config (
|
||
id, tenant_id, box_type, inner_length_cm, inner_width_cm, inner_height_cm,
|
||
edge_addition_cm, remark, initialization_key, created_by, created_at,
|
||
updated_by, updated_at, deleted, version
|
||
)
|
||
SELECT UUID_SHORT(), tenant.tenant_id, defaults.box_type,
|
||
defaults.inner_length_cm, defaults.inner_width_cm, defaults.inner_height_cm,
|
||
2.000, defaults.remark,
|
||
CONCAT('unified-four-box-default-v1:', tenant.tenant_id),
|
||
COALESCE(tenant.created_by, 0), CURRENT_TIMESTAMP(3),
|
||
COALESCE(tenant.created_by, 0), CURRENT_TIMESTAMP(3), 0, 0
|
||
FROM (
|
||
SELECT id AS tenant_id, created_by
|
||
FROM baiyue_iam.iam_tenant
|
||
WHERE tenant_type = 'MERCHANT' AND deleted = 0 AND id > 0
|
||
) tenant
|
||
CROSS JOIN (
|
||
SELECT 'SMALL' AS box_type, 30.000 AS inner_length_cm, 20.000 AS inner_width_cm,
|
||
20.000 AS inner_height_cm, '标准小箱' AS remark
|
||
UNION ALL
|
||
SELECT 'MEDIUM', 40.000, 30.000, 30.000, '标准中箱'
|
||
UNION ALL
|
||
SELECT 'LARGE', 50.000, 40.000, 40.000, '标准大箱'
|
||
UNION ALL
|
||
SELECT 'EXTRA_LARGE', 60.000, 50.000, 50.000, '特大箱'
|
||
) defaults
|
||
ON DUPLICATE KEY UPDATE id = id;
|
||
|
||
DROP PROCEDURE IF EXISTS unified_assert_final_extensions;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE unified_assert_final_extensions()
|
||
BEGIN
|
||
IF (SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order'
|
||
AND index_name = 'uk_order_tenant_inbound_code') <> 2 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:订单入仓码唯一索引未正确创建';
|
||
END IF;
|
||
IF EXISTS (
|
||
SELECT 1 FROM baiyue_order.ord_order
|
||
WHERE deleted = 0
|
||
AND (
|
||
((status = 'DRAFT' OR (status IN ('REJECTED', 'CANCELLED') AND submitted_at IS NULL))
|
||
AND inbound_code IS NOT NULL)
|
||
OR
|
||
(status <> 'DRAFT'
|
||
AND (submitted_at IS NOT NULL
|
||
OR status IN ('SUBMITTED', 'APPROVED', 'ACCEPTED', 'PROCESSING', 'COMPLETED'))
|
||
AND inbound_code IS NULL)
|
||
)
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:订单状态与入仓码数据不一致';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name IN ('fl_preload_plan', 'fl_split_operation',
|
||
'fl_loading_evidence', 'fl_loading_operation',
|
||
'fl_loading_pick_task')) <> 5 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:三期分柜、预装或装柜表未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_preload_plan'
|
||
AND column_name IN ('id', 'tenant_id', 'inbound_id', 'status', 'version',
|
||
'items_json', 'remark', 'created_by', 'created_by_name',
|
||
'updated_by', 'updated_by_name', 'created_at', 'updated_at')) <> 13
|
||
OR (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_split_operation'
|
||
AND column_name IN ('id', 'tenant_id', 'inbound_id', 'operator_id', 'operation',
|
||
'idempotency_key', 'status', 'result_json', 'created_at')) <> 9
|
||
OR (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_evidence'
|
||
AND column_name IN ('id', 'tenant_id', 'inbound_id', 'evidence_type', 'file_id',
|
||
'file_name', 'seal_no', 'remark', 'version', 'created_by',
|
||
'created_by_name', 'updated_by', 'updated_by_name',
|
||
'created_at', 'updated_at')) <> 15
|
||
OR (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_operation'
|
||
AND column_name IN ('id', 'tenant_id', 'inbound_id', 'operator_id', 'operation',
|
||
'idempotency_key', 'request_hash', 'status', 'result_json',
|
||
'created_at', 'completed_at')) <> 11
|
||
OR (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task'
|
||
AND column_name IN ('id', 'tenant_id', 'inbound_id', 'status', 'version',
|
||
'expected_count', 'picked_count', 'remark', 'updated_by',
|
||
'updated_by_name', 'created_at', 'updated_at')) <> 12 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:三期分柜、预装或装柜关键字段未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name IN ('fl_preload_plan', 'fl_split_operation', 'fl_loading_operation')
|
||
AND column_name IN ('items_json', 'result_json') AND data_type = 'json') <> 3
|
||
OR (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_inbound_order'
|
||
AND column_name = 'process_status' AND character_maximum_length >= 24) <> 1 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:三期 JSON 字段或入库状态字段类型不兼容';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT CONCAT(table_name, '.', index_name))
|
||
FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND index_name IN ('uk_preload_tenant_inbound', 'idx_preload_status',
|
||
'uk_split_operation', 'idx_split_operation_time',
|
||
'uk_loading_evidence_type', 'idx_loading_evidence_time',
|
||
'uk_loading_operation', 'idx_loading_operation_time',
|
||
'uk_loading_pick_tenant_inbound', 'idx_loading_pick_status')) <> 10 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:三期分柜、预装或装柜索引未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.table_constraints
|
||
WHERE constraint_schema = 'baiyue_firstleg' AND constraint_type = 'FOREIGN KEY'
|
||
AND table_name IN ('fl_preload_plan', 'fl_split_operation',
|
||
'fl_loading_evidence', 'fl_loading_operation',
|
||
'fl_loading_pick_task')) <> 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 app_code = 'PLATFORM' AND status = 'ACTIVE' AND deleted = 0
|
||
AND permission_code IN (
|
||
'firstleg:inbound:split', 'firstleg:inbound:preload',
|
||
'firstleg:inbound:preload-view',
|
||
'platform:firstleg:inbound:loading:edit',
|
||
'platform:firstleg:inbound:loading:view',
|
||
'platform:firstleg:inbound:loading:complete',
|
||
'platform:firstleg:inbound:delivery:complete',
|
||
'platform:firstleg:inbound:picking:edit',
|
||
'platform:firstleg:inbound:picking:view')) <> 9 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:三期分柜、预装或装柜权限未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT rp.permission_id)
|
||
FROM baiyue_iam.iam_role_permission rp
|
||
JOIN baiyue_iam.iam_permission p ON p.id = rp.permission_id
|
||
WHERE rp.role_id = 4000001 AND rp.tenant_id = 0
|
||
AND p.permission_code IN (
|
||
'firstleg:inbound:split', 'firstleg:inbound:preload',
|
||
'firstleg:inbound:preload-view',
|
||
'platform:firstleg:inbound:loading:edit',
|
||
'platform:firstleg:inbound:loading:view',
|
||
'platform:firstleg:inbound:loading:complete',
|
||
'platform:firstleg:inbound:delivery:complete',
|
||
'platform:firstleg:inbound:picking:edit',
|
||
'platform:firstleg:inbound:picking:view')) <> 9 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:平台系统管理员未获得完整三期操作权限';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name IN ('fl_fee_item', 'fl_inbound_fee_detail')) <> 2 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:费用项目或入库费用明细表未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name IN ('fl_fee_item', 'fl_inbound_fee_detail')
|
||
AND column_name = 'tenant_id'
|
||
AND column_comment = '当前客户ID(客户隔离键);物理字段名沿用 tenant_id,当前不表示上级租户') <> 2 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:费用表 tenant_id 客户隔离语义未同步';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_fee_item'
|
||
AND column_name = 'fee_code') <> 1
|
||
OR (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_inbound_fee_detail'
|
||
AND column_name IN (
|
||
'source_type', 'source_fee_id', 'source_fee_version', 'source_fee_no',
|
||
'customer_id', 'customer_name', 'invoice_title',
|
||
'chargeable_quantity', 'charge_unit', 'publication_status',
|
||
'published_by', 'published_by_name', 'published_at', 'inbounded_at',
|
||
'settlement_included')) <> 15 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:已发布入库运费明细字段未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_fee_item'
|
||
AND index_name = 'uk_fee_item_code' AND non_unique = 0) <> 2
|
||
OR (SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_inbound_fee_detail'
|
||
AND index_name = 'uk_inbound_fee_source' AND non_unique = 0) <> 3
|
||
OR (SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_inbound_fee_detail'
|
||
AND index_name = 'idx_inbound_fee_published') <> 4 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:已发布入库运费明细索引未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT CONCAT(table_name, '.', index_name))
|
||
FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND index_name IN ('idx_fee_item_query', 'idx_fee_item_name',
|
||
'idx_inbound_fee_detail', 'idx_inbound_fee_review',
|
||
'idx_inbound_fee_item')) <> 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 (
|
||
'firstleg:fee-item:view', 'firstleg:fee-item:create',
|
||
'firstleg:fee-item:edit', 'firstleg:fee-item:delete',
|
||
'firstleg:inbound:fee-detail:view', 'firstleg:inbound:fee-detail:edit',
|
||
'firstleg:inbound:fee-detail:delete', 'firstleg:inbound:fee-detail:review')) <> 8 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:费用项目或入库费用明细权限未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||
WHERE table_schema IN ('baiyue_auth', 'baiyue_iam', 'baiyue_order',
|
||
'baiyue_firstleg', 'baiyue_warehouse')
|
||
AND table_name = 'sys_audit_outbox') <> 5 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:可靠审计 Outbox 未覆盖五个业务库';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT CONCAT(table_schema, '.', index_name))
|
||
FROM information_schema.statistics
|
||
WHERE table_schema IN ('baiyue_auth', 'baiyue_iam', 'baiyue_order',
|
||
'baiyue_firstleg', 'baiyue_warehouse')
|
||
AND table_name = 'sys_audit_outbox'
|
||
AND index_name IN ('PRIMARY', 'idx_audit_outbox_publish',
|
||
'idx_audit_outbox_retention')) <> 15 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:可靠审计 Outbox 主键或索引未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema IN ('baiyue_auth', 'baiyue_iam', 'baiyue_order',
|
||
'baiyue_firstleg', 'baiyue_warehouse')
|
||
AND table_name = 'sys_audit_outbox'
|
||
AND column_name IN ('event_id', 'payload_json', 'status',
|
||
'next_retry_at', 'lease_until')) <> 25 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:可靠审计 Outbox 关键字段未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||
WHERE table_schema = 'baiyue_audit'
|
||
AND table_name = 'sys_audit_dead_letter') <> 1 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:审计死信补偿表未创建';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT index_name) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_audit'
|
||
AND table_name = 'sys_audit_dead_letter'
|
||
AND index_name IN ('PRIMARY', 'uk_audit_dead_event', 'idx_audit_dead_retry')) <> 3 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:审计死信补偿表主键或索引未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_audit' AND table_name = 'sys_audit_log'
|
||
AND column_name = 'event_id') <> 1
|
||
OR (SELECT COUNT(DISTINCT index_name) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_audit' AND table_name = 'sys_audit_log'
|
||
AND index_name = 'uk_audit_event_id' AND non_unique = 0) <> 1 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:审计消费幂等 event_id 唯一约束未就绪';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_third_party_call_log'
|
||
AND column_name = 'tenant_id' AND column_default = '0'
|
||
AND column_comment = '第三方未知/未解析主体哨兵值;不是平台客户记录或平台作用域,不得用于业务数据授权') <> 1 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:第三方未知主体 tenant_id=0 哨兵语义未就绪';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM baiyue_warehouse.wh_warehouse WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_warehouse_address WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_service_capability WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_express_company WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_partner
|
||
WHERE tenant_id <> 0 OR data_scope_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_partner_type
|
||
WHERE tenant_id <> 0 OR data_scope_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_pallet WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_location WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_location_reservation WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_warehouse.wh_location_occupancy WHERE tenant_id <> 0) > 0
|
||
OR (SELECT COUNT(*) FROM baiyue_firstleg.fl_inbound_pallet_allocation
|
||
WHERE warehouse_resource_tenant_id <> 0) > 0 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:平台公共仓储资源仍有 tenant_id<>0';
|
||
END IF;
|
||
IF EXISTS (
|
||
SELECT 1 FROM baiyue_warehouse.wh_warehouse_address a
|
||
JOIN baiyue_warehouse.wh_warehouse w ON w.id = a.warehouse_id
|
||
WHERE a.tenant_id <> w.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM baiyue_warehouse.wh_service_capability c
|
||
JOIN baiyue_warehouse.wh_warehouse w ON w.id = c.warehouse_id
|
||
WHERE c.tenant_id <> w.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM baiyue_warehouse.wh_pallet p
|
||
JOIN baiyue_warehouse.wh_warehouse w ON w.id = p.warehouse_id
|
||
WHERE p.tenant_id <> w.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM baiyue_warehouse.wh_location l
|
||
JOIN baiyue_warehouse.wh_warehouse w ON w.id = l.warehouse_id
|
||
WHERE l.tenant_id <> w.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM baiyue_warehouse.wh_location_reservation r
|
||
JOIN baiyue_warehouse.wh_warehouse w ON w.id = r.warehouse_id
|
||
JOIN baiyue_warehouse.wh_pallet p ON p.id = r.pallet_id
|
||
JOIN baiyue_warehouse.wh_location l ON l.id = r.location_id
|
||
WHERE r.tenant_id <> w.tenant_id OR r.tenant_id <> p.tenant_id OR r.tenant_id <> l.tenant_id
|
||
) OR EXISTS (
|
||
SELECT 1 FROM baiyue_warehouse.wh_location_occupancy o
|
||
JOIN baiyue_warehouse.wh_warehouse w ON w.id = o.warehouse_id
|
||
JOIN baiyue_warehouse.wh_pallet p ON p.id = o.pallet_id
|
||
JOIN baiyue_warehouse.wh_location l ON l.id = o.location_id
|
||
JOIN baiyue_warehouse.wh_location_reservation r ON r.id = o.reservation_id
|
||
WHERE o.tenant_id <> w.tenant_id OR o.tenant_id <> p.tenant_id
|
||
OR o.tenant_id <> l.tenant_id OR o.tenant_id <> r.tenant_id
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:Warehouse 公共资源父子归属不一致';
|
||
END IF;
|
||
IF EXISTS (SELECT 1 FROM baiyue_warehouse.wh_overseas_storage_fee_rule WHERE tenant_id = 0) THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户费用规则缺少客户 tenant_id';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_inbound_carton_label') <> 1 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:稳定箱号映射表未创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_inbound_measurement_item'
|
||
AND column_name IN ('box_code', 'machine_no', 'device_measured_at', 'updated_at')) <> 4 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:单箱当前测量字段未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT CONCAT(table_name, '.', index_name))
|
||
FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND ((table_name = 'fl_inbound_carton_label'
|
||
AND index_name IN ('uk_carton_label_box_code', 'uk_carton_label_index'))
|
||
OR (table_name = 'fl_inbound_measurement_item'
|
||
AND index_name = 'uk_measure_box_code'))
|
||
AND non_unique = 0) <> 3 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:稳定箱号或单箱测量唯一约束未完整创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_customer_dimension_config') <> 1 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户尺寸计算配置表未创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.statistics
|
||
WHERE table_schema = 'baiyue_firstleg'
|
||
AND table_name = 'fl_customer_dimension_config'
|
||
AND index_name = 'uk_customer_dimension_config_tenant_box'
|
||
AND non_unique = 0
|
||
AND ((seq_in_index = 1 AND column_name = 'tenant_id')
|
||
OR (seq_in_index = 2 AND column_name = 'box_type'))) <> 2 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户四箱规尺寸配置唯一约束未创建';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_customer_dimension_config'
|
||
AND column_name IN ('id', 'tenant_id', 'box_type', 'inner_length_cm', 'inner_width_cm',
|
||
'inner_height_cm', 'edge_addition_cm', 'remark', 'initialization_key',
|
||
'created_by', 'created_at', 'updated_by', 'updated_at', 'deleted', 'version')) <> 15 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户四箱规尺寸配置字段不完整';
|
||
END IF;
|
||
IF EXISTS (
|
||
SELECT tenant.id
|
||
FROM baiyue_iam.iam_tenant tenant
|
||
LEFT JOIN baiyue_firstleg.fl_customer_dimension_config config
|
||
ON config.tenant_id = tenant.id AND config.deleted = 0
|
||
WHERE tenant.tenant_type = 'MERCHANT' AND tenant.deleted = 0 AND tenant.id > 0
|
||
GROUP BY tenant.id
|
||
HAVING COUNT(config.id) <> 4
|
||
OR COUNT(DISTINCT CASE
|
||
WHEN config.box_type IN ('SMALL', 'MEDIUM', 'LARGE', 'EXTRA_LARGE')
|
||
THEN config.box_type END) <> 4
|
||
) THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:现有企业客户未完整持有固定四箱规尺寸配置';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM baiyue_iam.iam_permission
|
||
WHERE id = 5100010 AND tenant_id = 0 AND app_code = 'PLATFORM'
|
||
AND permission_code = 'platform:customer:list' AND permission_name = '企业客户'
|
||
AND status = 'ACTIVE' AND deleted = 0) <> 1 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户尺寸计算配置权限父节点企业客户不存在';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM baiyue_iam.iam_permission
|
||
WHERE tenant_id = 0 AND app_code = 'PLATFORM' AND permission_type = 'BUTTON'
|
||
AND parent_id = 5100010 AND status = 'ACTIVE' AND deleted = 0
|
||
AND ((id = 5102111 AND permission_code = 'firstleg:dimension-config:view')
|
||
OR (id = 5102112 AND permission_code = 'firstleg:dimension-config:edit'))) <> 2 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:客户尺寸计算配置权限码、固定ID或父节点不正确';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT p.permission_code)
|
||
FROM baiyue_iam.iam_role_permission rp
|
||
JOIN baiyue_iam.iam_role r ON r.id = rp.role_id AND r.tenant_id = rp.tenant_id
|
||
JOIN baiyue_iam.iam_permission p ON p.id = rp.permission_id AND p.tenant_id = rp.tenant_id
|
||
WHERE r.tenant_id = 0 AND r.app_code = 'PLATFORM' AND r.role_code = 'PLATFORM_ADMIN'
|
||
AND p.permission_code IN ('firstleg:dimension-config:view', 'firstleg:dimension-config:edit')) <> 2 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:平台管理员未获得客户尺寸计算配置读写权限';
|
||
END IF;
|
||
IF (SELECT COUNT(DISTINCT p.permission_code)
|
||
FROM baiyue_iam.iam_role_permission rp
|
||
JOIN baiyue_iam.iam_role r ON r.id = rp.role_id AND r.tenant_id = rp.tenant_id
|
||
JOIN baiyue_iam.iam_permission p ON p.id = rp.permission_id AND p.tenant_id = rp.tenant_id
|
||
WHERE r.tenant_id = 0 AND r.app_code = 'PLATFORM' AND r.role_code = 'ORDER_OPERATOR'
|
||
AND p.permission_code = 'firstleg:dimension-config:view') <> 1
|
||
OR (SELECT COUNT(*)
|
||
FROM baiyue_iam.iam_role_permission rp
|
||
JOIN baiyue_iam.iam_role r ON r.id = rp.role_id AND r.tenant_id = rp.tenant_id
|
||
JOIN baiyue_iam.iam_permission p ON p.id = rp.permission_id AND p.tenant_id = rp.tenant_id
|
||
WHERE r.tenant_id = 0 AND r.app_code = 'PLATFORM' AND r.role_code = 'ORDER_OPERATOR'
|
||
AND p.permission_code = 'firstleg:dimension-config:edit') <> 0 THEN
|
||
SIGNAL SQLSTATE '45000'
|
||
SET MESSAGE_TEXT = '统一迁移失败:订单运营角色的客户尺寸计算配置权限不是只读';
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
CALL unified_assert_final_extensions();
|
||
DROP PROCEDURE IF EXISTS unified_assert_final_extensions;
|
||
|
||
-- tenant_id=0 在此表仅为未知/未解析第三方主体;数量可非零,但不得用于业务授权。
|
||
SELECT COUNT(*) AS unresolved_third_party_calls
|
||
FROM baiyue_firstleg.fl_third_party_call_log
|
||
WHERE tenant_id = 0;
|
||
|
||
SELECT 'PASS' AS migration_status,
|
||
'统一增量全部执行完成;箱号映射、单箱测量、三期出仓、费用、公共资源及可靠审计结构校验通过' AS message;
|