Files
baiyue-lastleg/scripts/db/incremental.sql
T
2026-08-17 13:38:48 +08:00

870 lines
71 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.
-- Baiyue last-leg platform incremental database archive
-- Encoding: UTF-8 without BOM
-- Policy:
-- 1. Append new numbered sections; never rewrite an applied section.
-- 2. DDL must be repeatable and must preserve existing business rows.
-- 3. Every new column and index must use an information_schema guard.
-- 4. Do not place test fixtures, DELETE, TRUNCATE or business-data UPDATE here.
-- ============================================================================
-- 2026-08-15 / 001
-- Event Bridge inbox and delivery-attempt baseline
-- ============================================================================
CREATE DATABASE IF NOT EXISTS baiyue_event_bridge
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE baiyue_event_bridge;
CREATE TABLE IF NOT EXISTS bridge_inbox (
event_id VARCHAR(128) NOT NULL COMMENT '事件全局标识',
idempotency_key VARCHAR(191) NOT NULL COMMENT '接收幂等键',
event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
event_version INT NOT NULL COMMENT '事件契约版本',
source_region VARCHAR(32) NOT NULL COMMENT '来源区域',
target_region VARCHAR(32) NOT NULL COMMENT '目标区域',
tenant_id VARCHAR(128) NOT NULL COMMENT '租户标识',
aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型',
aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合标识',
aggregate_version BIGINT NOT NULL COMMENT '聚合版本',
handover_version BIGINT NULL COMMENT '跨区交接版本',
trace_id VARCHAR(128) NOT NULL COMMENT '链路标识',
correlation_id VARCHAR(128) NOT NULL COMMENT '业务关联标识',
causation_id VARCHAR(128) NULL COMMENT '上游事件标识',
occurred_at DATETIME(3) NOT NULL COMMENT '业务事实发生时间',
payload_hash VARCHAR(71) NOT NULL COMMENT '规范化负载摘要',
payload_json JSON NOT NULL COMMENT '事件负载',
status VARCHAR(32) NOT NULL DEFAULT 'RECEIVED' COMMENT '消费状态',
lease_owner VARCHAR(128) NULL COMMENT '消费租约持有者',
lease_until DATETIME(3) NULL COMMENT '消费租约截止时间',
retry_count INT NOT NULL DEFAULT 0 COMMENT '消费重试次数',
next_retry_at DATETIME(3) NULL COMMENT '下次消费时间',
last_error VARCHAR(1000) NULL COMMENT '最后错误',
received_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '接收时间',
processed_at DATETIME(3) NULL COMMENT '消费完成时间',
PRIMARY KEY (event_id),
UNIQUE KEY uk_bridge_inbox_idempotency (idempotency_key),
KEY idx_bridge_inbox_consume (status, next_retry_at, lease_until)
) ENGINE=InnoDB COMMENT='跨区域事件已接收箱';
CREATE TABLE IF NOT EXISTS bridge_delivery_attempt (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
event_id VARCHAR(128) NOT NULL COMMENT '事件全局标识',
source_region VARCHAR(32) NOT NULL COMMENT '来源区域',
target_region VARCHAR(32) NOT NULL COMMENT '目标区域',
attempt_no INT NOT NULL COMMENT '投递序号',
status VARCHAR(32) NOT NULL COMMENT '投递结果',
response_code VARCHAR(64) NULL COMMENT '对端响应码',
error_message VARCHAR(1000) NULL COMMENT '错误信息',
started_at DATETIME(3) NOT NULL COMMENT '开始时间',
finished_at DATETIME(3) NULL COMMENT '完成时间',
PRIMARY KEY (id),
UNIQUE KEY uk_bridge_attempt (event_id, attempt_no),
KEY idx_bridge_attempt_event (event_id, started_at)
) ENGINE=InnoDB COMMENT='跨区域事件投递尝试记录';
-- Upgrade an existing bridge_inbox without replacing payload JSON or other rows.
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='bridge_inbox' AND column_name='lease_owner'), 'SELECT 1', 'ALTER TABLE bridge_inbox ADD COLUMN lease_owner VARCHAR(128) NULL COMMENT ''消费租约持有者'' AFTER status'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
-- ============================================================================
-- 2026-08-15 / 002
-- Warehouse locations, pallets, resource locks and UTF-8 descriptions
-- ============================================================================
CREATE DATABASE IF NOT EXISTS baiyue_lastlag_warehouse
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE baiyue_lastlag_warehouse;
CREATE TABLE IF NOT EXISTS wh_location (
id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
zone_code VARCHAR(50) NOT NULL COMMENT '仓库分区编码',
location_code VARCHAR(64) NOT NULL COMMENT '仓库内唯一库位编码',
location_type VARCHAR(32) NOT NULL COMMENT '库位类型',
max_load_kg DECIMAL(18,3) NOT NULL COMMENT '最大承重(千克)',
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '库位状态:ACTIVE启用、INACTIVE停用',
remark VARCHAR(500) NULL COMMENT '备注',
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_location_code (tenant_id,warehouse_id,location_code,deleted),
KEY idx_location_query (tenant_id,warehouse_id,zone_code,status,deleted)
) ENGINE=InnoDB COMMENT='仓库库位表:按租户和仓库维护库位及承重信息';
CREATE TABLE IF NOT EXISTS wh_pallet (
id BIGINT UNSIGNED NOT NULL COMMENT '托盘ID(雪花ID)',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
location_id BIGINT UNSIGNED NULL COMMENT '同仓库内绑定的库位ID,可为空',
pallet_code VARCHAR(128) NOT NULL COMMENT '仓库内唯一托盘编码',
pallet_type VARCHAR(32) NOT NULL COMMENT '托盘类型',
capacity_cbm DECIMAL(18,4) NOT NULL DEFAULT 2.0000 COMMENT '托盘容量(立方米)',
unit_price DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '托盘单价',
status VARCHAR(20) NOT NULL DEFAULT 'IDLE' COMMENT '托盘状态:IDLE闲置、OCCUPIED占用、SCRAPPED废弃',
remark VARCHAR(500) NULL COMMENT '备注',
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_pallet_code (tenant_id,warehouse_id,pallet_code,deleted),
KEY idx_pallet_query (tenant_id,warehouse_id,status,deleted),
KEY idx_pallet_location (tenant_id,warehouse_id,location_id,deleted)
) ENGINE=InnoDB COMMENT='仓库托盘表:按租户和仓库维护托盘、容量、单价及状态';
CREATE TABLE IF NOT EXISTS wh_resource_lock (
id BIGINT UNSIGNED NOT NULL COMMENT '资源锁ID(雪花ID)',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
pallet_id BIGINT UNSIGNED NOT NULL COMMENT '锁定的托盘ID',
location_id BIGINT UNSIGNED NOT NULL COMMENT '锁定的库位ID',
business_type VARCHAR(50) NOT NULL COMMENT '调用方业务类型',
business_id VARCHAR(100) NOT NULL COMMENT '调用方业务标识',
reservation_key VARCHAR(160) NOT NULL COMMENT '调用方资源预留幂等键',
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '资源锁状态:ACTIVE有效、RELEASED释放、SCRAPPED报废',
locked_at DATETIME(3) NOT 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_resource_lock_reservation (tenant_id,reservation_key),
KEY idx_resource_lock_pallet (tenant_id,warehouse_id,pallet_id,status),
KEY idx_resource_lock_location (tenant_id,warehouse_id,location_id,status),
KEY idx_resource_lock_business (tenant_id,business_type,business_id)
) ENGINE=InnoDB COMMENT='仓库托盘与库位资源锁表:支持跨服务幂等预留和释放';
-- Fix legacy mojibake/English descriptions without changing row values.
ALTER TABLE wh_location COMMENT='仓库库位表:按租户和仓库维护库位及承重信息';
ALTER TABLE wh_location
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)',
MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
MODIFY COLUMN warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
MODIFY COLUMN zone_code VARCHAR(50) NOT NULL COMMENT '仓库分区编码',
MODIFY COLUMN location_code VARCHAR(64) NOT NULL COMMENT '仓库内唯一库位编码',
MODIFY COLUMN location_type VARCHAR(32) NOT NULL COMMENT '库位类型',
MODIFY COLUMN max_load_kg DECIMAL(18,3) NOT NULL COMMENT '最大承重(千克)',
MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '库位状态:ACTIVE启用、INACTIVE停用',
MODIFY COLUMN remark VARCHAR(500) NULL COMMENT '备注',
MODIFY COLUMN created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
MODIFY COLUMN updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID',
MODIFY COLUMN updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
MODIFY COLUMN deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
MODIFY COLUMN version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号';
ALTER TABLE wh_pallet COMMENT='仓库托盘表:按租户和仓库维护托盘、容量、单价及状态';
ALTER TABLE wh_pallet
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '托盘ID(雪花ID)',
MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
MODIFY COLUMN warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
MODIFY COLUMN location_id BIGINT UNSIGNED NULL COMMENT '同仓库内绑定的库位ID,可为空',
MODIFY COLUMN pallet_code VARCHAR(128) NOT NULL COMMENT '仓库内唯一托盘编码',
MODIFY COLUMN pallet_type VARCHAR(32) NOT NULL COMMENT '托盘类型',
MODIFY COLUMN capacity_cbm DECIMAL(18,4) NOT NULL DEFAULT 2.0000 COMMENT '托盘容量(立方米)',
MODIFY COLUMN unit_price DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '托盘单价',
MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'IDLE' COMMENT '托盘状态:IDLE闲置、OCCUPIED占用、SCRAPPED废弃',
MODIFY COLUMN remark VARCHAR(500) NULL COMMENT '备注',
MODIFY COLUMN created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
MODIFY COLUMN updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID',
MODIFY COLUMN updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
MODIFY COLUMN deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
MODIFY COLUMN version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号';
ALTER TABLE wh_resource_lock COMMENT='仓库托盘与库位资源锁表:支持跨服务幂等预留和释放';
ALTER TABLE wh_resource_lock
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '资源锁ID(雪花ID)',
MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
MODIFY COLUMN warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
MODIFY COLUMN pallet_id BIGINT UNSIGNED NOT NULL COMMENT '锁定的托盘ID',
MODIFY COLUMN location_id BIGINT UNSIGNED NOT NULL COMMENT '锁定的库位ID',
MODIFY COLUMN business_type VARCHAR(50) NOT NULL COMMENT '调用方业务类型',
MODIFY COLUMN business_id VARCHAR(100) NOT NULL COMMENT '调用方业务标识',
MODIFY COLUMN reservation_key VARCHAR(160) NOT NULL COMMENT '调用方资源预留幂等键',
MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '资源锁状态:ACTIVE有效、RELEASED释放、SCRAPPED报废',
MODIFY COLUMN locked_at DATETIME(3) NOT NULL COMMENT '锁定时间',
MODIFY COLUMN released_at DATETIME(3) NULL COMMENT '释放或报废时间',
MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
MODIFY COLUMN updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间';
-- Guard every operational index for existing installations.
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_location' AND index_name='uk_location_code'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_location_code ON wh_location(tenant_id,warehouse_id,location_code,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_location' AND index_name='idx_location_query'), 'SELECT 1', 'CREATE INDEX idx_location_query ON wh_location(tenant_id,warehouse_id,zone_code,status,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_pallet' AND index_name='uk_pallet_code'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_pallet_code ON wh_pallet(tenant_id,warehouse_id,pallet_code,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_pallet' AND index_name='idx_pallet_query'), 'SELECT 1', 'CREATE INDEX idx_pallet_query ON wh_pallet(tenant_id,warehouse_id,status,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_pallet' AND index_name='idx_pallet_location'), 'SELECT 1', 'CREATE INDEX idx_pallet_location ON wh_pallet(tenant_id,warehouse_id,location_id,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_resource_lock' AND index_name='uk_resource_lock_reservation'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_resource_lock_reservation ON wh_resource_lock(tenant_id,reservation_key)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_resource_lock' AND index_name='idx_resource_lock_pallet'), 'SELECT 1', 'CREATE INDEX idx_resource_lock_pallet ON wh_resource_lock(tenant_id,warehouse_id,pallet_id,status)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_resource_lock' AND index_name='idx_resource_lock_location'), 'SELECT 1', 'CREATE INDEX idx_resource_lock_location ON wh_resource_lock(tenant_id,warehouse_id,location_id,status)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_resource_lock' AND index_name='idx_resource_lock_business'), 'SELECT 1', 'CREATE INDEX idx_resource_lock_business ON wh_resource_lock(tenant_id,business_type,business_id)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
-- ============================================================================
-- 2026-08-15 / 003
-- Last-leg inbound plan, pallet allocation and PDA workflow
-- ============================================================================
CREATE DATABASE IF NOT EXISTS baiyue_lastleg
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_inbound_plan (
id BIGINT NOT NULL COMMENT '入库计划ID(雪花ID)',
plan_no VARCHAR(32) NOT NULL COMMENT '入库单号',
tenant_id VARCHAR(128) NOT NULL COMMENT '租户/客户账号标识',
container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号',
status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ASSIGNMENT' COMMENT '入库计划状态',
line_count INT NOT NULL DEFAULT 0 COMMENT '入仓码明细数量',
pallet_count INT NOT NULL DEFAULT 0 COMMENT '系统自动分配托盘数量',
total_volume_cbm DECIMAL(18,4) 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_inbound_plan_no (plan_no),
UNIQUE KEY uk_ll_inbound_plan_container (tenant_id,container_no)
) ENGINE=InnoDB COMMENT='尾程入库计划表:每个租户的每个集装箱生成一张入库单';
CREATE TABLE IF NOT EXISTS ll_inbound_plan_line (
id BIGINT NOT NULL COMMENT '入库计划明细ID(雪花ID)',
plan_id BIGINT NOT NULL COMMENT '入库计划ID',
order_id BIGINT NOT NULL COMMENT '尾程订单ID',
inbound_code 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 '目的仓名称快照',
volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '入仓码体积(立方米)',
planned_pallet_count INT NOT NULL DEFAULT 0 COMMENT '该明细分配的托盘数量',
required_package_count INT NOT NULL DEFAULT 0 COMMENT '计划应收箱数',
PRIMARY KEY (id),
UNIQUE KEY uk_ll_inbound_line_order (plan_id,order_id),
KEY idx_ll_inbound_line_plan (plan_id)
) ENGINE=InnoDB COMMENT='尾程入库计划明细表:按入仓码和尾程订单维度记录';
CREATE TABLE IF NOT EXISTS ll_inbound_plan_pallet (
id BIGINT NOT NULL COMMENT '计划托盘ID(雪花ID)',
plan_id BIGINT NOT NULL COMMENT '入库计划ID',
pallet_no VARCHAR(64) 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 '目的仓名称快照',
capacity_cbm DECIMAL(18,4) NOT NULL DEFAULT 2.0000 COMMENT '托盘容量(立方米)',
allocated_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '已分配体积(立方米)',
sequence_no INT NOT NULL COMMENT '计划内托盘序号',
warehouse_pallet_id BIGINT NULL COMMENT '仓库托盘ID',
warehouse_location_id BIGINT NULL COMMENT '仓库库位ID',
warehouse_resource_lock_id BIGINT NULL COMMENT '仓库资源锁ID',
assignment_status VARCHAR(32) NOT NULL DEFAULT 'UNASSIGNED' COMMENT '仓库资源分配状态',
locked_at DATETIME(3) NULL COMMENT '资源锁定时间',
actual_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '实际入托体积(立方米)',
actual_package_count INT NOT NULL DEFAULT 0 COMMENT '实际入托箱数',
PRIMARY KEY (id),
UNIQUE KEY uk_ll_inbound_pallet_no (pallet_no),
UNIQUE KEY uk_ll_inbound_pallet_sequence (plan_id,sequence_no),
KEY idx_ll_inbound_pallet_plan (plan_id)
) ENGINE=InnoDB COMMENT='尾程入库计划托盘表:按目的仓隔离合托';
CREATE TABLE IF NOT EXISTS ll_inbound_plan_pallet_allocation (
id BIGINT NOT NULL COMMENT '托盘分配记录ID(雪花ID)',
plan_id BIGINT NOT NULL COMMENT '入库计划ID',
line_id BIGINT NOT NULL COMMENT '入库计划明细ID',
pallet_id BIGINT NOT NULL COMMENT '计划托盘ID',
allocated_volume_cbm DECIMAL(18,4) NOT NULL COMMENT '计划分配体积(立方米)',
planned_package_count INT NOT NULL DEFAULT 0 COMMENT '计划分配箱数',
counted_package_count INT NOT NULL DEFAULT 0 COMMENT '清点箱数',
picked_package_count INT NOT NULL DEFAULT 0 COMMENT '上架箱数',
actual_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '实际分配体积(立方米)',
status VARCHAR(32) NOT NULL DEFAULT 'PENDING_COUNT' COMMENT 'PDA作业状态',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_ll_inbound_allocation (line_id,pallet_id),
KEY idx_ll_inbound_allocation_plan (plan_id),
KEY idx_ll_inbound_allocation_pallet (pallet_id)
) ENGINE=InnoDB COMMENT='尾程入库计划托盘分配表:记录入仓码明细与计划托盘的分配关系';
-- Columns introduced after the initial inbound-plan release.
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='required_package_count'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_line ADD COLUMN required_package_count INT NOT NULL DEFAULT 0 COMMENT ''计划应收箱数'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='warehouse_pallet_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN warehouse_pallet_id BIGINT NULL COMMENT ''仓库托盘ID'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='warehouse_location_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN warehouse_location_id BIGINT NULL COMMENT ''仓库库位ID'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='warehouse_resource_lock_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN warehouse_resource_lock_id BIGINT NULL COMMENT ''仓库资源锁ID'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='assignment_status'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN assignment_status VARCHAR(32) NOT NULL DEFAULT ''UNASSIGNED'' COMMENT ''仓库资源分配状态'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='locked_at'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN locked_at DATETIME(3) NULL COMMENT ''资源锁定时间'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='actual_volume_cbm'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN actual_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''实际入托体积(立方米)'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='actual_package_count'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN actual_package_count INT NOT NULL DEFAULT 0 COMMENT ''实际入托箱数'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='planned_package_count'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN planned_package_count INT NOT NULL DEFAULT 0 COMMENT ''计划分配箱数'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='counted_package_count'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN counted_package_count INT NOT NULL DEFAULT 0 COMMENT ''清点箱数'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='picked_package_count'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN picked_package_count INT NOT NULL DEFAULT 0 COMMENT ''上架箱数'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='actual_volume_cbm'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN actual_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''实际分配体积(立方米)'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='status'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN status VARCHAR(32) NOT NULL DEFAULT ''PENDING_COUNT'' COMMENT ''PDA作业状态'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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='version'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN version INT NOT NULL DEFAULT 0 COMMENT ''乐观锁版本号'''));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
CREATE TABLE IF NOT EXISTS ll_inbound_pda_task (
id BIGINT NOT NULL COMMENT 'PDA任务ID', tenant_id VARCHAR(128) NOT NULL COMMENT '租户ID',
plan_id BIGINT NOT NULL COMMENT '入库计划ID', task_no VARCHAR(64) NOT NULL COMMENT 'PDA任务号',
status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '任务状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID',
operator_name VARCHAR(255) NULL COMMENT '操作人名称', pushed_at DATETIME(3) NULL COMMENT '推送时间',
started_at DATETIME(3) NULL COMMENT '开始时间', completed_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_inbound_pda_task_plan (tenant_id,plan_id),
UNIQUE KEY uk_ll_inbound_pda_task_no (task_no)
) ENGINE=InnoDB COMMENT='尾程入库PDA任务表';
CREATE TABLE IF NOT EXISTS ll_inbound_pda_operation (
id BIGINT NOT NULL COMMENT 'PDA操作记录ID', tenant_id VARCHAR(128) NOT NULL COMMENT '租户ID',
task_id BIGINT NOT NULL COMMENT 'PDA任务ID', allocation_id BIGINT NULL COMMENT '托盘分配记录ID',
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 '请求JSON',
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_inbound_pda_operation_key (tenant_id,idempotency_key),
KEY idx_ll_inbound_pda_operation_task (task_id), KEY idx_ll_inbound_pda_operation_allocation (allocation_id)
) ENGINE=InnoDB COMMENT='尾程入库PDA幂等操作记录';
CREATE TABLE IF NOT EXISTS ll_inbound_pallet_merge (
id BIGINT NOT NULL COMMENT '合托记录ID', tenant_id VARCHAR(128) NOT NULL COMMENT '租户ID',
task_id BIGINT NOT NULL COMMENT 'PDA任务ID', merge_group_no VARCHAR(64) NOT NULL COMMENT '合托组号',
source_pallet_id BIGINT NOT NULL COMMENT '来源托盘ID', target_pallet_id BIGINT NOT NULL COMMENT '目标托盘ID',
source_allocation_id BIGINT NOT NULL COMMENT '来源分配ID', target_allocation_id BIGINT NOT NULL COMMENT '目标分配ID',
source_line_id BIGINT NOT NULL COMMENT '来源计划明细ID', target_line_id BIGINT NOT NULL COMMENT '目标计划明细ID',
source_order_id BIGINT NOT NULL COMMENT '来源订单ID', target_order_id BIGINT NOT NULL COMMENT '目标订单ID',
moved_package_count INT NOT NULL COMMENT '移动箱数', moved_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '移动体积(立方米)',
source_pallet_scrapped TINYINT NOT NULL DEFAULT 0 COMMENT '来源托盘是否报废', status VARCHAR(32) NOT NULL COMMENT '合托状态',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id),
KEY idx_ll_inbound_merge_task (tenant_id,task_id), KEY idx_ll_inbound_merge_group (merge_group_no)
) ENGINE=InnoDB COMMENT='尾程入库PDA合托记录';
-- ============================================================================
-- 2026-08-15 / 004
-- Upgrade an existing Event Bridge inbox with retry/lease fields and indexes
-- ============================================================================
USE baiyue_event_bridge;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='bridge_inbox' AND column_name='lease_until'), 'SELECT 1', 'ALTER TABLE bridge_inbox ADD COLUMN lease_until DATETIME(3) NULL COMMENT ''消费租约截止时间'' AFTER lease_owner'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='bridge_inbox' AND column_name='retry_count'), 'SELECT 1', 'ALTER TABLE bridge_inbox ADD COLUMN retry_count INT NOT NULL DEFAULT 0 COMMENT ''消费重试次数'' AFTER lease_until'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='bridge_inbox' AND column_name='next_retry_at'), 'SELECT 1', 'ALTER TABLE bridge_inbox ADD COLUMN next_retry_at DATETIME(3) NULL COMMENT ''下次消费时间'' AFTER retry_count'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='bridge_inbox' AND column_name='last_error'), 'SELECT 1', 'ALTER TABLE bridge_inbox ADD COLUMN last_error VARCHAR(1000) NULL COMMENT ''最后错误'' AFTER next_retry_at'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='bridge_inbox' AND index_name='idx_bridge_inbox_consume'), 'SELECT 1', 'CREATE INDEX idx_bridge_inbox_consume ON bridge_inbox(status,next_retry_at,lease_until)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='bridge_inbox' AND index_name='uk_bridge_inbox_idempotency'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_bridge_inbox_idempotency ON bridge_inbox(idempotency_key)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
-- ============================================================================
-- 2026-08-15 / 005
-- FirstLegLoadingPlanCompleted -> last-leg order projection
-- ============================================================================
CREATE DATABASE IF NOT EXISTS baiyue_lastleg
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_loading_event_inbox (
event_id VARCHAR(128) NOT NULL COMMENT '事件全局唯一标识',
tenant_id VARCHAR(128) NOT NULL COMMENT '租户/客户账号标识',
event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
event_version INT NOT NULL COMMENT '事件契约版本',
payload_hash VARCHAR(71) NOT NULL COMMENT '规范化事件负载SHA-256摘要',
payload_json JSON NOT NULL COMMENT '事件冻结负载JSON',
status VARCHAR(32) NOT NULL DEFAULT 'RECEIVED' COMMENT '消费状态:RECEIVED/PROCESSED',
received_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '接收时间',
processed_at DATETIME(3) NULL COMMENT '处理完成时间',
last_error VARCHAR(1000) NULL COMMENT '最近一次处理错误',
PRIMARY KEY (event_id),
UNIQUE KEY uk_ll_loading_inbox_tenant_key (tenant_id,event_type,event_id)
) ENGINE=InnoDB COMMENT='头程装柜完成事件接收幂等箱';
CREATE TABLE IF NOT EXISTS ll_order (
id BIGINT NOT NULL COMMENT '雪花ID',
order_no VARCHAR(32) NOT NULL COMMENT '尾程单号,同柜入仓单共享',
tenant_id VARCHAR(128) NOT NULL COMMENT '租户/客户账号标识',
order_type VARCHAR(32) NOT NULL DEFAULT 'FIRST_LEG' COMMENT '订单类型',
inbound_code VARCHAR(128) NOT NULL COMMENT '入仓码',
source_region VARCHAR(32) NOT NULL COMMENT '来源区域/系统',
source_inbound_id VARCHAR(128) NOT NULL COMMENT '最终实装LOADED分片ID,建单幂等键',
root_inbound_id VARCHAR(128) NULL COMMENT '根入仓单ID',
source_order_id VARCHAR(128) NULL COMMENT '来源订单ID',
source_order_no VARCHAR(128) NULL COMMENT '来源订单号',
root_order_id VARCHAR(128) NULL COMMENT '根订单ID',
customer_name VARCHAR(255) NULL COMMENT '货主名称',
overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID',
overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称',
transfer_warehouse_id VARCHAR(128) NULL COMMENT '转入目的仓ID',
transfer_warehouse_code VARCHAR(128) NULL COMMENT '转入目的仓编码',
transfer_warehouse_name VARCHAR(255) NULL COMMENT '转入目的仓名称',
fba_warehouse_code VARCHAR(128) NULL COMMENT 'FBA仓库编码',
container_no VARCHAR(64) NULL COMMENT '实际集装箱号',
container_status VARCHAR(32) NULL DEFAULT '待转柜' COMMENT '货柜状态',
abnormal TINYINT NOT NULL DEFAULT 0 COMMENT '是否异常:0否1是',
detained TINYINT NOT NULL DEFAULT 0 COMMENT '是否暂扣:0否1是',
pallet_count INT NOT NULL DEFAULT 0 COMMENT '托数',
package_count INT NOT NULL DEFAULT 0 COMMENT '箱数',
volume_cbm DECIMAL(18,4) NULL COMMENT '体积(立方米)',
product_quantity INT NULL COMMENT '货物数量',
volume_weight_kg DECIMAL(18,4) NULL COMMENT '体积重量(千克)',
estimated_arrival_at DATETIME(3) NULL COMMENT '预计到港时间',
actual_arrival_at DATETIME(3) NULL COMMENT '实际到港时间',
estimated_warehouse_at DATETIME(3) NULL COMMENT '预计到仓时间',
inbound_order_no VARCHAR(128) NULL COMMENT '入库单号',
outbound_order_no VARCHAR(128) NULL COMMENT '出库单号',
delivery_order_no VARCHAR(128) NULL COMMENT '派送单号',
relabel_order_no VARCHAR(128) NULL COMMENT '换标单号',
relabel_status VARCHAR(32) NULL COMMENT '换标状态',
pallet_merge_flag VARCHAR(32) NULL COMMENT '合托标记',
current_status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ASSIGNMENT' COMMENT '当前业务状态',
private_remark VARCHAR(1000) NULL COMMENT '备注(仅自己)',
customer_remark VARCHAR(1000) NULL COMMENT '备注(客户)',
warehouse_remark VARCHAR(1000) NULL COMMENT '备注(仓库)',
source_event_id VARCHAR(128) NOT NULL COMMENT '来源事件ID',
source_loading_plan_id VARCHAR(128) NOT NULL COMMENT '来源装柜计划ID',
source_loading_plan_version BIGINT NULL COMMENT '来源装柜计划版本',
source_handover_version BIGINT NULL COMMENT '交接版本',
source_payload_hash VARCHAR(71) 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),
UNIQUE KEY uk_ll_order_source (tenant_id,source_region,source_inbound_id),
KEY idx_ll_order_group (tenant_id,order_no),
KEY idx_ll_order_list (tenant_id,current_status,created_at)
) ENGINE=InnoDB COMMENT='尾程订单主表';
CREATE TABLE IF NOT EXISTS ll_order_detail (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '订单明细主键',
order_id BIGINT NOT NULL COMMENT '尾程订单ID',
source_inbound_detail_id VARCHAR(128) NOT NULL COMMENT '来源入仓明细ID',
sku_code VARCHAR(128) NULL COMMENT 'SKU编码',
product_name_zh VARCHAR(255) NULL COMMENT '中文品名',
product_name_en VARCHAR(255) NULL COMMENT '英文品名',
package_count INT NOT NULL DEFAULT 0 COMMENT '箱数',
product_quantity INT NULL COMMENT '数量',
pallet_count INT NULL COMMENT '托数',
gross_weight_kg DECIMAL(18,4) NULL COMMENT '毛重(千克)',
net_weight_kg DECIMAL(18,4) NULL COMMENT '净重(千克)',
dimensional_weight_kg DECIMAL(18,4) NULL COMMENT '体积重量(千克)',
volume_cbm DECIMAL(18,4) 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_tracking_no VARCHAR(255) NULL COMMENT 'FBA跟踪号',
shipment_no VARCHAR(255) NULL COMMENT '货件编号',
shipping_mark VARCHAR(255) NULL COMMENT '唛头',
PRIMARY KEY (id),
UNIQUE KEY uk_ll_detail_source (order_id,source_inbound_detail_id),
KEY idx_ll_detail_order (order_id)
) ENGINE=InnoDB COMMENT='尾程订单实装商品冻结明细';
CREATE TABLE IF NOT EXISTS ll_loading_order_status_history (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '状态历史主键',
order_id BIGINT NOT NULL COMMENT '尾程订单ID',
from_status VARCHAR(32) NULL COMMENT '变更前状态',
to_status VARCHAR(32) NOT NULL COMMENT '变更后状态',
event_id VARCHAR(128) NULL COMMENT '触发事件ID',
remark VARCHAR(500) NULL COMMENT '状态变更备注',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '记录时间',
PRIMARY KEY (id),
KEY idx_ll_loading_history_order (order_id,created_at)
) ENGINE=InnoDB COMMENT='尾程订单状态变更历史';
-- Existing order installations: add transfer fields without replacing row data.
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='transfer_warehouse_id'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN transfer_warehouse_id VARCHAR(128) NULL COMMENT ''转入目的仓ID'' AFTER overseas_warehouse_name'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='transfer_warehouse_code'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN transfer_warehouse_code VARCHAR(128) NULL COMMENT ''转入目的仓编码'' AFTER transfer_warehouse_id'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='transfer_warehouse_name'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN transfer_warehouse_name VARCHAR(255) NULL COMMENT ''转入目的仓名称'' AFTER transfer_warehouse_code'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
-- One container/loading-plan number groups multiple inbound-code rows, so order_no
-- must not be unique. Source inbound identity remains uniquely constrained.
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='uk_ll_order_no' AND non_unique=0), 'ALTER TABLE ll_order DROP INDEX uk_ll_order_no', 'SELECT 1'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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_group'), 'SELECT 1', 'CREATE INDEX idx_ll_order_group ON ll_order(tenant_id,order_no)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='uk_ll_order_source'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_ll_order_source ON ll_order(tenant_id,source_region,source_inbound_id)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_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_list'), 'SELECT 1', 'CREATE INDEX idx_ll_order_list ON ll_order(tenant_id,current_status,created_at)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_loading_event_inbox' AND index_name='uk_ll_loading_inbox_tenant_key'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_ll_loading_inbox_tenant_key ON ll_loading_event_inbox(tenant_id,event_type,event_id)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
-- ============================================================================
-- 2026-08-15 / 006
-- Warehouse master-data descriptions and query indexes
-- ============================================================================
USE baiyue_lastlag_warehouse;
CREATE TABLE IF NOT EXISTS wh_warehouse (
id BIGINT UNSIGNED NOT NULL COMMENT '仓库ID(雪花ID)', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '仓库所属租户ID',
warehouse_code VARCHAR(50) NOT NULL COMMENT '租户内唯一仓库编码', warehouse_name VARCHAR(120) NOT NULL COMMENT '仓库名称',
warehouse_type VARCHAR(32) NOT NULL DEFAULT 'OVERSEAS' COMMENT '仓库类型', country_code CHAR(2) NOT NULL COMMENT '所在国家二字码',
timezone VARCHAR(64) NOT NULL COMMENT '仓库所在地IANA时区', contact_name VARCHAR(64) NULL COMMENT '仓库联系人',
contact_phone VARCHAR(32) NULL COMMENT '联系电话', contact_email VARCHAR(128) NULL COMMENT '联系邮箱',
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '仓库状态', remark VARCHAR(500) NULL COMMENT '仓库备注',
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id), UNIQUE KEY uk_wh_tenant_code (tenant_id,warehouse_code,deleted),
KEY idx_wh_tenant_status (tenant_id,status,deleted), KEY idx_wh_country (tenant_id,country_code,deleted)
) ENGINE=InnoDB COMMENT='仓库主数据表:以租户为边界维护仓库编码、名称、国家、时区和启停状态';
CREATE TABLE IF NOT EXISTS wh_warehouse_address (
id BIGINT UNSIGNED NOT NULL COMMENT '仓库地址ID', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID', address_type VARCHAR(20) NOT NULL DEFAULT 'OPERATING' COMMENT '地址类型:OPERATING运营、RETURN退货',
country_code CHAR(2) NOT NULL COMMENT '国家二字码', state_province VARCHAR(100) NULL COMMENT '省或州',
city VARCHAR(100) NOT NULL COMMENT '城市', district VARCHAR(100) NULL COMMENT '区县', postal_code VARCHAR(20) NULL COMMENT '邮政编码',
address_line1 VARCHAR(255) NOT NULL COMMENT '主地址行', address_line2 VARCHAR(255) NULL COMMENT '补充地址行',
latitude DECIMAL(10,7) NULL COMMENT '纬度', longitude DECIMAL(10,7) NULL COMMENT '经度',
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id), UNIQUE KEY uk_address_type (tenant_id,warehouse_id,address_type,deleted),
KEY idx_address_warehouse (tenant_id,warehouse_id,deleted)
) ENGINE=InnoDB COMMENT='仓库地址表:保存运营、退货等不同用途的地址及可选经纬度';
CREATE TABLE IF NOT EXISTS wh_service_capability (
id BIGINT UNSIGNED NOT NULL COMMENT '服务能力ID', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID', capability_code VARCHAR(50) NOT NULL COMMENT '能力编码',
capability_name VARCHAR(100) NOT NULL COMMENT '能力名称', enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
cutoff_time TIME NULL COMMENT '当日作业截单时间', description VARCHAR(500) NULL COMMENT '能力说明',
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id), UNIQUE KEY uk_capability (tenant_id,warehouse_id,capability_code,deleted),
KEY idx_capability_query (tenant_id,warehouse_id,enabled,deleted)
) ENGINE=InnoDB COMMENT='仓库服务能力表:声明仓库可提供的收货、仓储、拣包、退货等能力及截单时间';
ALTER TABLE wh_warehouse COMMENT='仓库主数据表:以租户为边界维护仓库编码、名称、国家、时区和启停状态';
ALTER TABLE wh_warehouse
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '仓库ID(雪花ID)', MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL COMMENT '仓库所属租户ID',
MODIFY COLUMN warehouse_code VARCHAR(50) NOT NULL COMMENT '租户内唯一仓库编码', MODIFY COLUMN warehouse_name VARCHAR(120) NOT NULL COMMENT '仓库名称',
MODIFY COLUMN warehouse_type VARCHAR(32) NOT NULL DEFAULT 'OVERSEAS' COMMENT '仓库类型', MODIFY COLUMN country_code CHAR(2) NOT NULL COMMENT '所在国家二字码',
MODIFY COLUMN timezone VARCHAR(64) NOT NULL COMMENT '仓库所在地IANA时区', MODIFY COLUMN contact_name VARCHAR(64) NULL COMMENT '仓库联系人',
MODIFY COLUMN contact_phone VARCHAR(32) NULL COMMENT '联系电话', MODIFY COLUMN contact_email VARCHAR(128) NULL COMMENT '联系邮箱',
MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '仓库状态', MODIFY COLUMN remark VARCHAR(500) NULL COMMENT '仓库备注',
MODIFY COLUMN created_by BIGINT UNSIGNED NULL COMMENT '创建人ID', MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
MODIFY COLUMN updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID', MODIFY COLUMN updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
MODIFY COLUMN deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记', MODIFY COLUMN version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号';
ALTER TABLE wh_warehouse_address COMMENT='仓库地址表:保存运营、退货等不同用途的地址及可选经纬度';
ALTER TABLE wh_warehouse_address
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '仓库地址ID', MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
MODIFY COLUMN warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID', MODIFY COLUMN address_type VARCHAR(20) NOT NULL DEFAULT 'OPERATING' COMMENT '地址类型:OPERATING运营、RETURN退货',
MODIFY COLUMN country_code CHAR(2) NOT NULL COMMENT '国家二字码', MODIFY COLUMN state_province VARCHAR(100) NULL COMMENT '省或州',
MODIFY COLUMN city VARCHAR(100) NOT NULL COMMENT '城市', MODIFY COLUMN district VARCHAR(100) NULL COMMENT '区县',
MODIFY COLUMN postal_code VARCHAR(20) NULL COMMENT '邮政编码', MODIFY COLUMN address_line1 VARCHAR(255) NOT NULL COMMENT '主地址行',
MODIFY COLUMN address_line2 VARCHAR(255) NULL COMMENT '补充地址行', MODIFY COLUMN latitude DECIMAL(10,7) NULL COMMENT '纬度',
MODIFY COLUMN longitude DECIMAL(10,7) NULL COMMENT '经度', MODIFY COLUMN created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', MODIFY COLUMN updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID',
MODIFY COLUMN updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
MODIFY COLUMN deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记', MODIFY COLUMN version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号';
ALTER TABLE wh_service_capability COMMENT='仓库服务能力表:声明仓库可提供的收货、仓储、拣包、退货等能力及截单时间';
ALTER TABLE wh_service_capability
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '服务能力ID', MODIFY COLUMN tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
MODIFY COLUMN warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID', MODIFY COLUMN capability_code VARCHAR(50) NOT NULL COMMENT '能力编码:RECEIVING收货、STORAGE仓储、PICK_PACK拣包、RETURN退货',
MODIFY COLUMN capability_name VARCHAR(100) NOT NULL COMMENT '能力名称', MODIFY COLUMN enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
MODIFY COLUMN cutoff_time TIME NULL COMMENT '当日作业截单时间', MODIFY COLUMN description VARCHAR(500) NULL COMMENT '能力说明',
MODIFY COLUMN created_by BIGINT UNSIGNED NULL COMMENT '创建人ID', MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
MODIFY COLUMN updated_by BIGINT UNSIGNED NULL COMMENT '最后修改人ID', MODIFY COLUMN updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
MODIFY COLUMN deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记', MODIFY COLUMN version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_warehouse' AND index_name='uk_wh_tenant_code'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_wh_tenant_code ON wh_warehouse(tenant_id,warehouse_code,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_warehouse' AND index_name='idx_wh_tenant_status'), 'SELECT 1', 'CREATE INDEX idx_wh_tenant_status ON wh_warehouse(tenant_id,status,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_warehouse' AND index_name='idx_wh_country'), 'SELECT 1', 'CREATE INDEX idx_wh_country ON wh_warehouse(tenant_id,country_code,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_warehouse_address' AND index_name='uk_address_type'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_address_type ON wh_warehouse_address(tenant_id,warehouse_id,address_type,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_warehouse_address' AND index_name='idx_address_warehouse'), 'SELECT 1', 'CREATE INDEX idx_address_warehouse ON wh_warehouse_address(tenant_id,warehouse_id,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_service_capability' AND index_name='uk_capability'), 'SELECT 1', 'CREATE UNIQUE INDEX uk_capability ON wh_service_capability(tenant_id,warehouse_id,capability_code,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_service_capability' AND index_name='idx_capability_query'), 'SELECT 1', 'CREATE INDEX idx_capability_query ON wh_service_capability(tenant_id,warehouse_id,enabled,deleted)'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
-- ============================================================================
-- 2026-08-17 / 007
-- Last-leg batch FBA appointments
-- ============================================================================
USE baiyue_lastleg;
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'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_line ADD COLUMN fba_warehouse_code VARCHAR(128) NULL AFTER inbound_code'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;
UPDATE ll_inbound_plan_line l JOIN ll_order o ON o.id=l.order_id
SET l.fba_warehouse_code=o.fba_warehouse_code
WHERE l.fba_warehouse_code IS NULL AND o.fba_warehouse_code IS NOT NULL;
CREATE TABLE IF NOT EXISTS ll_inbound_fba_appointment (
id BIGINT NOT NULL COMMENT 'Snowflake ID',
tenant_id VARCHAR(128) NOT NULL,
appointment_no VARCHAR(64) NOT NULL,
appointment_at DATETIME(3) NOT NULL,
appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
appointment_remark VARCHAR(1000) NULL,
fba_warehouse_code VARCHAR(128) NOT NULL,
selected_count INT NOT NULL DEFAULT 0,
created_by VARCHAR(128) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_ll_fba_appointment_no (tenant_id, appointment_no),
KEY idx_ll_fba_appointment_list (tenant_id, appointment_status, fba_warehouse_code, created_at)
) ENGINE=InnoDB COMMENT='Batch FBA appointment';
CREATE TABLE IF NOT EXISTS ll_inbound_fba_appointment_item (
id BIGINT NOT NULL COMMENT 'Snowflake ID',
appointment_id BIGINT NOT NULL,
plan_id BIGINT NOT NULL,
line_id BIGINT NOT NULL,
order_id BIGINT NOT NULL,
inbound_code VARCHAR(128) NOT NULL,
fba_warehouse_code VARCHAR(128) NOT NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_ll_fba_appointment_item_line (appointment_id, line_id),
KEY idx_ll_fba_appointment_item_plan (plan_id),
KEY idx_ll_fba_appointment_item_order (order_id)
) ENGINE=InnoDB COMMENT='FBA appointment line snapshot';
-- ============================================================================
-- 2026-08-17 / 008
-- Last-leg SKU/package inventory balances, positions and immutable ledger
-- ============================================================================
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_inventory_balance (
id BIGINT NOT NULL COMMENT 'Snowflake ID', tenant_id VARCHAR(128) NOT NULL, customer_name VARCHAR(255) NULL,
overseas_warehouse_id VARCHAR(128) NOT NULL, overseas_warehouse_code VARCHAR(128) NULL,
overseas_warehouse_name VARCHAR(255) NULL, destination_warehouse_id VARCHAR(128) NULL,
destination_warehouse_code VARCHAR(128) NOT NULL DEFAULT '', destination_warehouse_name VARCHAR(255) NULL,
sku_code VARCHAR(128) NOT NULL, sku_name_zh VARCHAR(255) NULL,
available_packages BIGINT NOT NULL DEFAULT 0, hold_packages BIGINT NOT NULL DEFAULT 0,
allocated_packages BIGINT NOT NULL DEFAULT 0, picked_packages BIGINT NOT NULL DEFAULT 0,
in_transit_packages BIGINT NOT NULL DEFAULT 0, receiving_packages BIGINT NOT NULL DEFAULT 0,
procurement_packages BIGINT NOT NULL DEFAULT 0,
available_quantity BIGINT NOT NULL DEFAULT 0, hold_quantity BIGINT NOT NULL DEFAULT 0,
allocated_quantity BIGINT NOT NULL DEFAULT 0, picked_quantity BIGINT NOT NULL DEFAULT 0,
in_transit_quantity BIGINT NOT NULL DEFAULT 0, receiving_quantity BIGINT NOT NULL DEFAULT 0,
procurement_quantity BIGINT NOT NULL DEFAULT 0, version BIGINT NOT NULL DEFAULT 0,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_ll_inventory_dimension (tenant_id,overseas_warehouse_id,destination_warehouse_code,sku_code),
KEY idx_ll_inventory_list (tenant_id,overseas_warehouse_id,updated_at),
KEY idx_ll_inventory_sku (tenant_id,sku_code)
) ENGINE=InnoDB COMMENT='Real-time SKU package inventory balance';
CREATE TABLE IF NOT EXISTS ll_inventory_position (
id BIGINT NOT NULL COMMENT 'Snowflake ID', tenant_id VARCHAR(128) NOT NULL, balance_id BIGINT NOT NULL,
overseas_warehouse_id VARCHAR(128) NOT NULL, destination_warehouse_code VARCHAR(128) NOT NULL DEFAULT '',
sku_code VARCHAR(128) NOT NULL, pallet_id BIGINT NOT NULL, pallet_no VARCHAR(64) NOT NULL,
batch_no VARCHAR(128) NOT NULL DEFAULT '', warehouse_location_id BIGINT NULL,
warehouse_location_code VARCHAR(128) NOT NULL,
available_packages BIGINT NOT NULL DEFAULT 0, hold_packages BIGINT NOT NULL DEFAULT 0,
allocated_packages BIGINT NOT NULL DEFAULT 0, picked_packages BIGINT NOT NULL DEFAULT 0,
receiving_packages BIGINT NOT NULL DEFAULT 0, product_quantity BIGINT NOT NULL DEFAULT 0,
status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE', version BIGINT NOT NULL DEFAULT 0,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_inventory_position (balance_id,pallet_id,batch_no),
KEY idx_ll_inventory_position_pallet (tenant_id,pallet_id),
KEY idx_ll_inventory_position_location (tenant_id,overseas_warehouse_id,warehouse_location_code)
) ENGINE=InnoDB COMMENT='SKU package stock by pallet, default location and batch';
CREATE TABLE IF NOT EXISTS ll_inventory_ledger (
id BIGINT NOT NULL COMMENT 'Snowflake ID', tenant_id VARCHAR(128) NOT NULL,
balance_id BIGINT NOT NULL, position_id BIGINT NULL, overseas_warehouse_id VARCHAR(128) NOT NULL,
destination_warehouse_code VARCHAR(128) NOT NULL DEFAULT '', sku_code VARCHAR(128) NOT NULL,
pallet_id BIGINT NULL, pallet_no VARCHAR(64) NULL, batch_no VARCHAR(128) NULL,
warehouse_location_code VARCHAR(128) NULL, business_type VARCHAR(32) NOT NULL,
business_order_id BIGINT NULL, business_order_no VARCHAR(128) NULL, inbound_code VARCHAR(128) NULL,
inbound_order_no VARCHAR(128) NULL, outbound_order_no VARCHAR(128) NULL,
source_event_id VARCHAR(128) NULL, idempotency_key VARCHAR(255) NOT NULL,
status_from VARCHAR(32) NULL, status_to VARCHAR(32) NULL,
before_packages BIGINT NOT NULL, delta_packages BIGINT NOT NULL, after_packages BIGINT NOT NULL,
before_quantity BIGINT NOT NULL, delta_quantity BIGINT NOT NULL, after_quantity BIGINT NOT NULL,
operator_id VARCHAR(128) NULL, remark VARCHAR(1000) NULL,
occurred_at DATETIME(3) NOT NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_inventory_ledger_idempotency (tenant_id,idempotency_key),
KEY idx_ll_inventory_ledger_query (tenant_id,overseas_warehouse_id,occurred_at),
KEY idx_ll_inventory_ledger_sku (tenant_id,sku_code,occurred_at),
KEY idx_ll_inventory_ledger_business (tenant_id,business_type,business_order_no)
) ENGINE=InnoDB COMMENT='Immutable inventory package and quantity ledger';
CREATE TABLE IF NOT EXISTS ll_inventory_operation (
id BIGINT NOT NULL COMMENT 'Snowflake ID', tenant_id VARCHAR(128) NOT NULL,
idempotency_key VARCHAR(255) NOT NULL, operation_type VARCHAR(32) NOT NULL,
request_hash VARCHAR(128) NOT NULL, status VARCHAR(32) NOT NULL DEFAULT 'PROCESSING',
result_json LONGTEXT NULL, last_error VARCHAR(2000) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_inventory_operation_key (tenant_id,idempotency_key),
KEY idx_ll_inventory_operation_status (tenant_id,status,updated_at)
) ENGINE=InnoDB COMMENT='Inventory command idempotency record';
-- ============================================================================
-- 2026-08-17 / 009
-- PDA SKU/pallet receipt snapshots for stock-in closure
-- ============================================================================
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_inbound_stock_receipt (
id BIGINT NOT NULL COMMENT 'Snowflake ID', tenant_id VARCHAR(128) NOT NULL,
plan_id BIGINT NOT NULL, task_id BIGINT NOT NULL, allocation_id BIGINT NOT NULL,
line_id BIGINT NOT NULL, order_id BIGINT NOT NULL, inbound_code VARCHAR(128) NOT NULL,
sku_code VARCHAR(128) NOT NULL, sku_name_zh VARCHAR(255) NULL, source_detail_ids VARCHAR(2000) NULL,
warehouse_pallet_id BIGINT NOT NULL, pallet_no VARCHAR(64) NOT NULL,
warehouse_location_id BIGINT NULL, warehouse_location_code VARCHAR(128) NULL,
batch_no VARCHAR(128) NOT NULL, received_packages BIGINT NOT NULL, received_quantity BIGINT NOT NULL,
inventory_balance_id BIGINT NOT NULL, inventory_position_id BIGINT NOT NULL,
inventory_operation_key VARCHAR(255) NOT NULL, received_at DATETIME(3) NOT NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_stock_receipt_task_allocation_sku (tenant_id,task_id,allocation_id,sku_code),
KEY idx_ll_stock_receipt_plan (tenant_id,plan_id,line_id), KEY idx_ll_stock_receipt_inventory (inventory_balance_id,inventory_position_id)
) ENGINE=InnoDB COMMENT='Immutable SKU-pallet PDA stock-in receipt snapshot';
-- 2026-08-17 warehouse virtual location and generated pallet code support.
USE baiyue_lastlag_warehouse;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='wh_pallet' AND column_name='pallet_code'),
'ALTER TABLE wh_pallet MODIFY COLUMN pallet_code VARCHAR(128) NOT NULL COMMENT ''Warehouse pallet code''', 'SELECT 1'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
INSERT INTO wh_location (id, tenant_id, warehouse_id, zone_code, location_code, location_type,
max_load_kg, status, remark)
SELECT UUID_SHORT(), w.tenant_id, w.id, 'DEFAULT', CONCAT('LOC-', w.warehouse_code, '-DEFAULT'),
'VIRTUAL', 999999999.000, 'ACTIVE', 'System default virtual location'
FROM wh_warehouse w
WHERE NOT EXISTS (
SELECT 1 FROM wh_location l
WHERE l.tenant_id = w.tenant_id AND l.warehouse_id = w.id
AND l.location_code = CONCAT('LOC-', w.warehouse_code, '-DEFAULT') AND l.deleted = 0
);
-- ============================================================================
-- 2026-08-17 / 010
-- Last-leg pre-dispatch orders and pallet locks
-- ============================================================================
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_dispatch_order (
id BIGINT NOT NULL COMMENT 'Snowflake ID', tenant_id VARCHAR(128) NOT NULL,
dispatch_no VARCHAR(64) NOT NULL, vehicle_plate VARCHAR(64) NULL, driver_name VARCHAR(128) NULL,
driver_phone VARCHAR(64) NULL, carrier_name VARCHAR(255) NULL, route VARCHAR(255) NULL,
depart_at DATETIME(3) NULL, fba_appointment_no VARCHAR(64) NULL,
fba_appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
vehicle_appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
estimated_arrival_at DATETIME(3) NULL, status VARCHAR(32) NOT NULL DEFAULT 'PENDING_DEPARTURE',
item_count INT NOT NULL DEFAULT 0, pallet_count INT NOT NULL DEFAULT 0, package_count INT NOT NULL DEFAULT 0,
created_by VARCHAR(128) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_order_no (tenant_id,dispatch_no),
KEY idx_ll_dispatch_order_list (tenant_id,status,depart_at), KEY idx_ll_dispatch_order_vehicle (tenant_id,vehicle_plate)
) ENGINE=InnoDB COMMENT='Last-leg pre-dispatch order';
CREATE TABLE IF NOT EXISTS ll_dispatch_item (
id BIGINT NOT NULL COMMENT 'Snowflake ID', dispatch_order_id BIGINT NOT NULL, tenant_id VARCHAR(128) NOT NULL,
plan_id BIGINT NULL, plan_pallet_id BIGINT NULL, warehouse_pallet_id BIGINT NULL,
order_id BIGINT NULL, order_no VARCHAR(64) NULL, order_refs VARCHAR(2000) NULL, inbound_code VARCHAR(128) NULL, pallet_no VARCHAR(128) NOT NULL,
destination_warehouse_id VARCHAR(128) NULL, destination_warehouse_code VARCHAR(128) NULL,
destination_warehouse_name VARCHAR(255) NULL, fba_warehouse_code VARCHAR(128) NULL,
package_count INT NOT NULL DEFAULT 0, volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0,
source_stage VARCHAR(32) NOT NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
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 (tenant_id,order_id), KEY idx_ll_dispatch_item_inbound (tenant_id,inbound_code),
KEY idx_ll_dispatch_item_pallet (tenant_id,plan_pallet_id,warehouse_pallet_id)
) ENGINE=InnoDB COMMENT='Frozen pallet and cargo snapshot for a dispatch order';
CREATE TABLE IF NOT EXISTS ll_dispatch_pallet_lock (
id BIGINT NOT NULL COMMENT 'Snowflake ID', tenant_id VARCHAR(128) NOT NULL,
source_pallet_key VARCHAR(160) NOT NULL, active_key VARCHAR(160) NULL,
plan_id BIGINT NULL, plan_pallet_id BIGINT NULL, warehouse_pallet_id BIGINT NULL,
dispatch_order_id BIGINT NOT NULL, status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
locked_at DATETIME(3) NOT NULL, released_at DATETIME(3) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_active_pallet (tenant_id,active_key),
KEY idx_ll_dispatch_pallet_lock_order (tenant_id,dispatch_order_id,status),
KEY idx_ll_dispatch_pallet_lock_source (tenant_id,source_pallet_key,status)
) ENGINE=InnoDB COMMENT='Active dispatch pallet exclusion lock';
-- ============================================================================
-- 2026-08-17 / 011
-- Dispatch PDA task and immutable pallet pick operations
-- ============================================================================
USE baiyue_lastleg;
CREATE TABLE IF NOT EXISTS ll_dispatch_pda_task (
id BIGINT NOT NULL, tenant_id VARCHAR(128) NOT NULL, dispatch_order_id BIGINT NOT NULL,
task_no VARCHAR(64) NOT NULL, status VARCHAR(32) NOT NULL, operator_id VARCHAR(128) NULL,
operator_name VARCHAR(128) NULL, pushed_at DATETIME(3) NOT NULL, completed_at DATETIME(3) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_pda_task_dispatch (tenant_id,dispatch_order_id),
UNIQUE KEY uk_ll_dispatch_pda_task_no (tenant_id,task_no)
) ENGINE=InnoDB COMMENT='PDA task for a pre-arranged dispatch';
CREATE TABLE IF NOT EXISTS ll_dispatch_pda_pick (
id BIGINT NOT NULL, tenant_id VARCHAR(128) NOT NULL, task_id BIGINT NOT NULL,
dispatch_item_id BIGINT NOT NULL, inventory_position_id BIGINT NOT NULL,
packages BIGINT NOT NULL, product_quantity BIGINT NOT NULL DEFAULT 0, idempotency_key VARCHAR(255) NOT NULL,
picked_at DATETIME(3) NOT NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_pda_pick_key (tenant_id,idempotency_key),
KEY idx_ll_dispatch_pda_pick_item (tenant_id,task_id,dispatch_item_id)
) ENGINE=InnoDB COMMENT='Immutable dispatch PDA pallet package picks';
CREATE TABLE IF NOT EXISTS ll_dispatch_pda_operation (
id BIGINT NOT NULL, tenant_id VARCHAR(128) NOT NULL, task_id BIGINT NULL,
operation_type VARCHAR(32) NOT NULL, idempotency_key VARCHAR(255) NOT NULL, request_hash CHAR(64) NOT NULL,
result_json LONGTEXT NULL, status VARCHAR(32) NOT NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_pda_operation_key (tenant_id,idempotency_key)
) ENGINE=InnoDB COMMENT='Idempotent dispatch PDA operations';
-- ============================================================================
-- 2026-08-17 / 012
-- Preserve all tail-leg orders included in one merged dispatch pallet
-- ============================================================================
USE baiyue_lastleg;
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 AFTER order_no'));
PREPARE migration_stmt FROM @ddl; EXECUTE migration_stmt; DEALLOCATE PREPARE migration_stmt;