2026-08-17 09:18:03 +08:00
-- 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,可为空' ,
2026-08-17 13:38:48 +08:00
pallet_code VARCHAR ( 128 ) NOT NULL COMMENT '仓库内唯一托盘编码' ,
2026-08-17 09:18:03 +08:00
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,可为空' ,
2026-08-17 13:38:48 +08:00
MODIFY COLUMN pallet_code VARCHAR ( 128 ) NOT NULL COMMENT '仓库内唯一托盘编码' ,
2026-08-17 09:18:03 +08:00
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 13:38:48 +08:00
-- ============================================================================
-- 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
2026-08-17 19:04:58 +08:00
-- Last-leg inbound-order/package inventory balances, positions and immutable ledger
2026-08-17 13:38:48 +08:00
-- ============================================================================
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 ,
2026-08-17 19:04:58 +08:00
inbound_order_id BIGINT NOT NULL , inbound_order_no VARCHAR ( 128 ) NULL , inbound_code VARCHAR ( 128 ) NOT NULL ,
2026-08-17 13:38:48 +08:00
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 ,
2026-08-17 19:04:58 +08:00
procurement_packages BIGINT NOT NULL DEFAULT 0 , version BIGINT NOT NULL DEFAULT 0 ,
2026-08-17 13:38:48 +08:00
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 ),
2026-08-17 19:04:58 +08:00
UNIQUE KEY uk_ll_inventory_dimension ( tenant_id , overseas_warehouse_id , destination_warehouse_code , inbound_order_id , inbound_code ),
2026-08-17 13:38:48 +08:00
KEY idx_ll_inventory_list ( tenant_id , overseas_warehouse_id , updated_at ),
2026-08-17 19:04:58 +08:00
KEY idx_ll_inventory_inbound ( tenant_id , inbound_code )
) ENGINE = InnoDB COMMENT = 'Real-time inbound-order package inventory balance' ;
2026-08-17 13:38:48 +08:00
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 '' ,
2026-08-17 19:04:58 +08:00
pallet_id BIGINT NOT NULL , pallet_no VARCHAR ( 64 ) NOT NULL ,
2026-08-17 13:38:48 +08:00
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 ,
2026-08-17 19:04:58 +08:00
receiving_packages BIGINT NOT NULL DEFAULT 0 ,
2026-08-17 13:38:48 +08:00
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 )
2026-08-17 19:04:58 +08:00
) ENGINE = InnoDB COMMENT = 'Inbound-order package stock by pallet, default location and batch' ;
2026-08-17 13:38:48 +08:00
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 ,
2026-08-17 19:04:58 +08:00
destination_warehouse_code VARCHAR ( 128 ) NOT NULL DEFAULT '' , inbound_order_id BIGINT NOT NULL ,
2026-08-17 13:38:48 +08:00
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 ,
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 ),
2026-08-17 19:04:58 +08:00
KEY idx_ll_inventory_ledger_inbound ( tenant_id , inbound_code , occurred_at ),
2026-08-17 13:38:48 +08:00
KEY idx_ll_inventory_ledger_business ( tenant_id , business_type , business_order_no )
2026-08-17 19:04:58 +08:00
) ENGINE = InnoDB COMMENT = 'Immutable inbound-order package inventory ledger' ;
2026-08-17 13:38:48 +08:00
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 ,
2026-08-17 19:04:58 +08:00
dispatch_no VARCHAR ( 64 ) NOT NULL , overseas_warehouse_id VARCHAR ( 128 ) NULL , overseas_warehouse_name VARCHAR ( 255 ) NULL ,
vehicle_plate VARCHAR ( 64 ) NULL , driver_name VARCHAR ( 128 ) NULL ,
2026-08-17 13:38:48 +08:00
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 ,
2026-08-17 19:04:58 +08:00
overseas_warehouse_id VARCHAR ( 128 ) NULL , overseas_warehouse_name VARCHAR ( 255 ) NULL ,
2026-08-17 13:38:48 +08:00
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 ,
2026-08-17 19:04:58 +08:00
operator_name VARCHAR ( 128 ) NULL , warehouse_id VARCHAR ( 128 ) NULL ,
pushed_at DATETIME ( 3 ) NOT NULL , completed_at DATETIME ( 3 ) NULL ,
2026-08-17 13:38:48 +08:00
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 ;
2026-08-17 19:04:58 +08:00
-- ============================================================================
-- 2026-08-17 / 013
-- Partial dispatch completion and cumulative package counters
-- ============================================================================
USE baiyue_lastleg ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_order' AND column_name = 'overseas_warehouse_id' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_order ADD COLUMN overseas_warehouse_id VARCHAR(128) NULL AFTER dispatch_no' ));
PREPARE warehouse_scope_stmt FROM @ ddl ; EXECUTE warehouse_scope_stmt ; DEALLOCATE PREPARE warehouse_scope_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_order' AND column_name = 'overseas_warehouse_name' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_order ADD COLUMN overseas_warehouse_name VARCHAR(255) NULL AFTER overseas_warehouse_id' ));
PREPARE warehouse_scope_stmt FROM @ ddl ; EXECUTE warehouse_scope_stmt ; DEALLOCATE PREPARE warehouse_scope_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_item' AND column_name = 'overseas_warehouse_id' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_item ADD COLUMN overseas_warehouse_id VARCHAR(128) NULL AFTER pallet_no' ));
PREPARE warehouse_scope_stmt FROM @ ddl ; EXECUTE warehouse_scope_stmt ; DEALLOCATE PREPARE warehouse_scope_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_item' AND column_name = 'overseas_warehouse_name' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_item ADD COLUMN overseas_warehouse_name VARCHAR(255) NULL AFTER overseas_warehouse_id' ));
PREPARE warehouse_scope_stmt FROM @ ddl ; EXECUTE warehouse_scope_stmt ; DEALLOCATE PREPARE warehouse_scope_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_pda_task' AND column_name = 'warehouse_id' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_pda_task ADD COLUMN warehouse_id VARCHAR(128) NULL AFTER operator_name' ));
PREPARE warehouse_scope_stmt FROM @ ddl ; EXECUTE warehouse_scope_stmt ; DEALLOCATE PREPARE warehouse_scope_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_order' AND column_name = 'picked_package_count' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_order ADD COLUMN picked_package_count INT NOT NULL DEFAULT 0 AFTER package_count' ));
PREPARE dispatch_partial_stmt FROM @ ddl ; EXECUTE dispatch_partial_stmt ; DEALLOCATE PREPARE dispatch_partial_stmt ;
CREATE TABLE IF NOT EXISTS ll_dispatch_pda_pick_order (
id BIGINT NOT NULL , tenant_id VARCHAR ( 128 ) NOT NULL , pick_id BIGINT NOT NULL ,
receipt_id BIGINT NOT NULL , order_id BIGINT NOT NULL , packages BIGINT NOT NULL ,
product_quantity BIGINT NOT NULL DEFAULT 0 , created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ),
PRIMARY KEY ( id ), KEY idx_ll_dispatch_pick_order_pick ( tenant_id , pick_id ),
KEY idx_ll_dispatch_pick_order_receipt ( tenant_id , receipt_id )
) ENGINE = InnoDB COMMENT = 'PDA pick attribution to frozen inbound receipt and tail order' ;
-- Tail order cumulative picking/shipping counters. Original package_count is immutable.
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_order' AND column_name = 'picked_package_count' ), 'SELECT 1' , 'ALTER TABLE ll_order ADD COLUMN picked_package_count INT NOT NULL DEFAULT 0 AFTER package_count' ));
PREPARE tail_order_partial_stmt FROM @ ddl ; EXECUTE tail_order_partial_stmt ; DEALLOCATE PREPARE tail_order_partial_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_order' AND column_name = 'shipped_package_count' ), 'SELECT 1' , 'ALTER TABLE ll_order ADD COLUMN shipped_package_count INT NOT NULL DEFAULT 0 AFTER picked_package_count' ));
PREPARE tail_order_partial_stmt FROM @ ddl ; EXECUTE tail_order_partial_stmt ; DEALLOCATE PREPARE tail_order_partial_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_order' AND column_name = 'shipped_package_count' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_order ADD COLUMN shipped_package_count INT NOT NULL DEFAULT 0 AFTER picked_package_count' ));
PREPARE dispatch_partial_stmt FROM @ ddl ; EXECUTE dispatch_partial_stmt ; DEALLOCATE PREPARE dispatch_partial_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_order' AND column_name = 'partial_completion_reason' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_order ADD COLUMN partial_completion_reason VARCHAR(1000) NULL AFTER shipped_package_count' ));
PREPARE dispatch_partial_stmt FROM @ ddl ; EXECUTE dispatch_partial_stmt ; DEALLOCATE PREPARE dispatch_partial_stmt ;
-- ============================================================================
-- 2026-08-17 / 014
-- Dispatch transfer to outbound and delivery documents
-- ============================================================================
USE baiyue_lastleg ;
CREATE TABLE IF NOT EXISTS ll_outbound_order (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , tenant_id VARCHAR ( 128 ) NOT NULL ,
outbound_no VARCHAR ( 64 ) NOT NULL , dispatch_order_id BIGINT NOT NULL , dispatch_no VARCHAR ( 64 ) NOT NULL ,
overseas_warehouse_id VARCHAR ( 128 ) NULL , status VARCHAR ( 32 ) NOT NULL DEFAULT 'WAIT_OUTBOUND' ,
package_count INT NOT NULL DEFAULT 0 , pallet_count INT NOT NULL DEFAULT 0 ,
idempotency_key VARCHAR ( 255 ) NOT NULL , 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_outbound_no ( tenant_id , outbound_no ),
UNIQUE KEY uk_ll_outbound_idempotency ( tenant_id , idempotency_key ), UNIQUE KEY uk_ll_outbound_dispatch ( tenant_id , dispatch_order_id ),
KEY idx_ll_outbound_list ( tenant_id , status , created_at )
) ENGINE = InnoDB COMMENT = 'Outbound document generated from a dispatch' ;
CREATE TABLE IF NOT EXISTS ll_outbound_pallet_item (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , tenant_id VARCHAR ( 128 ) NOT NULL , outbound_order_id BIGINT NOT NULL ,
warehouse_pallet_id BIGINT NOT 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 ,
package_count INT NOT NULL DEFAULT 0 , order_refs VARCHAR ( 2000 ) NULL , inbound_code VARCHAR ( 128 ) NULL ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id ),
UNIQUE KEY uk_ll_outbound_pallet ( tenant_id , outbound_order_id , warehouse_pallet_id ),
KEY idx_ll_outbound_pallet_list ( tenant_id , outbound_order_id ), KEY idx_ll_outbound_pallet_destination ( tenant_id , destination_warehouse_code )
) ENGINE = InnoDB COMMENT = 'Pallet detail snapshot for an outbound document' ;
CREATE TABLE IF NOT EXISTS ll_delivery_order (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , tenant_id VARCHAR ( 128 ) NOT NULL ,
delivery_no VARCHAR ( 64 ) NOT NULL , outbound_order_id BIGINT NOT NULL , outbound_no VARCHAR ( 64 ) NOT NULL ,
dispatch_order_id BIGINT NOT NULL , dispatch_no VARCHAR ( 64 ) NOT NULL , overseas_warehouse_id VARCHAR ( 128 ) NULL ,
status VARCHAR ( 32 ) NOT NULL DEFAULT 'WAIT_DELIVERY' , package_count INT NOT NULL DEFAULT 0 , pallet_count INT NOT NULL DEFAULT 0 ,
idempotency_key VARCHAR ( 255 ) NOT NULL , 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_delivery_no ( tenant_id , delivery_no ),
UNIQUE KEY uk_ll_delivery_idempotency ( tenant_id , idempotency_key ), UNIQUE KEY uk_ll_delivery_outbound ( tenant_id , outbound_order_id ),
KEY idx_ll_delivery_list ( tenant_id , status , created_at )
) ENGINE = InnoDB COMMENT = 'Delivery document linked to an outbound document' ;
-- ============================================================================
-- 2026-08-17 / 015
-- Change inventory ownership from SKU/quantity to inbound-order/package count.
-- Legacy SKU columns become nullable and quantity columns remain untouched so original data is preserved.
-- ============================================================================
USE baiyue_lastleg ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_balance' AND column_name = 'inbound_order_id' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_balance ADD COLUMN inbound_order_id BIGINT NULL AFTER destination_warehouse_name' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 = 'inbound_order_no' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_balance ADD COLUMN inbound_order_no VARCHAR(128) NULL AFTER inbound_order_id' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 = 'inbound_code' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_balance ADD COLUMN inbound_code VARCHAR(128) NULL AFTER inbound_order_no' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_stmt ;
-- One legacy balance row represented one SKU. Keep each row intact and give it a
-- collision-free migration identity while retaining the best known inbound snapshots.
UPDATE ll_inventory_balance b
LEFT JOIN (
SELECT balance_id , MAX ( inbound_order_no ) AS inbound_order_no , MAX ( inbound_code ) AS inbound_code
FROM ll_inventory_ledger GROUP BY balance_id
) l ON l . balance_id = b . id
SET b . inbound_order_id = COALESCE ( b . inbound_order_id , b . id ),
b . inbound_order_no = COALESCE ( b . inbound_order_no , l . inbound_order_no ),
b . inbound_code = COALESCE ( NULLIF ( b . inbound_code , '' ), NULLIF ( l . inbound_code , '' ), CONCAT ( 'LEGACY-' , b . id ))
WHERE b . inbound_order_id IS NULL OR b . inbound_code IS NULL OR b . inbound_code = '' ;
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) NULL' , 'SELECT 1' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 = 'inbound_order_id' ), 'ALTER TABLE ll_inventory_balance MODIFY COLUMN inbound_order_id BIGINT NOT NULL' , 'SELECT 1' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 = 'inbound_code' ), 'ALTER TABLE ll_inventory_balance MODIFY COLUMN inbound_code VARCHAR(128) NOT NULL' , 'SELECT 1' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 (tenant_id,overseas_warehouse_id,destination_warehouse_code,inbound_order_id,inbound_code)' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 = 'idx_ll_inventory_inbound' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_balance ADD KEY idx_ll_inventory_inbound (tenant_id,inbound_code)' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 = 'idx_ll_inventory_sku' ), 'ALTER TABLE ll_inventory_balance DROP INDEX idx_ll_inventory_sku' , 'SELECT 1' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_position' AND column_name = 'sku_code' ), 'ALTER TABLE ll_inventory_position MODIFY COLUMN sku_code VARCHAR(128) NULL' , 'SELECT 1' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 = 'inbound_order_id' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_ledger ADD COLUMN inbound_order_id BIGINT NULL AFTER destination_warehouse_code' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_stmt ;
UPDATE ll_inventory_ledger SET inbound_order_id = COALESCE ( inbound_order_id , business_order_id , balance_id ) WHERE inbound_order_id IS NULL ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND column_name = 'sku_code' ), 'ALTER TABLE ll_inventory_ledger MODIFY COLUMN sku_code VARCHAR(128) NULL' , 'SELECT 1' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_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 = 'inbound_order_id' ), 'ALTER TABLE ll_inventory_ledger MODIFY COLUMN inbound_order_id BIGINT NOT NULL' , 'SELECT 1' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND index_name = 'idx_ll_inventory_ledger_inbound' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_ledger ADD KEY idx_ll_inventory_ledger_inbound (tenant_id,inbound_code,occurred_at)' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND index_name = 'idx_ll_inventory_ledger_sku' ), 'ALTER TABLE ll_inventory_ledger DROP INDEX idx_ll_inventory_ledger_sku' , 'SELECT 1' ));
PREPARE inventory_v2_stmt FROM @ ddl ; EXECUTE inventory_v2_stmt ; DEALLOCATE PREPARE inventory_v2_stmt ;
-- ============================================================================
-- 2026-08-17 / 016
-- PDA stock receipts follow the same inbound-order/package-only inventory model.
-- Legacy SKU and quantity columns remain in place but become nullable/defaulted.
-- ============================================================================
USE baiyue_lastleg ;
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' ), 'ALTER TABLE ll_inbound_stock_receipt MODIFY COLUMN sku_code VARCHAR(128) NULL' , 'SELECT 1' ));
PREPARE stock_receipt_v2_stmt FROM @ ddl ; EXECUTE stock_receipt_v2_stmt ; DEALLOCATE PREPARE stock_receipt_v2_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 = 'received_quantity' ), 'ALTER TABLE ll_inbound_stock_receipt MODIFY COLUMN received_quantity BIGINT NULL DEFAULT 0' , 'SELECT 1' ));
PREPARE stock_receipt_v2_stmt FROM @ ddl ; EXECUTE stock_receipt_v2_stmt ; DEALLOCATE PREPARE stock_receipt_v2_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' ), 'ALTER TABLE ll_inbound_stock_receipt DROP INDEX uk_ll_stock_receipt_task_allocation_sku' , 'SELECT 1' ));
PREPARE stock_receipt_v2_stmt FROM @ ddl ; EXECUTE stock_receipt_v2_stmt ; DEALLOCATE PREPARE stock_receipt_v2_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' ), 'SELECT 1' , 'ALTER TABLE ll_inbound_stock_receipt ADD UNIQUE KEY uk_ll_stock_receipt_task_allocation (tenant_id,task_id,allocation_id)' ));
PREPARE stock_receipt_v2_stmt FROM @ ddl ; EXECUTE stock_receipt_v2_stmt ; DEALLOCATE PREPARE stock_receipt_v2_stmt ;
-- ============================================================================
-- 2026-08-17 / 017
-- Customer relabel applications, cargo snapshots, and process status history
-- ============================================================================
USE baiyue_lastleg ;
CREATE TABLE IF NOT EXISTS ll_relabel_application (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , tenant_id VARCHAR ( 128 ) NOT NULL ,
relabel_no VARCHAR ( 64 ) NOT NULL , lastleg_order_id BIGINT NOT NULL ,
customer_order_no VARCHAR ( 128 ) NOT NULL , overseas_warehouse_id VARCHAR ( 128 ) NOT NULL ,
label_deadline DATETIME ( 3 ) NOT NULL , contact_name VARCHAR ( 128 ) NOT NULL ,
contact_phone VARCHAR ( 64 ) NOT NULL , remark VARCHAR ( 1000 ) NULL ,
status VARCHAR ( 32 ) NOT NULL DEFAULT 'PENDING_PROCESSING' , item_count INT NOT NULL DEFAULT 0 ,
total_package_count INT NOT NULL DEFAULT 0 , notified_package_count INT NOT NULL DEFAULT 0 ,
idempotency_key VARCHAR ( 255 ) NOT NULL , request_hash CHAR ( 64 ) NOT NULL ,
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 )
) ENGINE = InnoDB COMMENT = 'Customer relabel application header' ;
CREATE TABLE IF NOT EXISTS ll_relabel_item (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , application_id BIGINT NOT NULL , tenant_id VARCHAR ( 128 ) NOT NULL ,
sku_code VARCHAR ( 128 ) NOT NULL , product_image_file_id VARCHAR ( 128 ) NULL ,
product_image_file_name VARCHAR ( 255 ) NULL , product_image_url VARCHAR ( 1000 ) NULL ,
product_name_zh VARCHAR ( 255 ) NOT NULL , total_package_count INT NOT NULL , notified_package_count INT NOT NULL ,
shipment_no VARCHAR ( 128 ) NOT NULL , tracking_code VARCHAR ( 255 ) NULL , new_sku_code VARCHAR ( 128 ) NOT NULL ,
label_requirement VARCHAR ( 1000 ) NULL , relabel_file_id VARCHAR ( 128 ) NULL ,
relabel_file_name VARCHAR ( 255 ) NULL , relabel_file_url VARCHAR ( 1000 ) NULL ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id )
) ENGINE = InnoDB COMMENT = 'Frozen customer relabel cargo items' ;
CREATE TABLE IF NOT EXISTS ll_relabel_status_history (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , tenant_id VARCHAR ( 128 ) NOT NULL , application_id BIGINT NOT NULL ,
from_status VARCHAR ( 32 ) NULL , to_status VARCHAR ( 32 ) NOT NULL , operator_id VARCHAR ( 128 ) NULL ,
remark VARCHAR ( 1000 ) NULL , created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id )
) ENGINE = InnoDB COMMENT = 'Immutable customer relabel process history' ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_application' AND index_name = 'uk_ll_relabel_application_no' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_application ADD UNIQUE KEY uk_ll_relabel_application_no (tenant_id,relabel_no)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_application' AND index_name = 'uk_ll_relabel_application_idempotency' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_application ADD UNIQUE KEY uk_ll_relabel_application_idempotency (tenant_id,idempotency_key)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_application' AND index_name = 'uk_ll_relabel_application_order' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_application ADD UNIQUE KEY uk_ll_relabel_application_order (lastleg_order_id)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_application' AND index_name = 'idx_ll_relabel_application_list' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_application ADD KEY idx_ll_relabel_application_list (tenant_id,status,created_at)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_application' AND index_name = 'idx_ll_relabel_application_customer' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_application ADD KEY idx_ll_relabel_application_customer (tenant_id,customer_order_no)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_application' AND index_name = 'idx_ll_relabel_application_warehouse' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_application ADD KEY idx_ll_relabel_application_warehouse (tenant_id,overseas_warehouse_id)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_item' AND index_name = 'idx_ll_relabel_item_application' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_item ADD KEY idx_ll_relabel_item_application (tenant_id,application_id)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_item' AND index_name = 'idx_ll_relabel_item_sku' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_item ADD KEY idx_ll_relabel_item_sku (tenant_id,sku_code)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_relabel_status_history' AND index_name = 'idx_ll_relabel_status_history_application' ), 'SELECT 1' , 'ALTER TABLE ll_relabel_status_history ADD KEY idx_ll_relabel_status_history_application (tenant_id,application_id,created_at)' ));
PREPARE relabel_schema_stmt FROM @ ddl ; EXECUTE relabel_schema_stmt ; DEALLOCATE PREPARE relabel_schema_stmt ;
-- ============================================================================
-- 2026-08-17 / 018
-- Existing-table correction: apply schema changes with ADD/UPDATE/ALTER guards
-- ============================================================================
-- Sections 008-017 keep CREATE TABLE definitions for fresh databases. This
-- section is the authoritative path for databases that already contain those
-- tables. Legacy SKU/quantity columns are retained and made nullable; no
-- business rows or Outbox rows are deleted.
USE baiyue_lastleg ;
-- Tail orders: cumulative PDA picking/shipping counters.
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_order' AND column_name = 'picked_package_count' ), 'SELECT 1' , 'ALTER TABLE ll_order ADD COLUMN picked_package_count INT NOT NULL DEFAULT 0 COMMENT ''累计已拣箱数'' AFTER package_count' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_order' AND column_name = 'shipped_package_count' ), 'SELECT 1' , 'ALTER TABLE ll_order ADD COLUMN shipped_package_count INT NOT NULL DEFAULT 0 COMMENT ''累计已出库箱数'' AFTER picked_package_count' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
-- Inventory balance: add inbound-order identity without dropping legacy SKU data.
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_balance' AND column_name = 'inbound_order_id' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_balance ADD COLUMN inbound_order_id BIGINT NULL COMMENT ''入仓单ID'' AFTER destination_warehouse_name' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_balance' AND column_name = 'inbound_order_no' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_balance ADD COLUMN inbound_order_no VARCHAR(128) NULL COMMENT ''入库单号快照'' AFTER inbound_order_id' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_balance' AND column_name = 'inbound_code' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_balance ADD COLUMN inbound_code VARCHAR(128) NULL COMMENT ''入仓码快照'' AFTER inbound_order_no' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
UPDATE ll_inventory_balance
SET inbound_order_id = COALESCE ( inbound_order_id , id ),
inbound_code = COALESCE ( NULLIF ( inbound_code , '' ), CONCAT ( 'LEGACY-' , id ))
WHERE inbound_order_id IS NULL OR inbound_code IS NULL OR inbound_code = '' ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_balance' AND column_name = 'inbound_order_id' ), 'ALTER TABLE ll_inventory_balance MODIFY COLUMN inbound_order_id BIGINT NOT NULL' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_balance' AND column_name = 'inbound_code' ), 'ALTER TABLE ll_inventory_balance MODIFY COLUMN inbound_code VARCHAR(128) NOT NULL' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
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 migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
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 (tenant_id,overseas_warehouse_id,destination_warehouse_code,inbound_order_id,inbound_code)' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
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' ), 'ALTER TABLE ll_inventory_balance DROP INDEX idx_ll_inventory_sku' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
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_inbound' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_balance ADD KEY idx_ll_inventory_inbound (tenant_id,inbound_code)' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
-- Inventory positions and ledger: preserve SKU columns, add inbound identity.
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_position' AND column_name = 'sku_code' ), 'ALTER TABLE ll_inventory_position MODIFY COLUMN sku_code VARCHAR(128) NULL' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND column_name = 'inbound_order_id' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_ledger ADD COLUMN inbound_order_id BIGINT NULL COMMENT ''入仓单ID'' AFTER destination_warehouse_code' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
UPDATE ll_inventory_ledger
SET inbound_order_id = COALESCE ( inbound_order_id , business_order_id , balance_id )
WHERE inbound_order_id IS NULL ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND column_name = 'inbound_order_id' ), 'ALTER TABLE ll_inventory_ledger MODIFY COLUMN inbound_order_id BIGINT NOT NULL' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND column_name = 'sku_code' ), 'ALTER TABLE ll_inventory_ledger MODIFY COLUMN sku_code VARCHAR(128) NULL' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND index_name = 'idx_ll_inventory_ledger_sku' ), 'ALTER TABLE ll_inventory_ledger DROP INDEX idx_ll_inventory_ledger_sku' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND index_name = 'idx_ll_inventory_ledger_inbound' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_ledger ADD KEY idx_ll_inventory_ledger_inbound (tenant_id,inbound_code,occurred_at)' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
-- Stock receipts: keep legacy SKU/quantity snapshots but allow inbound-only rows.
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' ), 'ALTER TABLE ll_inbound_stock_receipt MODIFY COLUMN sku_code VARCHAR(128) NULL' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
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 = 'received_quantity' ), 'ALTER TABLE ll_inbound_stock_receipt MODIFY COLUMN received_quantity BIGINT NULL DEFAULT 0' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
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' ), 'ALTER TABLE ll_inbound_stock_receipt DROP INDEX uk_ll_stock_receipt_task_allocation_sku' , 'SELECT 1' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
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' ), 'SELECT 1' , 'ALTER TABLE ll_inbound_stock_receipt ADD UNIQUE KEY uk_ll_stock_receipt_task_allocation (tenant_id,task_id,allocation_id)' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
-- Dispatch/PDA fields are also ADD operations for existing installations.
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_order' AND column_name = 'picked_package_count' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_order ADD COLUMN picked_package_count INT NOT NULL DEFAULT 0 COMMENT ''累计已拣箱数'' AFTER package_count' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_order' AND column_name = 'shipped_package_count' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_order ADD COLUMN shipped_package_count INT NOT NULL DEFAULT 0 COMMENT ''累计已出库箱数'' AFTER picked_package_count' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dispatch_order' AND column_name = 'partial_completion_reason' ), 'SELECT 1' , 'ALTER TABLE ll_dispatch_order ADD COLUMN partial_completion_reason VARCHAR(1000) NULL COMMENT ''部分完成原因'' AFTER shipped_package_count' ));
PREPARE migration_018 FROM @ ddl ; EXECUTE migration_018 ; DEALLOCATE PREPARE migration_018 ;
-- No DROP COLUMN is included. Existing columns and business rows remain recoverable.
2026-08-18 11:39:40 +08:00
-- ============================================================================
-- 2026-08-17 / 019
-- Warehouse transfer orders with historical customer-order/inbound bindings.
-- ============================================================================
USE baiyue_lastleg ;
CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_order (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , tenant_id VARCHAR ( 128 ) NOT NULL ,
transfer_no VARCHAR ( 64 ) NOT NULL , inbound_order_id BIGINT NOT NULL , inbound_code VARCHAR ( 128 ) NOT NULL ,
lastleg_order_id BIGINT NOT NULL , lastleg_order_no VARCHAR ( 32 ) NOT NULL ,
operating_warehouse_id VARCHAR ( 128 ) NOT NULL , fba_warehouse_code VARCHAR ( 128 ) NOT NULL ,
delivery_address VARCHAR ( 1000 ) NOT NULL , package_count INT NOT NULL , delivery_method VARCHAR ( 64 ) NOT NULL ,
estimated_arrival_at DATETIME ( 3 ) NOT NULL , fba_shipment_no VARCHAR ( 128 ) NOT NULL ,
tracking_no VARCHAR ( 255 ) NULL , fba_box_nos VARCHAR ( 2000 ) NULL , remark VARCHAR ( 1000 ) NULL ,
need_relabel TINYINT NOT NULL DEFAULT 0 , relabel_application_id BIGINT NULL , relabel_no VARCHAR ( 64 ) NULL ,
status VARCHAR ( 32 ) NOT NULL DEFAULT 'PENDING_REVIEW' , idempotency_key VARCHAR ( 255 ) NOT NULL ,
request_hash CHAR ( 64 ) NOT NULL , 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 )
) ENGINE = InnoDB COMMENT = 'Customer warehouse transfer order' ;
CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_source_order (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , transfer_order_id BIGINT NOT NULL , tenant_id VARCHAR ( 128 ) NOT NULL ,
source_lastleg_order_id BIGINT NOT NULL , source_lastleg_order_no VARCHAR ( 32 ) NOT NULL ,
inbound_order_id BIGINT NOT NULL , inbound_code VARCHAR ( 128 ) NOT NULL ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id )
) ENGINE = InnoDB COMMENT = 'Selected historical customer orders and inbound bindings' ;
CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_item (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , transfer_order_id BIGINT NOT NULL , tenant_id VARCHAR ( 128 ) NOT NULL ,
sku_code VARCHAR ( 128 ) NOT NULL , product_name_zh VARCHAR ( 255 ) NOT NULL ,
package_count INT NOT NULL , shipping_mark VARCHAR ( 255 ) NULL ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id )
) ENGINE = InnoDB COMMENT = 'Frozen warehouse transfer cargo items' ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_order' AND index_name = 'uk_ll_wh_transfer_no' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_order ADD UNIQUE KEY uk_ll_wh_transfer_no (tenant_id,transfer_no)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_order' AND index_name = 'uk_ll_wh_transfer_key' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_order ADD UNIQUE KEY uk_ll_wh_transfer_key (tenant_id,idempotency_key)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_order' AND index_name = 'uk_ll_wh_transfer_tail_order' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_order ADD UNIQUE KEY uk_ll_wh_transfer_tail_order (lastleg_order_id)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_order' AND index_name = 'idx_ll_wh_transfer_list' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_order ADD KEY idx_ll_wh_transfer_list (tenant_id,status,created_at)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_order' AND index_name = 'idx_ll_wh_transfer_inbound' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_order ADD KEY idx_ll_wh_transfer_inbound (tenant_id,inbound_code)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_source_order' AND index_name = 'uk_ll_wh_transfer_source' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_source_order ADD UNIQUE KEY uk_ll_wh_transfer_source (transfer_order_id,source_lastleg_order_id)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_source_order' AND index_name = 'idx_ll_wh_transfer_source_list' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_source_order ADD KEY idx_ll_wh_transfer_source_list (tenant_id,transfer_order_id)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_item' AND index_name = 'idx_ll_wh_transfer_item_list' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_item ADD KEY idx_ll_wh_transfer_item_list (tenant_id,transfer_order_id)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_warehouse_transfer_item' AND index_name = 'idx_ll_wh_transfer_item_sku' ), 'SELECT 1' , 'ALTER TABLE ll_warehouse_transfer_item ADD KEY idx_ll_wh_transfer_item_sku (tenant_id,sku_code)' ));
PREPARE transfer_019 FROM @ ddl ; EXECUTE transfer_019 ; DEALLOCATE PREPARE transfer_019 ;
-- 2026-08-17 / customer naming and one-click dropship carton inventory.
-- Rename only existing columns; deployed data and index definitions remain intact.
DELIMITER //
CREATE PROCEDURE migrate_tenant_columns_to_customer ()
BEGIN
DECLARE done INT DEFAULT FALSE ;
DECLARE table_name_value VARCHAR ( 128 );
DECLARE column_cursor CURSOR FOR
SELECT c . table_name FROM information_schema . columns c
WHERE c . table_schema = DATABASE () AND c . column_name = 'tenant_id'
AND NOT EXISTS ( SELECT 1 FROM information_schema . columns c2
WHERE c2 . table_schema = c . table_schema AND c2 . table_name = c . table_name AND c2 . column_name = 'customer_id' );
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE ;
OPEN column_cursor ;
rename_loop : LOOP
FETCH column_cursor INTO table_name_value ;
IF done THEN LEAVE rename_loop ; END IF ;
SET @ rename_sql = CONCAT ( 'ALTER TABLE `' , table_name_value , '` RENAME COLUMN tenant_id TO customer_id' );
PREPARE rename_statement FROM @ rename_sql ;
EXECUTE rename_statement ;
DEALLOCATE PREPARE rename_statement ;
END LOOP ;
CLOSE column_cursor ;
END //
DELIMITER ;
CALL migrate_tenant_columns_to_customer ();
DROP PROCEDURE migrate_tenant_columns_to_customer ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND column_name = 'sku_code' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_ledger ADD COLUMN sku_code VARCHAR(128) NULL AFTER batch_no' ));
PREPARE inventory_sku_020 FROM @ ddl ; EXECUTE inventory_sku_020 ; DEALLOCATE PREPARE inventory_sku_020 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND column_name = 'carton_mark' ), 'SELECT 1' , IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND column_name = 'carton_no' ), 'ALTER TABLE ll_inventory_ledger RENAME COLUMN carton_no TO carton_mark' , 'ALTER TABLE ll_inventory_ledger ADD COLUMN carton_mark VARCHAR(128) NULL AFTER sku_code' ))));
PREPARE inventory_carton_020 FROM @ ddl ; EXECUTE inventory_carton_020 ; DEALLOCATE PREPARE inventory_carton_020 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_inventory_ledger' AND column_name = 'carton_packages' ), 'SELECT 1' , 'ALTER TABLE ll_inventory_ledger ADD COLUMN carton_packages BIGINT NULL AFTER carton_mark' ));
PREPARE inventory_carton_qty_020 FROM @ ddl ; EXECUTE inventory_carton_qty_020 ; DEALLOCATE PREPARE inventory_carton_qty_020 ;
CREATE TABLE IF NOT EXISTS ll_dropship_order_profile (
id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL , order_id BIGINT NOT NULL ,
warehouse_pallet_id BIGINT NOT NULL , pallet_no VARCHAR ( 128 ) NOT NULL , inventory_position_id BIGINT NULL ,
status VARCHAR ( 32 ) NOT NULL DEFAULT 'RECEIVED' , idempotency_key VARCHAR ( 255 ) NOT NULL , 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_dropship_profile_order ( customer_id , order_id ), UNIQUE KEY uk_ll_dropship_profile_key ( customer_id , idempotency_key )
) ENGINE = InnoDB ;
CREATE TABLE IF NOT EXISTS ll_dropship_carton (
id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL , order_id BIGINT NOT NULL , profile_id BIGINT NOT NULL ,
warehouse_pallet_id BIGINT NOT NULL , pallet_no VARCHAR ( 128 ) NOT NULL , sku_code VARCHAR ( 128 ) NOT NULL , carton_mark VARCHAR ( 128 ) NOT NULL , carton_sequence INT NOT NULL ,
status VARCHAR ( 32 ) NOT NULL DEFAULT 'AVAILABLE' , outbound_order_no VARCHAR ( 128 ) NULL , 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_dropship_carton ( customer_id , order_id , carton_mark ), KEY idx_ll_dropship_carton_status ( customer_id , status ),
KEY idx_ll_dropship_carton_sku ( customer_id , sku_code , status )
) ENGINE = InnoDB ;
CREATE TABLE IF NOT EXISTS ll_dropship_sku_inventory (
id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL , order_id BIGINT NOT NULL , profile_id BIGINT NOT NULL ,
sku_code VARCHAR ( 128 ) NOT NULL , product_name VARCHAR ( 255 ) NULL , package_count BIGINT NOT NULL , product_quantity BIGINT 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_dropship_sku_inventory ( customer_id , order_id , sku_code )
) ENGINE = InnoDB ;
CREATE TABLE IF NOT EXISTS ll_dropship_carton_ledger (
id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL , order_id BIGINT NOT NULL , carton_id BIGINT NOT NULL ,
carton_mark VARCHAR ( 128 ) NOT NULL , sku_code VARCHAR ( 128 ) NOT NULL , operation_type VARCHAR ( 32 ) NOT NULL ,
before_packages BIGINT NOT NULL , delta_packages BIGINT NOT NULL , after_packages BIGINT NOT NULL ,
business_order_no VARCHAR ( 128 ) NULL , idempotency_key VARCHAR ( 255 ) NOT 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_dropship_ledger_key ( customer_id , idempotency_key ),
KEY idx_ll_dropship_ledger_sku ( customer_id , sku_code , carton_mark )
) ENGINE = InnoDB ;
-- Dropship profile stores the immutable first-leg pallet number snapshot.
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . columns WHERE table_schema = DATABASE () AND table_name = 'll_dropship_order_profile' AND column_name = 'source_pallet_no' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_order_profile ADD COLUMN source_pallet_no VARCHAR(128) NULL COMMENT ''Pallet number snapshot supplied by first-leg handover'' AFTER pallet_no' ));
PREPARE dropship_source_pallet_no_stmt FROM @ ddl ; EXECUTE dropship_source_pallet_no_stmt ; DEALLOCATE PREPARE dropship_source_pallet_no_stmt ;
-- Explicit index upgrades for existing installations. CREATE TABLE IF NOT EXISTS
-- does not add indexes to tables that already exist.
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' ), 'SELECT 1' , 'ALTER TABLE ll_order ADD KEY idx_ll_order_container (customer_id,container_no)' ));
PREPARE lastleg_indexes_020 FROM @ ddl ; EXECUTE lastleg_indexes_020 ; DEALLOCATE PREPARE lastleg_indexes_020 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_order_profile' AND index_name = 'uk_ll_dropship_profile_key' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_order_profile ADD UNIQUE KEY uk_ll_dropship_profile_key (customer_id,idempotency_key)' ));
PREPARE lastleg_indexes_020 FROM @ ddl ; EXECUTE lastleg_indexes_020 ; DEALLOCATE PREPARE lastleg_indexes_020 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_carton' AND index_name = 'uk_ll_dropship_carton' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_carton ADD UNIQUE KEY uk_ll_dropship_carton (customer_id,order_id,carton_mark)' ));
PREPARE lastleg_indexes_020 FROM @ ddl ; EXECUTE lastleg_indexes_020 ; DEALLOCATE PREPARE lastleg_indexes_020 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_carton' AND index_name = 'idx_ll_dropship_carton_status' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_carton ADD KEY idx_ll_dropship_carton_status (customer_id,status)' ));
PREPARE lastleg_indexes_020 FROM @ ddl ; EXECUTE lastleg_indexes_020 ; DEALLOCATE PREPARE lastleg_indexes_020 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_carton' AND index_name = 'idx_ll_dropship_carton_sku' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_carton ADD KEY idx_ll_dropship_carton_sku (customer_id,sku_code,status)' ));
PREPARE lastleg_indexes_020 FROM @ ddl ; EXECUTE lastleg_indexes_020 ; DEALLOCATE PREPARE lastleg_indexes_020 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_carton_ledger' AND index_name = 'uk_ll_dropship_ledger_key' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_carton_ledger ADD UNIQUE KEY uk_ll_dropship_ledger_key (customer_id,idempotency_key)' ));
PREPARE lastleg_indexes_020 FROM @ ddl ; EXECUTE lastleg_indexes_020 ; DEALLOCATE PREPARE lastleg_indexes_020 ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_carton_ledger' AND index_name = 'idx_ll_dropship_ledger_sku' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_carton_ledger ADD KEY idx_ll_dropship_ledger_sku (customer_id,sku_code,carton_mark)' ));
PREPARE lastleg_indexes_020 FROM @ ddl ; EXECUTE lastleg_indexes_020 ; DEALLOCATE PREPARE lastleg_indexes_020 ;
-- ============================================================================
-- 2026-08-18 / dropship multi-pallet cardinality
-- One one-click dropship inbound order may own multiple source pallets.
-- ============================================================================
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_order_profile' AND index_name = 'uk_ll_dropship_profile_order' ), 'ALTER TABLE ll_dropship_order_profile DROP INDEX uk_ll_dropship_profile_order' , 'SELECT 1' ));
PREPARE dropship_drop_single_pallet_stmt FROM @ ddl ; EXECUTE dropship_drop_single_pallet_stmt ; DEALLOCATE PREPARE dropship_drop_single_pallet_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_order_profile' AND index_name = 'uk_ll_dropship_profile_order_pallet' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_order_profile ADD UNIQUE KEY uk_ll_dropship_profile_order_pallet(customer_id,order_id,source_pallet_no)' ));
PREPARE dropship_add_order_pallet_stmt FROM @ ddl ; EXECUTE dropship_add_order_pallet_stmt ; DEALLOCATE PREPARE dropship_add_order_pallet_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_order_profile' AND index_name = 'idx_ll_dropship_profile_order' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_order_profile ADD KEY idx_ll_dropship_profile_order(customer_id,order_id)' ));
PREPARE dropship_add_order_idx_stmt FROM @ ddl ; EXECUTE dropship_add_order_idx_stmt ; DEALLOCATE PREPARE dropship_add_order_idx_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_sku_inventory' AND index_name = 'uk_ll_dropship_sku_inventory' ), 'ALTER TABLE ll_dropship_sku_inventory DROP INDEX uk_ll_dropship_sku_inventory' , 'SELECT 1' ));
PREPARE dropship_drop_order_sku_stmt FROM @ ddl ; EXECUTE dropship_drop_order_sku_stmt ; DEALLOCATE PREPARE dropship_drop_order_sku_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_sku_inventory' AND index_name = 'uk_ll_dropship_sku_profile' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_sku_inventory ADD UNIQUE KEY uk_ll_dropship_sku_profile(profile_id,sku_code)' ));
PREPARE dropship_add_profile_sku_stmt FROM @ ddl ; EXECUTE dropship_add_profile_sku_stmt ; DEALLOCATE PREPARE dropship_add_profile_sku_stmt ;
SET @ ddl = ( SELECT IF ( EXISTS ( SELECT 1 FROM information_schema . statistics WHERE table_schema = DATABASE () AND table_name = 'll_dropship_sku_inventory' AND index_name = 'idx_ll_dropship_sku_order' ), 'SELECT 1' , 'ALTER TABLE ll_dropship_sku_inventory ADD KEY idx_ll_dropship_sku_order(customer_id,order_id,sku_code)' ));
PREPARE dropship_add_order_sku_idx_stmt FROM @ ddl ; EXECUTE dropship_add_order_sku_idx_stmt ; DEALLOCATE PREPARE dropship_add_order_sku_idx_stmt ;
2026-08-18 16:31:55 +08:00
-- ============================================================================
-- 2026-08-18 / 021 cargo discard application, carton reservation and approval.
-- ============================================================================
USE baiyue_lastleg ;
CREATE TABLE IF NOT EXISTS ll_cargo_discard_application (
id BIGINT NOT NULL COMMENT 'Snowflake ID' , customer_id VARCHAR ( 128 ) NOT NULL ,
discard_no VARCHAR ( 64 ) NOT NULL , overseas_warehouse_id VARCHAR ( 128 ) NOT NULL ,
overseas_warehouse_name VARCHAR ( 255 ) NULL , inbound_codes VARCHAR ( 2000 ) NOT NULL ,
total_packages INT NOT NULL , fee_per_package DECIMAL ( 18 , 2 ) NOT NULL ,
total_fee DECIMAL ( 18 , 2 ) NOT NULL , currency CHAR ( 3 ) NOT NULL DEFAULT 'USD' ,
status VARCHAR ( 32 ) NOT NULL DEFAULT 'PENDING_REVIEW' , remark VARCHAR ( 1000 ) NULL ,
idempotency_key VARCHAR ( 255 ) NOT NULL , request_hash CHAR ( 64 ) NOT NULL ,
created_by VARCHAR ( 128 ) NULL , reviewed_by VARCHAR ( 128 ) NULL , review_remark VARCHAR ( 1000 ) NULL ,
reviewed_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_cargo_discard_no ( customer_id , discard_no ),
UNIQUE KEY uk_ll_cargo_discard_key ( customer_id , idempotency_key ),
KEY idx_ll_cargo_discard_list ( customer_id , status , created_at ),
KEY idx_ll_cargo_discard_warehouse ( customer_id , overseas_warehouse_id , created_at )
) ENGINE = InnoDB COMMENT = 'Cargo discard application requiring warehouse approval' ;
CREATE TABLE IF NOT EXISTS ll_cargo_discard_item (
id BIGINT NOT NULL , application_id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL ,
order_id BIGINT NOT NULL , inbound_code VARCHAR ( 128 ) NOT NULL , profile_id BIGINT NOT NULL ,
sku_inventory_id BIGINT NOT NULL , sku_code VARCHAR ( 128 ) NOT NULL , product_name VARCHAR ( 255 ) NULL ,
available_packages_snapshot INT NOT NULL , discard_packages INT NOT NULL ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id ),
UNIQUE KEY uk_ll_cargo_discard_item ( application_id , profile_id , sku_code ),
KEY idx_ll_cargo_discard_item_list ( customer_id , application_id ),
KEY idx_ll_cargo_discard_item_inbound ( customer_id , inbound_code , sku_code )
) ENGINE = InnoDB COMMENT = 'Frozen SKU quantities in a cargo discard application' ;
CREATE TABLE IF NOT EXISTS ll_cargo_discard_carton (
id BIGINT NOT NULL , application_id BIGINT NOT NULL , item_id BIGINT NOT NULL ,
customer_id VARCHAR ( 128 ) NOT NULL , carton_id BIGINT NOT NULL , carton_mark VARCHAR ( 128 ) NOT NULL ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id ),
UNIQUE KEY uk_ll_cargo_discard_carton ( application_id , carton_id ),
KEY idx_ll_cargo_discard_carton_application ( customer_id , application_id , item_id ),
KEY idx_ll_cargo_discard_carton_identity ( customer_id , carton_id )
) ENGINE = InnoDB COMMENT = 'Cartons reserved while a cargo discard application awaits review' ;
CREATE TABLE IF NOT EXISTS ll_cargo_discard_status_history (
id BIGINT NOT NULL , application_id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL ,
from_status VARCHAR ( 32 ) NULL , to_status VARCHAR ( 32 ) NOT NULL , operator_id VARCHAR ( 128 ) NULL ,
remark VARCHAR ( 1000 ) NULL , created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id ),
KEY idx_ll_cargo_discard_history ( customer_id , application_id , created_at )
) ENGINE = InnoDB COMMENT = 'Immutable cargo discard approval history' ;
-- ============================================================================
-- 2026-08-18 / 022 overseas procurement approval, inventory and outbound flow.
-- ============================================================================
USE baiyue_lastleg ;
CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order (
id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL , customer_name VARCHAR ( 255 ) NULL ,
order_no VARCHAR ( 64 ) NOT NULL , purchase_category VARCHAR ( 128 ) NOT NULL , product_name VARCHAR ( 255 ) NOT NULL ,
product_specification VARCHAR ( 500 ) NULL , product_url VARCHAR ( 2000 ) NULL , purchase_quantity BIGINT NOT NULL ,
budget_unit_price DECIMAL ( 18 , 2 ) NULL , currency CHAR ( 3 ) NOT NULL DEFAULT 'USD' , receiving_address VARCHAR ( 1000 ) NULL ,
contact_name VARCHAR ( 128 ) NOT NULL , contact_phone VARCHAR ( 64 ) NOT NULL , purchase_warehouse_id VARCHAR ( 128 ) NULL ,
purchase_warehouse_name VARCHAR ( 255 ) NULL , inbound_quantity BIGINT NOT NULL DEFAULT 0 , outbound_quantity BIGINT NOT NULL DEFAULT 0 ,
domestic_carrier VARCHAR ( 128 ) NULL , domestic_tracking_no VARCHAR ( 128 ) NULL , overseas_carrier VARCHAR ( 128 ) NULL ,
overseas_tracking_no VARCHAR ( 128 ) NULL , estimated_arrival_at DATETIME ( 3 ) NULL , status VARCHAR ( 32 ) NOT NULL DEFAULT 'PENDING_REVIEW' ,
remark VARCHAR ( 1000 ) NULL , idempotency_key VARCHAR ( 255 ) NOT NULL , request_hash CHAR ( 64 ) NOT NULL ,
created_by VARCHAR ( 128 ) NULL , reviewed_by VARCHAR ( 128 ) NULL , review_remark VARCHAR ( 1000 ) NULL , reviewed_at DATETIME ( 3 ) NULL ,
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_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 = 'Overseas procurement order awaiting business approval' ;
CREATE TABLE IF NOT EXISTS ll_overseas_procurement_outbound (
id BIGINT NOT NULL , order_id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL , quantity BIGINT NOT NULL ,
outbound_no VARCHAR ( 128 ) NOT NULL , carrier VARCHAR ( 128 ) NULL , tracking_no VARCHAR ( 128 ) NULL , outbound_at DATETIME ( 3 ) NOT NULL ,
remark VARCHAR ( 1000 ) NULL , created_by VARCHAR ( 128 ) NULL , created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id ),
UNIQUE KEY uk_ll_overseas_procurement_outbound_no ( customer_id , order_id , outbound_no ), KEY idx_ll_overseas_procurement_outbound_order ( customer_id , order_id , outbound_at )
) ENGINE = InnoDB COMMENT = 'Manual outbound records for overseas procurement inventory' ;
CREATE TABLE IF NOT EXISTS ll_overseas_procurement_status_history (
id BIGINT NOT NULL , order_id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL ,
from_status VARCHAR ( 32 ) NULL , to_status VARCHAR ( 32 ) NOT NULL , operator_id VARCHAR ( 128 ) NULL , remark VARCHAR ( 1000 ) NULL ,
created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), PRIMARY KEY ( id ), KEY idx_ll_overseas_procurement_history ( customer_id , order_id , created_at )
) ENGINE = InnoDB COMMENT = 'Immutable overseas procurement review history' ;
-- 2026-08-18 / 023 US domestic trucking customer and platform workflow.
USE baiyue_lastleg ;
CREATE TABLE IF NOT EXISTS ll_us_truck_order (
id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL , order_no VARCHAR ( 64 ) NOT NULL ,
transport_type VARCHAR ( 32 ) NOT NULL , origin VARCHAR ( 255 ) NOT NULL , origin_address VARCHAR ( 500 ) NULL ,
destination VARCHAR ( 255 ) NOT NULL , destination_address VARCHAR ( 500 ) NULL , container_type VARCHAR ( 32 ) NOT NULL ,
package_count INT NOT NULL DEFAULT 0 , total_weight_kg DECIMAL ( 18 , 3 ) NOT NULL DEFAULT 0 ,
total_volume_cbm DECIMAL ( 18 , 6 ) NOT NULL DEFAULT 0 , budget_amount DECIMAL ( 18 , 2 ) NULL ,
currency VARCHAR ( 3 ) NOT NULL DEFAULT 'USD' , contact_name VARCHAR ( 128 ) NOT NULL ,
contact_info VARCHAR ( 128 ) NOT NULL , requested_date DATE NOT NULL , status VARCHAR ( 32 ) NOT NULL ,
remark VARCHAR ( 1000 ) NULL , idempotency_key VARCHAR ( 255 ) NOT NULL , request_hash CHAR ( 64 ) NOT NULL ,
created_by VARCHAR ( 128 ) NULL , 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 ),
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 ),
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 = 'US domestic trucking customer order' ;
CREATE TABLE IF NOT EXISTS ll_us_truck_order_status_history (
id BIGINT NOT NULL , order_id BIGINT NOT NULL , customer_id VARCHAR ( 128 ) NOT NULL ,
from_status VARCHAR ( 32 ) NULL , to_status VARCHAR ( 32 ) NOT NULL , operator_id VARCHAR ( 128 ) NULL ,
remark VARCHAR ( 1000 ) NULL , created_at DATETIME ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ),
PRIMARY KEY ( id ), KEY idx_ll_us_truck_history ( customer_id , order_id , created_at )
) ENGINE = InnoDB COMMENT = 'Immutable US trucking order status history' ;