Files
baiyue-firstleg/deploy/sql/海外区域统一增量-MySQL8.sql
T

1159 lines
106 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 海外区域固定增量入口。空库先执行 lastleg-service/src/main/resources/db/lastleg.sql 基线;
-- 本入口同时初始化海外 Event Bridge 独立库,避免国内/海外实例误共用 Inbox。
-- 本文件只由人工审核执行,服务部署默认不自动执行 SQL。
SET NAMES utf8mb4;
CREATE DATABASE IF NOT EXISTS baiyue_event_bridge_overseas
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE baiyue_event_bridge_overseas;
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 '目标区域',
customer_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 '目标区域',
customer_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='海外跨区域事件投递尝试记录';
DROP PROCEDURE IF EXISTS assert_overseas_event_bridge_schema;
DELIMITER $$
CREATE PROCEDURE assert_overseas_event_bridge_schema()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema='baiyue_event_bridge_overseas'
AND table_name IN ('bridge_outbox','bridge_inbox','bridge_delivery_attempt')) <> 3 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT='海外区域初始化失败:Event Bridge 三张表未完整创建';
END IF;
IF (SELECT COUNT(DISTINCT CONCAT(table_name, ':', index_name)) FROM information_schema.statistics
WHERE table_schema='baiyue_event_bridge_overseas'
AND ((table_name='bridge_outbox' AND index_name IN ('PRIMARY','uk_bridge_outbox_idempotency','idx_bridge_outbox_schedule'))
OR (table_name='bridge_inbox' AND index_name IN ('PRIMARY','uk_bridge_inbox_idempotency','idx_bridge_inbox_consume'))
OR (table_name='bridge_delivery_attempt' AND index_name IN ('PRIMARY','uk_bridge_attempt','idx_bridge_attempt_event')))) <> 9 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT='海外区域初始化失败:Event Bridge 索引未完整创建';
END IF;
END$$
DELIMITER ;
CALL assert_overseas_event_bridge_schema();
DROP PROCEDURE IF EXISTS assert_overseas_event_bridge_schema;
CREATE DATABASE IF NOT EXISTS baiyue_lastleg
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_event_outbox (
id BIGINT NOT NULL COMMENT '事件主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型', aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合标识',
event_type VARCHAR(64) NOT NULL COMMENT '事件类型', event_version INT NOT NULL COMMENT '事件版本',
event_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', payload_json LONGTEXT NOT NULL COMMENT '事件载荷JSON',
status VARCHAR(32) 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 '发布时间',
locked_at DATETIME(3) NULL COMMENT '投递租约获取时间', locked_by VARCHAR(128) NULL COMMENT '投递租约持有者',
last_error VARCHAR(1000) NULL COMMENT '最后一次发布错误', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
PRIMARY KEY (id), UNIQUE KEY uk_ll_event_outbox_key (event_key),
KEY idx_ll_event_outbox_publish (status,next_retry_at,created_at)
) ENGINE=InnoDB COMMENT='尾程跨区业务事件发件箱';
CREATE TABLE IF NOT EXISTS ll_overseas_quote (
id BIGINT NOT NULL COMMENT '报价ID', name VARCHAR(128) NOT NULL COMMENT '报价名称',
warehouse_id BIGINT NOT NULL COMMENT '国内平台海外合作仓ID', warehouse_code VARCHAR(64) NOT NULL COMMENT '合作仓编码快照',
warehouse_name VARCHAR(128) NOT NULL COMMENT '合作仓名称快照', country_code VARCHAR(2) NOT NULL COMMENT '国家二字码快照',
provider_name VARCHAR(128) NOT NULL COMMENT '报价方', currency CHAR(3) NOT NULL COMMENT '币种',
effective_start DATE NOT NULL COMMENT '生效开始日期', effective_end DATE NOT NULL COMMENT '生效结束日期',
version_code VARCHAR(64) NOT NULL COMMENT '业务版本号', status VARCHAR(16) NOT NULL DEFAULT 'INACTIVE' COMMENT '状态:ACTIVE/INACTIVE',
remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本',
created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_warehouse_provider_version (warehouse_id,provider_name,version_code),
KEY idx_ll_quote_page (status,updated_at,id), KEY idx_ll_quote_effective (warehouse_id,provider_name,currency,effective_start,effective_end)
) ENGINE=InnoDB COMMENT='海外仓报价主表';
CREATE TABLE IF NOT EXISTS ll_overseas_quote_fee (
id BIGINT NOT NULL COMMENT '费用明细ID', quote_id BIGINT NOT NULL COMMENT '报价ID', sequence_no INT NOT NULL COMMENT '显示顺序',
item VARCHAR(128) NOT NULL COMMENT '费用项目', billing_unit VARCHAR(64) NOT NULL COMMENT '计费单位',
unit_price DECIMAL(18,4) NOT NULL COMMENT '单价', minimum_charge DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '最低收费',
remark VARCHAR(500) NULL COMMENT '备注', PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_fee_sequence (quote_id,sequence_no),
KEY idx_ll_quote_fee_quote (quote_id)
) ENGINE=InnoDB COMMENT='海外仓报价仓库费用';
CREATE TABLE IF NOT EXISTS ll_overseas_quote_transit_price (
id BIGINT NOT NULL COMMENT '中转价格ID', quote_id BIGINT NOT NULL COMMENT '报价ID', sequence_no INT NOT NULL COMMENT '显示顺序',
fba_warehouse_code VARCHAR(64) NOT NULL COMMENT 'FBA仓编码', delivery_method VARCHAR(64) NOT NULL COMMENT '报价运输方式',
estimated_miles DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '预估英里数', price DECIMAL(18,4) NOT NULL COMMENT '报价金额',
minimum_charge DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '最低收费', remark VARCHAR(500) NULL COMMENT '备注',
PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_transit_sequence (quote_id,sequence_no),
KEY idx_ll_quote_transit_quote (quote_id)
) ENGINE=InnoDB COMMENT='海外仓报价中转价格明细';
CREATE TABLE IF NOT EXISTS ll_monthly_exchange_rate (
id BIGINT NOT NULL COMMENT '月度汇率ID', rate_month CHAR(7) NOT NULL COMMENT '汇率月份,格式yyyy-MM',
base_currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '基准币种', quote_currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '报价币种',
usd_to_cny_average DECIMAL(18,8) NOT NULL COMMENT '美元兑人民币月平均汇率', status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态:ACTIVE/INACTIVE',
remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本',
created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (id), UNIQUE KEY uk_ll_exchange_rate_month (rate_month), KEY idx_ll_exchange_rate_page (status,rate_month)
) ENGINE=InnoDB COMMENT='美元兑人民币月度平均汇率';
CREATE TABLE IF NOT EXISTS ll_monthly_exchange_rate_history (
id BIGINT NOT NULL COMMENT '汇率变更历史ID', exchange_rate_id BIGINT NOT NULL COMMENT '月度汇率ID',
before_rate DECIMAL(18,8) NULL COMMENT '变更前汇率', after_rate DECIMAL(18,8) NOT NULL COMMENT '变更后汇率',
before_status VARCHAR(16) NULL COMMENT '变更前状态', after_status VARCHAR(16) NOT NULL COMMENT '变更后状态',
operator_id VARCHAR(128) NOT NULL COMMENT '操作人', remark VARCHAR(1000) NULL COMMENT '变更说明',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_exchange_rate_history (exchange_rate_id,created_at)
) ENGINE=InnoDB COMMENT='月度汇率变更历史';
CREATE TABLE IF NOT EXISTS ll_vehicle (
id BIGINT NOT NULL COMMENT '车辆档案ID', plate_number VARCHAR(64) NOT NULL COMMENT '车牌号',
model VARCHAR(128) NOT NULL COMMENT '车型', fuel_consumption_per100_km DECIMAL(10,2) NOT NULL COMMENT '百公里油耗,单位升',
mileage_km BIGINT NOT NULL COMMENT '当前公里码,单位公里', driver_or_dispatch_company VARCHAR(128) NULL COMMENT '司机姓名或外派单位',
phone VARCHAR(64) NULL COMMENT '司机或外派单位联系电话', region VARCHAR(16) NOT NULL COMMENT '区域:DOMESTIC/OVERSEAS',
ownership VARCHAR(16) NOT NULL COMMENT '车辆归属:OWNED/DISPATCHED',
status VARCHAR(32) NOT NULL COMMENT '状态:IN_SERVICE/DISPATCHED/MAINTENANCE/INACTIVE/RETURNED',
remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本',
created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (id), UNIQUE KEY uk_ll_vehicle_plate (plate_number), KEY idx_ll_vehicle_page (ownership,region,status,updated_at,id)
) ENGINE=InnoDB COMMENT='平台车辆主数据';
CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order (
id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
customer_name VARCHAR(255) NULL COMMENT '客户名称快照', order_no VARCHAR(64) NOT NULL COMMENT '订单号',
purchase_category VARCHAR(128) NOT NULL COMMENT '采购品类', product_name VARCHAR(255) NOT NULL COMMENT '产品名称',
product_specification VARCHAR(500) NULL COMMENT '产品规格', product_url VARCHAR(2000) NULL COMMENT '产品链接',
purchase_quantity BIGINT NOT NULL COMMENT '采购数量', budget_unit_price DECIMAL(18,2) NULL COMMENT '预算单价',
currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', receiving_address VARCHAR(1000) NULL COMMENT '收货地址',
contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(64) NOT NULL COMMENT '联系人电话',
purchase_warehouse_id VARCHAR(128) NULL COMMENT '采购入仓仓库ID', purchase_warehouse_name VARCHAR(255) NULL COMMENT '采购入仓仓库名称',
inbound_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '采购单据累计入库数量', domestic_carrier VARCHAR(128) NULL COMMENT '境内承运商',
domestic_tracking_no VARCHAR(128) NULL COMMENT '境内物流单号', overseas_carrier VARCHAR(128) NULL COMMENT '海外承运商',
overseas_tracking_no VARCHAR(128) NULL COMMENT '海外物流单号', estimated_arrival_at DATETIME(3) NULL COMMENT '预计到达时间',
status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '业务状态', remark VARCHAR(1000) NULL COMMENT '备注',
idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希',
created_by VARCHAR(128) NULL COMMENT '创建人ID', reviewed_by VARCHAR(128) NULL COMMENT '审核人ID',
review_remark VARCHAR(1000) NULL COMMENT '审核备注', review_idempotency_key VARCHAR(255) NULL COMMENT '审核幂等键',
review_request_hash CHAR(64) NULL COMMENT '审核请求内容哈希', reviewed_at DATETIME(3) NULL COMMENT '审核时间',
version BIGINT 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 '更新时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_overseas_procurement_order_no(customer_id,order_no),
UNIQUE KEY uk_ll_overseas_procurement_order_key(customer_id,idempotency_key),
KEY idx_ll_overseas_procurement_list(customer_id,status,created_at),
KEY idx_ll_overseas_procurement_warehouse(customer_id,purchase_warehouse_id,created_at)
) ENGINE=InnoDB COMMENT='海外采购订单';
SET @ddl = (SELECT IF(EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='review_idempotency_key'
), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_idempotency_key VARCHAR(255) NULL COMMENT ''审核幂等键'' AFTER review_remark'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='review_request_hash'
), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_request_hash CHAR(64) NULL COMMENT ''审核请求内容哈希'' AFTER review_idempotency_key'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
CREATE TABLE IF NOT EXISTS ll_overseas_procurement_status_history (
id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
operation_type VARCHAR(32) NOT NULL COMMENT '操作类型:CREATE、REVIEW或UPDATE', from_status VARCHAR(32) NULL COMMENT '变更前状态',
to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID',
idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '备注',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id),
KEY idx_ll_overseas_procurement_history(customer_id,order_id,created_at)
) ENGINE=InnoDB COMMENT='海外采购操作流水';
SET @ddl = (SELECT IF(EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_status_history' AND column_name='idempotency_key'
), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_status_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
CREATE TABLE IF NOT EXISTS ll_us_truck_order (
id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_no VARCHAR(64) NOT NULL COMMENT '订单号',
transport_type VARCHAR(32) NOT NULL COMMENT '运输类型', origin VARCHAR(255) NOT NULL COMMENT '起运地', origin_address VARCHAR(500) NULL COMMENT '起运地址',
destination VARCHAR(255) NOT NULL COMMENT '目的地', destination_address VARCHAR(500) NULL COMMENT '目的地址',
container_type VARCHAR(32) NULL COMMENT '历史兼容设备类型,零担托盘业务不采集', pallet_count INT NOT NULL DEFAULT 1 COMMENT '客户申报托盘数',
package_count INT NULL COMMENT '可选箱数,零或空值均有效', received_pallet_count INT NOT NULL DEFAULT 0 COMMENT 'PDA实收托盘数',
allocated_pallet_count INT NOT NULL DEFAULT 0 COMMENT '已分配到合车行程的托盘数', shipped_pallet_count INT NOT NULL DEFAULT 0 COMMENT '已出库托盘数',
total_weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '总重量(千克)', total_volume_cbm DECIMAL(18,6) NOT NULL DEFAULT 0 COMMENT '总体积(立方米)',
budget_amount DECIMAL(18,2) NULL COMMENT '预算金额', currency VARCHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种',
contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_info VARCHAR(128) NOT NULL COMMENT '联系人联系方式',
requested_date DATE NOT NULL COMMENT '要求服务日期', status VARCHAR(32) NOT NULL COMMENT '美国卡车订单状态', remark VARCHAR(1000) NULL COMMENT '备注',
receipt_idempotency_key VARCHAR(255) NULL COMMENT '实物收货幂等键', receipt_request_hash CHAR(64) NULL COMMENT '实物收货请求哈希',
idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID',
version BIGINT 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) COMMENT '更新时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_us_truck_order_no(customer_id,order_no), UNIQUE KEY uk_ll_us_truck_order_key(customer_id,idempotency_key),
UNIQUE KEY uk_ll_us_truck_receipt_key(customer_id,receipt_idempotency_key), KEY idx_ll_us_truck_order_list(customer_id,status,created_at),
KEY idx_ll_us_truck_order_date(customer_id,requested_date,created_at)
) ENGINE=InnoDB COMMENT='美国卡车运输订单';
CREATE TABLE IF NOT EXISTS ll_us_truck_order_pallet (
id BIGINT NOT NULL COMMENT '托盘记录ID', order_id BIGINT NOT NULL COMMENT '美国卡车订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
pallet_no VARCHAR(128) NOT NULL COMMENT '业务托盘号', sequence_no INT NOT NULL COMMENT '订单内托盘序号',
source VARCHAR(32) NOT NULL COMMENT '托盘来源:订单计划或PDA超收', status VARCHAR(32) NOT NULL COMMENT '托盘状态:待收、已收或超收待审核',
warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘资源ID', package_count INT NULL COMMENT '托盘箱数', received_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_ll_us_truck_order_pallet_no(customer_id,order_id,pallet_no), UNIQUE KEY uk_ll_us_truck_order_pallet_seq(customer_id,order_id,sequence_no),
KEY idx_ll_us_truck_order_pallet_list(customer_id,order_id,status)
) ENGINE=InnoDB COMMENT='美国卡车订单托盘实收记录';
CREATE TABLE IF NOT EXISTS ll_us_truck_order_status_history (
id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
operation_type VARCHAR(64) NOT NULL COMMENT '具名操作类型', from_status VARCHAR(32) NULL COMMENT '变更前状态',
to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID',
idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键',
remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id),
KEY idx_ll_us_truck_history(customer_id,order_id,created_at)
) ENGINE=InnoDB COMMENT='美国卡车订单状态历史';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_us_truck_order_status_history' AND column_name='operation_type'), 'SELECT 1',
'ALTER TABLE ll_us_truck_order_status_history ADD COLUMN operation_type VARCHAR(64) NOT NULL DEFAULT ''UPDATE'' COMMENT ''具名操作类型'' AFTER customer_id'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_us_truck_order_status_history' AND column_name='idempotency_key'), 'SELECT 1',
'ALTER TABLE ll_us_truck_order_status_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
CREATE TABLE IF NOT EXISTS ll_us_truck_order_operation (
id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '美国卡车订单ID',
customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(64) NOT NULL COMMENT '具名操作类型',
idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '操作请求内容哈希',
result_version BIGINT NOT NULL COMMENT '操作完成后的订单版本', created_by VARCHAR(128) NULL COMMENT '操作人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_us_truck_operation_key(customer_id,order_id,idempotency_key),
KEY idx_ll_us_truck_operation_order(customer_id,order_id,created_at)
) ENGINE=InnoDB COMMENT='美国卡车订单幂等操作账';
CREATE TABLE IF NOT EXISTS ll_local_looseboard_order (
id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', lastleg_order_id BIGINT NULL COMMENT '关联尾程主订单ID', order_no VARCHAR(64) NOT NULL COMMENT '本土散板订单号',
transport_mode VARCHAR(32) NOT NULL COMMENT '运输方式:拼车或优先拼载', pallet_required VARCHAR(8) NOT NULL COMMENT '是否需要打盘:YES或NO',
transport_type VARCHAR(32) NOT NULL COMMENT '运输类型', origin VARCHAR(255) NOT NULL COMMENT '起运地', origin_address VARCHAR(500) NULL COMMENT '起运详细地址',
destination VARCHAR(255) NOT NULL COMMENT '目的地', destination_address VARCHAR(500) NULL COMMENT '目的详细地址、码头或仓号',
container_type VARCHAR(32) NULL COMMENT '柜型', package_count INT NOT NULL DEFAULT 0 COMMENT '货物件数',
total_weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '总重量(千克)', total_volume_cbm DECIMAL(18,6) NOT NULL DEFAULT 0 COMMENT '总体积(立方米)',
budget_amount DECIMAL(18,2) NULL COMMENT '预算总价', currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '预算币种',
contact_name VARCHAR(128) NULL COMMENT '联系人姓名', contact_info VARCHAR(128) NULL COMMENT '联系人联系方式',
requested_date DATE NULL COMMENT '要求服务日期', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ACCEPTANCE' COMMENT '本土散板订单状态',
remark VARCHAR(1000) NULL COMMENT '备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '创建幂等键', request_hash CHAR(64) NOT NULL COMMENT '创建请求内容哈希',
created_by VARCHAR(128) NULL COMMENT '创建人ID', version BIGINT 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 '更新时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_local_looseboard_no(customer_id,order_no), UNIQUE KEY uk_ll_local_looseboard_key(customer_id,idempotency_key),
UNIQUE KEY uk_ll_local_looseboard_lastleg(lastleg_order_id),
KEY idx_ll_local_looseboard_list(customer_id,status,created_at), KEY idx_ll_local_looseboard_date(customer_id,requested_date,created_at)
) ENGINE=InnoDB COMMENT='本土散板订单';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_local_looseboard_order' AND column_name='lastleg_order_id'), 'SELECT 1',
'ALTER TABLE ll_local_looseboard_order ADD COLUMN lastleg_order_id BIGINT NULL COMMENT ''关联尾程主订单ID'' AFTER customer_id'));
PREPARE phase4_looseboard_tail_stmt FROM @ddl; EXECUTE phase4_looseboard_tail_stmt; DEALLOCATE PREPARE phase4_looseboard_tail_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
AND table_name='ll_local_looseboard_order' AND index_name='uk_ll_local_looseboard_lastleg'), 'SELECT 1',
'ALTER TABLE ll_local_looseboard_order ADD UNIQUE KEY uk_ll_local_looseboard_lastleg(lastleg_order_id)'));
PREPARE phase4_looseboard_tail_stmt FROM @ddl; EXECUTE phase4_looseboard_tail_stmt; DEALLOCATE PREPARE phase4_looseboard_tail_stmt;
CREATE TABLE IF NOT EXISTS ll_local_looseboard_history (
id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '本土散板订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
operation_type VARCHAR(32) NOT NULL COMMENT '操作类型:CREATE、UPDATE或STATUS', from_status VARCHAR(32) NULL COMMENT '变更前状态',
to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID',
idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '操作备注',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id),
KEY idx_ll_local_looseboard_history(customer_id,order_id,created_at)
) ENGINE=InnoDB COMMENT='本土散板操作流水';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_local_looseboard_history' AND column_name='idempotency_key'), 'SELECT 1',
'ALTER TABLE ll_local_looseboard_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
CREATE TABLE IF NOT EXISTS ll_local_looseboard_operation (
id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '本土散板订单ID',
customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型',
idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '操作请求内容哈希',
result_version BIGINT NOT NULL COMMENT '操作完成后的订单版本', created_by VARCHAR(128) NULL COMMENT '操作人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_local_looseboard_operation_key(customer_id,order_id,idempotency_key),
KEY idx_ll_local_looseboard_operation_order(customer_id,order_id,created_at)
) ENGINE=InnoDB COMMENT='本土散板订单幂等操作账';
-- 尾程主订单状态历史补齐客户隔离键。代码写入 customer_id,已有表需显式升级;
-- 先允许 NULL 以便从主订单回填,再收紧为 NOT NULL,脚本可重复执行。
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_loading_order_status_history' AND column_name='customer_id'), 'SELECT 1',
'ALTER TABLE ll_loading_order_status_history ADD COLUMN customer_id VARCHAR(128) NULL COMMENT ''客户数据隔离键'' AFTER id'));
PREPARE phase4_loading_history_customer_stmt FROM @ddl; EXECUTE phase4_loading_history_customer_stmt; DEALLOCATE PREPARE phase4_loading_history_customer_stmt;
UPDATE ll_loading_order_status_history history
JOIN ll_order orders ON orders.id=history.order_id
SET history.customer_id=orders.customer_id
WHERE history.customer_id IS NULL;
ALTER TABLE ll_loading_order_status_history
MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
AND table_name='ll_loading_order_status_history' AND index_name='idx_ll_loading_history_customer_order'), 'SELECT 1',
'ALTER TABLE ll_loading_order_status_history ADD KEY idx_ll_loading_history_customer_order(customer_id,order_id,created_at)'));
PREPARE phase4_loading_history_customer_stmt FROM @ddl; EXECUTE phase4_loading_history_customer_stmt; DEALLOCATE PREPARE phase4_loading_history_customer_stmt;
-- 尾程订单明细实体、事件消费者和详情查询均使用 customer_id;已有开发库需从主订单回填。
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_order_detail' AND column_name='customer_id'), 'SELECT 1',
'ALTER TABLE ll_order_detail ADD COLUMN customer_id VARCHAR(128) NULL COMMENT ''客户数据隔离键'' AFTER id'));
PREPARE phase4_order_detail_customer_stmt FROM @ddl; EXECUTE phase4_order_detail_customer_stmt; DEALLOCATE PREPARE phase4_order_detail_customer_stmt;
UPDATE ll_order_detail detail
JOIN ll_order orders ON orders.id=detail.order_id
SET detail.customer_id=orders.customer_id
WHERE detail.customer_id IS NULL;
ALTER TABLE ll_order_detail
MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
AND table_name='ll_order_detail' AND index_name='idx_ll_detail_customer_order'), 'SELECT 1',
'ALTER TABLE ll_order_detail ADD KEY idx_ll_detail_customer_order(customer_id,order_id,id)'));
PREPARE phase4_order_detail_customer_stmt FROM @ddl; EXECUTE phase4_order_detail_customer_stmt; DEALLOCATE PREPARE phase4_order_detail_customer_stmt;
-- 四期平台排车查询、智能预排与草稿锁;不开放编辑、发车、PDA 出库或派送。
CREATE TABLE IF NOT EXISTS ll_dispatch_order (
id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
dispatch_no VARCHAR(64) NOT NULL COMMENT '派车单号', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID',
overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', vehicle_plate VARCHAR(64) NULL COMMENT '车牌号',
driver_name VARCHAR(128) NULL COMMENT '司机姓名', driver_phone VARCHAR(64) NULL COMMENT '司机电话',
carrier_name VARCHAR(255) NULL COMMENT '承运商名称', route VARCHAR(255) NULL COMMENT '运输路线',
depart_at DATETIME(3) NULL COMMENT '发车时间', fba_appointment_no VARCHAR(64) NULL COMMENT 'FBA预约号',
fba_appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT 'FBA预约状态',
vehicle_appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '车辆预约状态',
estimated_arrival_at DATETIME(3) NULL COMMENT '预计到达时间',
status VARCHAR(32) NOT NULL DEFAULT 'PENDING_DEPARTURE' COMMENT '业务状态',
item_count INT NOT NULL DEFAULT 0 COMMENT '明细数量', pallet_count INT NOT NULL DEFAULT 0 COMMENT '托盘数',
package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', picked_package_count INT NOT NULL DEFAULT 0 COMMENT 'PDA累计已拣箱数',
shipped_package_count INT NOT NULL DEFAULT 0 COMMENT '累计已出库箱数', partial_completion_reason VARCHAR(1000) NULL COMMENT '部分完成原因',
created_by VARCHAR(128) 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 '更新时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_dispatch_order_no(customer_id,dispatch_no),
KEY idx_ll_dispatch_order_list(customer_id,status,depart_at), KEY idx_ll_dispatch_order_vehicle(customer_id,vehicle_plate)
) ENGINE=InnoDB COMMENT='尾程派车单';
CREATE TABLE IF NOT EXISTS ll_dispatch_item (
id BIGINT NOT NULL COMMENT '主键ID', dispatch_order_id BIGINT NOT NULL COMMENT '派车单ID',
customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', plan_id BIGINT NULL COMMENT '入仓计划ID',
plan_pallet_id BIGINT NULL COMMENT '计划托盘ID', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID',
order_id BIGINT NULL COMMENT '订单ID', order_no VARCHAR(64) NULL COMMENT '订单号',
order_refs VARCHAR(2000) NULL COMMENT '关联订单信息', inbound_code VARCHAR(128) NULL COMMENT '入仓单号快照',
pallet_no VARCHAR(128) NOT NULL COMMENT '托盘号', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID',
overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID',
destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照',
fba_warehouse_code VARCHAR(128) NULL COMMENT 'FBA仓库编码', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数',
volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '体积(立方米)', source_stage VARCHAR(32) NOT NULL COMMENT '数据来源阶段',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_dispatch_item_source(dispatch_order_id,plan_pallet_id,warehouse_pallet_id),
KEY idx_ll_dispatch_item_order(customer_id,order_id), KEY idx_ll_dispatch_item_inbound(customer_id,inbound_code),
KEY idx_ll_dispatch_item_pallet(customer_id,plan_pallet_id,warehouse_pallet_id)
) ENGINE=InnoDB COMMENT='派车货物冻结明细';
CREATE TABLE IF NOT EXISTS ll_dispatch_pallet_lock (
id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
source_pallet_key VARCHAR(160) NOT NULL COMMENT '来源托盘业务键', active_key VARCHAR(160) NULL COMMENT '生效中的资源排他键',
plan_id BIGINT NULL COMMENT '入仓计划ID', plan_pallet_id BIGINT NULL COMMENT '计划托盘ID',
warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID', dispatch_order_id BIGINT NULL COMMENT '正式派车单ID,草稿锁阶段为空',
draft_container_id BIGINT NULL COMMENT '智能排车草稿装车托盘ID', draft_token VARCHAR(64) NULL COMMENT '智能排车草稿随机标识',
operator_id VARCHAR(128) NULL COMMENT '草稿锁操作人ID', status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '业务状态',
locked_at DATETIME(3) NOT NULL COMMENT '锁定时间', expires_at DATETIME(3) NULL COMMENT '草稿锁失效时间,正式派车锁为空',
released_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_ll_dispatch_active_pallet(customer_id,active_key),
KEY idx_ll_dispatch_pallet_lock_order(customer_id,dispatch_order_id,status),
KEY idx_ll_dispatch_pallet_lock_source(customer_id,source_pallet_key,status)
) ENGINE=InnoDB COMMENT='派车托盘排他锁';
CREATE TABLE IF NOT EXISTS ll_dispatch_draft (
id BIGINT NOT NULL COMMENT '主键ID', draft_token VARCHAR(64) NOT NULL COMMENT '智能排车草稿随机标识',
customer_id VARCHAR(128) NULL COMMENT '客户租户ID', operator_id VARCHAR(128) NULL COMMENT '草稿操作人ID',
plan_ids_json VARCHAR(4000) NULL COMMENT '所选入仓计划ID列表JSON', containers_json LONGTEXT NULL COMMENT '草稿装车布局JSON快照',
status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '草稿状态', expires_at DATETIME(3) NULL COMMENT '草稿失效时间',
released_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_ll_dispatch_draft_token(draft_token), KEY idx_ll_dispatch_draft_operator(operator_id,status)
) ENGINE=InnoDB COMMENT='智能排车草稿';
CREATE TABLE IF NOT EXISTS ll_dispatch_draft_container (
id BIGINT NOT NULL COMMENT '主键ID', draft_id BIGINT NOT NULL COMMENT '智能排车草稿ID',
draft_token VARCHAR(64) NOT NULL COMMENT '智能排车草稿随机标识', sequence_no INT NOT NULL COMMENT '草稿车厢顺序号',
capacity INT NOT 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),
KEY idx_ll_dispatch_draft_container_token(draft_token)
) ENGINE=InnoDB COMMENT='智能排车草稿装车托盘';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_item' AND column_name='order_refs'),
'SELECT 1', 'ALTER TABLE ll_dispatch_item ADD COLUMN order_refs VARCHAR(2000) NULL COMMENT ''关联订单信息'' AFTER order_no'));
PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='draft_container_id'),
'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN draft_container_id BIGINT NULL COMMENT ''智能排车草稿装车托盘ID'' AFTER dispatch_order_id'));
PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='draft_token'),
'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN draft_token VARCHAR(64) NULL COMMENT ''智能排车草稿随机标识'' AFTER draft_container_id'));
PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='operator_id'),
'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN operator_id VARCHAR(128) NULL COMMENT ''草稿锁操作人ID'' AFTER draft_token'));
PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='expires_at'),
'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN expires_at DATETIME(3) NULL COMMENT ''草稿锁失效时间,正式派车锁为空'' AFTER locked_at'));
PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='dispatch_order_id' AND is_nullable='YES'),
'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock MODIFY COLUMN dispatch_order_id BIGINT NULL COMMENT ''正式派车单ID,草稿锁阶段为空'''));
PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt;
-- 入仓库存按 SKU 冻结维度;旧环境只补结构,不由部署自动执行。
CREATE TABLE IF NOT EXISTS ll_inbound_plan_carton (
id BIGINT NOT NULL COMMENT '箱唛作业主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID',
order_id BIGINT NULL COMMENT '海外首扫确权后的尾程订单ID', source_inbound_detail_id VARCHAR(128) NOT NULL COMMENT '来源入库明细ID',
sku_code VARCHAR(128) NULL COMMENT 'SKU编码快照', carton_mark VARCHAR(128) NOT NULL COMMENT '国内冻结箱唛',
destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID快照', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照',
destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', plan_id BIGINT NULL COMMENT '海外入库计划ID',
line_id BIGINT NULL COMMENT '入库计划明细ID', plan_pallet_id BIGINT NULL COMMENT '海外计划托盘ID', warehouse_pallet_id BIGINT NULL COMMENT '海外实物托盘ID',
warehouse_location_id BIGINT NULL COMMENT '海外库位ID', pda_task_id BIGINT NULL COMMENT '首次扫码PDA任务ID',
status VARCHAR(32) NOT NULL COMMENT '箱唛状态:UNASSIGNED、ON_PALLET、BULK_RECEIVED、AVAILABLE', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本',
bound_at DATETIME(3) NULL COMMENT '绑定托盘时间', received_at DATETIME(3) NULL COMMENT '完成入库时间',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_inbound_carton_mark(customer_id,carton_mark),
KEY idx_ll_inbound_carton_plan(plan_id,status), KEY idx_ll_inbound_carton_pallet(plan_pallet_id,status), KEY idx_ll_inbound_carton_order(order_id,status)
) ENGINE=InnoDB COMMENT='柜次冻结箱唛及海外入库箱级作业账';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_container_booking_id'),
'ALTER TABLE ll_order MODIFY COLUMN source_container_booking_id VARCHAR(128) NULL COMMENT ''来源头程货柜预订ID''',
'ALTER TABLE ll_order ADD COLUMN source_container_booking_id VARCHAR(128) NULL COMMENT ''来源头程货柜预订ID'' AFTER source_loading_plan_id'));
PREPARE phase4_event_stmt FROM @ddl; EXECUTE phase4_event_stmt; DEALLOCATE PREPARE phase4_event_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='idx_ll_order_pending_container'),
'ALTER TABLE ll_order DROP INDEX idx_ll_order_pending_container','SELECT 1'));
PREPARE phase4_container_progress_idx_stmt FROM @ddl; EXECUTE phase4_container_progress_idx_stmt; DEALLOCATE PREPARE phase4_container_progress_idx_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='idx_ll_order_container_progress'),
'SELECT 1','ALTER TABLE ll_order ADD INDEX idx_ll_order_container_progress(source_container_booking_id,estimated_warehouse_at,created_at,id)'));
PREPARE phase4_container_progress_idx_stmt FROM @ddl; EXECUTE phase4_container_progress_idx_stmt; DEALLOCATE PREPARE phase4_container_progress_idx_stmt;
DROP PROCEDURE IF EXISTS assert_container_progress_index_ready;
DELIMITER $$
CREATE PROCEDURE assert_container_progress_index_ready()
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE()
AND table_name='ll_order' AND index_name='idx_ll_order_container_progress') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外区域初始化失败:柜级入库计划进度索引缺失';
END IF;
END$$
DELIMITER ;
CALL assert_container_progress_index_ready();
DROP PROCEDURE assert_container_progress_index_ready;
-- 头程 V2 事件冻结目的类型;只补结构,不由部署脚本自动执行历史数据回填。
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='destination_type'),
'ALTER TABLE ll_order MODIFY COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码''',
'ALTER TABLE ll_order ADD COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER order_type'));
PREPARE phase4_destination_type_stmt FROM @ddl; EXECUTE phase4_destination_type_stmt; DEALLOCATE PREPARE phase4_destination_type_stmt;
CREATE TABLE IF NOT EXISTS ll_order_no_daily_sequence (
business_date DATE NOT NULL COMMENT '业务日期(Asia/Shanghai)',
last_sequence INT NOT NULL COMMENT '当日已分配尾程单流水号',
PRIMARY KEY(business_date)
) ENGINE=InnoDB COMMENT='尾程单号按日原子流水';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='customer_id'),
'SELECT 1',
'ALTER TABLE ll_inbound_plan_line ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id'));
PREPARE phase4_receiving_line_stmt FROM @ddl; EXECUTE phase4_receiving_line_stmt; DEALLOCATE PREPARE phase4_receiving_line_stmt;
UPDATE ll_inbound_plan_line l JOIN ll_inbound_plan p ON p.id=l.plan_id SET l.customer_id=p.customer_id WHERE l.customer_id IS NULL OR l.customer_id='';
ALTER TABLE ll_inbound_plan_line MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND index_name='idx_ll_inbound_line_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_line ADD KEY idx_ll_inbound_line_customer_plan(customer_id,plan_id)'));
PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND column_name='customer_id'),
'SELECT 1',
'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id'));
PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt;
UPDATE ll_inbound_plan_pallet v JOIN ll_inbound_plan p ON p.id=v.plan_id SET v.customer_id=p.customer_id WHERE v.customer_id IS NULL OR v.customer_id='';
ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND index_name='idx_ll_inbound_pallet_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD KEY idx_ll_inbound_pallet_customer_plan(customer_id,plan_id)'));
PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet_allocation' AND column_name='customer_id'),
'SELECT 1',
'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id'));
PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt;
UPDATE ll_inbound_plan_pallet_allocation a JOIN ll_inbound_plan p ON p.id=a.plan_id SET a.customer_id=p.customer_id WHERE a.customer_id IS NULL OR a.customer_id='';
ALTER TABLE ll_inbound_plan_pallet_allocation MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet_allocation' AND index_name='idx_ll_inbound_allocation_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD KEY idx_ll_inbound_allocation_customer_plan(customer_id,plan_id)'));
PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt;
DROP PROCEDURE IF EXISTS assert_phase4_inbound_plan_customer_scope_ready;
DELIMITER $$
CREATE PROCEDURE assert_phase4_inbound_plan_customer_scope_ready()
BEGIN
IF EXISTS (SELECT 1 FROM ll_inbound_plan_line l LEFT JOIN ll_inbound_plan p ON p.id=l.plan_id WHERE l.customer_id IS NULL OR l.customer_id='' OR p.id IS NULL OR l.customer_id<>p.customer_id)
OR EXISTS (SELECT 1 FROM ll_inbound_plan_pallet v LEFT JOIN ll_inbound_plan p ON p.id=v.plan_id WHERE v.customer_id IS NULL OR v.customer_id='' OR p.id IS NULL OR v.customer_id<>p.customer_id)
OR EXISTS (SELECT 1 FROM ll_inbound_plan_pallet_allocation a LEFT JOIN ll_inbound_plan p ON p.id=a.plan_id WHERE a.customer_id IS NULL OR a.customer_id='' OR p.id IS NULL OR a.customer_id<>p.customer_id) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Inbound plan child customer scope migration is incomplete';
END IF;
END$$
DELIMITER ;
CALL assert_phase4_inbound_plan_customer_scope_ready();
DROP PROCEDURE assert_phase4_inbound_plan_customer_scope_ready;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='fba_warehouse_code'),
'ALTER TABLE ll_inbound_plan_line MODIFY COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''FBA仓库编码''',
'ALTER TABLE ll_inbound_plan_line ADD COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''FBA仓库编码'' AFTER inbound_code'));
PREPARE phase4_receiving_line_stmt FROM @ddl; EXECUTE phase4_receiving_line_stmt; DEALLOCATE PREPARE phase4_receiving_line_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='destination_type'),
'ALTER TABLE ll_inbound_plan_line MODIFY COLUMN destination_type VARCHAR(32) NOT NULL DEFAULT ''OVERSEAS'' COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码''',
'ALTER TABLE ll_inbound_plan_line ADD COLUMN destination_type VARCHAR(32) NOT NULL DEFAULT ''OVERSEAS'' COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER inbound_code'));
PREPARE phase4_receiving_line_stmt FROM @ddl; EXECUTE phase4_receiving_line_stmt; DEALLOCATE PREPARE phase4_receiving_line_stmt;
UPDATE ll_inbound_plan_line l JOIN ll_order o ON o.id=l.order_id
SET l.destination_type=COALESCE(NULLIF(o.destination_type,''),CASE WHEN NULLIF(l.fba_warehouse_code,'') IS NULL THEN 'OVERSEAS' ELSE 'FBA' END)
WHERE l.destination_type IS NULL OR l.destination_type='' OR l.destination_type='OVERSEAS';
SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_warehouse_id'),
'SELECT 1','ALTER TABLE ll_order ADD COLUMN source_warehouse_id VARCHAR(128) NULL COMMENT ''来源国内装柜仓ID快照'' AFTER customer_name'));
PREPARE phase4_source_warehouse_id_stmt FROM @ddl; EXECUTE phase4_source_warehouse_id_stmt; DEALLOCATE PREPARE phase4_source_warehouse_id_stmt;
SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_warehouse_name'),
'SELECT 1','ALTER TABLE ll_order ADD COLUMN source_warehouse_name VARCHAR(255) NULL COMMENT ''来源国内装柜仓名称快照'' AFTER source_warehouse_id'));
PREPARE phase4_source_warehouse_name_stmt FROM @ddl; EXECUTE phase4_source_warehouse_name_stmt; DEALLOCATE PREPARE phase4_source_warehouse_name_stmt;
SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='overseas_warehouse_id'),
'SELECT 1','ALTER TABLE ll_inbound_plan ADD COLUMN overseas_warehouse_id BIGINT NULL COMMENT ''海外实际收货共享物理仓ID,由PDA认领柜号时冻结'' AFTER container_no'));
PREPARE phase4_plan_receiving_warehouse_stmt FROM @ddl; EXECUTE phase4_plan_receiving_warehouse_stmt; DEALLOCATE PREPARE phase4_plan_receiving_warehouse_stmt;
UPDATE ll_order o JOIN ll_loading_event_inbox i ON i.event_id=o.source_event_id
SET o.source_warehouse_id=COALESCE(o.source_warehouse_id,JSON_UNQUOTE(JSON_EXTRACT(i.payload_json,'$.warehouseId'))),
o.source_warehouse_name=COALESCE(o.source_warehouse_name,JSON_UNQUOTE(JSON_EXTRACT(i.payload_json,'$.warehouseName'))),
o.overseas_warehouse_id=NULL,o.overseas_warehouse_name=NULL
WHERE o.current_status<>'INBOUND_COMPLETED'
AND o.overseas_warehouse_id=JSON_UNQUOTE(JSON_EXTRACT(i.payload_json,'$.warehouseId'));
DROP PROCEDURE IF EXISTS assert_pending_orders_do_not_use_source_warehouse;
DELIMITER $$
CREATE PROCEDURE assert_pending_orders_do_not_use_source_warehouse()
BEGIN
IF EXISTS(SELECT 1 FROM ll_order o JOIN ll_loading_event_inbox i ON i.event_id=o.source_event_id
WHERE o.current_status<>'INBOUND_COMPLETED' AND o.overseas_warehouse_id IS NOT NULL
AND o.overseas_warehouse_id=JSON_UNQUOTE(JSON_EXTRACT(i.payload_json,'$.warehouseId'))) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='未完成尾程单仍将国内来源仓冒充海外实际收货仓';
END IF;
END$$
DELIMITER ;
CALL assert_pending_orders_do_not_use_source_warehouse();
DROP PROCEDURE assert_pending_orders_do_not_use_source_warehouse;
CREATE TABLE IF NOT EXISTS ll_receiving_container_session (
id BIGINT NOT NULL COMMENT '柜号签收会话ID', customer_id VARCHAR(128) NOT NULL COMMENT '所选柜解析出的客户标识',
source_container_booking_id VARCHAR(128) NOT NULL COMMENT '稳定来源柜预订ID', container_fact_hash VARCHAR(64) NOT NULL COMMENT '领取时整柜订单与计划事实摘要', container_no VARCHAR(64) NOT NULL COMMENT '集装箱号',
overseas_warehouse_id BIGINT NOT NULL COMMENT '操作员Token绑定并冻结的海外实际收货共享物理仓ID', overseas_warehouse_name VARCHAR(255) NOT NULL COMMENT '仓库服务校验后的海外实际收货共享物理仓名称快照',
operator_key VARCHAR(128) NOT NULL COMMENT '操作账号唯一标识', operator_name VARCHAR(255) NULL COMMENT '操作账号名称', active_operator_key VARCHAR(255) NULL COMMENT '未完成会话平台操作账号全局唯一锁键',
active_container_key VARCHAR(255) NULL COMMENT '未完成会话柜号全局唯一锁键', status VARCHAR(32) NOT NULL DEFAULT 'WAIT_SIGN' COMMENT '会话状态:WAIT_SIGN、SIGNED、RECEIVING、COMPLETED',
sign_photos JSON NULL COMMENT '签收卸柜照片角色与文件ID列表', prepared_at DATETIME(3) NULL COMMENT '选择柜号时间', signed_at DATETIME(3) NULL COMMENT '签收时间',
receiving_at DATETIME(3) NULL COMMENT '首次收货时间', 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 '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', PRIMARY KEY(id),
UNIQUE KEY uk_ll_receiving_active_operator(active_operator_key), UNIQUE KEY uk_ll_receiving_active_container(active_container_key),
KEY idx_ll_receiving_container(customer_id,container_no,status), KEY idx_ll_receiving_operator(customer_id,operator_key,created_at)
) ENGINE=InnoDB COMMENT='海外PDA柜号签收收货会话';
SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='source_container_booking_id'),
'SELECT 1','ALTER TABLE ll_receiving_container_session ADD COLUMN source_container_booking_id VARCHAR(128) NULL COMMENT ''稳定来源柜预订ID'' AFTER customer_id'));
PREPARE phase4_receiving_fact_stmt FROM @ddl; EXECUTE phase4_receiving_fact_stmt; DEALLOCATE PREPARE phase4_receiving_fact_stmt;
SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='container_fact_hash'),
'SELECT 1','ALTER TABLE ll_receiving_container_session ADD COLUMN container_fact_hash VARCHAR(64) NULL COMMENT ''领取时整柜订单与计划事实摘要'' AFTER source_container_booking_id'));
PREPARE phase4_receiving_fact_stmt FROM @ddl; EXECUTE phase4_receiving_fact_stmt; DEALLOCATE PREPARE phase4_receiving_fact_stmt;
SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='overseas_warehouse_id'),
'SELECT 1','ALTER TABLE ll_receiving_container_session ADD COLUMN overseas_warehouse_id BIGINT NULL COMMENT ''操作员Token绑定并冻结的海外实际收货共享物理仓ID'' AFTER container_no'));
PREPARE phase4_session_receiving_warehouse_stmt FROM @ddl; EXECUTE phase4_session_receiving_warehouse_stmt; DEALLOCATE PREPARE phase4_session_receiving_warehouse_stmt;
SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='overseas_warehouse_name'),
'SELECT 1','ALTER TABLE ll_receiving_container_session ADD COLUMN overseas_warehouse_name VARCHAR(255) NULL COMMENT ''仓库服务校验后的海外实际收货共享物理仓名称快照'' AFTER overseas_warehouse_id'));
PREPARE phase4_session_receiving_warehouse_name_stmt FROM @ddl; EXECUTE phase4_session_receiving_warehouse_name_stmt; DEALLOCATE PREPARE phase4_session_receiving_warehouse_name_stmt;
DROP PROCEDURE IF EXISTS assert_active_receiving_session_has_warehouse;
DELIMITER $$
CREATE PROCEDURE assert_active_receiving_session_has_warehouse()
BEGIN
IF EXISTS(SELECT 1 FROM ll_receiving_container_session WHERE active_container_key IS NOT NULL
AND (overseas_warehouse_id IS NULL OR overseas_warehouse_name IS NULL OR overseas_warehouse_name='')) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='存在无法安全推断海外实际收货仓的未完成PDA柜会话';
END IF;
END$$
DELIMITER ;
CALL assert_active_receiving_session_has_warehouse();
DROP PROCEDURE assert_active_receiving_session_has_warehouse;
ALTER TABLE ll_receiving_container_session
MODIFY COLUMN overseas_warehouse_id BIGINT NOT NULL COMMENT '操作员Token绑定并冻结的海外实际收货共享物理仓ID',
MODIFY COLUMN overseas_warehouse_name VARCHAR(255) NOT NULL COMMENT '仓库服务校验后的海外实际收货共享物理仓名称快照';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='sign_photos'),
'ALTER TABLE ll_receiving_container_session MODIFY COLUMN sign_photos JSON NULL COMMENT ''签收卸柜照片角色与文件ID列表''',
'ALTER TABLE ll_receiving_container_session ADD COLUMN sign_photos JSON NULL COMMENT ''签收卸柜照片角色与文件ID列表'' AFTER status'));
PREPARE phase4_receiving_sign_photos_stmt FROM @ddl; EXECUTE phase4_receiving_sign_photos_stmt; DEALLOCATE PREPARE phase4_receiving_sign_photos_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='photo_file_ids'),
'ALTER TABLE ll_receiving_container_session DROP COLUMN photo_file_ids', 'SELECT 1'));
PREPARE phase4_receiving_drop_raw_photos_stmt FROM @ddl; EXECUTE phase4_receiving_drop_raw_photos_stmt; DEALLOCATE PREPARE phase4_receiving_drop_raw_photos_stmt;
DROP PROCEDURE IF EXISTS assert_receiving_global_locks_migratable;
UPDATE ll_receiving_container_session
SET active_operator_key=NULL,active_container_key=NULL
WHERE status='COMPLETED' AND (active_operator_key IS NOT NULL OR active_container_key IS NOT NULL);
DELIMITER $$
CREATE PROCEDURE assert_receiving_global_locks_migratable()
BEGIN
IF EXISTS (SELECT operator_key FROM ll_receiving_container_session
WHERE active_operator_key IS NOT NULL GROUP BY operator_key HAVING COUNT(*) > 1) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA全局账号锁迁移失败:同一账号存在多个未完成柜';
END IF;
IF EXISTS (SELECT UPPER(TRIM(container_no)) FROM ll_receiving_container_session
WHERE active_container_key IS NOT NULL GROUP BY UPPER(TRIM(container_no)) HAVING COUNT(*) > 1) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA全局柜号锁迁移失败:同一柜存在多个未完成会话';
END IF;
END$$
DELIMITER ;
CALL assert_receiving_global_locks_migratable();
DROP PROCEDURE assert_receiving_global_locks_migratable;
UPDATE ll_receiving_container_session
SET active_operator_key=CONCAT('OPERATOR:',operator_key),
active_container_key=CONCAT('CONTAINER:',UPPER(TRIM(container_no)))
WHERE active_operator_key IS NOT NULL OR active_container_key IS NOT NULL;
ALTER TABLE ll_receiving_container_session
MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '所选柜解析出的客户标识',
MODIFY COLUMN active_operator_key VARCHAR(255) NULL COMMENT '未完成会话平台操作账号全局唯一锁键',
MODIFY COLUMN active_container_key VARCHAR(255) NULL COMMENT '未完成会话柜号全局唯一锁键';
CREATE TABLE IF NOT EXISTS ll_receiving_sku_receipt (
id BIGINT NOT NULL COMMENT 'FBA SKU实收进度ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识',
session_id BIGINT NOT NULL COMMENT '柜号签收会话ID', plan_id BIGINT NOT NULL COMMENT '入仓计划ID',
line_id BIGINT NOT NULL COMMENT '入仓计划明细ID', pallet_id BIGINT NOT NULL COMMENT '计划托盘ID',
order_id BIGINT NOT NULL COMMENT '尾程订单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓码快照',
sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码快照', product_name VARCHAR(255) NULL COMMENT '产品名称快照',
received_packages INT NOT NULL COMMENT 'SKU实收箱数', 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_ll_receiving_sku_pallet (customer_id,line_id,pallet_id,sku_code),
KEY idx_ll_receiving_sku_session (customer_id,session_id,line_id),
KEY idx_ll_receiving_sku_plan (customer_id,plan_id,line_id)
) ENGINE=InnoDB COMMENT='海外PDA柜号FBA SKU实收进度';
CREATE TABLE IF NOT EXISTS ll_receiving_container_operation (
id BIGINT NOT NULL COMMENT '柜号收货操作ID', session_id BIGINT NOT NULL COMMENT '柜号签收会话ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识',
operator_key VARCHAR(128) NOT NULL COMMENT '操作账号唯一标识', action VARCHAR(32) NOT NULL COMMENT '操作动作', idempotency_key VARCHAR(255) NOT NULL COMMENT '客户端幂等键',
request_hash VARCHAR(128) NOT NULL COMMENT '请求内容哈希', request_json LONGTEXT NOT NULL COMMENT '请求内容快照', result_json LONGTEXT NOT NULL COMMENT '响应内容快照',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_receiving_operation(operator_key,idempotency_key), KEY idx_ll_receiving_operation_session(session_id,created_at)
) ENGINE=InnoDB COMMENT='海外PDA柜号收货幂等审计记录';
DROP PROCEDURE IF EXISTS assert_receiving_operation_global_key_migratable;
DELIMITER $$
CREATE PROCEDURE assert_receiving_operation_global_key_migratable()
BEGIN
IF EXISTS (SELECT operator_key,idempotency_key FROM ll_receiving_container_operation
GROUP BY operator_key,idempotency_key HAVING COUNT(*) > 1) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA全局幂等键迁移失败:同一操作账号存在重复幂等键';
END IF;
END$$
DELIMITER ;
CALL assert_receiving_operation_global_key_migratable();
DROP PROCEDURE assert_receiving_operation_global_key_migratable;
SET @receiving_operation_global_index = (
SELECT COUNT(*) FROM (
SELECT index_name FROM information_schema.statistics
WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_operation'
AND index_name='uk_ll_receiving_operation'
GROUP BY index_name
HAVING GROUP_CONCAT(column_name ORDER BY seq_in_index)= 'operator_key,idempotency_key'
) ready_index
);
SET @receiving_operation_named_index = (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_operation'
AND index_name='uk_ll_receiving_operation'
);
SET @ddl = IF(@receiving_operation_global_index=1, 'SELECT 1',
IF(@receiving_operation_named_index>0,
'ALTER TABLE ll_receiving_container_operation DROP INDEX uk_ll_receiving_operation, ADD UNIQUE KEY uk_ll_receiving_operation(operator_key,idempotency_key)',
'ALTER TABLE ll_receiving_container_operation ADD UNIQUE KEY uk_ll_receiving_operation(operator_key,idempotency_key)'));
PREPARE phase4_receiving_operation_index_stmt FROM @ddl; EXECUTE phase4_receiving_operation_index_stmt; DEALLOCATE PREPARE phase4_receiving_operation_index_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_order' AND column_name='destination_type'),
'ALTER TABLE ll_inbound_order MODIFY COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码''',
'ALTER TABLE ll_inbound_order ADD COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER destination_warehouse_name'));
PREPARE phase4_destination_type_stmt FROM @ddl; EXECUTE phase4_destination_type_stmt; DEALLOCATE PREPARE phase4_destination_type_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='sub_order_status'),
'SELECT 1',
'ALTER TABLE ll_order ADD COLUMN sub_order_status VARCHAR(255) NULL COMMENT ''子单据状态汇总'' AFTER current_status'));
PREPARE phase4_sub_order_status_stmt FROM @ddl; EXECUTE phase4_sub_order_status_stmt; DEALLOCATE PREPARE phase4_sub_order_status_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='order_type' AND COALESCE(column_comment,'') LIKE '订单类型:%'),
'SELECT 1',
'ALTER TABLE ll_order MODIFY COLUMN order_type VARCHAR(32) NOT NULL DEFAULT ''FIRST_LEG'' COMMENT ''订单类型:FIRST_LEG头程订单、RELABEL_APPLICATION换标下单、WAREHOUSE_TRANSFER仓储转运、LOCAL_LOOSEBOARD本土散板、RETURN_RELABEL退货换标、ONE_CLICK_DROPSHIP一件代发'''));
PREPARE phase4_order_type_comment_stmt FROM @ddl; EXECUTE phase4_order_type_comment_stmt; DEALLOCATE PREPARE phase4_order_type_comment_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='current_status' AND COALESCE(column_comment,'') LIKE '当前业务状态:%'),
'SELECT 1',
'ALTER TABLE ll_order MODIFY COLUMN current_status VARCHAR(32) NOT NULL DEFAULT ''PENDING_ASSIGNMENT'' COMMENT ''当前业务状态:PENDING_ASSIGNMENT待分配、PENDING_INBOUND待入库、INBOUND_COMPLETED入库完成、PENDING_DELIVERY待派送、DELIVERING派送中、DELIVERED派送完成'''));
PREPARE phase4_order_status_comment_stmt FROM @ddl; EXECUTE phase4_order_status_comment_stmt; DEALLOCATE PREPARE phase4_order_status_comment_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='unload_photo_file_ids'),
'ALTER TABLE ll_inbound_pda_task MODIFY COLUMN unload_photo_file_ids JSON NULL COMMENT ''卸柜照片文件ID列表''',
'ALTER TABLE ll_inbound_pda_task ADD COLUMN unload_photo_file_ids JSON NULL COMMENT ''卸柜照片文件ID列表'' AFTER completed_at'));
PREPARE phase4_event_stmt FROM @ddl; EXECUTE phase4_event_stmt; DEALLOCATE PREPARE phase4_event_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='unload_photo_uploaded_at'),
'ALTER TABLE ll_inbound_pda_task MODIFY COLUMN unload_photo_uploaded_at DATETIME(3) NULL COMMENT ''卸柜照片上传成功时间''',
'ALTER TABLE ll_inbound_pda_task ADD COLUMN unload_photo_uploaded_at DATETIME(3) NULL COMMENT ''卸柜照片上传成功时间'' AFTER unload_photo_file_ids'));
PREPARE phase4_event_stmt FROM @ddl; EXECUTE phase4_event_stmt; DEALLOCATE PREPARE phase4_event_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='estimated_empty_return_at'),
'ALTER TABLE ll_inbound_pda_task MODIFY COLUMN estimated_empty_return_at DATETIME(3) NULL COMMENT ''预计报空时间(卸柜照片上传成功后两天)''',
'ALTER TABLE ll_inbound_pda_task ADD COLUMN estimated_empty_return_at DATETIME(3) NULL COMMENT ''预计报空时间(卸柜照片上传成功后两天)'' AFTER unload_photo_uploaded_at'));
PREPARE phase4_event_stmt FROM @ddl; EXECUTE phase4_event_stmt; DEALLOCATE PREPARE phase4_event_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND index_name='uk_ll_inbound_plan_container'),
'ALTER TABLE ll_inbound_plan DROP INDEX uk_ll_inbound_plan_container', 'SELECT 1'));
PREPARE phase4_inbound_stmt FROM @ddl; EXECUTE phase4_inbound_stmt; DEALLOCATE PREPARE phase4_inbound_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND index_name='idx_ll_inbound_plan_container'),
'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD KEY idx_ll_inbound_plan_container (customer_id,container_no)'));
PREPARE phase4_inbound_stmt FROM @ddl; EXECUTE phase4_inbound_stmt; DEALLOCATE PREPARE phase4_inbound_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND column_name='sku_code'),
'ALTER TABLE ll_inventory_balance MODIFY COLUMN sku_code VARCHAR(128) NOT NULL DEFAULT ''UNSPECIFIED'' COMMENT ''SKU快照;多SKU汇总时为MIXED,不参与当前库存唯一维度''',
'ALTER TABLE ll_inventory_balance ADD COLUMN sku_code VARCHAR(128) NOT NULL DEFAULT ''UNSPECIFIED'' COMMENT ''SKU快照;多SKU汇总时为MIXED,不参与当前库存唯一维度'' AFTER inbound_code'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND column_name='customer_name'),
'ALTER TABLE ll_inventory_balance MODIFY COLUMN customer_name VARCHAR(255) NOT NULL COMMENT ''客户名称不可变快照''',
'ALTER TABLE ll_inventory_balance ADD COLUMN customer_name VARCHAR(255) NOT NULL COMMENT ''客户名称不可变快照'' AFTER customer_id'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_ledger' AND column_name='customer_name'),
'ALTER TABLE ll_inventory_ledger MODIFY COLUMN customer_name VARCHAR(255) NOT NULL COMMENT ''客户名称不可变快照''',
'ALTER TABLE ll_inventory_ledger ADD COLUMN customer_name VARCHAR(255) NOT NULL COMMENT ''客户名称不可变快照'' AFTER customer_id'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND column_name='product_name_zh'),
'SELECT 1', 'ALTER TABLE ll_inventory_balance ADD COLUMN product_name_zh VARCHAR(255) NULL COMMENT ''中文品名快照'' AFTER sku_code'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND column_name='product_name_en'),
'SELECT 1', 'ALTER TABLE ll_inventory_balance ADD COLUMN product_name_en VARCHAR(255) NULL COMMENT ''英文品名快照'' AFTER product_name_zh'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND index_name='uk_ll_inventory_dimension'),
'ALTER TABLE ll_inventory_balance DROP INDEX uk_ll_inventory_dimension', 'SELECT 1'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND index_name='uk_ll_inventory_dimension'),
'SELECT 1', 'ALTER TABLE ll_inventory_balance ADD UNIQUE KEY uk_ll_inventory_dimension (customer_id,overseas_warehouse_id,destination_warehouse_code,inbound_order_id,inbound_code)'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
ALTER TABLE ll_inventory_balance COMMENT='客户入仓单与海外目的仓维度实时库存余额';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND index_name='idx_ll_inventory_sku'),
'SELECT 1', 'ALTER TABLE ll_inventory_balance ADD KEY idx_ll_inventory_sku (customer_id,sku_code,updated_at)'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND column_name='sku_code'),
'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN sku_code VARCHAR(128) NOT NULL DEFAULT ''UNSPECIFIED'' COMMENT ''SKU编码快照'' AFTER inbound_code'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND column_name='product_name_zh'),
'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN product_name_zh VARCHAR(255) NULL COMMENT ''中文品名快照'' AFTER sku_code'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND column_name='product_name_en'),
'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN product_name_en VARCHAR(255) NULL COMMENT ''英文品名快照'' AFTER product_name_zh'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND index_name='uk_ll_stock_receipt_task_allocation'),
'ALTER TABLE ll_inbound_stock_receipt DROP INDEX uk_ll_stock_receipt_task_allocation', 'SELECT 1'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND index_name='uk_ll_stock_receipt_task_allocation_sku'),
'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD UNIQUE KEY uk_ll_stock_receipt_task_allocation_sku (customer_id,task_id,allocation_id,sku_code)'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
-- 海运节点达到可提柜后才允许海外 PDA 认领;装柜完成只建立等待门禁快照。
CREATE TABLE IF NOT EXISTS ll_container_shipping_gate (
container_booking_id VARCHAR(128) NOT NULL COMMENT '来源头程柜预订ID',
customer_id VARCHAR(128) NOT NULL COMMENT '客户标识',
ocean_booking_id VARCHAR(128) NOT NULL COMMENT '来源海运订舱ID',
container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号',
status VARCHAR(32) NOT NULL DEFAULT 'AWAITING_PICKUP_READY' COMMENT '海外收货门禁状态:AWAITING_PICKUP_READY、RECEIVING_AVAILABLE',
standard_node VARCHAR(64) NULL COMMENT '最新有效标准船节点',
node_sequence INT NOT NULL DEFAULT 0 COMMENT '最新有效节点单调序号',
observed_at DATETIME(3) NULL COMMENT '供应商节点观测时间',
actual_at DATETIME(3) NULL COMMENT '节点实际发生时间',
location_code VARCHAR(128) NULL COMMENT '节点地点编码',
location_name VARCHAR(255) NULL COMMENT '节点地点名称',
provider_code VARCHAR(64) NULL COMMENT '船节点供应商编码',
provider_event_id VARCHAR(128) NULL COMMENT '供应商事件ID',
provider_node_code VARCHAR(128) NULL COMMENT '供应商原始节点编码',
source_reference VARCHAR(255) NULL COMMENT '供应商来源引用',
raw_payload_hash VARCHAR(64) NULL COMMENT '供应商原始负载SHA-256',
aggregate_version BIGINT NOT NULL DEFAULT 0 COMMENT '来源查询聚合版本',
handover_version BIGINT NOT NULL DEFAULT 1 COMMENT '跨区交接版本',
last_event_id VARCHAR(128) NULL COMMENT '最近采纳的跨区事件ID',
payload_hash VARCHAR(71) 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(container_booking_id),
KEY idx_ll_shipping_gate_candidate(customer_id,container_no,status),
KEY idx_ll_shipping_gate_version(container_booking_id,aggregate_version,node_sequence)
) ENGINE=InnoDB COMMENT='海外PDA柜号船节点收货资格快照';
INSERT IGNORE INTO ll_container_shipping_gate (
container_booking_id,customer_id,ocean_booking_id,container_no,status,
node_sequence,aggregate_version,handover_version,created_at,updated_at
)
SELECT source_container_booking_id,customer_id,'',container_no,'AWAITING_PICKUP_READY',
0,COALESCE(MAX(source_loading_plan_version),0),COALESCE(MAX(source_handover_version),1),NOW(3),NOW(3)
FROM ll_order
WHERE source_container_booking_id IS NOT NULL AND source_container_booking_id <> ''
AND container_no IS NOT NULL AND container_no <> ''
GROUP BY source_container_booking_id,customer_id,container_no;
CREATE TABLE IF NOT EXISTS ll_pda_operation_history (
id BIGINT NOT NULL COMMENT 'PDA作业历史ID',
overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID',
customer_id VARCHAR(128) NULL COMMENT '作业涉及的客户标识',
operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识',
operation_type VARCHAR(64) NOT NULL COMMENT '作业类型',
business_key VARCHAR(255) NOT NULL COMMENT '作业业务键',
status VARCHAR(32) NOT NULL COMMENT '作业结果状态',
idempotency_key VARCHAR(255) NULL COMMENT '写操作幂等键',
request_hash VARCHAR(128) NULL COMMENT '写请求内容哈希',
summary VARCHAR(1000) NULL COMMENT '作业结果摘要',
occurred_at DATETIME(3) NOT NULL COMMENT '作业发生时间',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
PRIMARY KEY(id),
UNIQUE KEY uk_ll_pda_history_idempotency(operator_key,idempotency_key),
KEY idx_ll_pda_history_operator(overseas_warehouse_id,operator_key,occurred_at),
KEY idx_ll_pda_history_business(overseas_warehouse_id,operation_type,business_key)
) ENGINE=InnoDB COMMENT='海外PDA真实作业历史';
CREATE TABLE IF NOT EXISTS ll_pda_pallet_operation (
id BIGINT NOT NULL COMMENT 'PDA托盘作业ID', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID',
operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', idempotency_key VARCHAR(128) NOT NULL COMMENT '设备幂等键',
operation_type VARCHAR(64) NOT NULL COMMENT '托盘作业类型', request_hash VARCHAR(128) NOT NULL COMMENT '请求内容摘要',
status VARCHAR(32) NOT NULL COMMENT '处理状态:PROCESSING、COMPLETED、FAILED_COMPENSATED、COMPENSATION_REQUIRED',
result_json LONGTEXT NULL COMMENT '成功响应快照', remote_transitions_json LONGTEXT NULL COMMENT '实物托盘状态变更回执',
last_error VARCHAR(2000) 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_ll_pda_pallet_idempotency(operator_key,idempotency_key),
KEY idx_ll_pda_pallet_warehouse(overseas_warehouse_id,status,updated_at)
) ENGINE=InnoDB COMMENT='海外PDA托盘作业幂等、补偿与结果记录';
CREATE TABLE IF NOT EXISTS ll_pda_stocktake_task (
id BIGINT NOT NULL COMMENT '盘点任务ID', task_no VARCHAR(64) NOT NULL COMMENT '盘点任务号',
overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', scope_type VARCHAR(16) NOT NULL COMMENT '盘点范围类型LOCATION或PALLET',
scope_resource_id BIGINT NOT NULL COMMENT '盘点库位或托盘资源ID', scope_code VARCHAR(128) NOT NULL COMMENT '盘点库位码或托盘码快照',
status VARCHAR(32) NOT NULL COMMENT '盘点任务状态', position_count INT NOT NULL COMMENT '库存位置总数',
counted_count INT NOT NULL DEFAULT 0 COMMENT '已盘库存位置数', difference_count INT NOT NULL DEFAULT 0 COMMENT '存在差异的库存位置数',
created_by VARCHAR(128) NOT NULL COMMENT '创建操作账号标识', submitted_by VARCHAR(128) NULL COMMENT '提交操作账号标识',
submit_reason VARCHAR(500) NULL COMMENT '盘点差异提交原因', idempotency_key VARCHAR(128) NOT NULL COMMENT '创建幂等键',
request_hash VARCHAR(128) NOT NULL COMMENT '创建请求哈希', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间',
submitted_at DATETIME(3) NULL COMMENT '提交完成时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_stocktake_no(task_no),
UNIQUE KEY uk_ll_pda_stocktake_create(overseas_warehouse_id,created_by,idempotency_key),
KEY idx_ll_pda_stocktake_list(overseas_warehouse_id,status,created_at)
) ENGINE=InnoDB COMMENT='海外PDA库存盘点任务';
CREATE TABLE IF NOT EXISTS ll_pda_stocktake_item (
id BIGINT NOT NULL COMMENT '盘点明细ID', task_id BIGINT NOT NULL COMMENT '盘点任务ID', customer_id VARCHAR(128) NOT NULL COMMENT '库存所属客户标识',
balance_id BIGINT NOT NULL COMMENT '库存余额ID', position_id BIGINT NOT NULL COMMENT '库存位置ID', sku_code VARCHAR(128) NULL COMMENT 'SKU快照',
product_name VARCHAR(255) NULL COMMENT '品名快照', inbound_code VARCHAR(128) NULL COMMENT '入仓码快照', pallet_id BIGINT NOT NULL COMMENT '实物托盘ID',
pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照', location_id BIGINT NOT NULL COMMENT '库位ID快照', location_code VARCHAR(128) NOT NULL COMMENT '库位码快照',
book_packages BIGINT NOT NULL COMMENT '任务创建时账面总箱数', actual_packages BIGINT NULL COMMENT '现场实盘总箱数',
difference_packages BIGINT NULL COMMENT '实盘与账面箱数差异', status VARCHAR(32) NOT NULL COMMENT '盘点明细状态',
position_version BIGINT NOT NULL COMMENT '任务创建时库存位置版本', counted_by VARCHAR(128) NULL COMMENT '盘点操作账号标识',
version BIGINT NOT NULL DEFAULT 0 COMMENT '明细乐观锁版本', counted_at DATETIME(3) NULL COMMENT '盘点时间',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_stocktake_item(task_id,position_id), KEY idx_ll_pda_stocktake_item_task(task_id,status,id)
) ENGINE=InnoDB COMMENT='海外PDA库存盘点位置明细';
CREATE TABLE IF NOT EXISTS ll_pda_stocktake_action (
id BIGINT NOT NULL COMMENT '盘点动作ID', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID',
operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', idempotency_key VARCHAR(128) NOT NULL COMMENT '动作幂等键',
action_type VARCHAR(32) NOT NULL COMMENT '盘点动作类型', task_id BIGINT NULL COMMENT '盘点任务ID', request_hash VARCHAR(128) NOT NULL COMMENT '动作请求哈希',
status VARCHAR(32) NOT NULL COMMENT '动作处理状态', result_json LONGTEXT NULL COMMENT '成功响应JSON',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_pda_stocktake_action(overseas_warehouse_id,operator_key,idempotency_key), KEY idx_ll_pda_stocktake_action_task(task_id,created_at)
) ENGINE=InnoDB COMMENT='海外PDA盘点动作幂等记录';
CREATE TABLE IF NOT EXISTS ll_pda_inventory_move (
id BIGINT NOT NULL COMMENT '移库操作ID', move_no VARCHAR(64) NOT NULL COMMENT '移库操作单号',
overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', pallet_id BIGINT NOT NULL COMMENT '整托移库的实物托盘ID',
pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照', source_location_id BIGINT NOT NULL COMMENT '来源库位ID',
source_location_code VARCHAR(128) NOT NULL COMMENT '来源库位码快照', target_location_id BIGINT NOT NULL COMMENT '目标库位ID',
target_location_code VARCHAR(128) NOT NULL COMMENT '目标库位码快照', customer_count INT NOT NULL COMMENT '托盘涉及客户数',
position_count INT NOT NULL COMMENT '迁移库存位置数', package_count BIGINT NOT NULL COMMENT '迁移总箱数',
pallet_version_before INT NOT NULL COMMENT '迁移前托盘版本', pallet_version_after INT NULL COMMENT '迁移后托盘版本',
operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', reason VARCHAR(500) NOT NULL COMMENT '移库原因',
idempotency_key VARCHAR(128) NOT NULL COMMENT '移库幂等键', request_hash VARCHAR(128) NOT NULL COMMENT '移库请求哈希',
status VARCHAR(32) NOT NULL COMMENT '移库处理状态', result_json LONGTEXT NULL COMMENT '成功响应JSON',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', completed_at DATETIME(3) NULL COMMENT '完成时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_pda_inventory_move_no(move_no),
UNIQUE KEY uk_ll_pda_inventory_move_key(overseas_warehouse_id,operator_key,idempotency_key),
KEY idx_ll_pda_inventory_move_pallet(overseas_warehouse_id,pallet_id,created_at)
) ENGINE=InnoDB COMMENT='海外PDA同仓整托移库记录';
CREATE TABLE IF NOT EXISTS ll_relabel_pda_task (
id BIGINT NOT NULL COMMENT '换标PDA任务ID', application_id BIGINT NOT NULL COMMENT '换标申请单ID',
customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', relabel_no VARCHAR(64) NOT NULL COMMENT '换标申请单号快照',
overseas_warehouse_id BIGINT NOT NULL COMMENT 'PDA令牌冻结的海外实际作业仓ID',
status VARCHAR(32) NOT NULL COMMENT '任务状态:PROCESSING、WAIT_REVIEW或COMPLETED',
operator_key VARCHAR(128) NOT NULL COMMENT '认领操作账号标识', operator_name VARCHAR(255) NOT NULL COMMENT '认领操作员名称快照',
reviewer_key VARCHAR(128) NULL COMMENT '复核账号标识', reviewer_name VARCHAR(255) NULL COMMENT '复核员名称快照',
expected_packages INT NOT NULL COMMENT '申请单通知的应换标箱数', relabelled_packages INT NOT NULL DEFAULT 0 COMMENT '已正常换标箱数',
skipped_packages INT NOT NULL DEFAULT 0 COMMENT '已说明原因跳过箱数', exception_packages INT NOT NULL DEFAULT 0 COMMENT '已登记异常箱数',
completion_photo_file_ids JSON NULL COMMENT '换标完成现场照片文件ID列表', completion_remark VARCHAR(1000) NULL COMMENT '完成提交备注',
review_decision VARCHAR(16) NULL COMMENT '最近复核结论:APPROVE或REWORK', review_remark VARCHAR(1000) NULL COMMENT '最近复核备注',
claimed_at DATETIME(3) NOT NULL COMMENT '任务认领时间', submitted_at DATETIME(3) NULL COMMENT '提交复核时间',
reviewed_at DATETIME(3) NULL COMMENT '最近复核时间', version INT 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 '更新时间',
PRIMARY KEY (id), UNIQUE KEY uk_ll_relabel_pda_task_application (customer_id,application_id),
UNIQUE KEY uk_ll_relabel_pda_task_no (relabel_no), KEY idx_ll_relabel_pda_task_warehouse (overseas_warehouse_id,status,updated_at),
KEY idx_ll_relabel_pda_task_operator (operator_key,status,updated_at)
) ENGINE=InnoDB COMMENT='海外PDA换标现场作业任务';
CREATE TABLE IF NOT EXISTS ll_relabel_pda_unit_fact (
id BIGINT NOT NULL COMMENT '逐件换标事实ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID',
application_id BIGINT NOT NULL COMMENT '换标申请单ID', item_id BIGINT NOT NULL COMMENT '换标申请明细ID',
customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', old_label VARCHAR(255) NULL COMMENT '扫描的实物旧标签或箱标',
new_label VARCHAR(255) NULL COMMENT '扫描的换标后新标签', result VARCHAR(32) NOT NULL COMMENT '逐件结果:RELABELLED、SKIPPED或EXCEPTION',
exception_code VARCHAR(32) NULL COMMENT '异常编码', reason VARCHAR(1000) NULL COMMENT '跳过或异常原因',
operator_key VARCHAR(128) NOT NULL COMMENT '操作账号标识', operator_name VARCHAR(255) NOT NULL COMMENT '操作员名称快照',
occurred_at DATETIME(3) NOT NULL COMMENT '逐件事实发生时间', PRIMARY KEY (id),
UNIQUE KEY uk_ll_relabel_pda_old_label (old_label), KEY idx_ll_relabel_pda_unit_task (customer_id,task_id,occurred_at,id),
KEY idx_ll_relabel_pda_unit_item (customer_id,application_id,item_id)
) ENGINE=InnoDB COMMENT='海外PDA逐件换标扫码与异常事实';
CREATE TABLE IF NOT EXISTS ll_relabel_pda_operation (
id BIGINT NOT NULL COMMENT '换标PDA幂等操作ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID',
customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', operator_key VARCHAR(128) NOT NULL COMMENT '请求操作账号标识',
action VARCHAR(32) NOT NULL COMMENT '幂等操作动作', idempotency_key VARCHAR(255) NOT NULL COMMENT '设备生成的幂等键',
request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', result_json LONGTEXT NOT NULL COMMENT '成功响应快照JSON',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id),
UNIQUE KEY uk_ll_relabel_pda_operation_key (operator_key,idempotency_key),
KEY idx_ll_relabel_pda_operation_task (customer_id,task_id,created_at)
) ENGINE=InnoDB COMMENT='海外PDA换标写操作幂等记录';
CREATE TABLE IF NOT EXISTS ll_relabel_pda_history (
id BIGINT NOT NULL COMMENT '换标PDA任务历史ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID',
application_id BIGINT NOT NULL COMMENT '换标申请单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
action VARCHAR(32) NOT NULL COMMENT '现场动作类型', from_status VARCHAR(32) NULL COMMENT '动作前任务状态',
to_status VARCHAR(32) NOT NULL COMMENT '动作后任务状态', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号标识',
operator_name VARCHAR(255) NOT NULL COMMENT '操作员名称快照', detail_json LONGTEXT NULL COMMENT '动作详情JSON',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id),
KEY idx_ll_relabel_pda_history_task (customer_id,task_id,created_at,id),
KEY idx_ll_relabel_pda_history_application (customer_id,application_id,created_at)
) ENGINE=InnoDB COMMENT='海外PDA换标任务不可变操作历史';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_cargo_discard_application' AND column_name='review_idempotency_key'),
'SELECT 1', 'ALTER TABLE ll_cargo_discard_application ADD COLUMN review_idempotency_key VARCHAR(255) NULL COMMENT ''审核幂等键'' AFTER request_hash'));
PREPARE phase4_discard_review_stmt FROM @ddl; EXECUTE phase4_discard_review_stmt; DEALLOCATE PREPARE phase4_discard_review_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_cargo_discard_application' AND column_name='review_request_hash'),
'SELECT 1', 'ALTER TABLE ll_cargo_discard_application ADD COLUMN review_request_hash CHAR(64) NULL COMMENT ''审核请求内容哈希'' AFTER review_idempotency_key'));
PREPARE phase4_discard_review_stmt FROM @ddl; EXECUTE phase4_discard_review_stmt; DEALLOCATE PREPARE phase4_discard_review_stmt;
-- Warehouse Overseas 与 Lastleg 使用同一海外区域发布入口但保持独立数据库。
-- 公共托盘详情实体读取 fba_warehouse_code;旧库缺列时创建可成功但详情会 S0500。
USE baiyue_lastlag_warehouse;
-- 仓库主档唯一权威已收口至国内 baiyue_warehouse;海外库只保留 warehouse_id 引用。
-- 当前开发阶段不兼容旧海外主档数据,按依赖顺序移除重复表。
DROP TABLE IF EXISTS wh_service_capability;
DROP TABLE IF EXISTS wh_warehouse_address;
DROP TABLE IF EXISTS wh_warehouse;
CREATE TABLE IF NOT EXISTS wh_pallet_operation (
id BIGINT NOT NULL COMMENT '托盘状态操作ID', operation_key VARCHAR(128) NOT NULL COMMENT '跨服务幂等操作键',
request_hash VARCHAR(128) NOT NULL COMMENT '状态变更请求摘要', warehouse_id BIGINT NOT NULL COMMENT '实际海外仓ID',
pallet_id BIGINT NOT NULL COMMENT '实物托盘ID', pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照',
before_status VARCHAR(20) NOT NULL COMMENT '变更前托盘状态', after_status VARCHAR(20) NOT NULL COMMENT '变更后托盘状态',
before_location_id BIGINT NOT NULL COMMENT '变更前库位ID', after_location_id BIGINT NOT NULL COMMENT '变更后库位ID',
before_version INT NOT NULL COMMENT '变更前托盘版本', after_version INT NOT NULL COMMENT '变更后托盘版本',
operation_status VARCHAR(32) NOT NULL COMMENT '操作状态:APPLIED已应用、COMPENSATED已补偿',
reason 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_wh_pallet_operation_key (operation_key),
KEY idx_wh_pallet_operation_pallet (warehouse_id,pallet_id,created_at)
) ENGINE=InnoDB COMMENT='实物托盘状态幂等变更与补偿记录';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema=DATABASE() AND table_name='wh_pallet' AND column_name='fba_warehouse_code'),
'SELECT 1',
'ALTER TABLE wh_pallet ADD COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''所属FBA仓编码'' AFTER remark'));
PREPARE phase4_warehouse_pallet_stmt FROM @ddl;
EXECUTE phase4_warehouse_pallet_stmt;
DEALLOCATE PREPARE phase4_warehouse_pallet_stmt;
SET @warehouse_pallet_fba_ready = (SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema='baiyue_lastlag_warehouse' AND table_name='wh_pallet'
AND column_name='fba_warehouse_code' AND column_type='varchar(128)');
DROP PROCEDURE IF EXISTS assert_phase4_warehouse_pallet_ready;
DELIMITER $$
CREATE PROCEDURE assert_phase4_warehouse_pallet_ready()
BEGIN
IF @warehouse_pallet_fba_ready <> 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='wh_pallet.fba_warehouse_code migration is incomplete';
END IF;
END$$
DELIMITER ;
CALL assert_phase4_warehouse_pallet_ready();
DROP PROCEDURE assert_phase4_warehouse_pallet_ready;
USE baiyue_lastleg;
DROP PROCEDURE IF EXISTS assert_phase4_pda_operations_ready;
DELIMITER $$
CREATE PROCEDURE assert_phase4_pda_operations_ready()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema='baiyue_lastleg' AND table_name IN (
'll_pda_pallet_operation','ll_pda_stocktake_task','ll_pda_stocktake_item',
'll_pda_stocktake_action','ll_pda_inventory_move','ll_relabel_pda_task',
'll_relabel_pda_unit_fact','ll_relabel_pda_operation','ll_relabel_pda_history')) <> 9 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA盘点、移库、托盘或换标表未完整部署';
END IF;
IF (SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema='baiyue_lastlag_warehouse' AND table_name='wh_pallet_operation') <> 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA实物托盘操作表未部署';
END IF;
END$$
DELIMITER ;
CALL assert_phase4_pda_operations_ready();
DROP PROCEDURE assert_phase4_pda_operations_ready;
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_security_event_inbox (
event_id VARCHAR(64) NOT NULL COMMENT '跨区安全事件ID', event_type VARCHAR(96) NOT NULL COMMENT 'IAM安全事件类型',
payload_hash CHAR(64) NOT NULL COMMENT '规范化载荷SHA-256哈希', payload_json JSON NOT NULL COMMENT '冻结事件载荷JSON',
status VARCHAR(16) NOT NULL COMMENT '消费状态:RECEIVED或PROCESSED',
result VARCHAR(32) NULL COMMENT '处理结果:APPLIED、STALE、DUPLICATE或DUPLICATE_VERSION',
received_at DATETIME(3) NOT NULL COMMENT '接收时间', processed_at DATETIME(3) NULL COMMENT '处理完成时间',
PRIMARY KEY (event_id), KEY idx_security_inbox_type_time (event_type,received_at)
) ENGINE=InnoDB COMMENT='海外IAM安全事件消费者收件箱';
CREATE TABLE IF NOT EXISTS ll_security_projection (
aggregate_type VARCHAR(32) NOT NULL COMMENT '聚合类型:USER、TENANT或AUTHORIZATION',
aggregate_id VARCHAR(64) NOT NULL COMMENT '用户或客户聚合ID', tenant_id BIGINT NOT NULL COMMENT '平台0或客户ID',
security_status VARCHAR(24) NULL COMMENT '当前安全状态:ACTIVE或DISABLED',
permission_version BIGINT NULL COMMENT '当前单调权限版本',
aggregate_version BIGINT NOT NULL COMMENT '事件聚合单调版本', payload_hash CHAR(64) NOT NULL COMMENT '当前版本载荷哈希',
last_event_id VARCHAR(64) NOT NULL COMMENT '最后应用的事件ID',
changed_at DATETIME(3) NOT NULL COMMENT '国内IAM事实发生时间', updated_at DATETIME(3) NOT NULL COMMENT '投影更新时间',
PRIMARY KEY (aggregate_type,aggregate_id), KEY idx_security_projection_tenant (tenant_id),
KEY idx_security_projection_permission (aggregate_id,permission_version)
) ENGINE=InnoDB COMMENT='海外IAM安全状态与权限版本投影';
-- 与国内固定 auth_account.id=1000001、tenant_id=0 的 platform_admin 一致;真实事件从版本1覆盖。
INSERT IGNORE INTO ll_security_projection (
aggregate_type,aggregate_id,tenant_id,security_status,permission_version,aggregate_version,
payload_hash,last_event_id,changed_at,updated_at
) VALUES
('USER','1000001',0,'ACTIVE',0,0,SHA2('lastleg-baseline:platform_admin:USER:0',256),
'baseline-platform-admin-user-v0','1970-01-01 00:00:00.000','1970-01-01 00:00:00.000'),
('AUTHORIZATION','1000001',0,NULL,0,0,SHA2('lastleg-baseline:platform_admin:AUTHORIZATION:0',256),
'baseline-platform-admin-authorization-v0','1970-01-01 00:00:00.000','1970-01-01 00:00:00.000');
DROP PROCEDURE IF EXISTS assert_lastleg_security_projection_ready;
DELIMITER $$
CREATE PROCEDURE assert_lastleg_security_projection_ready()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg'
AND table_name IN ('ll_security_event_inbox','ll_security_projection')) <> 2 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外IAM安全Inbox或投影表未完整部署';
END IF;
END$$
DELIMITER ;
CALL assert_lastleg_security_projection_ready();
DROP PROCEDURE assert_lastleg_security_projection_ready;
CREATE TABLE IF NOT EXISTS ll_finance_fee_source (
id BIGINT NOT NULL COMMENT '费用版本记录ID', source_fee_id BIGINT NOT NULL COMMENT '跨版本稳定费用来源ID',
source_version INT NOT NULL COMMENT '费用来源版本,从1递增', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键',
customer_name VARCHAR(200) NULL COMMENT '客户名称快照', source_type VARCHAR(64) NOT NULL COMMENT '海外费用来源类型',
source_no VARCHAR(128) NOT NULL COMMENT '来源业务编号或入仓码快照', business_type VARCHAR(32) NOT NULL COMMENT '来源业务类型',
business_id BIGINT NULL COMMENT '来源业务记录ID', business_no VARCHAR(128) NOT NULL COMMENT '来源业务编号',
order_id BIGINT NULL COMMENT '关联订单ID', inbound_id BIGINT NULL COMMENT '关联海外入仓计划或入仓记录ID',
inbound_code VARCHAR(64) NULL COMMENT '关联入仓码;并非所有费用必填', container_id BIGINT NULL COMMENT '关联柜次ID',
container_booking_id BIGINT NULL COMMENT '来源订舱柜ID', container_no VARCHAR(64) NULL COMMENT '真实集装箱号快照',
warehouse_id BIGINT NULL COMMENT '关联海外仓ID', fee_item_code VARCHAR(64) NOT NULL COMMENT '费用项目编码快照',
fee_item_name VARCHAR(200) NOT NULL COMMENT '费用项目名称快照', direction VARCHAR(16) NOT NULL COMMENT 'RECEIVABLE应收或PAYABLE应付',
supplier_id BIGINT NULL COMMENT '应付供应商ID', supplier_name VARCHAR(200) NULL COMMENT '应付供应商名称快照',
supplier_category VARCHAR(32) NULL COMMENT '应付供应商类别约束', settlement_mode VARCHAR(16) NULL COMMENT 'ON_ACCOUNT账期应付或DIRECT_PAID业务已付',
paid_at DATETIME(3) NULL COMMENT '直接已付时间', payment_method VARCHAR(32) NULL COMMENT '直接已付方式',
payment_reference_no VARCHAR(128) NULL COMMENT '直接已付流水号', payment_voucher_file_ids JSON NULL COMMENT '直接已付凭证文件ID快照',
business_date DATE NOT NULL COMMENT '费用业务日期', currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '财务结算币种,当前固定CNY',
amount DECIMAL(20,6) NOT NULL COMMENT '费用金额', review_status VARCHAR(16) NOT NULL COMMENT 'DRAFT、PENDING、APPROVED或REJECTED',
publication_status VARCHAR(16) NOT NULL COMMENT 'UNPUBLISHED或PUBLISHED', source_status VARCHAR(16) NOT NULL COMMENT 'ACTIVE、SUPERSEDED或VOIDED',
review_reason VARCHAR(500) NULL COMMENT '审核或作废原因', reviewer_id VARCHAR(128) NULL COMMENT '审核人ID', reviewed_at DATETIME(3) NULL COMMENT '审核时间',
created_by VARCHAR(128) NOT NULL COMMENT '创建人ID', updated_by VARCHAR(128) NOT NULL COMMENT '最后更新人ID',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_finance_fee_version(source_fee_id,source_version),
KEY idx_ll_finance_fee_customer(customer_id,source_status,created_at), KEY idx_ll_finance_fee_business(business_type,business_no,created_at),
CONSTRAINT chk_ll_finance_fee_amount CHECK(amount>0), CONSTRAINT chk_ll_finance_fee_currency CHECK(currency='CNY'),
CONSTRAINT chk_ll_finance_fee_direction CHECK(direction IN('RECEIVABLE','PAYABLE')),
CONSTRAINT chk_ll_finance_fee_review CHECK(review_status IN('DRAFT','PENDING','APPROVED','REJECTED')),
CONSTRAINT chk_ll_finance_fee_publication CHECK(publication_status IN('UNPUBLISHED','PUBLISHED')),
CONSTRAINT chk_ll_finance_fee_status CHECK(source_status IN('ACTIVE','SUPERSEDED','VOIDED'))
) ENGINE=InnoDB COMMENT='海外业务不可变费用来源版本;发布后经跨区事件进入Finance';
CREATE TABLE IF NOT EXISTS ll_finance_fee_command (
id BIGINT NOT NULL COMMENT '幂等命令ID', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID',
action VARCHAR(16) NOT NULL COMMENT 'CREATE、SUBMIT、REVIEW、ADJUST或VOID', idempotency_key VARCHAR(128) NOT NULL COMMENT '操作幂等键',
request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256', source_fee_id BIGINT NOT NULL COMMENT '稳定费用来源ID',
source_version INT NOT NULL COMMENT '命令结果版本', created_at DATETIME(3) NOT NULL COMMENT '命令创建时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_finance_fee_command(operator_id,action,idempotency_key),
KEY idx_ll_finance_fee_command_source(source_fee_id,source_version)
) ENGINE=InnoDB COMMENT='海外费用来源写操作幂等审计';
SELECT 'PASS' AS migration_status, '海外仓业务、海外仓资源与IAM安全投影结构已就绪' AS message;