-- 海外区域唯一数据库初始化入口;空库和存量测试库均只执行本文件。 -- 本文件内联 Lastleg 与海外仓空库基线,再执行统一增量和最终结构校验。 -- 本文件只由人工审核执行,服务部署默认不自动执行 SQL。 -- 空库先执行 lastleg-service/src/main/resources/db/lastleg.sql 基线;本入口同时内联该基线用于固定部署。 SET NAMES utf8mb4; -- 海外 Event Bridge 空库基线必须先于业务服务表初始化。 CREATE DATABASE IF NOT EXISTS baiyue_event_bridge_overseas DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE baiyue_event_bridge_overseas; CREATE TABLE IF NOT EXISTS bridge_outbox ( event_id VARCHAR(128) NOT NULL COMMENT '事件全局标识', idempotency_key VARCHAR(191) NOT NULL COMMENT '发送幂等键', event_type VARCHAR(64) NOT NULL COMMENT '事件类型', event_version INT NOT NULL COMMENT '事件契约版本', source_region VARCHAR(32) NOT NULL COMMENT '来源区域', target_region VARCHAR(32) NOT NULL COMMENT '目标区域', customer_id VARCHAR(128) NOT NULL COMMENT '客户标识', aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型', aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合标识', aggregate_version BIGINT NOT NULL COMMENT '聚合版本', handover_version BIGINT NULL COMMENT '跨区交接版本', trace_id VARCHAR(128) NOT NULL COMMENT '链路标识', correlation_id VARCHAR(128) NOT NULL COMMENT '业务关联标识', causation_id VARCHAR(128) NULL COMMENT '上游事件标识', occurred_at DATETIME(3) NOT NULL COMMENT '业务事实发生时间', payload_hash VARCHAR(71) NOT NULL COMMENT '规范化负载摘要', payload_json JSON NOT NULL COMMENT '事件负载', status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '投递状态', retry_count INT NOT NULL DEFAULT 0 COMMENT '已重试次数', next_retry_at DATETIME(3) NULL COMMENT '下次重试时间', lease_owner VARCHAR(128) NULL COMMENT '租约持有者', lease_until DATETIME(3) NULL COMMENT '租约截止时间', last_error VARCHAR(1000) NULL COMMENT '最后错误', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', delivered_at DATETIME(3) NULL COMMENT '投递成功时间', PRIMARY KEY (event_id), UNIQUE KEY uk_bridge_outbox_idempotency (idempotency_key), KEY idx_bridge_outbox_schedule (target_region,status,next_retry_at,lease_until) ) ENGINE=InnoDB COMMENT='海外跨区域事件待投递箱'; CREATE TABLE IF NOT EXISTS bridge_inbox ( event_id VARCHAR(128) NOT NULL COMMENT '事件全局标识', idempotency_key VARCHAR(191) NOT NULL COMMENT '接收幂等键', event_type VARCHAR(64) NOT NULL COMMENT '事件类型', event_version INT NOT NULL COMMENT '事件契约版本', source_region VARCHAR(32) NOT NULL COMMENT '来源区域', target_region VARCHAR(32) NOT NULL COMMENT '目标区域', customer_id VARCHAR(128) NOT NULL COMMENT '客户标识', aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型', aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合标识', aggregate_version BIGINT NOT NULL COMMENT '聚合版本', handover_version BIGINT NULL COMMENT '跨区交接版本', trace_id VARCHAR(128) NOT NULL COMMENT '链路标识', correlation_id VARCHAR(128) NOT NULL COMMENT '业务关联标识', causation_id VARCHAR(128) NULL COMMENT '上游事件标识', occurred_at DATETIME(3) NOT NULL COMMENT '业务事实发生时间', payload_hash VARCHAR(71) NOT NULL COMMENT '规范化负载摘要', payload_json JSON NOT NULL COMMENT '事件负载', status VARCHAR(32) NOT NULL DEFAULT 'RECEIVED' COMMENT '消费状态', lease_owner VARCHAR(128) NULL COMMENT '消费租约持有者', lease_until DATETIME(3) NULL COMMENT '消费租约截止时间', retry_count INT NOT NULL DEFAULT 0 COMMENT '消费重试次数', next_retry_at DATETIME(3) NULL COMMENT '下次消费时间', last_error VARCHAR(1000) NULL COMMENT '最后错误', received_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '接收时间', processed_at DATETIME(3) NULL COMMENT '消费完成时间', PRIMARY KEY (event_id), UNIQUE KEY uk_bridge_inbox_idempotency (idempotency_key), KEY idx_bridge_inbox_consume (status,next_retry_at,lease_until) ) ENGINE=InnoDB COMMENT='海外跨区域事件已接收箱'; CREATE TABLE IF NOT EXISTS bridge_delivery_attempt ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键', event_id VARCHAR(128) NOT NULL COMMENT '事件全局标识', source_region VARCHAR(32) NOT NULL COMMENT '来源区域', target_region VARCHAR(32) NOT NULL COMMENT '目标区域', attempt_no INT NOT NULL COMMENT '投递序号', status VARCHAR(32) NOT NULL COMMENT '投递结果', response_code VARCHAR(64) NULL COMMENT '对端响应码', error_message VARCHAR(1000) NULL COMMENT '错误信息', started_at DATETIME(3) NOT NULL COMMENT '开始时间', finished_at DATETIME(3) NULL COMMENT '完成时间', PRIMARY KEY (id), UNIQUE KEY uk_bridge_attempt (event_id,attempt_no), KEY idx_bridge_attempt_event (event_id,started_at) ) ENGINE=InnoDB COMMENT='海外跨区域事件投递尝试记录'; DROP PROCEDURE IF EXISTS assert_overseas_event_bridge_schema; -- BEGIN INLINE EMPTY-DATABASE BASELINE: LASTLEG SET NAMES utf8mb4; 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 '事件全局唯一标识', customer_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 (customer_id,event_type,event_id) ) ENGINE=InnoDB COMMENT='头程装柜完成事件接收幂等箱'; CREATE TABLE IF NOT EXISTS ll_container_shipping_gate ( container_booking_id VARCHAR(128) NOT NULL COMMENT '来源头程柜预订ID', ocean_booking_id VARCHAR(128) NULL COMMENT '来源海运订舱ID;货柜未关联订舱时为空', container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号', status VARCHAR(32) NOT NULL DEFAULT 'AWAITING_PICKUP_READY' COMMENT '海外收货门禁状态:AWAITING_PICKUP_READY、RECEIVING_AVAILABLE', standard_node VARCHAR(64) NULL COMMENT '最新有效标准船节点', node_sequence INT NOT NULL DEFAULT 0 COMMENT '最新有效节点单调序号', observed_at DATETIME(3) NULL COMMENT '供应商节点观测时间', actual_at DATETIME(3) NULL COMMENT '节点实际发生时间', location_code VARCHAR(128) NULL COMMENT '节点地点编码', location_name VARCHAR(255) NULL COMMENT '节点地点名称', provider_code VARCHAR(64) NULL COMMENT '船节点供应商编码', provider_event_id VARCHAR(128) NULL COMMENT '供应商事件ID', provider_node_code VARCHAR(128) NULL COMMENT '供应商原始节点编码', source_reference VARCHAR(255) NULL COMMENT '供应商来源引用', raw_payload_hash VARCHAR(64) NULL COMMENT '供应商原始负载SHA-256', aggregate_version BIGINT NOT NULL DEFAULT 0 COMMENT '来源查询聚合版本', handover_version BIGINT NOT NULL DEFAULT 1 COMMENT '跨区交接版本', last_event_id VARCHAR(128) NULL COMMENT '最近采纳的跨区事件ID', payload_hash VARCHAR(71) NULL COMMENT '最近采纳事件规范化负载摘要', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(container_booking_id), KEY idx_ll_shipping_gate_candidate(container_no,status), KEY idx_ll_shipping_gate_version(container_booking_id,aggregate_version,node_sequence) ) ENGINE=InnoDB COMMENT='海外PDA柜号船节点收货资格快照'; CREATE TABLE IF NOT EXISTS ll_order_no_daily_sequence ( business_date DATE NOT NULL COMMENT '业务日期(Asia/Shanghai)', last_sequence INT NOT NULL COMMENT '当日已分配尾程单流水号', PRIMARY KEY(business_date) ) ENGINE=InnoDB COMMENT='尾程单号按日原子流水'; CREATE TABLE IF NOT EXISTS ll_order ( id BIGINT NOT NULL COMMENT '雪花 ID', order_no VARCHAR(32) NOT NULL COMMENT '尾程单号', customer_id VARCHAR(128) NOT NULL COMMENT '租户/客户账号标识', order_type VARCHAR(32) NOT NULL DEFAULT 'FIRST_LEG' COMMENT '订单类型:FIRST_LEG头程订单、RELABEL_APPLICATION换标下单、WAREHOUSE_TRANSFER仓储转运、LOCAL_LOOSEBOARD本土散板、RETURN_RELABEL退货换标、ONE_CLICK_DROPSHIP一件代发', lx_code VARCHAR(128) NULL COMMENT '一件代发领星入库单代码', destination_type VARCHAR(32) NULL COMMENT '目的类型:FBA按箱数接收、OVERSEAS逐箱扫码', inbound_code VARCHAR(128) NULL COMMENT '真实来源入仓码;无入仓关系的海外本土业务为空', source_region VARCHAR(32) NOT NULL COMMENT '来源区域/系统', source_inbound_id VARCHAR(128) NOT NULL COMMENT '最终实装 LOADED 分片 ID,建单幂等键', root_inbound_id VARCHAR(128) COMMENT '根入仓单 ID', source_order_id VARCHAR(128) COMMENT '来源订单 ID', source_order_no VARCHAR(128) COMMENT '来源订单号', root_order_id VARCHAR(128) COMMENT '根订单 ID', customer_name VARCHAR(255) COMMENT '货主名称', source_warehouse_id VARCHAR(128) COMMENT '来源国内装柜仓 ID 快照', source_warehouse_name VARCHAR(255) COMMENT '来源国内装柜仓名称快照', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外接柜仓ID;新建尾程订单由业务服务预分配', overseas_warehouse_code VARCHAR(128) NULL COMMENT '海外接柜仓业务编码快照', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外接柜仓名称快照', receiving_warehouse_version INT NOT NULL DEFAULT 0 COMMENT '柜级接柜仓分配乐观锁版本', transfer_warehouse_id VARCHAR(128) COMMENT '转入目的仓 ID', transfer_warehouse_code VARCHAR(128) COMMENT '转入目的仓编码', transfer_warehouse_name VARCHAR(255) COMMENT '转入目的仓名称', fba_warehouse_code VARCHAR(128) COMMENT 'FBA 仓库编码', container_no VARCHAR(64) COMMENT '集装箱号', abnormal TINYINT NOT NULL DEFAULT 0 COMMENT '是否异常:0否1是', detained TINYINT NOT NULL DEFAULT 0 COMMENT '是否暂扣:0否1是', hold_chargeable TINYINT NOT NULL DEFAULT 0 COMMENT '当前暂扣是否计费:0否1是', hold_reason VARCHAR(500) NULL COMMENT '当前暂扣原因;解除后为空', manual_node_override TINYINT NOT NULL DEFAULT 0 COMMENT '是否启用单票人工计划节点覆盖:0否1是,启用后不再继承柜级节点', version INT NOT NULL DEFAULT 0 COMMENT '尾程订单命令乐观锁版本', pallet_count INT NOT NULL DEFAULT 0 COMMENT '托数', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', picked_package_count INT NOT NULL DEFAULT 0 COMMENT '累计已拣箱数', shipped_package_count INT NOT NULL DEFAULT 0 COMMENT '累计已出库箱数', volume_cbm DECIMAL(18,4) COMMENT '体积(立方米)', product_quantity INT COMMENT '货物数量', volume_weight_kg DECIMAL(18,4) COMMENT '体积重量(千克)', estimated_arrival_at DATETIME(3) COMMENT '预计到港时间', actual_arrival_at DATETIME(3) COMMENT '实际到港时间', estimated_warehouse_at DATETIME(3) COMMENT '预计到仓时间', inbound_order_no VARCHAR(128) COMMENT '入库单号', outbound_order_no VARCHAR(128) COMMENT '出库单号', delivery_order_no VARCHAR(128) COMMENT '派送单号', relabel_order_no VARCHAR(128) COMMENT '换标单号', relabel_status VARCHAR(32) COMMENT '换标状态', pallet_merge_flag VARCHAR(32) COMMENT '合托标记', pallet_merge_batch_id VARCHAR(64) NULL COMMENT '平台预标记合托分组号', current_status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ASSIGNMENT' COMMENT '当前业务状态:PENDING_ASSIGNMENT待分配、PENDING_INBOUND待入库、INBOUND_COMPLETED入库完成、PENDING_DELIVERY待派送、DELIVERING派送中、DELIVERED派送完成', sub_order_status VARCHAR(255) NULL COMMENT '子单据状态汇总', private_remark VARCHAR(1000) COMMENT '备注(仅自己)', customer_remark VARCHAR(1000) COMMENT '备注(客户)', warehouse_remark VARCHAR(1000) COMMENT '备注(仓库)', source_event_id VARCHAR(128) NOT NULL COMMENT '来源事件 ID', source_loading_plan_id VARCHAR(128) NOT NULL COMMENT '来源装柜计划 ID', source_container_booking_id VARCHAR(128) NULL COMMENT '来源头程货柜预订ID', source_loading_plan_version BIGINT COMMENT '来源装柜计划版本', source_handover_version BIGINT 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 (customer_id,source_region,source_inbound_id), KEY idx_ll_order_group(customer_id,order_no), KEY idx_ll_order_container(customer_id,container_no), KEY idx_ll_order_list(customer_id,current_status,created_at), KEY idx_ll_order_container_progress(source_container_booking_id,estimated_warehouse_at,created_at,id) ) ENGINE=InnoDB COMMENT='尾程订单主表'; CREATE TABLE IF NOT EXISTS ll_order_source_pallet ( id BIGINT NOT NULL COMMENT '来源托盘快照ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', source_pallet_no VARCHAR(128) NOT NULL COMMENT '头程冻结托盘码', sequence_no INT NOT NULL COMMENT '订单内稳定顺序', source_event_id VARCHAR(128) NOT NULL COMMENT '来源装柜完成事件ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_source_pallet_no(source_pallet_no), UNIQUE KEY uk_ll_source_pallet_sequence(customer_id,order_id,sequence_no), KEY idx_ll_source_pallet_order(customer_id,order_id), CONSTRAINT fk_ll_source_pallet_order FOREIGN KEY(order_id) REFERENCES ll_order(id) ) ENGINE=InnoDB COMMENT='头程交接的不可变托盘码快照'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='pallet_merge_batch_id'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN pallet_merge_batch_id VARCHAR(64) NULL COMMENT ''平台预标记合托分组号'' AFTER pallet_merge_flag')); PREPARE ll_order_merge_batch_ddl FROM @ddl; EXECUTE ll_order_merge_batch_ddl; DEALLOCATE PREPARE ll_order_merge_batch_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='hold_chargeable'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN hold_chargeable TINYINT NOT NULL DEFAULT 0 COMMENT ''当前暂扣是否计费:0否1是'' AFTER detained')); PREPARE ll_order_command_ddl FROM @ddl; EXECUTE ll_order_command_ddl; DEALLOCATE PREPARE ll_order_command_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='hold_reason'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN hold_reason VARCHAR(500) NULL COMMENT ''当前暂扣原因;解除后为空'' AFTER hold_chargeable')); PREPARE ll_order_command_ddl FROM @ddl; EXECUTE ll_order_command_ddl; DEALLOCATE PREPARE ll_order_command_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='manual_node_override'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN manual_node_override TINYINT NOT NULL DEFAULT 0 COMMENT ''是否启用单票人工计划节点覆盖:0否1是'' AFTER hold_reason')); PREPARE ll_order_command_ddl FROM @ddl; EXECUTE ll_order_command_ddl; DEALLOCATE PREPARE ll_order_command_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='version'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN version INT NOT NULL DEFAULT 0 COMMENT ''尾程订单命令乐观锁版本'' AFTER manual_node_override')); PREPARE ll_order_command_ddl FROM @ddl; EXECUTE ll_order_command_ddl; DEALLOCATE PREPARE ll_order_command_ddl; CREATE TABLE IF NOT EXISTS ll_order_detail ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT '订单明细主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单 ID', source_inbound_detail_id VARCHAR(128) NOT NULL COMMENT '来源入仓明细 ID', sku_code VARCHAR(128) COMMENT 'SKU 编码', product_name_zh VARCHAR(255) COMMENT '中文品名', product_name_en VARCHAR(255) COMMENT '英文品名', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', product_quantity INT COMMENT '数量', pallet_count INT COMMENT '托数', gross_weight_kg DECIMAL(18,4) COMMENT '毛重(千克)', net_weight_kg DECIMAL(18,4) COMMENT '净重(千克)', dimensional_weight_kg DECIMAL(18,4) COMMENT '体积重量(千克)', volume_cbm DECIMAL(18,4) COMMENT '体积(立方米)', destination_warehouse_id VARCHAR(128) COMMENT '目的仓 ID', destination_warehouse_code VARCHAR(128) COMMENT '目的仓编码', destination_warehouse_name VARCHAR(255) COMMENT '目的仓名称', fba_tracking_no VARCHAR(255) COMMENT 'FBA跟踪号', shipment_no VARCHAR(255) COMMENT '货件编号', shipping_mark VARCHAR(255) COMMENT '唛头', PRIMARY KEY(id), UNIQUE KEY uk_ll_detail_source(order_id,source_inbound_detail_id), KEY idx_ll_detail_order(order_id), KEY idx_ll_detail_customer_order(customer_id,order_id,id) ) ENGINE=InnoDB COMMENT='尾程订单实装商品冻结明细'; CREATE TABLE IF NOT EXISTS ll_loading_order_status_history ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT '状态历史主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单 ID', from_status VARCHAR(32) COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', event_id VARCHAR(128) COMMENT '触发事件 ID', remark VARCHAR(500) COMMENT '状态变更备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '记录时间', PRIMARY KEY(id), KEY idx_ll_loading_history_customer_order(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单状态变更历史'; CREATE TABLE IF NOT EXISTS ll_order_operation_log ( id BIGINT NOT NULL COMMENT '操作记录主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', operation_node VARCHAR(64) NOT NULL COMMENT '操作节点', operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', result VARCHAR(500) NOT NULL COMMENT '处理结果', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间', PRIMARY KEY(id), KEY idx_ll_order_operation_customer_order(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单操作记录'; CREATE TABLE IF NOT EXISTS ll_order_command_record ( id BIGINT NOT NULL COMMENT '尾程订单命令幂等记录ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', action VARCHAR(32) NOT NULL COMMENT '命令动作:MANUAL_PLAN、HOLD、MANUAL_NODES', operator_id VARCHAR(128) NOT NULL COMMENT '平台操作人ID', idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', request_hash VARCHAR(64) NOT NULL COMMENT '规范化请求SHA-256摘要', result_ref VARCHAR(128) NULL COMMENT '结果业务引用', result_json LONGTEXT NOT NULL COMMENT '首次成功响应JSON快照', result_version INT NOT NULL COMMENT '命令成功后的订单版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '首次成功时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_command_key(customer_id,order_id,action,operator_id,idempotency_key), KEY idx_ll_order_command_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单写命令幂等与结果审计记录'; CREATE TABLE IF NOT EXISTS ll_order_hold_history ( id BIGINT NOT NULL COMMENT '尾程订单暂扣历史ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', held TINYINT NOT NULL COMMENT '操作后是否暂扣:0否1是', chargeable TINYINT NOT NULL COMMENT '本次暂扣是否计费:0否1是', reason VARCHAR(500) NOT NULL COMMENT '暂扣或解除原因', order_version INT NOT NULL COMMENT '操作成功后的订单版本', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID', operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', created_at DATETIME(3) NOT NULL COMMENT '操作时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_hold_key(customer_id,order_id,operator_id,idempotency_key), KEY idx_ll_order_hold_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单暂扣与解除不可变历史'; CREATE TABLE IF NOT EXISTS ll_order_manual_node ( id BIGINT NOT NULL COMMENT '尾程订单人工节点ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', node_code VARCHAR(32) NOT NULL COMMENT '八行人工展示节点稳定代码,与Carrier标准节点隔离', node_at DATETIME(3) NULL COMMENT '人工填写节点时间,允许为空', source VARCHAR(16) NOT NULL DEFAULT 'MANUAL' COMMENT '节点来源,固定MANUAL', order_version INT NOT NULL COMMENT '最近编辑后的订单版本', updated_by VARCHAR(128) NOT NULL COMMENT '最近操作人ID', updated_at DATETIME(3) NOT NULL COMMENT '最近编辑时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_manual_node(customer_id,order_id,node_code), KEY idx_ll_order_manual_node_order(customer_id,order_id,node_at) ) ENGINE=InnoDB COMMENT='尾程订单当前人工节点覆盖事实'; CREATE TABLE IF NOT EXISTS ll_order_manual_node_history ( id BIGINT NOT NULL COMMENT '尾程订单人工节点历史ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', nodes_json LONGTEXT NOT NULL COMMENT '本次全量人工节点JSON快照', order_version INT NOT NULL COMMENT '操作成功后的订单版本', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID', operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', created_at DATETIME(3) NOT NULL COMMENT '操作时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_manual_node_history_key(customer_id,order_id,operator_id,idempotency_key), KEY idx_ll_order_manual_node_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单人工节点覆盖不可变历史'; CREATE TABLE IF NOT EXISTS ll_receiving_warehouse_operation ( id BIGINT NOT NULL COMMENT '柜级接柜仓修改操作ID', source_container_booking_id VARCHAR(128) NOT NULL COMMENT '稳定来源柜预订ID', idempotency_key VARCHAR(255) NOT NULL COMMENT '平台请求幂等键', request_hash VARCHAR(64) NOT NULL COMMENT '规范化修改请求SHA-256摘要', result_version INT NOT NULL COMMENT '修改成功后的柜级分配版本', operator_name VARCHAR(128) NOT NULL COMMENT '平台操作人名称', remark VARCHAR(500) NULL COMMENT '接柜仓修改备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_warehouse_idempotency(idempotency_key), KEY idx_ll_receiving_warehouse_container(source_container_booking_id,created_at) ) ENGINE=InnoDB COMMENT='柜级海外接柜仓修改幂等审计记录'; -- 派送单列表与详情快照、转派送费用及操作记录。 CREATE TABLE IF NOT EXISTS ll_delivery_order ( id BIGINT NOT NULL COMMENT '派送单主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', delivery_no VARCHAR(64) NOT NULL COMMENT '派送单号', outbound_order_id BIGINT NOT NULL COMMENT '关联出库单ID', outbound_no VARCHAR(64) NOT NULL COMMENT '关联出库单号', dispatch_order_id BIGINT NOT NULL COMMENT '关联派车单ID', dispatch_no VARCHAR(64) NOT NULL COMMENT '关联派车单号', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', customer_name VARCHAR(255) NULL COMMENT '客户名称快照', status VARCHAR(32) NOT NULL DEFAULT 'WAIT_DELIVERY' COMMENT '派送状态:WAIT_DELIVERY待派送及后续正式状态', waybill_no VARCHAR(128) NULL COMMENT '承运运单号', bol_no VARCHAR(128) NULL COMMENT '派送资料BOL号,不作为文件归属标识', documents_json JSON NULL COMMENT '派送三类资料当前绑定及权威文件元数据快照', delivery_method VARCHAR(32) NULL COMMENT '派送方式', carrier_name VARCHAR(255) NULL COMMENT '派送承运商', pickup_method VARCHAR(64) NULL COMMENT '提货方式', loading_type VARCHAR(64) NULL COMMENT '装车类型', vehicle_type VARCHAR(64) NULL COMMENT '车辆类型', vehicle_size VARCHAR(64) NULL COMMENT '车辆大小', vehicle_plate VARCHAR(64) NULL COMMENT '车牌号', driver_name VARCHAR(128) NULL COMMENT '司机或车队名称', driver_phone VARCHAR(64) NULL COMMENT '车队联系电话', appointment_account VARCHAR(128) NULL COMMENT '预约账号', seller_name VARCHAR(128) NULL COMMENT '卖家姓名', package_count INT NOT NULL DEFAULT 0 COMMENT '派送箱数', pallet_count INT NOT NULL DEFAULT 0 COMMENT '派送托盘数', total_weight_kg DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '总重量(千克)', total_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '总体积(立方米)', planned_delivery_at DATETIME(3) NULL COMMENT '预计派送时间', dispatched_at DATETIME(3) NULL COMMENT '实际派送时间', expected_arrival_at DATETIME(3) NULL COMMENT '预计到达时间', signed_at DATETIME(3) NULL COMMENT '签收时间', remark VARCHAR(1000) NULL COMMENT '派送备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', created_by VARCHAR(128) NULL COMMENT '创建人ID', version BIGINT NOT NULL DEFAULT 0 COMMENT '派送单乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_delivery_no (customer_id,delivery_no), UNIQUE KEY uk_ll_delivery_idempotency (customer_id,idempotency_key), UNIQUE KEY uk_ll_delivery_outbound (customer_id,outbound_order_id), KEY idx_ll_delivery_list (customer_id,status,created_at) ) ENGINE=InnoDB COMMENT='尾程派送单'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='overseas_warehouse_name'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN overseas_warehouse_name VARCHAR(255) NULL COMMENT ''海外仓名称快照'' AFTER overseas_warehouse_id')); PREPARE delivery_detail_stmt FROM @ddl; EXECUTE delivery_detail_stmt; DEALLOCATE PREPARE delivery_detail_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='customer_name'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN customer_name VARCHAR(255) NULL COMMENT ''客户名称快照'' AFTER overseas_warehouse_name')); PREPARE delivery_detail_stmt FROM @ddl; EXECUTE delivery_detail_stmt; DEALLOCATE PREPARE delivery_detail_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='waybill_no'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN waybill_no VARCHAR(128) NULL COMMENT ''承运运单号'', ADD COLUMN delivery_method VARCHAR(32) NULL COMMENT ''派送方式'', ADD COLUMN carrier_name VARCHAR(255) NULL COMMENT ''派送承运商'', ADD COLUMN pickup_method VARCHAR(64) NULL COMMENT ''提货方式'', ADD COLUMN loading_type VARCHAR(64) NULL COMMENT ''装车类型'', ADD COLUMN vehicle_type VARCHAR(64) NULL COMMENT ''车辆类型'', ADD COLUMN vehicle_size VARCHAR(64) NULL COMMENT ''车辆大小'', ADD COLUMN vehicle_plate VARCHAR(64) NULL COMMENT ''车牌号'', ADD COLUMN driver_name VARCHAR(128) NULL COMMENT ''司机或车队名称'', ADD COLUMN driver_phone VARCHAR(64) NULL COMMENT ''车队联系电话'', ADD COLUMN appointment_account VARCHAR(128) NULL COMMENT ''预约账号'', ADD COLUMN seller_name VARCHAR(128) NULL COMMENT ''卖家姓名'' AFTER status')); PREPARE delivery_detail_stmt FROM @ddl; EXECUTE delivery_detail_stmt; DEALLOCATE PREPARE delivery_detail_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='total_weight_kg'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN total_weight_kg DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''总重量(千克)'', ADD COLUMN total_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''总体积(立方米)'', ADD COLUMN planned_delivery_at DATETIME(3) NULL COMMENT ''预计派送时间'', ADD COLUMN dispatched_at DATETIME(3) NULL COMMENT ''实际派送时间'', ADD COLUMN expected_arrival_at DATETIME(3) NULL COMMENT ''预计到达时间'', ADD COLUMN signed_at DATETIME(3) NULL COMMENT ''签收时间'', ADD COLUMN remark VARCHAR(1000) NULL COMMENT ''派送备注'' AFTER pallet_count')); PREPARE delivery_detail_stmt FROM @ddl; EXECUTE delivery_detail_stmt; DEALLOCATE PREPARE delivery_detail_stmt; CREATE TABLE IF NOT EXISTS ll_delivery_document_revision ( id BIGINT NOT NULL COMMENT '派送资料历史ID', customer_id VARCHAR(128) NOT NULL COMMENT '派送所属客户隔离键', delivery_order_id BIGINT NOT NULL COMMENT '派送单ID', version BIGINT NOT NULL COMMENT '保存成功时派送单版本', idempotency_key VARCHAR(128) NOT NULL COMMENT '资料保存幂等键', request_hash VARCHAR(64) NOT NULL COMMENT '完整保存请求哈希', snapshot_json JSON NOT NULL COMMENT '不可变三类资料及BOL号结果快照', operator_id VARCHAR(128) NOT NULL COMMENT '保存操作人ID', created_at DATETIME(3) NOT NULL COMMENT '资料保存时间', PRIMARY KEY(id), UNIQUE KEY uk_delivery_document_command(customer_id,delivery_order_id,idempotency_key), UNIQUE KEY uk_delivery_document_version(customer_id,delivery_order_id,version) ) ENGINE=InnoDB COMMENT='派送资料版本历史与幂等保存记录'; CREATE TABLE IF NOT EXISTS ll_delivery_operation ( id BIGINT NOT NULL COMMENT '派送操作主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', delivery_order_id BIGINT NOT NULL COMMENT '派送单ID', operation_node VARCHAR(64) NOT NULL COMMENT '操作节点', operator_id VARCHAR(128) NULL COMMENT '操作人ID', operator_name VARCHAR(128) NULL COMMENT '操作人名称', result VARCHAR(500) NOT NULL COMMENT '处理结果', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间', PRIMARY KEY(id), KEY idx_ll_delivery_operation_order(customer_id,delivery_order_id,created_at,id) ) ENGINE=InnoDB COMMENT='派送单操作记录'; CREATE TABLE IF NOT EXISTS ll_event_conflict ( id BIGINT NOT NULL COMMENT '冲突记录主键', event_id VARCHAR(128) NOT NULL COMMENT '冲突事件 ID', customer_id BIGINT NOT NULL COMMENT '租户 ID', conflict_type VARCHAR(64) NOT NULL COMMENT '冲突类型', conflict_message VARCHAR(512) NOT NULL COMMENT '冲突说明', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_conflict_event(event_id,customer_id) ) ENGINE=InnoDB COMMENT='事件冲突记录'; CREATE TABLE IF NOT EXISTS ll_event_inbox ( id BIGINT NOT NULL COMMENT '事件接收记录主键', event_id VARCHAR(128) NOT NULL COMMENT '事件全局唯一 ID', customer_id BIGINT NOT NULL COMMENT '租户 ID', event_type VARCHAR(128) NOT NULL COMMENT '事件类型', aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型', aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合 ID', aggregate_version BIGINT NOT NULL COMMENT '聚合版本', payload_hash VARCHAR(71) NOT NULL COMMENT '负载摘要', status VARCHAR(32) NOT NULL COMMENT '消费状态', error_message VARCHAR(512) NULL COMMENT '错误信息', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_inbox_event(event_id), KEY idx_ll_inbox_source(customer_id,aggregate_id) ) ENGINE=InnoDB COMMENT='通用事件接收幂等箱'; CREATE TABLE IF NOT EXISTS ll_inbound_order ( id BIGINT NOT NULL COMMENT '入仓单主键', customer_id BIGINT NOT NULL COMMENT '客户账号标识', source_region VARCHAR(32) NOT NULL COMMENT '来源区域', source_inbound_id VARCHAR(128) NOT NULL COMMENT '来源入仓分片 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', inbound_code VARCHAR(128) NULL COMMENT '入仓码', lx_code VARCHAR(128) NULL COMMENT '一件代发领星入库单代码', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓 ID', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称', destination_type VARCHAR(32) NULL COMMENT '目的类型:FBA按箱数接收、OVERSEAS逐箱扫码', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', product_quantity INT NULL COMMENT '数量', pallet_count INT NULL COMMENT '托数', gross_weight_kg DECIMAL(18,3) NULL COMMENT '毛重(千克)', net_weight_kg DECIMAL(18,3) NULL COMMENT '净重(千克)', volume_cbm DECIMAL(18,6) 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 NOT NULL COMMENT '装柜计划版本', handover_version BIGINT NOT NULL COMMENT '交接版本', payload_hash VARCHAR(71) NOT NULL COMMENT '负载摘要', status VARCHAR(32) NOT NULL COMMENT '入仓单状态', exception_flag VARCHAR(32) NOT NULL DEFAULT 'NONE' COMMENT '异常标记', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_source(customer_id,source_region,source_inbound_id), UNIQUE KEY uk_ll_order_event(source_event_id,source_inbound_id) ) ENGINE=InnoDB COMMENT='尾程入仓单快照'; CREATE TABLE IF NOT EXISTS ll_inbound_order_item ( id BIGINT NOT NULL COMMENT '入仓明细主键', customer_id BIGINT NOT NULL COMMENT '租户 ID', order_id BIGINT NOT NULL COMMENT '入仓单 ID', source_inbound_detail_id VARCHAR(128) NOT NULL COMMENT '来源入仓明细 ID', package_count INT NOT NULL COMMENT '箱数', product_quantity INT NULL COMMENT '数量', pallet_count INT NULL COMMENT '托数', gross_weight_kg DECIMAL(18,3) NULL COMMENT '毛重(千克)', net_weight_kg DECIMAL(18,3) NULL COMMENT '净重(千克)', dimensional_weight_kg DECIMAL(18,3) NULL COMMENT '体积重量(千克)', volume_cbm DECIMAL(18,6) 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(128) NULL COMMENT 'FBA跟踪号', shipment_no VARCHAR(128) NULL COMMENT '货件编号', shipping_mark VARCHAR(255) NULL COMMENT '唛头', sku_code VARCHAR(128) NULL COMMENT 'SKU 编码', product_name_zh VARCHAR(255) NULL COMMENT '中文品名', product_name_en VARCHAR(255) NULL COMMENT '英文品名', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_item_order(customer_id,order_id) ) ENGINE=InnoDB COMMENT='尾程入仓商品明细快照'; CREATE TABLE IF NOT EXISTS ll_order_status_history ( id BIGINT NOT NULL COMMENT '订单状态历史主键', customer_id BIGINT NOT NULL COMMENT '租户 ID', order_id BIGINT NOT NULL COMMENT '订单 ID', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', reason VARCHAR(255) NULL COMMENT '变更原因', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间', PRIMARY KEY(id) ) ENGINE=InnoDB COMMENT='尾程订单状态历史'; -- 幂等注释迁移:CREATE TABLE IF NOT EXISTS 对已有表不会更新表/字段注释。 ALTER TABLE ll_loading_event_inbox COMMENT='头程装柜完成事件接收幂等箱'; ALTER TABLE ll_order COMMENT='尾程订单主表'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_container_booking_id'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN source_container_booking_id VARCHAR(128) NULL COMMENT ''来源头程货柜预订ID'' AFTER source_loading_plan_id')); PREPARE lastleg_order_container_booking_stmt FROM @ddl; EXECUTE lastleg_order_container_booking_stmt; DEALLOCATE PREPARE lastleg_order_container_booking_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='idx_ll_order_pending_container'), 'ALTER TABLE ll_order DROP INDEX idx_ll_order_pending_container', 'SELECT 1')); PREPARE lastleg_order_pending_container_idx_stmt FROM @ddl; EXECUTE lastleg_order_pending_container_idx_stmt; DEALLOCATE PREPARE lastleg_order_pending_container_idx_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='idx_ll_order_container_progress'), 'SELECT 1', 'ALTER TABLE ll_order ADD INDEX idx_ll_order_container_progress(source_container_booking_id,estimated_warehouse_at,created_at,id)')); PREPARE lastleg_order_container_progress_idx_stmt FROM @ddl; EXECUTE lastleg_order_container_progress_idx_stmt; DEALLOCATE PREPARE lastleg_order_container_progress_idx_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='destination_type'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER order_type')); PREPARE lastleg_order_destination_type_stmt FROM @ddl; EXECUTE lastleg_order_destination_type_stmt; DEALLOCATE PREPARE lastleg_order_destination_type_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_warehouse_id'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN source_warehouse_id VARCHAR(128) NULL COMMENT ''来源国内装柜仓 ID 快照'' AFTER customer_name')); PREPARE lastleg_order_source_warehouse_stmt FROM @ddl; EXECUTE lastleg_order_source_warehouse_stmt; DEALLOCATE PREPARE lastleg_order_source_warehouse_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_warehouse_name'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN source_warehouse_name VARCHAR(255) NULL COMMENT ''来源国内装柜仓名称快照'' AFTER source_warehouse_id')); PREPARE lastleg_order_source_warehouse_stmt FROM @ddl; EXECUTE lastleg_order_source_warehouse_stmt; DEALLOCATE PREPARE lastleg_order_source_warehouse_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_order' AND column_name='destination_type'), 'SELECT 1', 'ALTER TABLE ll_inbound_order ADD COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER destination_warehouse_name')); PREPARE lastleg_inbound_destination_type_stmt FROM @ddl; EXECUTE lastleg_inbound_destination_type_stmt; DEALLOCATE PREPARE lastleg_inbound_destination_type_stmt; ALTER TABLE ll_order_detail COMMENT='尾程订单实装商品冻结明细'; ALTER TABLE ll_loading_order_status_history COMMENT='尾程订单状态变更历史'; ALTER TABLE ll_event_conflict COMMENT='事件冲突记录'; ALTER TABLE ll_event_inbox COMMENT='通用事件接收幂等箱'; ALTER TABLE ll_inbound_order COMMENT='尾程入仓单快照'; ALTER TABLE ll_inbound_order_item COMMENT='尾程入仓商品明细快照'; ALTER TABLE ll_order_status_history COMMENT='尾程订单状态历史'; ALTER TABLE ll_event_conflict MODIFY COLUMN id BIGINT NOT NULL COMMENT '冲突记录主键', MODIFY COLUMN event_id VARCHAR(128) NOT NULL COMMENT '冲突事件 ID', MODIFY COLUMN customer_id BIGINT NOT NULL COMMENT '租户 ID', MODIFY COLUMN conflict_type VARCHAR(64) NOT NULL COMMENT '冲突类型', MODIFY COLUMN conflict_message VARCHAR(512) NOT NULL COMMENT '冲突说明', MODIFY COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'; ALTER TABLE ll_event_inbox MODIFY COLUMN id BIGINT NOT NULL COMMENT '事件接收记录主键', MODIFY COLUMN event_id VARCHAR(128) NOT NULL COMMENT '事件全局唯一 ID', MODIFY COLUMN customer_id BIGINT NOT NULL COMMENT '租户 ID', MODIFY COLUMN event_type VARCHAR(128) NOT NULL COMMENT '事件类型', MODIFY COLUMN aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型', MODIFY COLUMN aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合 ID', MODIFY COLUMN aggregate_version BIGINT NOT NULL COMMENT '聚合版本', MODIFY COLUMN payload_hash VARCHAR(71) NOT NULL COMMENT '负载摘要', MODIFY COLUMN status VARCHAR(32) NOT NULL COMMENT '消费状态', MODIFY COLUMN error_message VARCHAR(512) NULL COMMENT '错误信息', MODIFY COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', MODIFY COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'; ALTER TABLE ll_inbound_order MODIFY COLUMN id BIGINT NOT NULL COMMENT '入仓单主键', MODIFY COLUMN customer_id BIGINT NOT NULL COMMENT '租户 ID', MODIFY COLUMN source_region VARCHAR(32) NOT NULL COMMENT '来源区域', MODIFY COLUMN source_inbound_id VARCHAR(128) NOT NULL COMMENT '来源入仓分片 ID', MODIFY COLUMN root_inbound_id VARCHAR(128) NULL COMMENT '根入仓单 ID', MODIFY COLUMN source_order_id VARCHAR(128) NULL COMMENT '来源订单 ID', MODIFY COLUMN source_order_no VARCHAR(128) NULL COMMENT '来源订单号', MODIFY COLUMN root_order_id VARCHAR(128) NULL COMMENT '根订单 ID', MODIFY COLUMN inbound_code VARCHAR(128) NULL COMMENT '入仓码', MODIFY COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓 ID', MODIFY COLUMN destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码', MODIFY COLUMN destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称', MODIFY COLUMN package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', MODIFY COLUMN product_quantity INT NULL COMMENT '数量', MODIFY COLUMN pallet_count INT NULL COMMENT '托数', MODIFY COLUMN gross_weight_kg DECIMAL(18,3) NULL COMMENT '毛重(千克)', MODIFY COLUMN net_weight_kg DECIMAL(18,3) NULL COMMENT '净重(千克)', MODIFY COLUMN volume_cbm DECIMAL(18,6) NULL COMMENT '体积(立方米)', MODIFY COLUMN source_event_id VARCHAR(128) NOT NULL COMMENT '来源事件 ID', MODIFY COLUMN source_loading_plan_id VARCHAR(128) NOT NULL COMMENT '装柜计划 ID', MODIFY COLUMN source_loading_plan_version BIGINT NOT NULL COMMENT '装柜计划版本', MODIFY COLUMN handover_version BIGINT NOT NULL COMMENT '交接版本', MODIFY COLUMN payload_hash VARCHAR(71) NOT NULL COMMENT '负载摘要', MODIFY COLUMN status VARCHAR(32) NOT NULL COMMENT '入仓单状态', MODIFY COLUMN exception_flag VARCHAR(32) NOT NULL DEFAULT 'NONE' COMMENT '异常标记', MODIFY COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', MODIFY COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'; ALTER TABLE ll_inbound_order_item MODIFY COLUMN id BIGINT NOT NULL COMMENT '入仓明细主键', MODIFY COLUMN customer_id BIGINT NOT NULL COMMENT '租户ID', MODIFY COLUMN order_id BIGINT NOT NULL COMMENT '入仓单ID', MODIFY COLUMN source_inbound_detail_id VARCHAR(128) NOT NULL COMMENT '来源入仓明细ID', MODIFY COLUMN package_count INT NOT NULL COMMENT '箱数', MODIFY COLUMN product_quantity INT NULL COMMENT '数量', MODIFY COLUMN pallet_count INT NULL COMMENT '托数', MODIFY COLUMN gross_weight_kg DECIMAL(18,3) NULL COMMENT '毛重(千克)', MODIFY COLUMN net_weight_kg DECIMAL(18,3) NULL COMMENT '净重(千克)', MODIFY COLUMN dimensional_weight_kg DECIMAL(18,3) NULL COMMENT '体积重量(千克)', MODIFY COLUMN volume_cbm DECIMAL(18,6) NULL COMMENT '体积(立方米)', MODIFY COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID', MODIFY COLUMN destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码', MODIFY COLUMN destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称', MODIFY COLUMN fba_tracking_no VARCHAR(128) NULL COMMENT 'FBA跟踪号', MODIFY COLUMN shipment_no VARCHAR(128) NULL COMMENT '货件编号', MODIFY COLUMN shipping_mark VARCHAR(255) NULL COMMENT '唛头', MODIFY COLUMN sku_code VARCHAR(128) NULL COMMENT 'SKU编码', MODIFY COLUMN product_name_zh VARCHAR(255) NULL COMMENT '中文品名', MODIFY COLUMN product_name_en VARCHAR(255) NULL COMMENT '英文品名', MODIFY COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'; ALTER TABLE ll_order_status_history MODIFY COLUMN id BIGINT NOT NULL COMMENT '订单状态历史主键', MODIFY COLUMN customer_id BIGINT NOT NULL COMMENT '租户 ID', MODIFY COLUMN order_id BIGINT NOT NULL COMMENT '订单 ID', MODIFY COLUMN from_status VARCHAR(32) NULL COMMENT '变更前状态', MODIFY COLUMN to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', MODIFY COLUMN reason VARCHAR(255) NULL COMMENT '变更原因', MODIFY COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间'; ALTER TABLE ll_loading_event_inbox MODIFY COLUMN event_id VARCHAR(128) NOT NULL COMMENT '事件全局唯一标识', MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '租户/客户账号标识', MODIFY COLUMN event_type VARCHAR(64) NOT NULL COMMENT '事件类型', MODIFY COLUMN event_version INT NOT NULL COMMENT '事件契约版本', MODIFY COLUMN payload_hash VARCHAR(71) NOT NULL COMMENT '规范化事件负载 SHA-256 摘要', MODIFY COLUMN payload_json JSON NOT NULL COMMENT '事件冻结负载 JSON', MODIFY COLUMN status VARCHAR(32) NOT NULL DEFAULT 'RECEIVED' COMMENT '消费状态:RECEIVED/PROCESSED', MODIFY COLUMN received_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '接收时间', MODIFY COLUMN processed_at DATETIME(3) NULL COMMENT '处理完成时间', MODIFY COLUMN last_error VARCHAR(1000) NULL COMMENT '最近一次处理错误'; ALTER TABLE ll_order MODIFY COLUMN id BIGINT NOT NULL COMMENT '雪花 ID', MODIFY COLUMN order_no VARCHAR(32) NOT NULL COMMENT '尾程单号', MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '租户/客户账号标识', MODIFY COLUMN order_type VARCHAR(32) NOT NULL DEFAULT 'FIRST_LEG' COMMENT '订单类型', MODIFY COLUMN inbound_code VARCHAR(128) NULL COMMENT '真实来源入仓码;无入仓关系的海外本土业务为空', MODIFY COLUMN source_region VARCHAR(32) NOT NULL COMMENT '来源区域/系统', MODIFY COLUMN source_inbound_id VARCHAR(128) NOT NULL COMMENT '最终实装 LOADED 分片 ID,建单幂等键', MODIFY COLUMN root_inbound_id VARCHAR(128) NULL COMMENT '根入仓单 ID', MODIFY COLUMN source_order_id VARCHAR(128) NULL COMMENT '来源订单 ID', MODIFY COLUMN source_order_no VARCHAR(128) NULL COMMENT '来源订单号', MODIFY COLUMN root_order_id VARCHAR(128) NULL COMMENT '根订单 ID', MODIFY COLUMN customer_name VARCHAR(255) NULL COMMENT '货主名称', MODIFY COLUMN overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外接柜仓ID;新建尾程订单由业务服务预分配', MODIFY COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT '海外接柜仓业务编码快照', MODIFY COLUMN overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外接柜仓名称快照', MODIFY COLUMN receiving_warehouse_version INT NOT NULL DEFAULT 0 COMMENT '柜级接柜仓分配乐观锁版本', MODIFY COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT 'FBA 仓库编码', MODIFY COLUMN container_no VARCHAR(64) NULL COMMENT '集装箱号', MODIFY COLUMN abnormal TINYINT NOT NULL DEFAULT 0 COMMENT '是否异常:0否1是', MODIFY COLUMN detained TINYINT NOT NULL DEFAULT 0 COMMENT '是否暂扣:0否1是', MODIFY COLUMN pallet_count INT NOT NULL DEFAULT 0 COMMENT '托数', MODIFY COLUMN package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', MODIFY COLUMN volume_cbm DECIMAL(18,4) NULL COMMENT '体积(立方米)', MODIFY COLUMN product_quantity INT NULL COMMENT '货物数量', MODIFY COLUMN volume_weight_kg DECIMAL(18,4) NULL COMMENT '体积重量(千克)', MODIFY COLUMN estimated_arrival_at DATETIME(3) NULL COMMENT '预计到港时间', MODIFY COLUMN actual_arrival_at DATETIME(3) NULL COMMENT '实际到港时间', MODIFY COLUMN estimated_warehouse_at DATETIME(3) NULL COMMENT '预计到仓时间', MODIFY COLUMN inbound_order_no VARCHAR(128) NULL COMMENT '入库单号', MODIFY COLUMN outbound_order_no VARCHAR(128) NULL COMMENT '出库单号', MODIFY COLUMN delivery_order_no VARCHAR(128) NULL COMMENT '派送单号', MODIFY COLUMN relabel_order_no VARCHAR(128) NULL COMMENT '换标单号', MODIFY COLUMN relabel_status VARCHAR(32) NULL COMMENT '换标状态', MODIFY COLUMN pallet_merge_flag VARCHAR(32) NULL COMMENT '合托标记', MODIFY COLUMN current_status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ASSIGNMENT' COMMENT '当前业务状态', MODIFY COLUMN private_remark VARCHAR(1000) NULL COMMENT '备注(仅自己)', MODIFY COLUMN customer_remark VARCHAR(1000) NULL COMMENT '备注(客户)', MODIFY COLUMN warehouse_remark VARCHAR(1000) NULL COMMENT '备注(仓库)', MODIFY COLUMN source_event_id VARCHAR(128) NOT NULL COMMENT '来源事件 ID', MODIFY COLUMN source_loading_plan_id VARCHAR(128) NOT NULL COMMENT '来源装柜计划 ID', MODIFY COLUMN source_container_booking_id VARCHAR(128) NULL COMMENT '来源头程货柜预订ID', MODIFY COLUMN source_loading_plan_version BIGINT NULL COMMENT '来源装柜计划版本', MODIFY COLUMN source_handover_version BIGINT NULL COMMENT '交接版本', MODIFY COLUMN source_payload_hash VARCHAR(71) NOT 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 '更新时间'; -- Existing installations: convert the row identity to an assigned Snowflake ID and -- make order_no a container/loading-plan grouping number rather than a row-unique key. SET @ll_add_transfer_warehouse_id = ( SELECT IF(COUNT(*) = 0, 'ALTER TABLE ll_order ADD COLUMN transfer_warehouse_id VARCHAR(128) NULL COMMENT ''转入目的仓ID'' AFTER overseas_warehouse_name', 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_order' AND column_name = 'transfer_warehouse_id' ); PREPARE ll_add_transfer_warehouse_id_stmt FROM @ll_add_transfer_warehouse_id; EXECUTE ll_add_transfer_warehouse_id_stmt; DEALLOCATE PREPARE ll_add_transfer_warehouse_id_stmt; SET @ll_add_transfer_warehouse_code = ( SELECT IF(COUNT(*) = 0, 'ALTER TABLE ll_order ADD COLUMN transfer_warehouse_code VARCHAR(128) NULL COMMENT ''转入目的仓编码'' AFTER transfer_warehouse_id', 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_order' AND column_name = 'transfer_warehouse_code' ); PREPARE ll_add_transfer_warehouse_code_stmt FROM @ll_add_transfer_warehouse_code; EXECUTE ll_add_transfer_warehouse_code_stmt; DEALLOCATE PREPARE ll_add_transfer_warehouse_code_stmt; SET @ll_add_transfer_warehouse_name = ( SELECT IF(COUNT(*) = 0, 'ALTER TABLE ll_order ADD COLUMN transfer_warehouse_name VARCHAR(255) NULL COMMENT ''转入目的仓名称'' AFTER transfer_warehouse_code', 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_order' AND column_name = 'transfer_warehouse_name' ); PREPARE ll_add_transfer_warehouse_name_stmt FROM @ll_add_transfer_warehouse_name; EXECUTE ll_add_transfer_warehouse_name_stmt; DEALLOCATE PREPARE ll_add_transfer_warehouse_name_stmt; ALTER TABLE ll_order MODIFY COLUMN transfer_warehouse_id VARCHAR(128) NULL COMMENT '转入目的仓ID', MODIFY COLUMN transfer_warehouse_code VARCHAR(128) NULL COMMENT '转入目的仓编码', MODIFY COLUMN transfer_warehouse_name VARCHAR(255) NULL COMMENT '转入目的仓名称'; SET @ll_drop_order_no_unique = ( SELECT IF(COUNT(*) > 0, 'ALTER TABLE ll_order DROP INDEX uk_ll_order_no', '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 ); PREPARE ll_drop_order_no_unique_stmt FROM @ll_drop_order_no_unique; EXECUTE ll_drop_order_no_unique_stmt; DEALLOCATE PREPARE ll_drop_order_no_unique_stmt; SET @ll_add_order_group_index = ( SELECT IF(COUNT(*) = 0, 'CREATE INDEX idx_ll_order_group ON ll_order(customer_id,order_no)', 'SELECT 1') FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'll_order' AND index_name = 'idx_ll_order_group' ); PREPARE ll_add_order_group_index_stmt FROM @ll_add_order_group_index; EXECUTE ll_add_order_group_index_stmt; DEALLOCATE PREPARE ll_add_order_group_index_stmt; ALTER TABLE ll_order_detail MODIFY COLUMN id BIGINT NOT NULL AUTO_INCREMENT COMMENT '订单明细主键', MODIFY COLUMN order_id BIGINT NOT NULL COMMENT '尾程订单 ID', MODIFY COLUMN source_inbound_detail_id VARCHAR(128) NOT NULL COMMENT '来源入仓明细 ID', MODIFY COLUMN sku_code VARCHAR(128) NULL COMMENT 'SKU 编码', MODIFY COLUMN product_name_zh VARCHAR(255) NULL COMMENT '中文品名', MODIFY COLUMN product_name_en VARCHAR(255) NULL COMMENT '英文品名', MODIFY COLUMN package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', MODIFY COLUMN product_quantity INT NULL COMMENT '数量', MODIFY COLUMN pallet_count INT NULL COMMENT '托数', MODIFY COLUMN gross_weight_kg DECIMAL(18,4) NULL COMMENT '毛重(千克)', MODIFY COLUMN net_weight_kg DECIMAL(18,4) NULL COMMENT '净重(千克)', MODIFY COLUMN dimensional_weight_kg DECIMAL(18,4) NULL COMMENT '体积重量(千克)', MODIFY COLUMN volume_cbm DECIMAL(18,4) NULL COMMENT '体积(立方米)', MODIFY COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓 ID', MODIFY COLUMN destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码', MODIFY COLUMN destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称', MODIFY COLUMN fba_tracking_no VARCHAR(255) NULL COMMENT 'FBA跟踪号', MODIFY COLUMN shipment_no VARCHAR(255) NULL COMMENT '货件编号', MODIFY COLUMN shipping_mark VARCHAR(255) NULL COMMENT '唛头'; CREATE TABLE IF NOT EXISTS ll_inbound_plan ( id BIGINT NOT NULL COMMENT '入库计划ID(雪花ID)', plan_no VARCHAR(32) NOT NULL COMMENT '入库单号', customer_id VARCHAR(128) NOT NULL COMMENT '租户/客户账号标识', source_order_id BIGINT NOT NULL COMMENT '来源尾程订单ID,一张入仓单对应一张入库计划', container_no VARCHAR(64) NOT NULL COMMENT '集装箱号', overseas_warehouse_id BIGINT NOT NULL DEFAULT 193000000000200003 COMMENT '平台预分配的海外实际收货共享物理仓ID', planned_arrival_date DATE NULL COMMENT '人工计划预计到仓日期', pallet_type VARCHAR(32) NULL COMMENT '人工计划托盘类型', assigned_flag TINYINT NOT NULL DEFAULT 0 COMMENT '人工计划是否已分配:0否1是', merge_required TINYINT NOT NULL DEFAULT 0 COMMENT '人工计划是否要求合托:0否1是', urgent_flag TINYINT NOT NULL DEFAULT 0 COMMENT '人工计划是否加急:0否1是', creation_mode VARCHAR(16) NOT NULL DEFAULT 'AUTO' COMMENT '计划生成方式:AUTO柜级自动、MANUAL单票人工', plan_remark VARCHAR(1000) NULL COMMENT '入仓计划备注', status VARCHAR(32) NOT NULL DEFAULT 'PLANNED' 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 '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '入库计划乐观锁版本', PRIMARY KEY (id), UNIQUE KEY uk_ll_inbound_plan_no (plan_no), UNIQUE KEY uk_ll_inbound_plan_source_order (customer_id, source_order_id), KEY idx_ll_inbound_plan_container (customer_id, container_no) ) ENGINE=InnoDB COMMENT='尾程入库计划表:每张来源入仓单生成一张入库计划,同柜计划共享集装箱号'; CREATE TABLE IF NOT EXISTS ll_container_plan_conversion_command ( id BIGINT NOT NULL COMMENT '柜级转换命令ID', source_container_booking_id VARCHAR(128) NOT NULL COMMENT '稳定来源柜预订ID', idempotency_key VARCHAR(128) NOT NULL COMMENT '调用方幂等键', request_hash CHAR(64) NOT NULL COMMENT '确认请求SHA-256摘要', snapshot_version BIGINT NOT NULL COMMENT '确认的柜级快照版本', snapshot_hash CHAR(64) NOT NULL COMMENT '确认的柜级快照SHA-256', warehouse_id BIGINT NOT NULL COMMENT '海外接柜仓ID', batch_key VARCHAR(160) NOT NULL COMMENT '海外仓托盘批次幂等键', status VARCHAR(32) NOT NULL COMMENT '命令状态:PREPARED/APPLYING/FAILED/LOCAL_COMMITTED/COMPLETED', lease_token VARCHAR(64) NULL COMMENT '当前执行租约令牌,用于陈旧执行者隔离', preparation_json JSON NOT NULL COMMENT '稳定计划号与托盘业务键快照', result_json JSON NULL COMMENT '本地计划提交结果', last_error VARCHAR(1000) 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_container_conversion_command(source_container_booking_id), UNIQUE KEY uk_ll_container_conversion_batch(warehouse_id,batch_key), KEY idx_ll_container_conversion_status(status,updated_at) ) ENGINE=InnoDB COMMENT='柜级入库计划转换Saga与幂等命令'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_container_plan_conversion_command' AND column_name='lease_token'), 'SELECT 1', 'ALTER TABLE ll_container_plan_conversion_command ADD COLUMN lease_token VARCHAR(64) NULL COMMENT ''当前执行租约令牌,用于陈旧执行者隔离'' AFTER status')); PREPARE container_conversion_lease_stmt FROM @ddl; EXECUTE container_conversion_lease_stmt; DEALLOCATE PREPARE container_conversion_lease_stmt; CREATE TABLE IF NOT EXISTS ll_inbound_plan_line ( id BIGINT NOT NULL COMMENT '入库计划明细ID(雪花ID)', customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识', plan_id BIGINT NOT NULL COMMENT '入库计划ID', order_id BIGINT NOT NULL COMMENT '尾程订单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '头程入仓码快照', destination_type VARCHAR(32) NOT NULL DEFAULT 'OVERSEAS' COMMENT '目的类型:FBA按箱数接收、OVERSEAS逐箱扫码', 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 '该明细分配的托盘数量', PRIMARY KEY (id), UNIQUE KEY uk_ll_inbound_line_order (plan_id, order_id), KEY idx_ll_inbound_line_plan (plan_id), KEY idx_ll_inbound_line_customer_plan (customer_id, plan_id) ) ENGINE=InnoDB COMMENT='尾程入库计划明细表:按入仓码和尾程订单维度记录'; CREATE TABLE IF NOT EXISTS ll_inbound_plan_carton ( id BIGINT NOT NULL COMMENT '箱唛作业主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_id BIGINT NULL COMMENT '生成尾程订单时绑定的尾程订单ID', source_inbound_detail_id VARCHAR(128) NOT NULL COMMENT '来源入库明细ID', sku_code VARCHAR(128) NULL COMMENT 'SKU编码快照', carton_mark VARCHAR(128) NOT NULL COMMENT '国内冻结箱唛', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID快照', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', plan_id BIGINT NULL COMMENT '海外入库计划ID', line_id BIGINT NULL COMMENT '入库计划明细ID', plan_pallet_id BIGINT NULL COMMENT '海外计划托盘ID', warehouse_pallet_id BIGINT NULL COMMENT '海外实物托盘ID', warehouse_location_id BIGINT NULL COMMENT '海外库位ID', pda_task_id BIGINT NULL COMMENT '首次扫码PDA任务ID', status VARCHAR(32) NOT NULL COMMENT '箱唛状态:UNASSIGNED、ON_PALLET、BULK_RECEIVED、AVAILABLE', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', bound_at DATETIME(3) NULL COMMENT '绑定托盘时间', received_at DATETIME(3) NULL COMMENT '完成入库时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_inbound_carton_mark(customer_id,carton_mark), KEY idx_ll_inbound_carton_plan(plan_id,status), KEY idx_ll_inbound_carton_pallet(plan_pallet_id,status), KEY idx_ll_inbound_carton_order(order_id,status) ) ENGINE=InnoDB COMMENT='柜次冻结箱唛及海外入库箱级作业账'; CREATE TABLE IF NOT EXISTS ll_inbound_plan_pallet ( id BIGINT NOT NULL COMMENT '计划托盘ID(雪花ID)', customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识', plan_id BIGINT NOT NULL COMMENT '入库计划ID', pallet_no VARCHAR(128) NOT NULL COMMENT '海外仓资源服务返回的真实托盘码', source_pallet_no VARCHAR(128) NULL COMMENT '一件代发不可变来源托盘号快照', pallet_type VARCHAR(32) 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 '托盘容量,固定为2立方米', allocated_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '已分配体积(立方米)', sequence_no INT NOT NULL COMMENT '计划内托盘序号', version INT NOT NULL DEFAULT 0 COMMENT '收货累计值乐观锁版本', PRIMARY KEY (id), KEY idx_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), KEY idx_ll_inbound_pallet_customer_plan (customer_id, plan_id) ) ENGINE=InnoDB COMMENT='尾程入库计划托盘表:按目的仓隔离合托'; CREATE TABLE IF NOT EXISTS ll_inbound_plan_pallet_allocation ( id BIGINT NOT NULL COMMENT '托盘分配记录ID(雪花ID)', customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识', 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 '该明细分配到托盘的体积(立方米)', 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_customer_plan (customer_id, plan_id), KEY idx_ll_inbound_allocation_pallet (pallet_id) ) ENGINE=InnoDB COMMENT='尾程入库计划托盘分配表:记录入仓码明细与计划托盘的分配关系'; -- 修复既有入库计划表的注释;历史“每柜一张计划”记录不在这里猜测拆分。 ALTER TABLE ll_inbound_plan COMMENT='尾程入库计划表:每张来源入仓单生成一张入库计划,同柜计划共享集装箱号'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='source_order_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN source_order_id BIGINT NOT NULL DEFAULT 0 COMMENT ''来源尾程订单ID,一张入仓单对应一张入库计划'' AFTER customer_id')); PREPARE inbound_plan_source_order_stmt FROM @ddl; EXECUTE inbound_plan_source_order_stmt; DEALLOCATE PREPARE inbound_plan_source_order_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='planned_arrival_date'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN planned_arrival_date DATE NULL COMMENT ''人工计划预计到仓日期'' AFTER overseas_warehouse_id')); PREPARE inbound_plan_manual_stmt FROM @ddl; EXECUTE inbound_plan_manual_stmt; DEALLOCATE PREPARE inbound_plan_manual_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='pallet_type'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN pallet_type VARCHAR(32) NULL COMMENT ''人工计划托盘类型'' AFTER planned_arrival_date')); PREPARE inbound_plan_manual_stmt FROM @ddl; EXECUTE inbound_plan_manual_stmt; DEALLOCATE PREPARE inbound_plan_manual_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='assigned_flag'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN assigned_flag TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否已分配:0否1是'' AFTER pallet_type')); PREPARE inbound_plan_manual_stmt FROM @ddl; EXECUTE inbound_plan_manual_stmt; DEALLOCATE PREPARE inbound_plan_manual_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='merge_required'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN merge_required TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否要求合托:0否1是'' AFTER assigned_flag')); PREPARE inbound_plan_manual_stmt FROM @ddl; EXECUTE inbound_plan_manual_stmt; DEALLOCATE PREPARE inbound_plan_manual_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='urgent_flag'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN urgent_flag TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否加急:0否1是'' AFTER merge_required')); PREPARE inbound_plan_manual_stmt FROM @ddl; EXECUTE inbound_plan_manual_stmt; DEALLOCATE PREPARE inbound_plan_manual_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='creation_mode'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN creation_mode VARCHAR(16) NOT NULL DEFAULT ''AUTO'' COMMENT ''计划生成方式:AUTO柜级自动、MANUAL单票人工'' AFTER urgent_flag')); PREPARE inbound_plan_manual_stmt FROM @ddl; EXECUTE inbound_plan_manual_stmt; DEALLOCATE PREPARE inbound_plan_manual_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='plan_remark'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN plan_remark VARCHAR(1000) NULL COMMENT ''入仓计划备注'' AFTER creation_mode')); PREPARE inbound_plan_manual_stmt FROM @ddl; EXECUTE inbound_plan_manual_stmt; DEALLOCATE PREPARE inbound_plan_manual_stmt; ALTER TABLE ll_inbound_plan MODIFY COLUMN id BIGINT NOT NULL COMMENT '入库计划ID(雪花ID)', MODIFY COLUMN plan_no VARCHAR(32) NOT NULL COMMENT '入库单号', MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '租户/客户账号标识', MODIFY COLUMN source_order_id BIGINT NOT NULL COMMENT '来源尾程订单ID,一张入仓单对应一张入库计划', MODIFY COLUMN container_no VARCHAR(64) NOT NULL COMMENT '集装箱号', MODIFY COLUMN status VARCHAR(32) NOT NULL DEFAULT 'PLANNED' COMMENT '入库计划状态', MODIFY COLUMN line_count INT NOT NULL DEFAULT 0 COMMENT '入仓码明细数量', MODIFY COLUMN pallet_count INT NOT NULL DEFAULT 0 COMMENT '系统自动分配托盘数量', MODIFY COLUMN total_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 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 '更新时间'; ALTER TABLE ll_inbound_plan_line COMMENT='尾程入库计划明细表:按入仓码和尾程订单维度记录'; ALTER TABLE ll_inbound_plan_line MODIFY COLUMN id BIGINT NOT NULL COMMENT '入库计划明细ID(雪花ID)', MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识', MODIFY COLUMN plan_id BIGINT NOT NULL COMMENT '入库计划ID', MODIFY COLUMN order_id BIGINT NOT NULL COMMENT '尾程订单ID', MODIFY COLUMN inbound_code VARCHAR(128) NOT NULL COMMENT '头程入仓码快照', MODIFY COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID快照', MODIFY COLUMN destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', MODIFY COLUMN destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', MODIFY COLUMN volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '入仓码体积(立方米)', MODIFY COLUMN planned_pallet_count INT NOT NULL DEFAULT 0 COMMENT '该明细分配的托盘数量'; ALTER TABLE ll_inbound_plan_pallet COMMENT='尾程入库计划托盘表:按目的仓隔离合托'; ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN id BIGINT NOT NULL COMMENT '计划托盘ID(雪花ID)', MODIFY COLUMN plan_id BIGINT NOT NULL COMMENT '入库计划ID', MODIFY COLUMN pallet_no VARCHAR(128) NOT NULL COMMENT '海外仓资源服务返回的真实托盘码', MODIFY COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID快照', MODIFY COLUMN destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', MODIFY COLUMN destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', MODIFY COLUMN capacity_cbm DECIMAL(18,4) NOT NULL DEFAULT 2.0000 COMMENT '托盘容量,固定为2立方米', MODIFY COLUMN allocated_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '已分配体积(立方米)', MODIFY COLUMN sequence_no INT NOT NULL COMMENT '计划内托盘序号'; ALTER TABLE ll_inbound_plan_pallet_allocation COMMENT='尾程入库计划托盘分配表:记录入仓码明细与计划托盘的分配关系'; ALTER TABLE ll_inbound_plan_pallet_allocation MODIFY COLUMN id BIGINT NOT NULL COMMENT '托盘分配记录ID(雪花ID)', MODIFY COLUMN plan_id BIGINT NOT NULL COMMENT '入库计划ID', MODIFY COLUMN line_id BIGINT NOT NULL COMMENT '入库计划明细ID', MODIFY COLUMN pallet_id BIGINT NOT NULL COMMENT '计划托盘ID', MODIFY COLUMN allocated_volume_cbm DECIMAL(18,4) NOT NULL COMMENT '该明细分配到托盘的体积(立方米)'; -- Additive inbound picking schema. Guarded statements preserve existing rows on restart. ALTER TABLE ll_inbound_plan MODIFY COLUMN status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ASSIGNMENT' COMMENT '入库计划状态:PENDING_ASSIGNMENT待分配及后续正式状态'; 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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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='pallet_type'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN pallet_type VARCHAR(32) NULL COMMENT ''人工计划托盘类型'' AFTER pallet_no')); PREPARE inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 ''托盘分配状态:UNASSIGNED未分配及后续正式状态''')); PREPARE inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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='version'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN version INT NOT NULL DEFAULT 0 COMMENT ''收货累计值乐观锁版本''')); PREPARE inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 ''分配作业状态:PENDING_COUNT待清点及后续正式状态''')); PREPARE inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_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 inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_stmt; CREATE TABLE IF NOT EXISTS ll_inbound_pda_task ( id BIGINT NOT NULL COMMENT '主键ID', customer_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 '完成时间', unload_photo_file_ids JSON NULL COMMENT '卸柜照片文件ID列表', unload_photo_uploaded_at DATETIME(3) NULL COMMENT '卸柜照片上传成功时间', estimated_empty_return_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 (customer_id, plan_id), UNIQUE KEY uk_ll_inbound_pda_task_no (task_no) ) ENGINE=InnoDB COMMENT='入仓PDA作业任务'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='unload_photo_file_ids'), 'SELECT 1', 'ALTER TABLE ll_inbound_pda_task ADD COLUMN unload_photo_file_ids JSON NULL COMMENT ''卸柜照片文件ID列表'' AFTER completed_at')); PREPARE inbound_pda_photo_stmt FROM @ddl; EXECUTE inbound_pda_photo_stmt; DEALLOCATE PREPARE inbound_pda_photo_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='unload_photo_uploaded_at'), 'SELECT 1', 'ALTER TABLE ll_inbound_pda_task ADD COLUMN unload_photo_uploaded_at DATETIME(3) NULL COMMENT ''卸柜照片上传成功时间'' AFTER unload_photo_file_ids')); PREPARE inbound_pda_photo_stmt FROM @ddl; EXECUTE inbound_pda_photo_stmt; DEALLOCATE PREPARE inbound_pda_photo_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='estimated_empty_return_at'), 'SELECT 1', 'ALTER TABLE ll_inbound_pda_task ADD COLUMN estimated_empty_return_at DATETIME(3) NULL COMMENT ''预计报空时间(卸柜照片上传成功后两天)'' AFTER unload_photo_uploaded_at')); PREPARE inbound_pda_photo_stmt FROM @ddl; EXECUTE inbound_pda_photo_stmt; DEALLOCATE PREPARE inbound_pda_photo_stmt; CREATE TABLE IF NOT EXISTS ll_event_outbox ( id BIGINT NOT NULL COMMENT '事件主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型', aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合标识', event_type VARCHAR(64) NOT NULL COMMENT '事件类型', event_version INT NOT NULL COMMENT '事件版本', event_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', payload_json LONGTEXT NOT NULL COMMENT '事件载荷JSON', status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '发布状态', retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数', next_retry_at DATETIME(3) NULL COMMENT '下次重试时间', published_at DATETIME(3) NULL COMMENT '发布时间', locked_at DATETIME(3) NULL COMMENT '投递租约获取时间', locked_by VARCHAR(128) NULL COMMENT '投递租约持有者', last_error VARCHAR(1000) NULL COMMENT '最后一次发布错误', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_event_outbox_key (event_key), KEY idx_ll_event_outbox_publish (status, next_retry_at, created_at) ) ENGINE=InnoDB COMMENT='尾程跨区业务事件发件箱'; CREATE TABLE IF NOT EXISTS ll_finance_fee_source ( id BIGINT NOT NULL COMMENT '费用版本记录ID', source_fee_id BIGINT NOT NULL COMMENT '跨版本稳定费用来源ID', source_version INT NOT NULL COMMENT '费用来源版本,从1递增', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', customer_name VARCHAR(200) NULL COMMENT '客户名称快照', source_type VARCHAR(64) NOT NULL COMMENT '海外费用来源类型', source_no VARCHAR(128) NOT NULL COMMENT '来源业务编号或入仓码快照', business_type VARCHAR(32) NOT NULL COMMENT '来源业务类型', business_id BIGINT NULL COMMENT '来源业务记录ID', business_no VARCHAR(128) NOT NULL COMMENT '来源业务编号', order_id BIGINT NULL COMMENT '关联订单ID', inbound_id BIGINT NULL COMMENT '关联海外入仓计划或入仓记录ID', inbound_code VARCHAR(64) NULL COMMENT '关联入仓码;并非所有费用必填', container_id BIGINT NULL COMMENT '关联柜次ID', container_booking_id BIGINT NULL COMMENT '来源订舱柜ID', container_no VARCHAR(64) NULL COMMENT '真实集装箱号快照', warehouse_id BIGINT NULL COMMENT '关联海外仓ID', fee_item_code VARCHAR(64) NOT NULL COMMENT '费用项目编码快照', fee_item_name VARCHAR(200) NOT NULL COMMENT '费用项目名称快照', direction VARCHAR(16) NOT NULL COMMENT 'RECEIVABLE应收或PAYABLE应付', supplier_id BIGINT NULL COMMENT '应付供应商ID', supplier_name VARCHAR(200) NULL COMMENT '应付供应商名称快照', supplier_category VARCHAR(32) NULL COMMENT '应付供应商类别约束', settlement_mode VARCHAR(16) NULL COMMENT 'ON_ACCOUNT账期应付或DIRECT_PAID业务已付', paid_at DATETIME(3) NULL COMMENT '直接已付时间', payment_method VARCHAR(32) NULL COMMENT '直接已付方式', payment_reference_no VARCHAR(128) NULL COMMENT '直接已付流水号', payment_voucher_file_ids JSON NULL COMMENT '直接已付凭证文件ID快照', business_date DATE NOT NULL COMMENT '费用业务日期', currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '财务结算币种,固定CNY', amount DECIMAL(20,6) NOT NULL COMMENT '人民币结算金额', original_currency CHAR(3) NOT NULL COMMENT '业务原币种,支持CNY或USD', original_amount DECIMAL(20,6) NOT NULL COMMENT '业务原币金额', exchange_rate DECIMAL(20,6) NOT NULL COMMENT '原币折算人民币汇率,人民币固定为1', exchange_rate_month CHAR(7) NOT NULL COMMENT '汇率月份yyyy-MM', chargeable_quantity DECIMAL(20,6) NULL COMMENT '计费数量,如箱数、托数、体积或天数', quantity_unit VARCHAR(32) NULL COMMENT '计费数量单位', unit_price DECIMAL(20,6) NULL COMMENT '原币计费单价', period_start DATE NULL COMMENT '仓租等期间费用开始日期', period_end DATE NULL COMMENT '仓租等期间费用结束日期', review_status VARCHAR(16) NOT NULL COMMENT 'DRAFT、PENDING、APPROVED或REJECTED', publication_status VARCHAR(16) NOT NULL COMMENT 'UNPUBLISHED或PUBLISHED', source_status VARCHAR(16) NOT NULL COMMENT 'ACTIVE、SUPERSEDED或VOIDED', review_reason VARCHAR(500) NULL COMMENT '审核或作废原因', reviewer_id VARCHAR(128) NULL COMMENT '审核人ID', reviewed_at DATETIME(3) NULL COMMENT '审核时间', created_by VARCHAR(128) NOT NULL COMMENT '创建人ID', updated_by VARCHAR(128) NOT NULL COMMENT '最后更新人ID', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_finance_fee_version(source_fee_id,source_version), KEY idx_ll_finance_fee_customer(customer_id,source_status,created_at), KEY idx_ll_finance_fee_business(business_type,business_no,created_at), KEY idx_ll_finance_fee_container_customer(container_booking_id,customer_id,source_status,created_at), CONSTRAINT chk_ll_finance_fee_amount CHECK(amount>0), CONSTRAINT chk_ll_finance_fee_currency CHECK(currency='CNY'), CONSTRAINT chk_ll_finance_fee_original_currency CHECK(original_currency IN('CNY','USD')), CONSTRAINT chk_ll_finance_fee_period CHECK((period_start IS NULL AND period_end IS NULL) OR (period_start IS NOT NULL AND period_end IS NOT NULL AND period_start<=period_end)), CONSTRAINT chk_ll_finance_fee_direction CHECK(direction IN('RECEIVABLE','PAYABLE')), CONSTRAINT chk_ll_finance_fee_review CHECK(review_status IN('DRAFT','PENDING','APPROVED','REJECTED')), CONSTRAINT chk_ll_finance_fee_publication CHECK(publication_status IN('UNPUBLISHED','PUBLISHED')), CONSTRAINT chk_ll_finance_fee_status CHECK(source_status IN('ACTIVE','SUPERSEDED','VOIDED')) ) ENGINE=InnoDB COMMENT='海外业务不可变费用来源版本;发布后经跨区事件进入Finance'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_finance_fee_source' AND index_name='idx_ll_finance_fee_container_customer'), 'SELECT 1', 'ALTER TABLE ll_finance_fee_source ADD KEY idx_ll_finance_fee_container_customer(container_booking_id,customer_id,source_status,created_at)')); PREPARE ll_finance_fee_ddl FROM @ddl; EXECUTE ll_finance_fee_ddl; DEALLOCATE PREPARE ll_finance_fee_ddl; CREATE TABLE IF NOT EXISTS ll_finance_fee_command ( id BIGINT NOT NULL COMMENT '幂等命令ID', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID', action VARCHAR(16) NOT NULL COMMENT 'CREATE、SUBMIT、REVIEW、ADJUST或VOID', idempotency_key VARCHAR(128) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256', source_fee_id BIGINT NOT NULL COMMENT '稳定费用来源ID', source_version INT NOT NULL COMMENT '命令结果版本', created_at DATETIME(3) NOT NULL COMMENT '命令创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_finance_fee_command(operator_id,action,idempotency_key), KEY idx_ll_finance_fee_command_source(source_fee_id,source_version) ) ENGINE=InnoDB COMMENT='海外费用来源写操作幂等审计'; CREATE TABLE IF NOT EXISTS ll_overseas_quote ( id BIGINT NOT NULL COMMENT '报价ID', name VARCHAR(128) NOT NULL COMMENT '报价名称', warehouse_id BIGINT NOT NULL COMMENT '国内平台海外合作仓ID', warehouse_code VARCHAR(64) NOT NULL COMMENT '合作仓编码快照', warehouse_name VARCHAR(128) NOT NULL COMMENT '合作仓名称快照', country_code VARCHAR(2) NOT NULL COMMENT '国家二字码快照', provider_name VARCHAR(128) NOT NULL COMMENT '报价方', currency CHAR(3) NOT NULL COMMENT '币种', effective_start DATE NOT NULL COMMENT '生效开始日期', effective_end DATE NOT NULL COMMENT '生效结束日期', version_code VARCHAR(64) NOT NULL COMMENT '业务版本号', status VARCHAR(16) NOT NULL DEFAULT 'INACTIVE' COMMENT '状态:ACTIVE/INACTIVE', remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_warehouse_provider_version (warehouse_id,provider_name,version_code), KEY idx_ll_quote_page (status,updated_at,id), KEY idx_ll_quote_effective (warehouse_id,provider_name,currency,effective_start,effective_end) ) ENGINE=InnoDB COMMENT='海外仓报价主表'; CREATE TABLE IF NOT EXISTS ll_overseas_quote_fee ( id BIGINT NOT NULL COMMENT '费用明细ID', quote_id BIGINT NOT NULL COMMENT '报价ID', sequence_no INT NOT NULL COMMENT '显示顺序', item VARCHAR(128) NOT NULL COMMENT '费用项目', billing_unit VARCHAR(64) NOT NULL COMMENT '计费单位', unit_price DECIMAL(18,4) NOT NULL COMMENT '单价', minimum_charge DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '最低收费', remark VARCHAR(500) NULL COMMENT '备注', PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_fee_sequence (quote_id,sequence_no), KEY idx_ll_quote_fee_quote (quote_id) ) ENGINE=InnoDB COMMENT='海外仓报价仓库费用'; CREATE TABLE IF NOT EXISTS ll_overseas_quote_transit_price ( id BIGINT NOT NULL COMMENT '中转价格ID', quote_id BIGINT NOT NULL COMMENT '报价ID', sequence_no INT NOT NULL COMMENT '显示顺序', fba_warehouse_code VARCHAR(64) NOT NULL COMMENT 'FBA仓编码', delivery_method VARCHAR(64) NOT NULL COMMENT '报价运输方式', estimated_miles DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '预估英里数', price DECIMAL(18,4) NOT NULL COMMENT '报价金额', minimum_charge DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '最低收费', remark VARCHAR(500) NULL COMMENT '备注', PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_transit_sequence (quote_id,sequence_no), KEY idx_ll_quote_transit_quote (quote_id) ) ENGINE=InnoDB COMMENT='海外仓报价中转价格明细'; CREATE TABLE IF NOT EXISTS ll_monthly_exchange_rate ( id BIGINT NOT NULL COMMENT '月度汇率ID', rate_month CHAR(7) NOT NULL COMMENT '汇率月份,格式yyyy-MM', base_currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '基准币种', quote_currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '报价币种', usd_to_cny_average DECIMAL(18,8) NOT NULL COMMENT '美元兑人民币月平均汇率', status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态:ACTIVE/INACTIVE', remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_exchange_rate_month (rate_month), KEY idx_ll_exchange_rate_page (status,rate_month) ) ENGINE=InnoDB COMMENT='美元兑人民币月度平均汇率'; CREATE TABLE IF NOT EXISTS ll_monthly_exchange_rate_history ( id BIGINT NOT NULL COMMENT '汇率变更历史ID', exchange_rate_id BIGINT NOT NULL COMMENT '月度汇率ID', before_rate DECIMAL(18,8) NULL COMMENT '变更前汇率', after_rate DECIMAL(18,8) NOT NULL COMMENT '变更后汇率', before_status VARCHAR(16) NULL COMMENT '变更前状态', after_status VARCHAR(16) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NOT NULL COMMENT '操作人', remark VARCHAR(1000) NULL COMMENT '变更说明', created_at DATETIME(3) NOT NULL COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_exchange_rate_history (exchange_rate_id,created_at) ) ENGINE=InnoDB COMMENT='月度汇率变更历史'; CREATE TABLE IF NOT EXISTS ll_vehicle ( id BIGINT NOT NULL COMMENT '车辆档案ID', plate_number VARCHAR(64) NOT NULL COMMENT '车牌号', model VARCHAR(128) NOT NULL COMMENT '车型', fuel_consumption_per100_km DECIMAL(10,2) NOT NULL COMMENT '百公里油耗,单位升', mileage_km BIGINT NOT NULL COMMENT '当前公里码,单位公里', driver_or_dispatch_company VARCHAR(128) NULL COMMENT '司机姓名或外派单位', phone VARCHAR(64) NULL COMMENT '司机或外派单位联系电话', region VARCHAR(16) NOT NULL COMMENT '区域:DOMESTIC/OVERSEAS', ownership VARCHAR(16) NOT NULL COMMENT '车辆归属:OWNED/DISPATCHED', status VARCHAR(32) NOT NULL COMMENT '状态:IN_SERVICE/DISPATCHED/MAINTENANCE/INACTIVE/RETURNED', remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_vehicle_plate (plate_number), KEY idx_ll_vehicle_page (ownership,region,status,updated_at,id) ) ENGINE=InnoDB COMMENT='平台车辆主数据'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_event_outbox' AND column_name='locked_at'), 'SELECT 1', 'ALTER TABLE ll_event_outbox ADD COLUMN locked_at DATETIME(3) NULL COMMENT ''投递租约获取时间'' AFTER published_at')); PREPARE ll_outbox_lease_stmt FROM @ddl; EXECUTE ll_outbox_lease_stmt; DEALLOCATE PREPARE ll_outbox_lease_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_event_outbox' AND column_name='locked_by'), 'SELECT 1', 'ALTER TABLE ll_event_outbox ADD COLUMN locked_by VARCHAR(128) NULL COMMENT ''投递租约持有者'' AFTER locked_at')); PREPARE ll_outbox_lease_stmt FROM @ddl; EXECUTE ll_outbox_lease_stmt; DEALLOCATE PREPARE ll_outbox_lease_stmt; CREATE TABLE IF NOT EXISTS ll_inbound_pda_operation ( id BIGINT NOT NULL COMMENT '主键ID', customer_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 (customer_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', customer_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 (customer_id, task_id), KEY idx_ll_inbound_merge_group (merge_group_no) ) ENGINE=InnoDB COMMENT='入仓托盘合托记录'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='fba_warehouse_code'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_line ADD COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''FBA仓库编码'' AFTER inbound_code')); PREPARE inbound_schema_stmt FROM @ddl; EXECUTE inbound_schema_stmt; DEALLOCATE PREPARE inbound_schema_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_line ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id')); PREPARE receiving_container_line_stmt FROM @ddl; EXECUTE receiving_container_line_stmt; DEALLOCATE PREPARE receiving_container_line_stmt; UPDATE ll_inbound_plan_line l JOIN ll_inbound_plan p ON p.id=l.plan_id SET l.customer_id=p.customer_id WHERE l.customer_id IS NULL OR l.customer_id=''; ALTER TABLE ll_inbound_plan_line MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND index_name='idx_ll_inbound_line_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_line ADD KEY idx_ll_inbound_line_customer_plan(customer_id,plan_id)')); PREPARE inbound_customer_scope_stmt FROM @ddl; EXECUTE inbound_customer_scope_stmt; DEALLOCATE PREPARE inbound_customer_scope_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id')); PREPARE inbound_customer_scope_stmt FROM @ddl; EXECUTE inbound_customer_scope_stmt; DEALLOCATE PREPARE inbound_customer_scope_stmt; UPDATE ll_inbound_plan_pallet v JOIN ll_inbound_plan p ON p.id=v.plan_id SET v.customer_id=p.customer_id WHERE v.customer_id IS NULL OR v.customer_id=''; ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND index_name='idx_ll_inbound_pallet_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD KEY idx_ll_inbound_pallet_customer_plan(customer_id,plan_id)')); PREPARE inbound_customer_scope_stmt FROM @ddl; EXECUTE inbound_customer_scope_stmt; DEALLOCATE PREPARE inbound_customer_scope_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet_allocation' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id')); PREPARE inbound_customer_scope_stmt FROM @ddl; EXECUTE inbound_customer_scope_stmt; DEALLOCATE PREPARE inbound_customer_scope_stmt; UPDATE ll_inbound_plan_pallet_allocation a JOIN ll_inbound_plan p ON p.id=a.plan_id SET a.customer_id=p.customer_id WHERE a.customer_id IS NULL OR a.customer_id=''; ALTER TABLE ll_inbound_plan_pallet_allocation MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet_allocation' AND index_name='idx_ll_inbound_allocation_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD KEY idx_ll_inbound_allocation_customer_plan(customer_id,plan_id)')); PREPARE inbound_customer_scope_stmt FROM @ddl; EXECUTE inbound_customer_scope_stmt; DEALLOCATE PREPARE inbound_customer_scope_stmt; DROP TEMPORARY TABLE IF EXISTS inbound_plan_customer_scope_assertion; CREATE TEMPORARY TABLE inbound_plan_customer_scope_assertion ( is_valid TINYINT NOT NULL, CONSTRAINT chk_inbound_plan_customer_scope_ready CHECK (is_valid=1) ); INSERT INTO inbound_plan_customer_scope_assertion(is_valid) SELECT 0 WHERE EXISTS (SELECT 1 FROM ll_inbound_plan_line l LEFT JOIN ll_inbound_plan p ON p.id=l.plan_id WHERE l.customer_id IS NULL OR l.customer_id='' OR p.id IS NULL OR l.customer_id<>p.customer_id) OR EXISTS (SELECT 1 FROM ll_inbound_plan_pallet v LEFT JOIN ll_inbound_plan p ON p.id=v.plan_id WHERE v.customer_id IS NULL OR v.customer_id='' OR p.id IS NULL OR v.customer_id<>p.customer_id) OR EXISTS (SELECT 1 FROM ll_inbound_plan_pallet_allocation a LEFT JOIN ll_inbound_plan p ON p.id=a.plan_id WHERE a.customer_id IS NULL OR a.customer_id='' OR p.id IS NULL OR a.customer_id<>p.customer_id); DROP TEMPORARY TABLE inbound_plan_customer_scope_assertion; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='destination_type'), 'ALTER TABLE ll_inbound_plan_line MODIFY COLUMN destination_type VARCHAR(32) NOT NULL DEFAULT ''OVERSEAS'' COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码''', 'ALTER TABLE ll_inbound_plan_line ADD COLUMN destination_type VARCHAR(32) NOT NULL DEFAULT ''OVERSEAS'' COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER inbound_code')); PREPARE receiving_container_line_stmt FROM @ddl; EXECUTE receiving_container_line_stmt; DEALLOCATE PREPARE receiving_container_line_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, l.destination_type=COALESCE(NULLIF(o.destination_type,''),CASE WHEN NULLIF(o.fba_warehouse_code,'') IS NULL THEN 'OVERSEAS' ELSE 'FBA' END) WHERE (l.fba_warehouse_code IS NULL AND o.fba_warehouse_code IS NOT NULL) OR l.destination_type IS NULL OR l.destination_type='' OR l.destination_type='OVERSEAS'; CREATE TABLE IF NOT EXISTS ll_receiving_container_session ( id BIGINT NOT NULL COMMENT '柜号签收会话ID', source_container_booking_id VARCHAR(128) NOT NULL COMMENT '稳定来源柜预订ID', container_fact_hash VARCHAR(64) NOT NULL COMMENT '领取时整柜订单与计划事实摘要', container_no VARCHAR(64) NOT NULL COMMENT '集装箱号', overseas_warehouse_id BIGINT NOT NULL COMMENT '平台预分配并由操作员Token匹配的海外接柜仓ID', overseas_warehouse_code VARCHAR(128) NOT NULL COMMENT '海外接柜仓业务编码快照', overseas_warehouse_name VARCHAR(255) NOT NULL COMMENT '仓库服务校验后的海外接柜仓名称快照', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号唯一标识', operator_name VARCHAR(255) NULL COMMENT '操作账号名称', active_operator_key VARCHAR(255) NULL COMMENT '未完成会话平台操作账号全局唯一锁键', active_container_key VARCHAR(255) NULL COMMENT '未完成会话柜号全局唯一锁键', status VARCHAR(32) NOT NULL DEFAULT 'WAIT_SIGN' COMMENT '会话状态:WAIT_SIGN、SIGNED、RECEIVING、COMPLETED、COMPLETED_WITH_DIFFERENCE', sign_photos JSON NULL COMMENT '签收卸柜照片角色与文件ID列表', prepared_at DATETIME(3) NULL COMMENT '选择柜号时间', signed_at DATETIME(3) NULL COMMENT '签收时间', receiving_at DATETIME(3) NULL COMMENT '首次收货时间', completed_at DATETIME(3) NULL COMMENT '完成时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_active_operator(active_operator_key), UNIQUE KEY uk_ll_receiving_active_container(active_container_key), KEY idx_ll_receiving_container(container_no,status), KEY idx_ll_receiving_operator(operator_key,created_at) ) ENGINE=InnoDB COMMENT='海外PDA柜号签收收货会话'; CREATE TABLE IF NOT EXISTS ll_receiving_sku_receipt ( id BIGINT NOT NULL COMMENT 'FBA SKU实收进度ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识', session_id BIGINT NOT NULL COMMENT '柜号签收会话ID', plan_id BIGINT NOT NULL COMMENT '入仓计划ID', line_id BIGINT NOT NULL COMMENT '入仓计划明细ID', pallet_id BIGINT NOT NULL COMMENT '计划托盘ID', order_id BIGINT NOT NULL COMMENT '尾程订单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓码快照', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码快照', product_name VARCHAR(255) NULL COMMENT '产品名称快照', received_packages INT NOT NULL COMMENT 'SKU实收箱数', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_sku_pallet (customer_id,line_id,pallet_id,sku_code), KEY idx_ll_receiving_sku_session (customer_id,session_id,line_id), KEY idx_ll_receiving_sku_plan (customer_id,plan_id,line_id) ) ENGINE=InnoDB COMMENT='海外PDA柜号FBA SKU实收进度'; CREATE TABLE IF NOT EXISTS ll_receiving_fba_pallet_count ( id BIGINT NOT NULL COMMENT 'FBA托盘现场累计箱数ID', session_id BIGINT NOT NULL COMMENT '柜号签收会话ID', group_key VARCHAR(255) NOT NULL COMMENT '柜号与FBA仓组成的收货组键', pallet_code VARCHAR(128) NOT NULL COMMENT '现有FBA托盘码', actual_packages INT NOT NULL COMMENT '该托现场累计实物箱数', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_fba_count(session_id,group_key,pallet_code), KEY idx_ll_receiving_fba_group(session_id,group_key) ) ENGINE=InnoDB COMMENT='海外PDA普通FBA托盘现场累计与超收标记'; CREATE TABLE IF NOT EXISTS ll_receiving_container_operation ( id BIGINT NOT NULL COMMENT '柜号收货操作ID', session_id BIGINT NOT NULL COMMENT '柜号签收会话ID', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号唯一标识', action VARCHAR(32) NOT NULL COMMENT '操作动作', idempotency_key VARCHAR(255) NOT NULL COMMENT '客户端幂等键', request_hash VARCHAR(128) NOT NULL COMMENT '请求内容哈希', request_json LONGTEXT NOT NULL COMMENT '请求内容快照', result_json LONGTEXT NOT NULL COMMENT '响应内容快照', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_operation(operator_key,idempotency_key), KEY idx_ll_receiving_operation_session(session_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA柜号收货幂等审计记录'; CREATE TABLE IF NOT EXISTS ll_pda_operation_history ( id BIGINT NOT NULL COMMENT 'PDA作业历史ID', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', customer_id VARCHAR(128) NULL COMMENT '作业涉及的客户标识', operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', operation_type VARCHAR(64) NOT NULL COMMENT '作业类型', business_key VARCHAR(255) NOT NULL COMMENT '作业业务键', status VARCHAR(32) NOT NULL COMMENT '作业结果状态', idempotency_key VARCHAR(255) NULL COMMENT '写操作幂等键', request_hash VARCHAR(128) NULL COMMENT '写请求内容哈希', summary VARCHAR(1000) NULL COMMENT '作业结果摘要', occurred_at DATETIME(3) NOT NULL COMMENT '作业发生时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_history_idempotency(operator_key,idempotency_key), KEY idx_ll_pda_history_operator(overseas_warehouse_id,operator_key,occurred_at), KEY idx_ll_pda_history_business(overseas_warehouse_id,operation_type,business_key) ) ENGINE=InnoDB COMMENT='海外PDA真实作业历史'; CREATE TABLE IF NOT EXISTS ll_pda_pallet_operation ( id BIGINT NOT NULL COMMENT 'PDA托盘作业ID', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', idempotency_key VARCHAR(128) NOT NULL COMMENT '设备幂等键', operation_type VARCHAR(64) NOT NULL COMMENT '托盘作业类型', request_hash VARCHAR(128) NOT NULL COMMENT '请求内容摘要', status VARCHAR(32) NOT NULL COMMENT '处理状态:PROCESSING、COMPLETED、FAILED_COMPENSATED、COMPENSATION_REQUIRED', result_json LONGTEXT NULL COMMENT '成功响应快照', remote_transitions_json LONGTEXT NULL COMMENT '实物托盘状态变更回执', last_error VARCHAR(2000) NULL COMMENT '最后失败原因', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_pallet_idempotency(operator_key,idempotency_key), KEY idx_ll_pda_pallet_warehouse(overseas_warehouse_id,status,updated_at) ) ENGINE=InnoDB COMMENT='海外PDA托盘作业幂等、补偿与结果记录'; CREATE TABLE IF NOT EXISTS ll_pda_stocktake_task ( id BIGINT NOT NULL COMMENT '盘点任务ID', task_no VARCHAR(64) NOT NULL COMMENT '盘点任务号', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', scope_type VARCHAR(16) NOT NULL COMMENT '盘点范围类型LOCATION或PALLET', scope_resource_id BIGINT NOT NULL COMMENT '盘点库位或托盘资源ID', scope_code VARCHAR(128) NOT NULL COMMENT '盘点库位码或托盘码快照', status VARCHAR(32) NOT NULL COMMENT '盘点任务状态', position_count INT NOT NULL COMMENT '库存位置总数', counted_count INT NOT NULL DEFAULT 0 COMMENT '已盘库存位置数', difference_count INT NOT NULL DEFAULT 0 COMMENT '存在差异的库存位置数', created_by VARCHAR(128) NOT NULL COMMENT '创建操作账号标识', submitted_by VARCHAR(128) NULL COMMENT '提交操作账号标识', submit_reason VARCHAR(500) NULL COMMENT '盘点差异提交原因', idempotency_key VARCHAR(128) NOT NULL COMMENT '创建幂等键', request_hash VARCHAR(128) NOT NULL COMMENT '创建请求哈希', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', submitted_at DATETIME(3) NULL COMMENT '提交完成时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_stocktake_no(task_no), UNIQUE KEY uk_ll_pda_stocktake_create(overseas_warehouse_id,created_by,idempotency_key), KEY idx_ll_pda_stocktake_list(overseas_warehouse_id,status,created_at) ) ENGINE=InnoDB COMMENT='海外PDA库存盘点任务'; CREATE TABLE IF NOT EXISTS ll_pda_stocktake_item ( id BIGINT NOT NULL COMMENT '盘点明细ID', task_id BIGINT NOT NULL COMMENT '盘点任务ID', customer_id VARCHAR(128) NOT NULL COMMENT '库存所属客户标识', balance_id BIGINT NOT NULL COMMENT '库存余额ID', position_id BIGINT NOT NULL COMMENT '库存位置ID', sku_code VARCHAR(128) NULL COMMENT 'SKU快照', product_name VARCHAR(255) NULL COMMENT '品名快照', inbound_code VARCHAR(128) NULL COMMENT '入仓码快照', pallet_id BIGINT NOT NULL COMMENT '实物托盘ID', pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照', location_id BIGINT NOT NULL COMMENT '库位ID快照', location_code VARCHAR(128) NOT NULL COMMENT '库位码快照', book_packages BIGINT NOT NULL COMMENT '任务创建时账面总箱数', actual_packages BIGINT NULL COMMENT '现场实盘总箱数', difference_packages BIGINT NULL COMMENT '实盘与账面箱数差异', status VARCHAR(32) NOT NULL COMMENT '盘点明细状态', position_version BIGINT NOT NULL COMMENT '任务创建时库存位置版本', counted_by VARCHAR(128) NULL COMMENT '盘点操作账号标识', version BIGINT NOT NULL DEFAULT 0 COMMENT '明细乐观锁版本', counted_at DATETIME(3) NULL COMMENT '盘点时间', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_stocktake_item(task_id,position_id), KEY idx_ll_pda_stocktake_item_task(task_id,status,id) ) ENGINE=InnoDB COMMENT='海外PDA库存盘点位置明细'; CREATE TABLE IF NOT EXISTS ll_pda_stocktake_action ( id BIGINT NOT NULL COMMENT '盘点动作ID', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', idempotency_key VARCHAR(128) NOT NULL COMMENT '动作幂等键', action_type VARCHAR(32) NOT NULL COMMENT '盘点动作类型', task_id BIGINT NULL COMMENT '盘点任务ID', request_hash VARCHAR(128) NOT NULL COMMENT '动作请求哈希', status VARCHAR(32) NOT NULL COMMENT '动作处理状态', result_json LONGTEXT NULL COMMENT '成功响应JSON', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_stocktake_action(overseas_warehouse_id,operator_key,idempotency_key), KEY idx_ll_pda_stocktake_action_task(task_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA盘点动作幂等记录'; CREATE TABLE IF NOT EXISTS ll_pda_inventory_move ( id BIGINT NOT NULL COMMENT '移库操作ID', move_no VARCHAR(64) NOT NULL COMMENT '移库操作单号', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', pallet_id BIGINT NOT NULL COMMENT '整托移库的实物托盘ID', pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照', source_location_id BIGINT NOT NULL COMMENT '来源库位ID', source_location_code VARCHAR(128) NOT NULL COMMENT '来源库位码快照', target_location_id BIGINT NOT NULL COMMENT '目标库位ID', target_location_code VARCHAR(128) NOT NULL COMMENT '目标库位码快照', customer_count INT NOT NULL COMMENT '托盘涉及客户数', position_count INT NOT NULL COMMENT '迁移库存位置数', package_count BIGINT NOT NULL COMMENT '迁移总箱数', pallet_version_before INT NOT NULL COMMENT '迁移前托盘版本', pallet_version_after INT NULL COMMENT '迁移后托盘版本', operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', reason VARCHAR(500) NOT NULL COMMENT '移库原因', idempotency_key VARCHAR(128) NOT NULL COMMENT '移库幂等键', request_hash VARCHAR(128) NOT NULL COMMENT '移库请求哈希', status VARCHAR(32) NOT NULL COMMENT '移库处理状态', result_json LONGTEXT NULL COMMENT '成功响应JSON', created_at DATETIME(3) NOT NULL COMMENT '创建时间', completed_at DATETIME(3) NULL COMMENT '完成时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_inventory_move_no(move_no), UNIQUE KEY uk_ll_pda_inventory_move_key(overseas_warehouse_id,operator_key,idempotency_key), KEY idx_ll_pda_inventory_move_pallet(overseas_warehouse_id,pallet_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA同仓整托移库记录'; CREATE TABLE IF NOT EXISTS ll_inbound_fba_appointment ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', appointment_no VARCHAR(64) NOT NULL COMMENT '预约单号', appointment_at DATETIME(3) NOT NULL COMMENT '预约时间', expected_loading_at DATETIME(3) NOT NULL COMMENT '预计装车时间', appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '预约状态', appointment_remark VARCHAR(1000) NULL COMMENT '预约备注', fba_warehouse_code VARCHAR(128) NOT NULL COMMENT 'FBA仓库编码', selected_count INT NOT NULL DEFAULT 0 COMMENT '已选明细数量', created_by VARCHAR(128) NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_fba_appointment_no (customer_id, appointment_no), KEY idx_ll_fba_appointment_list (customer_id, appointment_status, fba_warehouse_code, created_at) ) ENGINE=InnoDB COMMENT='FBA入仓预约单'; CREATE TABLE IF NOT EXISTS ll_inbound_fba_appointment_item ( id BIGINT NOT NULL COMMENT '主键ID', appointment_id BIGINT NOT NULL COMMENT '预约单ID', plan_id BIGINT NOT NULL COMMENT '入仓计划ID', line_id BIGINT NOT NULL COMMENT '入仓计划明细ID', order_id BIGINT NOT NULL COMMENT '订单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓单号快照', fba_warehouse_code VARCHAR(128) NOT NULL COMMENT 'FBA仓库编码', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', 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入仓预约明细'; ALTER TABLE ll_loading_order_status_history MODIFY COLUMN id BIGINT NOT NULL AUTO_INCREMENT COMMENT '状态历史主键', MODIFY COLUMN order_id BIGINT NOT NULL COMMENT '尾程订单 ID', MODIFY COLUMN from_status VARCHAR(32) NULL COMMENT '变更前状态', MODIFY COLUMN to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', MODIFY COLUMN event_id VARCHAR(128) NULL COMMENT '触发事件 ID', MODIFY COLUMN remark VARCHAR(500) NULL COMMENT '状态变更备注', MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '记录时间'; CREATE TABLE IF NOT EXISTS ll_inventory_balance ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', customer_name VARCHAR(255) NOT NULL COMMENT '客户名称不可变快照', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', overseas_warehouse_code VARCHAR(128) NULL COMMENT '海外仓编码快照', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID', destination_warehouse_code VARCHAR(128) NOT NULL DEFAULT '' COMMENT '目的仓编码快照', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', inbound_order_id BIGINT NOT NULL COMMENT '入仓单ID', inbound_order_no VARCHAR(128) NULL COMMENT '入仓单号快照', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓单号快照', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU快照;多SKU汇总时为MIXED,不参与当前库存唯一维度', product_name_zh VARCHAR(255) NULL COMMENT '中文品名快照', product_name_en VARCHAR(255) NULL COMMENT '英文品名快照', available_packages BIGINT NOT NULL DEFAULT 0 COMMENT '可用箱数', hold_packages BIGINT NOT NULL DEFAULT 0 COMMENT '冻结箱数', allocated_packages BIGINT NOT NULL DEFAULT 0 COMMENT '已分配箱数', picked_packages BIGINT NOT NULL DEFAULT 0 COMMENT '已拣箱数', in_transit_packages BIGINT NOT NULL DEFAULT 0 COMMENT '在途箱数', receiving_packages BIGINT NOT NULL DEFAULT 0 COMMENT '收货处理中箱数', procurement_packages BIGINT NOT NULL DEFAULT 0 COMMENT '采购业务占用箱数', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_inventory_dimension (customer_id,overseas_warehouse_id,destination_warehouse_code,inbound_order_id,inbound_code), KEY idx_ll_inventory_list (customer_id,overseas_warehouse_id,updated_at), KEY idx_ll_inventory_inbound (customer_id,inbound_code), KEY idx_ll_inventory_sku (customer_id,sku_code,updated_at) ) ENGINE=InnoDB COMMENT='客户入仓单与海外目的仓维度实时库存余额'; CREATE TABLE IF NOT EXISTS ll_inventory_position ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', balance_id BIGINT NOT NULL COMMENT '库存余额记录ID', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', destination_warehouse_code VARCHAR(128) NOT NULL DEFAULT '' COMMENT '目的仓编码快照', pallet_id BIGINT NOT NULL COMMENT '托盘ID', pallet_no VARCHAR(64) NOT NULL COMMENT '托盘号', batch_no VARCHAR(128) NOT NULL DEFAULT '' COMMENT '库存批次号', warehouse_location_id BIGINT NULL COMMENT '仓库库位ID', warehouse_location_code VARCHAR(128) NOT NULL COMMENT '仓库库位编码', available_packages BIGINT NOT NULL DEFAULT 0 COMMENT '可用箱数', hold_packages BIGINT NOT NULL DEFAULT 0 COMMENT '冻结箱数', allocated_packages BIGINT NOT NULL DEFAULT 0 COMMENT '已分配箱数', picked_packages BIGINT NOT NULL DEFAULT 0 COMMENT '已拣箱数', receiving_packages BIGINT NOT NULL DEFAULT 0 COMMENT '收货处理中箱数', status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '业务状态', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_inventory_position (balance_id,pallet_id,batch_no), KEY idx_ll_inventory_position_pallet (customer_id,pallet_id), KEY idx_ll_inventory_position_location (customer_id,overseas_warehouse_id,warehouse_location_code) ) ENGINE=InnoDB COMMENT='托盘库位批次库存明细'; CREATE TABLE IF NOT EXISTS ll_inventory_ledger ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', customer_name VARCHAR(255) NOT NULL COMMENT '客户名称不可变快照', balance_id BIGINT NOT NULL COMMENT '库存余额记录ID', position_id BIGINT NULL COMMENT '库存仓位记录ID', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', destination_warehouse_code VARCHAR(128) NOT NULL DEFAULT '' COMMENT '目的仓编码快照', inbound_order_id BIGINT NOT NULL COMMENT '入仓单ID', pallet_id BIGINT NULL COMMENT '托盘ID', pallet_no VARCHAR(64) NULL COMMENT '托盘号', batch_no VARCHAR(128) NULL COMMENT '库存批次号', warehouse_location_code VARCHAR(128) NULL COMMENT '仓库库位编码', sku_code VARCHAR(128) NULL COMMENT 'SKU编码', carton_mark VARCHAR(128) NULL COMMENT '箱唛', carton_packages BIGINT NULL COMMENT '箱内箱数', business_type VARCHAR(32) NOT NULL COMMENT '业务类型', business_order_id BIGINT NULL COMMENT '业务单据ID', business_order_no VARCHAR(128) NULL COMMENT '业务单号', inbound_code VARCHAR(128) NULL COMMENT '入仓单号快照', inbound_order_no VARCHAR(128) NULL COMMENT '入仓单号快照', outbound_order_no VARCHAR(128) NULL COMMENT '出库单号', source_event_id VARCHAR(128) NULL COMMENT '来源事件ID', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', status_from VARCHAR(32) NULL COMMENT '操作前状态', status_to VARCHAR(32) NULL COMMENT '操作后状态', before_packages BIGINT NOT NULL COMMENT '变动前箱数', delta_packages BIGINT NOT NULL COMMENT '箱数变动量', after_packages BIGINT NOT NULL COMMENT '变动后箱数', operator_id VARCHAR(128) NULL COMMENT '操作人ID', remark VARCHAR(1000) NULL COMMENT '备注', occurred_at DATETIME(3) NOT NULL COMMENT '业务发生时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_inventory_ledger_idempotency (customer_id,idempotency_key), KEY idx_ll_inventory_ledger_query (customer_id,overseas_warehouse_id,occurred_at), KEY idx_ll_inventory_ledger_inbound (customer_id,inbound_code,occurred_at), KEY idx_ll_inventory_ledger_business (customer_id,business_type,business_order_no) ) ENGINE=InnoDB COMMENT='不可变库存变动流水'; CREATE TABLE IF NOT EXISTS ll_inventory_operation ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型', request_hash VARCHAR(128) NOT NULL COMMENT '请求内容哈希', status VARCHAR(32) NOT NULL DEFAULT 'PROCESSING' COMMENT '库存命令处理状态', result_json LONGTEXT NULL COMMENT '处理结果JSON', last_error VARCHAR(2000) NULL COMMENT '最后错误信息', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_inventory_operation_key (customer_id,idempotency_key), KEY idx_ll_inventory_operation_status (customer_id,status,updated_at) ) ENGINE=InnoDB COMMENT='库存命令幂等记录'; CREATE TABLE IF NOT EXISTS ll_inbound_stock_receipt ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', plan_id BIGINT NOT NULL COMMENT '入仓计划ID', task_id BIGINT NOT NULL COMMENT 'PDA任务ID', allocation_id BIGINT NOT NULL COMMENT '分配记录ID', line_id BIGINT NOT NULL COMMENT '入仓计划明细ID', order_id BIGINT NOT NULL COMMENT '订单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓单号快照', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码快照', product_name_zh VARCHAR(255) NULL COMMENT '中文品名快照', product_name_en VARCHAR(255) NULL COMMENT '英文品名快照', warehouse_pallet_id BIGINT NOT NULL COMMENT '仓库实物托盘ID', pallet_no VARCHAR(64) NOT NULL COMMENT '海外仓实物托盘码', source_pallet_no VARCHAR(128) NULL COMMENT '一件代发不可变来源托盘号快照', warehouse_location_id BIGINT NULL COMMENT '仓库库位ID', warehouse_location_code VARCHAR(128) NULL COMMENT '仓库库位编码', batch_no VARCHAR(128) NOT NULL COMMENT '库存批次号', received_packages BIGINT NOT NULL COMMENT '实收箱数', inventory_balance_id BIGINT NOT NULL COMMENT '库存余额记录ID', inventory_position_id BIGINT NOT NULL COMMENT '库存仓位记录ID', inventory_operation_key VARCHAR(255) NOT NULL COMMENT '库存操作幂等键', received_at DATETIME(3) NOT NULL COMMENT '实收时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_stock_receipt_task_allocation_sku (customer_id,task_id,allocation_id,sku_code), KEY idx_ll_stock_receipt_plan (customer_id,plan_id,line_id), KEY idx_ll_stock_receipt_inventory (inventory_balance_id,inventory_position_id) ) ENGINE=InnoDB COMMENT='入仓PDA库存实收快照'; CREATE TABLE IF NOT EXISTS ll_dispatch_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', dispatch_no VARCHAR(64) NOT NULL COMMENT '派车单号', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', vehicle_plate VARCHAR(64) NULL COMMENT '车牌号', driver_name VARCHAR(128) NULL COMMENT '司机姓名', driver_phone VARCHAR(64) NULL COMMENT '司机电话', carrier_name VARCHAR(255) NULL COMMENT '承运商名称', route VARCHAR(255) NULL COMMENT '运输路线', depart_at DATETIME(3) NULL COMMENT '发车时间', fba_appointment_no VARCHAR(64) NULL COMMENT 'FBA预约号', fba_appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT 'FBA预约状态', vehicle_appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '车辆预约状态', estimated_arrival_at DATETIME(3) NULL COMMENT '预计到达时间', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_DEPARTURE' COMMENT '业务状态', item_count INT NOT NULL DEFAULT 0 COMMENT '明细数量', pallet_count INT NOT NULL DEFAULT 0 COMMENT '托盘数', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', picked_package_count INT NOT NULL DEFAULT 0 COMMENT 'PDA累计已拣箱数', shipped_package_count INT NOT NULL DEFAULT 0 COMMENT '累计已出库箱数', partial_completion_reason VARCHAR(1000) NULL COMMENT '部分完成原因', created_by VARCHAR(128) NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_order_no (dispatch_no), KEY idx_ll_dispatch_order_list (customer_id,status,depart_at), KEY idx_ll_dispatch_order_vehicle (customer_id,vehicle_plate) ) ENGINE=InnoDB COMMENT='尾程派车单'; CREATE TABLE IF NOT EXISTS ll_dispatch_item ( id BIGINT NOT NULL COMMENT '主键ID', dispatch_order_id BIGINT NOT NULL COMMENT '派车单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', plan_id BIGINT NULL COMMENT '入仓计划ID', plan_pallet_id BIGINT NULL COMMENT '计划托盘ID', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID', order_id BIGINT NULL COMMENT '订单ID', order_no VARCHAR(64) NULL COMMENT '订单号', order_refs VARCHAR(2000) NULL COMMENT '关联订单信息', inbound_code VARCHAR(128) NULL COMMENT '入仓单号快照', pallet_no VARCHAR(128) NOT NULL COMMENT '托盘号', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', fba_warehouse_code VARCHAR(128) NULL COMMENT 'FBA仓库编码', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '体积(立方米)', source_stage VARCHAR(32) NOT NULL COMMENT '数据来源阶段', carton_marks VARCHAR(4000) NULL COMMENT '换标箱唛映射快照', source_business_type VARCHAR(32) NULL COMMENT '来源业务类型', source_business_no VARCHAR(128) NULL COMMENT '来源业务单号', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_item_source (dispatch_order_id,plan_pallet_id,warehouse_pallet_id), KEY idx_ll_dispatch_item_order (customer_id,order_id), KEY idx_ll_dispatch_item_inbound (customer_id,inbound_code), KEY idx_ll_dispatch_item_pallet (customer_id,plan_pallet_id,warehouse_pallet_id) ) ENGINE=InnoDB COMMENT='派车货物冻结明细'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_item' AND column_name='carton_marks'), 'SELECT 1', 'ALTER TABLE ll_dispatch_item ADD COLUMN carton_marks VARCHAR(4000) NULL COMMENT ''换标箱唛映射快照'' AFTER source_stage')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_item' AND column_name='source_business_type'), 'SELECT 1', 'ALTER TABLE ll_dispatch_item ADD COLUMN source_business_type VARCHAR(32) NULL COMMENT ''来源业务类型'' AFTER carton_marks')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_item' AND column_name='source_business_no'), 'SELECT 1', 'ALTER TABLE ll_dispatch_item ADD COLUMN source_business_no VARCHAR(128) NULL COMMENT ''来源业务单号'' AFTER source_business_type')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_dispatch_pallet_lock ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', source_pallet_key VARCHAR(160) NOT NULL COMMENT '来源托盘业务键', active_key VARCHAR(160) NULL COMMENT '生效中的资源排他键', plan_id BIGINT NULL COMMENT '入仓计划ID', plan_pallet_id BIGINT NULL COMMENT '计划托盘ID', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID', dispatch_order_id BIGINT NULL COMMENT '正式派车单ID,草稿锁阶段为空', draft_container_id BIGINT NULL COMMENT '智能排车草稿装车托盘ID', draft_token VARCHAR(64) NULL COMMENT '智能排车草稿随机标识', operator_id VARCHAR(128) NULL COMMENT '草稿锁操作人ID', status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '业务状态', locked_at DATETIME(3) NOT NULL COMMENT '锁定时间', expires_at DATETIME(3) NULL COMMENT '草稿锁失效时间,正式派车锁为空', released_at DATETIME(3) NULL COMMENT '释放时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_active_pallet (customer_id,active_key), KEY idx_ll_dispatch_pallet_lock_order (customer_id,dispatch_order_id,status), KEY idx_ll_dispatch_pallet_lock_source (customer_id,source_pallet_key,status) ) ENGINE=InnoDB COMMENT='派车托盘排他锁'; CREATE TABLE IF NOT EXISTS ll_dispatch_draft ( id BIGINT NOT NULL COMMENT '主键ID', draft_token VARCHAR(64) NOT NULL COMMENT '智能排车草稿随机标识', customer_id VARCHAR(128) NULL COMMENT '客户租户ID', operator_id VARCHAR(128) NULL COMMENT '草稿操作人ID', plan_ids_json VARCHAR(4000) NULL COMMENT '所选入仓计划ID列表JSON', containers_json LONGTEXT NULL COMMENT '草稿装车布局JSON快照', status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '草稿状态', expires_at DATETIME(3) NULL COMMENT '草稿失效时间', released_at DATETIME(3) NULL COMMENT '草稿释放时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_dispatch_draft_token(draft_token), KEY idx_ll_dispatch_draft_operator(operator_id,status) ) ENGINE=InnoDB COMMENT='智能排车草稿'; CREATE TABLE IF NOT EXISTS ll_dispatch_draft_container ( id BIGINT NOT NULL COMMENT '主键ID', draft_id BIGINT NOT NULL COMMENT '智能排车草稿ID', draft_token VARCHAR(64) NOT NULL COMMENT '智能排车草稿随机标识', sequence_no INT NOT NULL COMMENT '草稿车厢顺序号', capacity INT NOT NULL COMMENT '草稿车厢托盘容量', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), KEY idx_ll_dispatch_draft_container_token(draft_token) ) ENGINE=InnoDB COMMENT='智能排车草稿装车托盘'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='draft_container_id'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN draft_container_id BIGINT NULL COMMENT ''智能排车草稿装车托盘ID'' AFTER dispatch_order_id')); PREPARE dispatch_draft_container_column_stmt FROM @ddl; EXECUTE dispatch_draft_container_column_stmt; DEALLOCATE PREPARE dispatch_draft_container_column_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='draft_token'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN draft_token VARCHAR(64) NULL COMMENT ''智能排车草稿随机标识'' AFTER dispatch_order_id')); PREPARE dispatch_schema_stmt FROM @ddl; EXECUTE dispatch_schema_stmt; DEALLOCATE PREPARE dispatch_schema_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='operator_id'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN operator_id VARCHAR(128) NULL COMMENT ''草稿锁操作人ID'' AFTER draft_token')); PREPARE dispatch_schema_stmt FROM @ddl; EXECUTE dispatch_schema_stmt; DEALLOCATE PREPARE dispatch_schema_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='expires_at'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN expires_at DATETIME(3) NULL COMMENT ''草稿锁失效时间,正式派车锁为空'' AFTER locked_at')); PREPARE dispatch_schema_stmt FROM @ddl; EXECUTE dispatch_schema_stmt; DEALLOCATE PREPARE dispatch_schema_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='dispatch_order_id' AND is_nullable='YES'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock MODIFY COLUMN dispatch_order_id BIGINT NULL COMMENT ''正式派车单ID,草稿锁阶段为空''')); PREPARE dispatch_schema_stmt FROM @ddl; EXECUTE dispatch_schema_stmt; DEALLOCATE PREPARE dispatch_schema_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='order_refs'), 'SELECT 1', 'ALTER TABLE ll_dispatch_item ADD COLUMN order_refs VARCHAR(2000) NULL COMMENT ''关联订单信息'' AFTER order_no')); PREPARE dispatch_schema_stmt FROM @ddl; EXECUTE dispatch_schema_stmt; DEALLOCATE PREPARE dispatch_schema_stmt; CREATE TABLE IF NOT EXISTS ll_dispatch_pda_task ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', dispatch_order_id BIGINT NOT NULL COMMENT '派车单ID', task_no VARCHAR(64) NOT NULL COMMENT 'PDA任务号', status VARCHAR(32) NOT NULL COMMENT '业务状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', warehouse_id VARCHAR(128) NOT NULL COMMENT 'Token绑定的海外仓库ID', operator_name VARCHAR(128) NULL COMMENT '操作人姓名', pushed_at DATETIME(3) NOT NULL COMMENT '任务下发时间', completed_at DATETIME(3) NULL COMMENT '完成时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_pda_task_dispatch (customer_id,dispatch_order_id), UNIQUE KEY uk_ll_dispatch_pda_task_no (task_no) ) ENGINE=InnoDB COMMENT='派车PDA拣货任务'; CREATE TABLE IF NOT EXISTS ll_dispatch_pda_pick ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', task_id BIGINT NOT NULL COMMENT 'PDA任务ID', dispatch_item_id BIGINT NOT NULL COMMENT '派车明细ID', inventory_position_id BIGINT NOT NULL COMMENT '库存仓位记录ID', packages BIGINT NOT NULL COMMENT '本次操作箱数', product_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '产品数量', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', picked_at DATETIME(3) NOT NULL COMMENT '拣货时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_pda_pick_key (customer_id,idempotency_key), KEY idx_ll_dispatch_pda_pick_item (customer_id,task_id,dispatch_item_id) ) ENGINE=InnoDB COMMENT='派车PDA拣货记录'; CREATE TABLE IF NOT EXISTS ll_dispatch_pda_operation ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', task_id BIGINT NULL COMMENT 'PDA任务ID', operation_type VARCHAR(32) NOT NULL COMMENT 'PDA操作类型', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', result_json LONGTEXT NULL COMMENT '处理结果JSON', status VARCHAR(32) NOT NULL COMMENT 'PDA操作处理状态', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_dispatch_pda_operation_key (customer_id,idempotency_key) ) ENGINE=InnoDB COMMENT='派车PDA操作幂等记录'; CREATE TABLE IF NOT EXISTS ll_dispatch_pda_pick_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', pick_id BIGINT NOT NULL COMMENT 'PDA拣货记录ID', receipt_id BIGINT NOT NULL COMMENT '入仓实收记录ID', order_id BIGINT NOT NULL COMMENT '订单ID', packages BIGINT NOT NULL COMMENT '本次操作箱数', product_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '产品数量', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_dispatch_pick_order_pick (customer_id,pick_id), KEY idx_ll_dispatch_pick_order_receipt (customer_id,receipt_id) ) ENGINE=InnoDB COMMENT='PDA拣货订单归属记录'; -- Transfer a dispatch to delivery: one outbound header, many pallet rows, one delivery header. CREATE TABLE IF NOT EXISTS ll_outbound_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', outbound_no VARCHAR(64) NOT NULL COMMENT '出库单号', dispatch_order_id BIGINT NULL COMMENT '派车单ID,一件代发为空', dispatch_no VARCHAR(64) NULL COMMENT '派车单号,一件代发为空', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID', status VARCHAR(32) NOT NULL DEFAULT 'WAIT_OUTBOUND' COMMENT '业务状态', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', pallet_count INT NOT NULL DEFAULT 0 COMMENT '托盘数', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', created_by VARCHAR(128) NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', outbound_type VARCHAR(32) NOT NULL DEFAULT 'DISPATCH_DELIVERY' COMMENT '出库类型:派送转出库、一件代发', lx_codes VARCHAR(1000) NULL COMMENT '关联一件代发领星入库单代码汇总', recipient_info VARCHAR(1000) NULL COMMENT '一件代发收件信息', PRIMARY KEY (id), UNIQUE KEY uk_ll_outbound_no (outbound_no), UNIQUE KEY uk_ll_outbound_idempotency (customer_id,idempotency_key), UNIQUE KEY uk_ll_outbound_dispatch (customer_id,dispatch_order_id), KEY idx_ll_outbound_list (customer_id,status,created_at) ) ENGINE=InnoDB COMMENT='尾程出库单'; CREATE TABLE IF NOT EXISTS ll_outbound_pallet_item ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', outbound_order_id BIGINT NOT NULL COMMENT '出库单ID', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID', pallet_no VARCHAR(128) NULL COMMENT '托盘号', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', picked_package_count INT NOT NULL DEFAULT 0 COMMENT '已拣箱数', status VARCHAR(32) NOT NULL DEFAULT 'WAIT_PICK' COMMENT '拣货状态', sku_code VARCHAR(128) NULL COMMENT '一件代发SKU', order_refs VARCHAR(2000) NULL COMMENT '关联订单信息', inbound_code VARCHAR(128) NULL COMMENT '入仓单号快照', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_outbound_pallet (customer_id,outbound_order_id,warehouse_pallet_id), KEY idx_ll_outbound_pallet_list (customer_id,outbound_order_id), KEY idx_ll_outbound_pallet_destination (customer_id,destination_warehouse_code) ) ENGINE=InnoDB COMMENT='出库托盘明细'; CREATE TABLE IF NOT EXISTS ll_outbound_pda_task ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', outbound_order_id BIGINT NOT NULL COMMENT '出库单ID', task_no VARCHAR(64) NOT NULL COMMENT 'PDA任务号', status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '任务状态:待拣货、拣货中、已完成', completion_idempotency_key VARCHAR(255) NULL COMMENT '完成命令幂等键', pushed_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '推送时间', completed_at DATETIME(3) NULL COMMENT '完成时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_outbound_pda_task_order(customer_id,outbound_order_id), UNIQUE KEY uk_ll_outbound_pda_task_no(task_no), UNIQUE KEY uk_ll_outbound_pda_complete_key(customer_id,completion_idempotency_key) ) ENGINE=InnoDB COMMENT='一件代发出库PDA拣货任务'; SET @ddl = (SELECT IF(EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pda_task' AND column_name='completion_idempotency_key' ), 'SELECT 1', 'ALTER TABLE ll_outbound_pda_task ADD COLUMN completion_idempotency_key VARCHAR(255) NULL COMMENT ''完成命令幂等键'' AFTER status')); PREPARE outbound_pda_completion_column_stmt FROM @ddl; EXECUTE outbound_pda_completion_column_stmt; DEALLOCATE PREPARE outbound_pda_completion_column_stmt; SET @index_ready = (SELECT COUNT(*)=2 AND MIN(non_unique)=0 AND SUM(seq_in_index=1 AND column_name='customer_id')=1 AND SUM(seq_in_index=2 AND column_name='completion_idempotency_key')=1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_complete_key'); SET @index_exists = (SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_complete_key'); SET @ddl = IF(@index_ready, 'SELECT 1', IF(@index_exists, 'ALTER TABLE ll_outbound_pda_task DROP INDEX uk_ll_outbound_pda_complete_key, ADD UNIQUE KEY uk_ll_outbound_pda_complete_key(customer_id,completion_idempotency_key)', 'ALTER TABLE ll_outbound_pda_task ADD UNIQUE KEY uk_ll_outbound_pda_complete_key(customer_id,completion_idempotency_key)')); PREPARE outbound_pda_completion_index_stmt FROM @ddl; EXECUTE outbound_pda_completion_index_stmt; DEALLOCATE PREPARE outbound_pda_completion_index_stmt; CREATE TABLE IF NOT EXISTS ll_outbound_pda_pick ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', task_id BIGINT NOT NULL COMMENT 'PDA任务ID', outbound_pallet_item_id BIGINT NOT NULL COMMENT '出库托盘明细ID', inventory_position_id BIGINT NOT NULL COMMENT '库存仓位ID', packages BIGINT NOT NULL COMMENT '拣货箱数', idempotency_key VARCHAR(255) NOT NULL COMMENT '拣货幂等键', picked_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '拣货时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_outbound_pda_pick_key(customer_id,idempotency_key) ) ENGINE=InnoDB COMMENT='一件代发出库PDA托盘拣货记录'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='outbound_type'), 'SELECT 1', 'ALTER TABLE ll_outbound_order ADD COLUMN outbound_type VARCHAR(32) NOT NULL DEFAULT ''DISPATCH_DELIVERY'' COMMENT ''出库类型'' AFTER status')); PREPARE outbound_upgrade_stmt FROM @ddl; EXECUTE outbound_upgrade_stmt; DEALLOCATE PREPARE outbound_upgrade_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='lx_codes'), 'SELECT 1', 'ALTER TABLE ll_outbound_order ADD COLUMN lx_codes VARCHAR(1000) NULL COMMENT ''关联一件代发领星入库单代码汇总'' AFTER outbound_type')); PREPARE outbound_upgrade_stmt FROM @ddl; EXECUTE outbound_upgrade_stmt; DEALLOCATE PREPARE outbound_upgrade_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='sku_code'), 'SELECT 1', 'ALTER TABLE ll_outbound_pallet_item ADD COLUMN sku_code VARCHAR(128) NULL COMMENT ''一件代发SKU''')); PREPARE outbound_upgrade_stmt FROM @ddl; EXECUTE outbound_upgrade_stmt; DEALLOCATE PREPARE outbound_upgrade_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='recipient_info'), 'SELECT 1', 'ALTER TABLE ll_outbound_order ADD COLUMN recipient_info VARCHAR(1000) NULL COMMENT ''一件代发收件信息'' AFTER lx_codes')); PREPARE outbound_upgrade_stmt FROM @ddl; EXECUTE outbound_upgrade_stmt; DEALLOCATE PREPARE outbound_upgrade_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='picked_package_count'), 'SELECT 1', 'ALTER TABLE ll_outbound_pallet_item ADD COLUMN picked_package_count INT NOT NULL DEFAULT 0 COMMENT ''已拣箱数'' AFTER package_count')); PREPARE outbound_upgrade_stmt FROM @ddl; EXECUTE outbound_upgrade_stmt; DEALLOCATE PREPARE outbound_upgrade_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='status'), 'SELECT 1', 'ALTER TABLE ll_outbound_pallet_item ADD COLUMN status VARCHAR(32) NOT NULL DEFAULT ''WAIT_PICK'' COMMENT ''拣货状态'' AFTER picked_package_count')); PREPARE outbound_upgrade_stmt FROM @ddl; EXECUTE outbound_upgrade_stmt; DEALLOCATE PREPARE outbound_upgrade_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='dispatch_order_id' AND is_nullable='YES'), 'SELECT 1', 'ALTER TABLE ll_outbound_order MODIFY COLUMN dispatch_order_id BIGINT NULL COMMENT ''派车单ID,一件代发为空'', MODIFY COLUMN dispatch_no VARCHAR(64) NULL COMMENT ''派车单号,一件代发为空''')); PREPARE outbound_upgrade_stmt FROM @ddl; EXECUTE outbound_upgrade_stmt; DEALLOCATE PREPARE outbound_upgrade_stmt; -- Customer warehouse transfer: generated tail order plus selected historical order/inbound bindings. CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', transfer_no VARCHAR(64) NOT NULL COMMENT '转仓单号', inbound_order_id BIGINT NOT NULL COMMENT '入仓单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓单号快照', lastleg_order_id BIGINT NOT NULL COMMENT '尾程订单ID', lastleg_order_no VARCHAR(32) NOT NULL COMMENT '尾程订单号', operating_warehouse_id VARCHAR(128) NOT NULL COMMENT '入库中转仓ID', fba_warehouse_code VARCHAR(128) NULL COMMENT '可选FBA目的仓编码', delivery_address VARCHAR(1000) NOT NULL COMMENT '提货地址或中转仓收货地址', package_count INT NOT NULL COMMENT '箱数', delivery_method VARCHAR(64) NOT NULL COMMENT '入仓方式', estimated_arrival_at DATETIME(3) NOT NULL COMMENT '预计入仓时间', fba_shipment_no VARCHAR(128) NULL COMMENT '可选FBA货件编号', tracking_no VARCHAR(255) NULL COMMENT '物流跟踪号', fba_box_nos VARCHAR(2000) NULL COMMENT 'FBA箱号集合', remark VARCHAR(1000) NULL COMMENT '备注', need_relabel TINYINT NOT NULL DEFAULT 0 COMMENT '是否需要换标', relabel_application_id BIGINT NULL COMMENT '换标申请单ID', relabel_no VARCHAR(64) NULL COMMENT '换标申请单号', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '业务状态', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', allocation_idempotency_key VARCHAR(255) NULL COMMENT '库存分配幂等键', allocation_request_hash CHAR(64) NULL COMMENT '库存分配请求哈希', outbound_idempotency_key VARCHAR(255) NULL COMMENT '出库幂等键', outbound_request_hash CHAR(64) NULL COMMENT '出库请求哈希', outbound_at DATETIME(3) NULL COMMENT '出库时间', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_wh_transfer_no (customer_id,transfer_no), UNIQUE KEY uk_ll_wh_transfer_key (customer_id,idempotency_key), UNIQUE KEY uk_ll_wh_transfer_tail_order (lastleg_order_id), KEY idx_ll_wh_transfer_list (customer_id,status,created_at), KEY idx_ll_wh_transfer_inbound (customer_id,inbound_code) ) ENGINE=InnoDB COMMENT='客户转仓单'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='fba_warehouse_code' AND is_nullable='NO'), 'ALTER TABLE ll_warehouse_transfer_order MODIFY COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''可选FBA目的仓编码'', MODIFY COLUMN fba_shipment_no VARCHAR(128) NULL COMMENT ''可选FBA货件编号'', MODIFY COLUMN delivery_address VARCHAR(1000) NOT NULL COMMENT ''提货地址或中转仓收货地址'', MODIFY COLUMN delivery_method VARCHAR(64) NOT NULL COMMENT ''入仓方式'', MODIFY COLUMN estimated_arrival_at DATETIME(3) NOT NULL COMMENT ''预计入仓时间''', 'SELECT 1')); PREPARE transfer_optional_fba_stmt FROM @ddl; EXECUTE transfer_optional_fba_stmt; DEALLOCATE PREPARE transfer_optional_fba_stmt; -- 兼容已存在的旧版转仓单表:CREATE TABLE IF NOT EXISTS 不会补充新增字段。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='allocation_idempotency_key'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN allocation_idempotency_key VARCHAR(255) NULL COMMENT ''库存分配幂等键'' AFTER status')); PREPARE transfer_allocation_key_stmt FROM @ddl; EXECUTE transfer_allocation_key_stmt; DEALLOCATE PREPARE transfer_allocation_key_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='allocation_request_hash'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN allocation_request_hash CHAR(64) NULL COMMENT ''库存分配请求哈希'' AFTER allocation_idempotency_key')); PREPARE transfer_allocation_hash_stmt FROM @ddl; EXECUTE transfer_allocation_hash_stmt; DEALLOCATE PREPARE transfer_allocation_hash_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='outbound_idempotency_key'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN outbound_idempotency_key VARCHAR(255) NULL COMMENT ''出库幂等键'' AFTER allocation_request_hash')); PREPARE transfer_outbound_key_stmt FROM @ddl; EXECUTE transfer_outbound_key_stmt; DEALLOCATE PREPARE transfer_outbound_key_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='outbound_request_hash'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN outbound_request_hash CHAR(64) NULL COMMENT ''出库请求哈希'' AFTER outbound_idempotency_key')); PREPARE transfer_outbound_hash_stmt FROM @ddl; EXECUTE transfer_outbound_hash_stmt; DEALLOCATE PREPARE transfer_outbound_hash_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='outbound_at'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN outbound_at DATETIME(3) NULL COMMENT ''出库时间'' AFTER outbound_request_hash')); PREPARE transfer_outbound_at_stmt FROM @ddl; EXECUTE transfer_outbound_at_stmt; DEALLOCATE PREPARE transfer_outbound_at_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='estimated_ship_at'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN estimated_ship_at DATETIME(3) NULL COMMENT ''预计发货时间'' AFTER estimated_arrival_at')); PREPARE transfer_estimated_ship_stmt FROM @ddl; EXECUTE transfer_estimated_ship_stmt; DEALLOCATE PREPARE transfer_estimated_ship_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='label_deadline'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN label_deadline DATETIME(3) NULL COMMENT ''换标截止时间'', ADD COLUMN relabel_contact_name VARCHAR(128) NULL COMMENT ''换标联系人'', ADD COLUMN relabel_contact_phone VARCHAR(64) NULL COMMENT ''换标联系电话'', ADD COLUMN relabel_charge_amount DECIMAL(20,2) NULL COMMENT ''换标费用CNY'', ADD COLUMN relabel_delivery_method VARCHAR(32) NULL COMMENT ''换标后派送方式''')); PREPARE transfer_relabel_config_stmt FROM @ddl; EXECUTE transfer_relabel_config_stmt; DEALLOCATE PREPARE transfer_relabel_config_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='palletize_idempotency_key'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN palletize_idempotency_key VARCHAR(255) NULL COMMENT ''PDA打托幂等键'', ADD COLUMN palletize_request_hash CHAR(64) NULL COMMENT ''PDA打托请求哈希'', ADD COLUMN confirmation_idempotency_key VARCHAR(255) NULL COMMENT ''客户测量确认幂等键'', ADD COLUMN confirmation_request_hash CHAR(64) NULL COMMENT ''客户测量确认请求哈希'', ADD COLUMN customer_confirmed_at DATETIME(3) NULL COMMENT ''客户确认测量时间''')); PREPARE transfer_fulfillment_stmt FROM @ddl; EXECUTE transfer_fulfillment_stmt; DEALLOCATE PREPARE transfer_fulfillment_stmt; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_source_order ( id BIGINT NOT NULL COMMENT '主键ID', transfer_order_id BIGINT NOT NULL COMMENT '转仓单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', source_lastleg_order_id BIGINT NOT NULL COMMENT '来源尾程订单ID', source_lastleg_order_no VARCHAR(32) NOT NULL COMMENT '来源尾程订单号', inbound_order_id BIGINT NOT NULL COMMENT '入仓单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓单号快照', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_wh_transfer_source (transfer_order_id,source_lastleg_order_id), KEY idx_ll_wh_transfer_source_list (customer_id,transfer_order_id) ) ENGINE=InnoDB COMMENT='转仓来源历史订单绑定'; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_item ( id BIGINT NOT NULL COMMENT '主键ID', transfer_order_id BIGINT NOT NULL COMMENT '转仓单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name_zh VARCHAR(255) NOT NULL COMMENT '产品中文名称', package_count INT NOT NULL COMMENT '箱数', shipping_mark VARCHAR(255) NULL COMMENT '运输唛头', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_wh_transfer_item_list (customer_id,transfer_order_id), KEY idx_ll_wh_transfer_item_sku (customer_id,sku_code) ) ENGINE=InnoDB COMMENT='转仓货物冻结明细'; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_carton ( id BIGINT NOT NULL COMMENT '预报箱主键', transfer_order_id BIGINT NOT NULL COMMENT '转运单ID', transfer_item_id BIGINT NOT NULL COMMENT '转运申报明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', carton_mark VARCHAR(255) NOT NULL COMMENT '系统生成的一箱一码箱唛', carton_index INT NOT NULL COMMENT '全单箱序号', total_cartons INT NOT NULL COMMENT '首次生成时全单总箱数', status VARCHAR(32) NOT NULL DEFAULT 'EXPECTED' COMMENT '箱状态:EXPECTED待实收', 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_wh_transfer_carton_mark (customer_id,carton_mark), UNIQUE KEY uk_ll_wh_transfer_carton_index (transfer_order_id,carton_index), KEY idx_ll_wh_transfer_carton_list (customer_id,transfer_order_id,status) ) ENGINE=InnoDB COMMENT='仓储转运系统箱唛预报'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='customer_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN customer_carton_mark VARCHAR(255) NULL COMMENT ''客户原箱唛,用于换标现场绑定'' AFTER carton_mark')); PREPARE transfer_customer_carton_stmt FROM @ddl; EXECUTE transfer_customer_carton_stmt; DEALLOCATE PREPARE transfer_customer_carton_stmt; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_pallet ( id BIGINT NOT NULL COMMENT '打托事实ID', transfer_order_id BIGINT NOT NULL COMMENT '转运单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', sequence_no INT NOT NULL COMMENT '托序号', warehouse_pallet_id BIGINT NOT NULL COMMENT '海外仓真实托盘ID', pallet_no VARCHAR(128) NOT NULL COMMENT '真实托盘码', warehouse_location_id BIGINT NOT NULL COMMENT '真实库位ID', warehouse_location_code VARCHAR(128) NULL COMMENT '真实库位码', warehouse_resource_lock_id BIGINT NOT NULL COMMENT '仓储资源锁ID', carton_count INT NOT NULL COMMENT '本托实收箱数', length_cm DECIMAL(12,2) NOT NULL COMMENT '实测长cm', width_cm DECIMAL(12,2) NOT NULL COMMENT '实测宽cm', height_cm DECIMAL(12,2) NOT NULL COMMENT '实测高cm', gross_weight_kg DECIMAL(12,3) NOT NULL COMMENT '实测毛重kg', volume_cbm DECIMAL(18,6) NOT NULL COMMENT '实测体积CBM', status VARCHAR(32) NOT NULL COMMENT '打托状态', completed_at DATETIME(3) NOT NULL COMMENT 'PDA打托完成时间', 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_transfer_pallet_seq(transfer_order_id,sequence_no), UNIQUE KEY uk_ll_transfer_pallet_physical(customer_id,warehouse_pallet_id), KEY idx_ll_transfer_pallet_order(customer_id,transfer_order_id,status) ) ENGINE=InnoDB COMMENT='仓储转运PDA实测打托事实'; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_pallet_item ( id BIGINT NOT NULL COMMENT '主键ID', transfer_order_id BIGINT NOT NULL COMMENT '转运单ID', transfer_pallet_id BIGINT NOT NULL COMMENT '转运托盘事实ID', transfer_item_id BIGINT NOT NULL COMMENT '转运申报明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', package_count INT NOT NULL COMMENT '本托该SKU实收箱数', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_transfer_pallet_item(transfer_pallet_id,transfer_item_id), KEY idx_ll_transfer_pallet_item_order(customer_id,transfer_order_id) ) ENGINE=InnoDB COMMENT='仓储转运每托SKU箱数回填'; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_relabel_binding ( id BIGINT NOT NULL COMMENT '主键ID', transfer_order_id BIGINT NOT NULL COMMENT '转运单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '换标类型', customer_carton_mark VARCHAR(255) NOT NULL COMMENT '客户原箱唛', original_sku VARCHAR(128) NOT NULL COMMENT '旧SKU', new_sku VARCHAR(128) NULL COMMENT '新SKU', quantity INT NOT NULL COMMENT '换标件数', fba_carton_mark VARCHAR(255) NULL COMMENT '新FBA箱唛', destination_warehouse_code VARCHAR(128) NULL COMMENT 'FBA目的仓', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_transfer_relabel_mark(transfer_order_id,customer_carton_mark), KEY idx_ll_transfer_relabel_order(customer_id,transfer_order_id) ) ENGINE=InnoDB COMMENT='仓储转运换标预绑定明细'; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_inventory_allocation ( id BIGINT NOT NULL COMMENT '雪花主键', transfer_order_id BIGINT NOT NULL COMMENT '转仓单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', inventory_position_id BIGINT NOT NULL COMMENT '来源库存仓位记录ID', inventory_balance_id BIGINT NOT NULL COMMENT '来源库存余额记录ID', inbound_order_id BIGINT NOT NULL COMMENT '来源入仓单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '来源入仓单号快照', pallet_id BIGINT NOT NULL COMMENT '来源托盘ID', pallet_no VARCHAR(128) NOT NULL COMMENT '来源托盘号快照', package_count INT NOT NULL COMMENT '分配箱数', status VARCHAR(32) NOT NULL DEFAULT 'RESERVED' COMMENT '分配状态', active_position_key VARCHAR(255) NULL COMMENT '生效中的仓位排他键', allocated_at DATETIME(3) NOT NULL COMMENT '分配时间', shipped_at DATETIME(3) NULL COMMENT '出库时间', received_at DATETIME(3) NULL COMMENT '收货时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_wh_transfer_allocation_position(transfer_order_id,inventory_position_id), UNIQUE KEY uk_ll_wh_transfer_active_position(customer_id,active_position_key), KEY idx_ll_wh_transfer_allocation_list(customer_id,transfer_order_id,status) ) ENGINE=InnoDB COMMENT='转仓单来源库存分配记录'; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_receipt ( id BIGINT NOT NULL COMMENT '雪花主键', transfer_order_id BIGINT NOT NULL COMMENT '转仓单ID', allocation_id BIGINT NOT NULL COMMENT '库存分配记录ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', source_inventory_position_id BIGINT NOT NULL COMMENT '来源库存仓位记录ID', destination_inventory_balance_id BIGINT NOT NULL COMMENT '目标库存余额记录ID', destination_inventory_position_id BIGINT NOT NULL COMMENT '目标库存仓位记录ID', package_count INT NOT NULL COMMENT '收货箱数', idempotency_key VARCHAR(255) NOT NULL COMMENT '收货幂等键', request_hash CHAR(64) NOT NULL COMMENT '收货请求哈希', inventory_operation_key VARCHAR(255) NOT NULL COMMENT '库存操作幂等键', created_by VARCHAR(128) NULL COMMENT '创建人ID', received_at DATETIME(3) NOT NULL COMMENT '收货时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_wh_transfer_receipt_source(transfer_order_id,source_inventory_position_id), UNIQUE KEY uk_ll_wh_transfer_receipt_key(customer_id,idempotency_key), UNIQUE KEY uk_ll_wh_transfer_receipt_operation(customer_id,inventory_operation_key), KEY idx_ll_wh_transfer_receipt_list(customer_id,transfer_order_id,received_at) ) ENGINE=InnoDB COMMENT='转仓来源仓位的目标库存收货记录'; -- Customer relabel application: header, item snapshots, and immutable process history. CREATE TABLE IF NOT EXISTS ll_relabel_application ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', relabel_no VARCHAR(64) NOT NULL COMMENT '换标申请单号', lastleg_order_id BIGINT NOT NULL COMMENT '尾程订单ID', customer_order_no VARCHAR(128) NOT NULL COMMENT '客户订单号', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', label_deadline DATETIME(3) NOT NULL COMMENT '换标截止时间', contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(64) NOT NULL COMMENT '联系人电话', delivery_method VARCHAR(32) NULL COMMENT '派送方式:TRUCK卡车、PICKUP自提、EXPRESS快递;仅涉及箱唛换标时必填', print_shipping_label TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否需要打印面单', shipping_label_file_id VARCHAR(128) NULL COMMENT '客户上传面单文件ID', shipping_label_file_name VARCHAR(255) NULL COMMENT '客户上传面单文件名', shipping_label_file_url VARCHAR(1000) NULL COMMENT '客户上传面单下载地址', fulfillment_status VARCHAR(32) NOT NULL DEFAULT 'WAIT_RELABEL' COMMENT '换标后履约状态', outbound_order_no VARCHAR(64) NULL COMMENT '自提或快递生成的换标出库单号', customer_confirmation_key VARCHAR(255) NULL COMMENT '客户确认完成幂等键', customer_confirmed_at DATETIME(3) NULL COMMENT '客户确认换标完成时间', remark VARCHAR(1000) NULL COMMENT '备注', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_PROCESSING' COMMENT '业务状态', item_count INT NOT NULL DEFAULT 0 COMMENT '明细数量', total_package_count INT NOT NULL DEFAULT 0 COMMENT '总箱数', notified_package_count INT NOT NULL DEFAULT 0 COMMENT '已通知箱数', charge_amount DECIMAL(20,2) NOT NULL DEFAULT 0 COMMENT '换标费用CNY', charge_currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '费用币种', wallet_status VARCHAR(32) NOT NULL DEFAULT 'FREEZE_PENDING' COMMENT '资金状态', wallet_error_code VARCHAR(64) NULL COMMENT '资金错误码', wallet_error_message VARCHAR(500) NULL COMMENT '资金错误说明', wallet_command_event_id VARCHAR(64) NULL COMMENT '当前资金指令事件ID', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_relabel_application_no (customer_id,relabel_no), UNIQUE KEY uk_ll_relabel_application_idempotency (customer_id,idempotency_key), UNIQUE KEY uk_ll_relabel_application_order (lastleg_order_id), KEY idx_ll_relabel_application_list (customer_id,status,created_at), KEY idx_ll_relabel_application_customer (customer_id,customer_order_no), KEY idx_ll_relabel_application_warehouse (customer_id,overseas_warehouse_id) ) ENGINE=InnoDB COMMENT='客户换标申请单'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_id VARCHAR(128) NULL COMMENT ''总换标PDF文件ID'' AFTER remark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_name'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_name VARCHAR(255) NULL COMMENT ''总换标PDF文件名'' AFTER total_file_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_url'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_url VARCHAR(1000) NULL COMMENT ''总换标PDF预览地址'' AFTER total_file_name')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='delivery_method'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN delivery_method VARCHAR(32) NULL COMMENT ''派送方式:TRUCK卡车、PICKUP自提、EXPRESS快递;仅涉及箱唛换标时必填'' AFTER contact_phone')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='print_shipping_label'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN print_shipping_label TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否需要打印面单'' AFTER delivery_method')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='shipping_label_file_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN shipping_label_file_id VARCHAR(128) NULL COMMENT ''客户上传面单文件ID'' AFTER print_shipping_label')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='shipping_label_file_name'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN shipping_label_file_name VARCHAR(255) NULL COMMENT ''客户上传面单文件名'' AFTER shipping_label_file_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='shipping_label_file_url'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN shipping_label_file_url VARCHAR(1000) NULL COMMENT ''客户上传面单下载地址'' AFTER shipping_label_file_name')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='fulfillment_status'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN fulfillment_status VARCHAR(32) NOT NULL DEFAULT ''WAIT_RELABEL'' COMMENT ''换标后履约状态'' AFTER shipping_label_file_url')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='outbound_order_no'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN outbound_order_no VARCHAR(64) NULL COMMENT ''自提或快递生成的换标出库单号'' AFTER fulfillment_status')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='customer_confirmation_key'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN customer_confirmation_key VARCHAR(255) NULL COMMENT ''客户确认完成幂等键'' AFTER fulfillment_status')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='customer_confirmed_at'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN customer_confirmed_at DATETIME(3) NULL COMMENT ''客户确认换标完成时间'' AFTER customer_confirmation_key')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_relabel_item ( return_carton_id BIGINT NULL COMMENT '退货换箱唛来源退货库存箱ID', source_carton_mark VARCHAR(255) NULL COMMENT '退货换箱唛原箱唛快照', new_carton_mark VARCHAR(255) NULL COMMENT '退货换箱唛新箱唛', id BIGINT NOT NULL COMMENT '主键ID', application_id BIGINT NOT NULL COMMENT '申请单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', sku_code VARCHAR(128) NULL COMMENT 'SKU编码(选填)', product_image_file_id VARCHAR(128) NULL COMMENT '产品图片文件ID', product_image_file_name VARCHAR(255) NULL COMMENT '产品图片文件名', product_image_url VARCHAR(1000) NULL COMMENT '产品图片地址', product_name_zh VARCHAR(255) NOT NULL COMMENT '产品中文名称', total_package_count INT NOT NULL COMMENT '总箱数', notified_package_count INT NOT NULL COMMENT '已通知箱数', shipment_no VARCHAR(128) NULL COMMENT '货件编号(无FBA去向时为空)', tracking_code VARCHAR(255) NULL COMMENT '物流跟踪编码', new_sku_code VARCHAR(128) NOT NULL COMMENT '换标后SKU编码', label_requirement VARCHAR(1000) NULL COMMENT '换标要求', remark VARCHAR(1000) NULL COMMENT '货物明细备注', relabel_file_id VARCHAR(128) NULL COMMENT '换标文件ID', relabel_file_name VARCHAR(255) NULL COMMENT '换标文件名', relabel_file_url VARCHAR(1000) NULL COMMENT '换标文件地址', carton_mark VARCHAR(255) NULL COMMENT '客户自有箱唛', fba_carton_mark VARCHAR(255) NULL COMMENT '关联FBA箱唛', destination_warehouse_id VARCHAR(128) NULL COMMENT '该箱目的海外仓ID', destination_fba_warehouse_code VARCHAR(128) NULL COMMENT '可选FBA目的仓编码(与海外操作仓分离)', operation_type VARCHAR(32) NOT NULL DEFAULT 'CARTON_LABEL' COMMENT '换标模式:箱唛、SKU或组合换标', sku_relabel_items_json JSON NULL COMMENT '同箱SKU换标子明细快照(数量按件)', source_inventory_balance_id BIGINT NULL COMMENT '原库存余额ID(预入仓换标任务可为空)', source_inventory_position_id BIGINT NULL COMMENT '原库存库位ID(预入仓换标任务可为空)', source_inbound_order_id BIGINT NULL COMMENT '原入仓单ID(预入仓换标任务可为空)', source_inbound_order_no VARCHAR(128) NULL COMMENT '原入仓单号快照', source_inbound_code VARCHAR(128) NULL COMMENT '原进仓编码快照', source_warehouse_id VARCHAR(128) NOT NULL COMMENT '原海外中转仓ID', source_warehouse_code VARCHAR(128) NULL COMMENT '原海外中转仓编码快照', source_warehouse_name VARCHAR(255) NULL COMMENT '原海外中转仓名称快照', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_relabel_item_application (customer_id,application_id), KEY idx_ll_relabel_item_sku (customer_id,sku_code), KEY idx_ll_relabel_item_destination (customer_id,destination_warehouse_id,application_id) ) ENGINE=InnoDB COMMENT='换标货物冻结明细'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='destination_fba_warehouse_code'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN destination_fba_warehouse_code VARCHAR(128) NULL COMMENT ''可选FBA目的仓编码(与海外操作仓分离)''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_inventory_balance_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_inventory_balance_id BIGINT NULL COMMENT ''原库存余额ID(预入仓换标任务可为空)''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_inventory_position_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_inventory_position_id BIGINT NULL COMMENT ''原库存库位ID(预入仓换标任务可为空)''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_inbound_order_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_inbound_order_id BIGINT NULL COMMENT ''原入仓单ID(预入仓换标任务可为空)''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name IN ('shipment_no','destination_fba_warehouse_code','source_inventory_balance_id','source_inventory_position_id','source_inbound_order_id') AND is_nullable='NO'), 'ALTER TABLE ll_relabel_item MODIFY COLUMN shipment_no VARCHAR(128) NULL COMMENT ''货件编号(无FBA去向时为空)'', MODIFY COLUMN destination_fba_warehouse_code VARCHAR(128) NULL COMMENT ''可选FBA目的仓编码(与海外操作仓分离)'', MODIFY COLUMN source_inventory_balance_id BIGINT NULL COMMENT ''原库存余额ID(预入仓换标任务可为空)'', MODIFY COLUMN source_inventory_position_id BIGINT NULL COMMENT ''原库存库位ID(预入仓换标任务可为空)'', MODIFY COLUMN source_inbound_order_id BIGINT NULL COMMENT ''原入仓单ID(预入仓换标任务可为空)''', 'SELECT 1')); PREPARE relabel_pre_inbound_stmt FROM @ddl; EXECUTE relabel_pre_inbound_stmt; DEALLOCATE PREPARE relabel_pre_inbound_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='remark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN remark VARCHAR(1000) NULL COMMENT ''货物明细备注'' AFTER label_requirement')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN carton_mark VARCHAR(255) NULL COMMENT ''客户自有箱唛'' AFTER relabel_file_url')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='fba_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN fba_carton_mark VARCHAR(255) NULL COMMENT ''关联FBA箱唛'' AFTER carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='destination_warehouse_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT ''该箱目的海外仓ID'' AFTER fba_carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE 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_destination'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD KEY idx_ll_relabel_item_destination (customer_id,destination_warehouse_id,application_id)')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_relabel_status_history ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', application_id BIGINT NOT NULL COMMENT '申请单ID', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_relabel_status_history_application (customer_id,application_id,created_at) ) ENGINE=InnoDB COMMENT='换标状态变更历史'; CREATE TABLE IF NOT EXISTS ll_relabel_pda_task ( id BIGINT NOT NULL COMMENT '换标PDA任务ID', application_id BIGINT NOT NULL COMMENT '换标申请单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', relabel_no VARCHAR(64) NOT NULL COMMENT '换标申请单号快照', overseas_warehouse_id BIGINT NOT NULL COMMENT 'PDA令牌冻结的海外实际作业仓ID', status VARCHAR(32) NOT NULL COMMENT '任务状态:PROCESSING、WAIT_REVIEW或COMPLETED', operator_key VARCHAR(128) NOT NULL COMMENT '认领操作账号标识', operator_name VARCHAR(255) NOT NULL COMMENT '认领操作员名称快照', reviewer_key VARCHAR(128) NULL COMMENT '复核账号标识', reviewer_name VARCHAR(255) NULL COMMENT '复核员名称快照', expected_packages INT NOT NULL COMMENT '申请单通知的应换标箱数', relabelled_packages INT NOT NULL DEFAULT 0 COMMENT '已正常换标箱数', skipped_packages INT NOT NULL DEFAULT 0 COMMENT '已说明原因跳过箱数', exception_packages INT NOT NULL DEFAULT 0 COMMENT '已登记异常箱数', completion_photo_file_ids JSON NULL COMMENT '换标完成现场照片文件ID列表', completion_remark VARCHAR(1000) NULL COMMENT '完成提交备注', review_decision VARCHAR(16) NULL COMMENT '最近复核结论:APPROVE或REWORK', review_remark VARCHAR(1000) NULL COMMENT '最近复核备注', claimed_at DATETIME(3) NOT NULL COMMENT '任务认领时间', submitted_at DATETIME(3) NULL COMMENT '提交复核时间', reviewed_at DATETIME(3) NULL COMMENT '最近复核时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_relabel_pda_task_application (customer_id,application_id), UNIQUE KEY uk_ll_relabel_pda_task_no (relabel_no), KEY idx_ll_relabel_pda_task_warehouse (overseas_warehouse_id,status,updated_at), KEY idx_ll_relabel_pda_task_operator (operator_key,status,updated_at) ) ENGINE=InnoDB COMMENT='海外PDA换标现场作业任务'; CREATE TABLE IF NOT EXISTS ll_relabel_pda_unit_fact ( id BIGINT NOT NULL COMMENT '逐件换标事实ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID', application_id BIGINT NOT NULL COMMENT '换标申请单ID', item_id BIGINT NOT NULL COMMENT '换标申请明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', old_label VARCHAR(255) NULL COMMENT '扫描的实物旧标签或箱标', new_label VARCHAR(255) NULL COMMENT '扫描的换标后新标签', result VARCHAR(32) NOT NULL COMMENT '逐件结果:RELABELLED、SKIPPED或EXCEPTION', exception_code VARCHAR(32) NULL COMMENT '异常编码', reason VARCHAR(1000) NULL COMMENT '跳过或异常原因', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号标识', operator_name VARCHAR(255) NOT NULL COMMENT '操作员名称快照', occurred_at DATETIME(3) NOT NULL COMMENT '逐件事实发生时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_relabel_pda_old_label (old_label), KEY idx_ll_relabel_pda_unit_task (customer_id,task_id,occurred_at,id), KEY idx_ll_relabel_pda_unit_item (customer_id,application_id,item_id) ) ENGINE=InnoDB COMMENT='海外PDA逐件换标扫码与异常事实'; CREATE TABLE IF NOT EXISTS ll_relabel_pda_operation ( id BIGINT NOT NULL COMMENT '换标PDA幂等操作ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', operator_key VARCHAR(128) NOT NULL COMMENT '请求操作账号标识', action VARCHAR(32) NOT NULL COMMENT '幂等操作动作', idempotency_key VARCHAR(255) NOT NULL COMMENT '设备生成的幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', result_json LONGTEXT NOT NULL COMMENT '成功响应快照JSON', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_relabel_pda_operation_key (operator_key,idempotency_key), KEY idx_ll_relabel_pda_operation_task (customer_id,task_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA换标写操作幂等记录'; CREATE TABLE IF NOT EXISTS ll_relabel_pda_history ( id BIGINT NOT NULL COMMENT '换标PDA任务历史ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID', application_id BIGINT NOT NULL COMMENT '换标申请单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', action VARCHAR(32) NOT NULL COMMENT '现场动作类型', from_status VARCHAR(32) NULL COMMENT '动作前任务状态', to_status VARCHAR(32) NOT NULL COMMENT '动作后任务状态', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号标识', operator_name VARCHAR(255) NOT NULL COMMENT '操作员名称快照', detail_json LONGTEXT NULL COMMENT '动作详情JSON', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_relabel_pda_history_task (customer_id,task_id,created_at,id), KEY idx_ll_relabel_pda_history_application (customer_id,application_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA换标任务不可变操作历史'; CREATE TABLE IF NOT EXISTS ll_dropship_order_profile ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_id BIGINT NOT NULL COMMENT '订单ID', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID', pallet_no VARCHAR(128) NULL COMMENT '托盘号', source_pallet_no VARCHAR(128) NOT NULL COMMENT '来源托盘号快照', manifest_version INT NOT NULL COMMENT '整托清单版本', manifest_package_count INT NOT NULL COMMENT '整托总箱数', manifest_fragment_count INT NOT NULL COMMENT '整托客户分片总数', manifest_hash CHAR(64) NOT NULL COMMENT '整托完整清单摘要', inventory_position_id BIGINT NULL COMMENT '库存仓位记录ID', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_INBOUND' COMMENT '业务状态', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_dropship_profile_order_pallet(customer_id,order_id,source_pallet_no), UNIQUE KEY uk_ll_dropship_profile_key(customer_id,idempotency_key), KEY idx_ll_dropship_profile_order(customer_id,order_id), KEY idx_ll_dropship_profile_manifest(source_pallet_no,manifest_hash) ) ENGINE=InnoDB COMMENT='一件代发托盘档案'; CREATE TABLE IF NOT EXISTS ll_dropship_carton ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_id BIGINT NOT NULL COMMENT '订单ID', profile_id BIGINT NOT NULL COMMENT '托盘档案ID', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID', pallet_no VARCHAR(128) NULL COMMENT '托盘号', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', carton_mark VARCHAR(128) NOT NULL COMMENT '箱唛', carton_sequence INT NOT NULL COMMENT '箱唛序号', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_INBOUND' COMMENT '业务状态', outbound_order_no VARCHAR(128) NULL COMMENT '出库单号', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_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 COMMENT='一件代发箱唛明细'; CREATE TABLE IF NOT EXISTS ll_dropship_sku_inventory ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_id BIGINT NOT NULL COMMENT '订单ID', profile_id BIGINT NOT NULL COMMENT '托盘档案ID', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name VARCHAR(255) NULL COMMENT '产品名称', package_count BIGINT NOT NULL COMMENT '箱数', product_quantity BIGINT 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_dropship_sku_inventory(profile_id,sku_code), KEY idx_ll_dropship_sku_order(customer_id,order_id,sku_code) ) ENGINE=InnoDB COMMENT='一件代发SKU库存汇总'; CREATE TABLE IF NOT EXISTS ll_dropship_carton_ledger ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_id BIGINT NOT NULL COMMENT '订单ID', carton_id BIGINT NOT NULL COMMENT '箱唛记录ID', carton_mark VARCHAR(128) NOT NULL COMMENT '箱唛', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型', before_packages BIGINT NOT NULL COMMENT '变动前箱数', delta_packages BIGINT NOT NULL COMMENT '箱数变动量', after_packages BIGINT NOT NULL COMMENT '变动后箱数', business_order_no VARCHAR(128) NULL COMMENT '业务单号', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', remark VARCHAR(1000) NULL COMMENT '备注', occurred_at DATETIME(3) NOT NULL COMMENT '业务发生时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_dropship_ledger_key(customer_id,idempotency_key), KEY idx_ll_dropship_ledger_sku(customer_id,sku_code,carton_mark) ) ENGINE=InnoDB COMMENT='一件代发箱唛库存流水'; CREATE TABLE IF NOT EXISTS ll_cargo_discard_application ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', discard_no VARCHAR(64) NOT NULL COMMENT '废弃申请单号', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', inbound_codes VARCHAR(2000) NOT NULL COMMENT '入仓单号集合', total_packages INT NOT NULL COMMENT '总箱数', fee_per_package DECIMAL(18,2) NOT NULL COMMENT '每箱处理费用', total_fee DECIMAL(18,2) NOT NULL COMMENT '费用合计', currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '业务状态', remark VARCHAR(1000) NULL COMMENT '备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', reviewed_by VARCHAR(128) NULL COMMENT '审核人ID', review_remark VARCHAR(1000) NULL COMMENT '审核备注', review_idempotency_key VARCHAR(255) NULL COMMENT '审核幂等键', review_request_hash CHAR(64) NULL COMMENT '审核请求内容哈希', reviewed_at DATETIME(3) NULL COMMENT '审核时间', 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_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='货物废弃申请单'; CREATE TABLE IF NOT EXISTS ll_cargo_discard_item ( id BIGINT NOT NULL COMMENT '主键ID', application_id BIGINT NOT NULL COMMENT '申请单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_id BIGINT NOT NULL COMMENT '订单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓单号快照', profile_id BIGINT NOT NULL COMMENT '托盘档案ID', sku_inventory_id BIGINT NOT NULL COMMENT 'SKU库存记录ID', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name VARCHAR(255) NULL COMMENT '产品名称', available_packages_snapshot INT NOT NULL COMMENT '可用箱数快照', discard_packages INT NOT NULL COMMENT '废弃箱数', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', 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='货物废弃SKU明细'; CREATE TABLE IF NOT EXISTS ll_cargo_discard_carton ( id BIGINT NOT NULL COMMENT '主键ID', application_id BIGINT NOT NULL COMMENT '申请单ID', item_id BIGINT NOT NULL COMMENT '明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', carton_id BIGINT NOT NULL COMMENT '箱唛记录ID', carton_mark VARCHAR(128) NOT NULL COMMENT '箱唛', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', 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='货物废弃锁定箱明细'; CREATE TABLE IF NOT EXISTS ll_cargo_discard_status_history ( id BIGINT NOT NULL COMMENT '主键ID', application_id BIGINT NOT NULL COMMENT '申请单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_cargo_discard_history(customer_id,application_id,created_at) ) ENGINE=InnoDB COMMENT='货物废弃审批历史'; CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', customer_name VARCHAR(255) NULL COMMENT '客户名称快照', order_no VARCHAR(64) NOT NULL COMMENT '订单号', purchase_category VARCHAR(128) NOT NULL COMMENT '采购品类', product_name VARCHAR(255) NOT NULL COMMENT '产品名称', product_specification VARCHAR(500) NULL COMMENT '产品规格', product_url VARCHAR(2000) NULL COMMENT '产品链接', purchase_quantity BIGINT NOT NULL COMMENT '采购数量', budget_unit_price DECIMAL(18,2) NULL COMMENT '预算单价', currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', receiving_address VARCHAR(1000) NULL COMMENT '收货地址', contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(64) NOT NULL COMMENT '联系人电话', purchase_warehouse_id VARCHAR(128) NULL COMMENT '采购入仓仓库ID', purchase_warehouse_name VARCHAR(255) NULL COMMENT '采购入仓仓库名称', outbound_details JSON NULL COMMENT '出库明细', inbound_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '采购单据累计入库数量', domestic_carrier VARCHAR(128) NULL COMMENT '境内承运商', domestic_tracking_no VARCHAR(128) NULL COMMENT '境内物流单号', overseas_carrier VARCHAR(128) NULL COMMENT '海外承运商', overseas_tracking_no VARCHAR(128) NULL COMMENT '海外物流单号', estimated_arrival_at DATETIME(3) NULL COMMENT '预计到达时间', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '业务状态', remark VARCHAR(1000) NULL COMMENT '备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', reviewed_by VARCHAR(128) NULL COMMENT '审核人ID', review_remark VARCHAR(1000) NULL COMMENT '审核备注', review_idempotency_key VARCHAR(255) NULL COMMENT '审核幂等键', review_request_hash CHAR(64) NULL COMMENT '审核请求内容哈希', reviewed_at DATETIME(3) NULL COMMENT '审核时间', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_overseas_procurement_order_no(customer_id,order_no), UNIQUE KEY uk_ll_overseas_procurement_order_key(customer_id,idempotency_key), KEY idx_ll_overseas_procurement_list(customer_id,status,created_at), KEY idx_ll_overseas_procurement_warehouse(customer_id,purchase_warehouse_id,created_at) ) ENGINE=InnoDB COMMENT='海外采购订单'; CREATE TABLE IF NOT EXISTS ll_overseas_procurement_status_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型:CREATE、REVIEW或UPDATE', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_overseas_procurement_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='海外采购操作流水'; CREATE TABLE IF NOT EXISTS ll_us_truck_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_no VARCHAR(64) NOT NULL COMMENT '订单号', transport_type VARCHAR(32) NOT NULL COMMENT '运输类型', origin VARCHAR(255) NOT NULL COMMENT '起运地', origin_address VARCHAR(500) NULL COMMENT '起运地址', destination VARCHAR(255) NOT NULL COMMENT '目的地', destination_address VARCHAR(500) NULL COMMENT '目的地址', container_type VARCHAR(32) NULL COMMENT '历史兼容设备类型,零担托盘业务不采集', pallet_count INT NOT NULL DEFAULT 1 COMMENT '客户申报托盘数', package_count INT NULL COMMENT '可选箱数,零或空值均有效', received_pallet_count INT NOT NULL DEFAULT 0 COMMENT 'PDA实收托盘数', allocated_pallet_count INT NOT NULL DEFAULT 0 COMMENT '已分配到合车行程的托盘数', total_weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '总重量(千克)', total_volume_cbm DECIMAL(18,6) NOT NULL DEFAULT 0 COMMENT '总体积(立方米)', budget_amount DECIMAL(18,2) NULL COMMENT '预算金额', currency VARCHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_info VARCHAR(128) NOT NULL COMMENT '联系人联系方式', requested_date DATE NOT NULL COMMENT '要求服务日期', status VARCHAR(32) NOT NULL COMMENT '美国卡车订单状态', remark VARCHAR(1000) NULL COMMENT '备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_us_truck_order_no(customer_id,order_no), UNIQUE KEY uk_ll_us_truck_order_key(customer_id,idempotency_key), KEY idx_ll_us_truck_order_list(customer_id,status,created_at), KEY idx_ll_us_truck_order_date(customer_id,requested_date,created_at) ) ENGINE=InnoDB COMMENT='美国卡车运输订单'; CREATE TABLE IF NOT EXISTS ll_us_truck_order_pallet ( id BIGINT NOT NULL COMMENT '托盘记录ID', order_id BIGINT NOT NULL COMMENT '美国卡车订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', pallet_no VARCHAR(128) NOT NULL COMMENT '业务托盘号', sequence_no INT NOT NULL COMMENT '订单内托盘序号', source VARCHAR(32) NOT NULL COMMENT '托盘来源:订单计划或PDA超收', status VARCHAR(32) NOT NULL COMMENT '托盘状态:待收、已收或超收待审核', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘资源ID', package_count INT NULL COMMENT '托盘箱数', received_at DATETIME(3) NULL COMMENT '实收时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_us_truck_order_pallet_no(customer_id,order_id,pallet_no), UNIQUE KEY uk_ll_us_truck_order_pallet_seq(customer_id,order_id,sequence_no), KEY idx_ll_us_truck_order_pallet_list(customer_id,order_id,status) ) ENGINE=InnoDB COMMENT='美国卡车订单托盘实收记录'; CREATE TABLE IF NOT EXISTS ll_us_truck_order_operation ( id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '美国卡车订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(64) NOT NULL COMMENT '具名操作类型', idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '操作请求内容哈希', result_version BIGINT NOT NULL COMMENT '操作完成后的订单版本', created_by VARCHAR(128) NULL COMMENT '操作人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_us_truck_operation_key(customer_id,order_id,idempotency_key), KEY idx_ll_us_truck_operation_order(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='美国卡车订单幂等操作账'; CREATE TABLE IF NOT EXISTS ll_us_truck_order_status_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(64) NOT NULL COMMENT '具名操作类型', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_us_truck_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='美国卡车订单状态历史'; CREATE TABLE IF NOT EXISTS ll_local_looseboard_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', lastleg_order_id BIGINT NULL COMMENT '关联尾程主订单ID', order_no VARCHAR(64) NOT NULL COMMENT '本土散板订单号', transport_mode VARCHAR(32) NOT NULL COMMENT '运输方式:拼车或优先拼载', pallet_required VARCHAR(8) NOT NULL COMMENT '是否需要打盘:YES或NO', transport_type VARCHAR(32) NOT NULL COMMENT '运输类型', origin VARCHAR(255) NOT NULL COMMENT '起运地', origin_address VARCHAR(500) NULL COMMENT '起运详细地址', destination VARCHAR(255) NOT NULL COMMENT '目的地', destination_address VARCHAR(500) NULL COMMENT '目的详细地址、码头或仓号', container_type VARCHAR(32) NULL COMMENT '柜型', package_count INT NOT NULL DEFAULT 0 COMMENT '货物件数', total_weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '总重量(千克)', total_volume_cbm DECIMAL(18,6) NOT NULL DEFAULT 0 COMMENT '总体积(立方米)', budget_amount DECIMAL(18,2) NULL COMMENT '预算总价', currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '预算币种', contact_name VARCHAR(128) NULL COMMENT '联系人姓名', contact_info VARCHAR(128) NULL COMMENT '联系人联系方式', requested_date DATE NULL COMMENT '要求服务日期', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ACCEPTANCE' COMMENT '本土散板订单状态', remark VARCHAR(1000) NULL COMMENT '备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '创建幂等键', request_hash CHAR(64) NOT NULL COMMENT '创建请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_local_looseboard_no(customer_id,order_no), UNIQUE KEY uk_ll_local_looseboard_lastleg(lastleg_order_id), UNIQUE KEY uk_ll_local_looseboard_key(customer_id,idempotency_key), KEY idx_ll_local_looseboard_list(customer_id,status,created_at), KEY idx_ll_local_looseboard_date(customer_id,requested_date,created_at) ) ENGINE=InnoDB COMMENT='本土散板订单'; CREATE TABLE IF NOT EXISTS ll_local_looseboard_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '本土散板订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型:CREATE、UPDATE或STATUS', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '操作备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_local_looseboard_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='本土散板操作流水'; CREATE TABLE IF NOT EXISTS ll_local_looseboard_operation ( id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '本土散板订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型', idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '操作请求内容哈希', result_version BIGINT NOT NULL COMMENT '操作完成后的订单版本', created_by VARCHAR(128) NULL COMMENT '操作人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_local_looseboard_operation_key(customer_id,order_id,idempotency_key), KEY idx_ll_local_looseboard_operation_order(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='本土散板订单幂等操作账'; CREATE TABLE IF NOT EXISTS ll_exception_order ( id BIGINT NOT NULL COMMENT '异常订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', exception_no VARCHAR(64) NOT NULL COMMENT '异常订单号', exception_type VARCHAR(32) NOT NULL COMMENT '异常类型', status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '异常处理状态', reason VARCHAR(1000) NOT NULL COMMENT '异常原因', last_mile_order_id BIGINT NULL COMMENT '关联尾程订单ID', last_mile_order_no VARCHAR(64) NULL COMMENT '关联尾程订单号', inbound_order_id BIGINT NULL COMMENT '关联入仓单ID', inbound_code VARCHAR(128) NULL COMMENT '关联入仓码', delivery_order_id BIGINT NULL COMMENT '关联派送单ID', delivery_no VARCHAR(64) NULL COMMENT '关联派送单号', outbound_no VARCHAR(64) NULL COMMENT '关联出库单号', customer_name VARCHAR(255) NULL COMMENT '客户名称快照', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID快照', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', sku_code VARCHAR(128) NULL COMMENT '异常货物SKU', package_count INT NULL COMMENT '异常箱数', return_direction VARCHAR(32) NULL COMMENT '退回方向', return_logistics_no VARCHAR(128) NULL COMMENT '退回物流单号', handling_action VARCHAR(500) NULL COMMENT '异常处理措施', handling_result VARCHAR(2000) NULL COMMENT '异常处理结果', evidence_file_ids_json JSON NULL COMMENT '异常处理证据文件ID列表', inventory_adjustment_id BIGINT NULL COMMENT '退回库存恢复操作ID', handler_id VARCHAR(128) NULL COMMENT '处理人ID', handler_name VARCHAR(128) NULL COMMENT '处理人名称', source_type VARCHAR(32) NOT NULL DEFAULT 'MANUAL' COMMENT '异常来源类型', created_by VARCHAR(128) NULL COMMENT '创建人ID', exception_at DATETIME(3) NOT NULL COMMENT '异常发生时间', completed_at DATETIME(3) NULL COMMENT '异常处理完成时间', version BIGINT NOT NULL DEFAULT 0 COMMENT '异常订单乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_exception_no(customer_id,exception_no), UNIQUE KEY uk_ll_exception_delivery_return(customer_id,delivery_order_id,exception_type), KEY idx_ll_exception_list(customer_id,status,exception_at), KEY idx_ll_exception_tail(customer_id,last_mile_order_no), KEY idx_ll_exception_inbound(customer_id,inbound_code) ) ENGINE=InnoDB COMMENT='海外仓异常订单'; CREATE TABLE IF NOT EXISTS ll_exception_return_item ( id BIGINT NOT NULL COMMENT '异常退回明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', exception_order_id BIGINT NOT NULL COMMENT '异常订单ID', outbound_pallet_item_id BIGINT NOT NULL COMMENT '原出库托盘明细ID', inventory_position_id BIGINT NOT NULL COMMENT '原出库库存位置ID', pallet_no VARCHAR(128) NULL COMMENT '原出库托盘码快照', sku_code VARCHAR(128) NULL COMMENT '原出库SKU快照', max_return_packages BIGINT NOT NULL COMMENT '原出库可退箱数上限', approved_return_packages BIGINT NOT NULL COMMENT '批准退回箱数', created_at DATETIME(3) NOT NULL COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_exception_return_source(customer_id,exception_order_id,outbound_pallet_item_id,inventory_position_id), KEY idx_ll_exception_return_order(customer_id,exception_order_id) ) ENGINE=InnoDB COMMENT='异常退回原出库库存冻结明细'; CREATE TABLE IF NOT EXISTS ll_exception_order_command ( id BIGINT NOT NULL COMMENT '异常处理命令ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', exception_order_id BIGINT NOT NULL COMMENT '异常订单ID', action VARCHAR(32) NOT NULL COMMENT '异常处理动作', idempotency_key VARCHAR(255) NOT NULL COMMENT '幂等键', request_hash VARCHAR(64) NOT NULL COMMENT '请求内容SHA256哈希', result_json JSON NOT NULL COMMENT '命令结果快照', created_at DATETIME(3) NOT NULL COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_exception_command_key(customer_id,action,idempotency_key), KEY idx_ll_exception_command_order(customer_id,exception_order_id,created_at) ) ENGINE=InnoDB COMMENT='异常处理命令幂等审计'; CREATE TABLE IF NOT EXISTS ll_customer_visit ( id BIGINT NOT NULL COMMENT '客户回访记录ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', delivery_order_id BIGINT NOT NULL COMMENT '关联派送单ID', delivery_no VARCHAR(64) NOT NULL COMMENT '关联派送单号', customer_name VARCHAR(255) NULL COMMENT '客户名称快照', contact_name VARCHAR(128) NULL COMMENT '客户联系人姓名快照', contact_phone VARCHAR(64) NULL COMMENT '客户联系人电话快照', destination VARCHAR(500) NULL COMMENT '派送目的仓编码汇总快照', delivery_completed_at DATETIME(3) NOT NULL COMMENT '派送完成时间', status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '回访状态:PENDING待回访或COMPLETED已回访', selected_last_mile_order_id BIGINT NULL COMMENT '本次回访选择的尾程订单ID', selected_last_mile_order_no VARCHAR(64) NULL COMMENT '本次回访选择的尾程订单号', selected_inbound_order_id BIGINT NULL COMMENT '本次回访选择的入仓单ID', selected_inbound_code VARCHAR(128) NULL COMMENT '本次回访选择的入仓码', visit_result VARCHAR(32) NULL COMMENT '最近一次回访结果', customer_feedback VARCHAR(2000) NULL COMMENT '最近一次客户反馈', remark VARCHAR(1000) NULL COMMENT '最近一次回访备注', attachment_json JSON NULL COMMENT '当前回访资料文件元数据列表', visited_by VARCHAR(128) NULL COMMENT '最近一次回访操作人ID', visited_at DATETIME(3) NULL COMMENT '最近一次回访时间', visit_count 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_customer_visit_delivery(customer_id,delivery_order_id), KEY idx_ll_customer_visit_list(customer_id,status,delivery_completed_at), KEY idx_ll_customer_visit_delivery_no(customer_id,delivery_no) ) ENGINE=InnoDB COMMENT='派送单维度客户回访记录'; CREATE TABLE IF NOT EXISTS ll_security_event_inbox ( event_id VARCHAR(64) NOT NULL COMMENT '跨区安全事件ID', event_type VARCHAR(96) NOT NULL COMMENT 'IAM安全事件类型', payload_hash CHAR(64) NOT NULL COMMENT '规范化载荷SHA-256哈希', payload_json JSON NOT NULL COMMENT '冻结事件载荷JSON', status VARCHAR(16) NOT NULL COMMENT '消费状态:RECEIVED或PROCESSED', result VARCHAR(32) NULL COMMENT '处理结果:APPLIED、STALE、DUPLICATE或DUPLICATE_VERSION', received_at DATETIME(3) NOT NULL COMMENT '接收时间', processed_at DATETIME(3) NULL COMMENT '处理完成时间', PRIMARY KEY (event_id), KEY idx_security_inbox_type_time (event_type,received_at) ) ENGINE=InnoDB COMMENT='海外IAM安全事件消费者收件箱'; CREATE TABLE IF NOT EXISTS ll_security_projection ( aggregate_type VARCHAR(32) NOT NULL COMMENT '聚合类型:USER、TENANT或AUTHORIZATION', aggregate_id VARCHAR(64) NOT NULL COMMENT '用户或客户聚合ID', tenant_id BIGINT NOT NULL COMMENT '平台0或客户ID', security_status VARCHAR(24) NULL COMMENT '当前安全状态:ACTIVE或DISABLED', permission_version BIGINT NULL COMMENT '当前单调权限版本', roles_json JSON NOT NULL COMMENT 'IAM投影的当前角色快照', authorities_json JSON NOT NULL COMMENT 'IAM投影的当前海外权限快照', aggregate_version BIGINT NOT NULL COMMENT '事件聚合单调版本', payload_hash CHAR(64) NOT NULL COMMENT '当前版本载荷哈希', last_event_id VARCHAR(64) NOT NULL COMMENT '最后应用的事件ID', changed_at DATETIME(3) NOT NULL COMMENT '国内IAM事实发生时间', updated_at DATETIME(3) NOT NULL COMMENT '投影更新时间', PRIMARY KEY (aggregate_type,aggregate_id), KEY idx_security_projection_tenant (tenant_id), KEY idx_security_projection_permission (aggregate_id,permission_version) ) ENGINE=InnoDB COMMENT='海外IAM安全状态与权限版本投影'; -- 收敛尚未具备授权快照字段的开发/测试库,CREATE TABLE IF NOT EXISTS 不会补充已存在表的字段。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_security_projection' AND column_name='roles_json'), 'SELECT 1', 'ALTER TABLE ll_security_projection ADD COLUMN roles_json JSON NULL COMMENT ''IAM投影的当前角色快照'' AFTER permission_version')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_security_projection' AND column_name='authorities_json'), 'SELECT 1', 'ALTER TABLE ll_security_projection ADD COLUMN authorities_json JSON NULL COMMENT ''IAM投影的当前海外权限快照'' AFTER roles_json')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; UPDATE ll_security_projection SET roles_json=JSON_ARRAY() WHERE roles_json IS NULL; UPDATE ll_security_projection SET authorities_json=JSON_ARRAY() WHERE authorities_json IS NULL; ALTER TABLE ll_security_projection MODIFY COLUMN roles_json JSON NOT NULL COMMENT 'IAM投影的当前角色快照', MODIFY COLUMN authorities_json JSON NOT NULL COMMENT 'IAM投影的当前海外权限快照'; -- 空库基线固定管理员必须携带当前海外授权快照;后续真实 IAM 事件从 aggregate_version=1 单调覆盖该 version=0 投影。 SET @platform_admin_overseas_roles = JSON_ARRAY('PLATFORM_ADMIN'); SET @platform_admin_overseas_authorities = JSON_ARRAY( 'platform:overseas-warehouse:warehouse-transfer:approve', 'platform:finance:bill:adjust', 'platform:finance:bill:update', 'platform:finance:bill:void', 'platform:finance:cost:create', 'platform:finance:cost:view', 'platform:finance:customer-account:adjust', 'platform:finance:customer-account:export', 'platform:finance:customer-account:list', 'platform:finance:customer-arap:export', 'platform:finance:customer-arap:list', 'platform:finance:customer-statement:export', 'platform:finance:customer-statement:list', 'platform:finance:customer-terms:update', 'platform:finance:customer-terms:view', 'platform:finance:fee-source:edit', 'platform:finance:fee-source:review', 'platform:finance:payment:create', 'platform:finance:receipt:create', 'platform:finance:receipt:view', 'platform:finance:receivable-statistics:export', 'platform:finance:receivable-statistics:list', 'platform:finance:recharge:review', 'platform:finance:reconciliation:adjust', 'platform:finance:reconciliation:create', 'platform:finance:reconciliation:issue', 'platform:finance:reconciliation:review', 'platform:finance:reconciliation:void', 'platform:finance:settlement-ap:create', 'platform:finance:settlement-ap:export', 'platform:finance:settlement-ap:list', 'platform:finance:settlement-ar:create', 'platform:finance:settlement-ar:export', 'platform:finance:settlement-ar:list', 'platform:finance:settlement:void', 'platform:overseas-business:looseboard:create', 'platform:overseas-business:looseboard:edit', 'platform:overseas-business:looseboard:list', 'platform:overseas-business:looseboard:status', 'platform:overseas-business:purchase:edit', 'platform:overseas-business:purchase:list', 'platform:overseas-business:purchase:review', 'platform:overseas-business:truck:create', 'platform:overseas-business:truck:edit', 'platform:overseas-business:truck:list', 'platform:overseas-business:truck:status', 'platform:overseas-master-data:exchange-rate:create', 'platform:overseas-master-data:exchange-rate:edit', 'platform:overseas-master-data:exchange-rate:export', 'platform:overseas-master-data:exchange-rate:list', 'platform:overseas-master-data:exchange-rate:status', 'platform:overseas-master-data:quote:create', 'platform:overseas-master-data:quote:edit', 'platform:overseas-master-data:quote:export', 'platform:overseas-master-data:quote:list', 'platform:overseas-master-data:quote:status', 'platform:overseas-master-data:vehicle:create', 'platform:overseas-master-data:vehicle:edit', 'platform:overseas-master-data:vehicle:export', 'platform:overseas-master-data:vehicle:list', 'platform:overseas-master-data:vehicle:status', 'platform:overseas-warehouse:customer-visit:edit', 'platform:overseas-warehouse:customer-visit:list', 'platform:overseas-warehouse:delivery:documents', 'platform:overseas-warehouse:delivery:list', 'platform:overseas-warehouse:delivery:return', 'platform:overseas-warehouse:delivery:status', 'platform:overseas-warehouse:dispatch:cancel', 'platform:overseas-warehouse:dispatch:edit', 'platform:overseas-warehouse:dispatch:list', 'platform:overseas-warehouse:dispatch:transfer-delivery', 'platform:overseas-warehouse:exception-order:create', 'platform:overseas-warehouse:exception-order:list', 'platform:overseas-warehouse:exception-order:process', 'platform:overseas-warehouse:inbound-order:create', 'platform:overseas-warehouse:inbound-order:edit', 'platform:overseas-warehouse:inbound-order:fba-appointment', 'platform:overseas-warehouse:inbound-order:list', 'platform:overseas-warehouse:inbound-order:smart-dispatch', 'platform:overseas-warehouse:inventory:adjust', 'platform:overseas-warehouse:inventory:edit', 'platform:overseas-warehouse:inventory:export', 'platform:overseas-warehouse:inventory:list', 'platform:overseas-warehouse:last-mile-order:edit', 'platform:overseas-warehouse:last-mile-order:export', 'platform:overseas-warehouse:last-mile-order:list', 'platform:overseas-warehouse:location:create', 'platform:overseas-warehouse:location:delete', 'platform:overseas-warehouse:location:edit', 'platform:overseas-warehouse:location:list', 'platform:overseas-warehouse:outbound:cancel', 'platform:overseas-warehouse:outbound:create', 'platform:overseas-warehouse:outbound:list', 'platform:overseas-warehouse:pallet:create', 'platform:overseas-warehouse:pallet:delete', 'platform:overseas-warehouse:pallet:edit', 'platform:overseas-warehouse:pallet:list', 'platform:overseas-warehouse:relabel-order:create', 'platform:overseas-warehouse:relabel-order:list', 'platform:overseas-warehouse:relabel-order:status', 'platform:overseas-warehouse:return-cartons:list', 'platform:overseas-warehouse:return-inventory:list', 'platform:overseas-warehouse:warehouse:create', 'platform:overseas-warehouse:warehouse:edit', 'platform:overseas-warehouse:warehouse:list', 'platform:overseas-warehouse:warehouse:status' ); INSERT IGNORE INTO ll_security_projection ( aggregate_type,aggregate_id,tenant_id,security_status,permission_version,roles_json,authorities_json,aggregate_version, payload_hash,last_event_id,changed_at,updated_at ) VALUES ('USER','1000001',0,'ACTIVE',0,JSON_ARRAY(),JSON_ARRAY(),0,SHA2('lastleg-baseline:platform_admin:USER:0',256), 'baseline-platform-admin-user-v0','1970-01-01 00:00:00.000','1970-01-01 00:00:00.000'), ('AUTHORIZATION','1000001',0,NULL,0,@platform_admin_overseas_roles,@platform_admin_overseas_authorities,0, SHA2('lastleg-baseline:platform_admin:AUTHORIZATION:0:current-authorities',256), 'baseline-platform-admin-authorization-v0','1970-01-01 00:00:00.000','1970-01-01 00:00:00.000'); UPDATE ll_security_projection SET roles_json=@platform_admin_overseas_roles, authorities_json=@platform_admin_overseas_authorities, payload_hash=SHA2('lastleg-baseline:platform_admin:AUTHORIZATION:0:current-authorities',256), updated_at=CURRENT_TIMESTAMP(3) WHERE aggregate_type='AUTHORIZATION' AND aggregate_id='1000001' AND tenant_id=0 AND aggregate_version=0 AND last_event_id='baseline-platform-admin-authorization-v0'; CREATE TABLE IF NOT EXISTS ll_wallet_event_inbox ( event_id VARCHAR(64) NOT NULL COMMENT '国内Finance资金结果事件ID', command_event_id VARCHAR(64) NOT NULL COMMENT '原海外资金指令事件ID', payload_hash VARCHAR(71) NOT NULL COMMENT '规范化载荷SHA-256,包含sha256:前缀', payload_json JSON NOT NULL COMMENT '冻结事件信封', status VARCHAR(16) NOT NULL COMMENT 'RECEIVED或PROCESSED', received_at DATETIME(3) NOT NULL COMMENT '接收时间', processed_at DATETIME(3) NULL COMMENT '处理完成时间', PRIMARY KEY (event_id), UNIQUE KEY uk_ll_wallet_command_result (command_event_id), KEY idx_ll_wallet_event_status (status,received_at) ) ENGINE=InnoDB COMMENT='跨区客户资金结果幂等收件箱'; CREATE TABLE IF NOT EXISTS ll_procurement_daily_sequence ( customer_id VARCHAR(128) NOT NULL COMMENT '客户ID', business_date DATE NOT NULL COMMENT '北京时间业务日期', sequence_value INT NOT NULL COMMENT '客户当日已分配最大序号', PRIMARY KEY (customer_id,business_date), CONSTRAINT chk_ll_procurement_sequence CHECK (sequence_value BETWEEN 1 AND 9999) ) ENGINE=InnoDB COMMENT='海外采购客户日序列'; CREATE TABLE IF NOT EXISTS ll_overseas_procurement_file ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID', category VARCHAR(16) NOT NULL COMMENT 'RECEIPT签收文件或VOUCHER费用凭证', file_id BIGINT NOT NULL COMMENT 'File服务文件ID', file_name VARCHAR(255) NOT NULL COMMENT '文件名快照', content_type VARCHAR(128) NULL COMMENT '媒体类型', size_bytes BIGINT NOT NULL DEFAULT 0 COMMENT '文件大小', created_by VARCHAR(128) NULL COMMENT '上传人', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '上传时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_procurement_file(order_id,file_id), KEY idx_ll_procurement_file_order(customer_id,order_id,category,created_at), CONSTRAINT chk_ll_procurement_file_category CHECK(category IN ('RECEIPT','VOUCHER')) ) ENGINE=InnoDB COMMENT='海外采购签收文件及费用凭证'; CREATE TABLE IF NOT EXISTS ll_overseas_procurement_fee ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID', fee_no VARCHAR(64) NOT NULL COMMENT '费用业务号', fee_item_code VARCHAR(32) NOT NULL COMMENT '费用项编码', fee_item_name VARCHAR(128) NOT NULL COMMENT '费用项名称', amount DECIMAL(20,2) NOT NULL COMMENT 'CNY金额', currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '费用币种', voucher_file_id BIGINT NOT NULL COMMENT '凭证文件ID', voucher_file_name VARCHAR(255) NOT NULL COMMENT '凭证文件名', remark VARCHAR(500) NULL COMMENT '说明', wallet_status VARCHAR(32) NOT NULL COMMENT '资金状态', wallet_error_code VARCHAR(64) NULL COMMENT '资金错误码', wallet_error_message VARCHAR(500) NULL COMMENT '资金错误说明', wallet_command_event_id VARCHAR(64) NULL COMMENT '当前资金指令事件ID', created_by VARCHAR(128) 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_procurement_fee_no(fee_no), KEY idx_ll_procurement_fee_order(customer_id,order_id,created_at), CONSTRAINT chk_ll_procurement_fee_amount CHECK(amount>0), CONSTRAINT chk_ll_procurement_fee_currency CHECK(currency='CNY') ) ENGINE=InnoDB COMMENT='海外采购费用明细及资金生命周期'; CREATE TABLE IF NOT EXISTS ll_destuff_pallet_cost ( id BIGINT NOT NULL COMMENT '主键ID', source_container_booking_id VARCHAR(128) NOT NULL COMMENT '来源柜次业务ID', container_no VARCHAR(64) NOT NULL COMMENT '集装箱号', warehouse_id BIGINT NULL COMMENT '海外仓ID', pallet_count INT NOT NULL COMMENT '实际打托数', total_actual_volume_cbm DECIMAL(20,6) NOT NULL COMMENT '客户实收总体积', total_cost DECIMAL(20,2) NOT NULL COMMENT '打托总成本', currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '成本币种', status VARCHAR(16) NOT NULL COMMENT '生成状态', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_destuff_cost_booking(source_container_booking_id), CONSTRAINT chk_ll_destuff_cost CHECK(pallet_count>0 AND total_actual_volume_cbm>0 AND total_cost>0 AND currency='CNY') ) ENGINE=InnoDB COMMENT='拆柜打托实际成本汇总'; CREATE TABLE IF NOT EXISTS ll_destuff_pallet_cost_allocation ( id BIGINT NOT NULL COMMENT '主键ID', cost_id BIGINT NOT NULL COMMENT '打托成本汇总ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID', actual_volume_cbm DECIMAL(20,6) NOT NULL COMMENT '客户实收体积', allocated_amount DECIMAL(20,2) NOT NULL COMMENT '客户分摊金额', fee_source_id BIGINT NOT NULL COMMENT '海外费用来源ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_destuff_customer(cost_id,customer_id), UNIQUE KEY uk_ll_destuff_fee_source(fee_source_id), CONSTRAINT chk_ll_destuff_allocation CHECK(actual_volume_cbm>0 AND allocated_amount>=0) ) ENGINE=InnoDB COMMENT='拆柜打托成本按客户实收体积分摊'; -- 客户退货预报、PDA 签收与仓储费起算批次 CREATE TABLE IF NOT EXISTS ll_return_order ( -- need_relabel is added below for existing deployments id BIGINT NOT NULL COMMENT '退货订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', return_no VARCHAR(128) NOT NULL COMMENT '退货订单号', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '操作海外仓ID', warehouse_contact_name VARCHAR(128) NULL COMMENT '中转仓联系人快照', warehouse_contact_phone VARCHAR(64) NULL COMMENT '中转仓联系电话快照', customer_reference_no VARCHAR(128) NULL COMMENT '客户参考号', lastleg_order_id BIGINT NULL COMMENT '尾程订单ID', lastleg_order_no VARCHAR(32) NULL COMMENT '尾程订单号', status VARCHAR(32) NOT NULL COMMENT 'PENDING_RECEIPT、PARTIALLY_RECEIVED或COMPLETED', expected_sku_types INT NOT NULL COMMENT '预报SKU种类数', expected_quantity BIGINT NOT NULL COMMENT '预报总数量', received_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '累计实收总数量', remark VARCHAR(1000) NULL COMMENT '客户备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '创建幂等键', request_hash CHAR(64) NOT NULL COMMENT '创建请求SHA-256', created_by VARCHAR(128) NULL COMMENT '创建操作人ID', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_order_customer_no(customer_id,return_no), UNIQUE KEY uk_ll_return_order_customer_key(customer_id,idempotency_key), KEY idx_ll_return_order_warehouse_status(overseas_warehouse_id,status,created_at), CONSTRAINT chk_ll_return_order_quantity CHECK(expected_sku_types>0 AND expected_quantity>0 AND received_quantity>=0 AND received_quantity<=expected_quantity) ) ENGINE=InnoDB COMMENT='客户退货订单及SKU实收汇总'; SET @ll_return_order_need_relabel = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='need_relabel'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN need_relabel TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否需要换标'' AFTER customer_reference_no')); PREPARE stmt FROM @ll_return_order_need_relabel; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='lastleg_order_id'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN lastleg_order_id BIGINT NULL COMMENT ''尾程订单ID'' AFTER customer_reference_no')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='lastleg_order_no'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN lastleg_order_no VARCHAR(32) NULL COMMENT ''尾程订单号'' AFTER lastleg_order_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='warehouse_contact_name'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN warehouse_contact_name VARCHAR(128) NULL COMMENT ''中转仓联系人快照'' AFTER overseas_warehouse_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='warehouse_contact_phone'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN warehouse_contact_phone VARCHAR(64) NULL COMMENT ''中转仓联系电话快照'' AFTER warehouse_contact_name')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='relabel_application_id'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN relabel_application_id BIGINT NULL COMMENT ''绑定换标申请单ID'' AFTER need_relabel')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='relabel_no'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN relabel_no VARCHAR(64) NULL COMMENT ''绑定换标单号'' AFTER relabel_application_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='relabel_status'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN relabel_status VARCHAR(32) NULL COMMENT ''换标状态'' AFTER relabel_no')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_return_order_item ( id BIGINT NOT NULL COMMENT '退货预报明细ID', return_order_id BIGINT NOT NULL COMMENT '退货订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name_zh VARCHAR(255) NULL COMMENT '中文品名', expected_quantity BIGINT NOT NULL COMMENT 'SKU预报数量', received_quantity BIGINT NOT NULL DEFAULT 0 COMMENT 'SKU累计实收数量', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_item_order_sku(return_order_id,sku_code), KEY idx_ll_return_item_sku(sku_code,received_quantity), CONSTRAINT chk_ll_return_item_quantity CHECK(expected_quantity>0 AND received_quantity>=0 AND received_quantity<=expected_quantity) ) ENGINE=InnoDB COMMENT='客户退货订单的SKU预报与实收明细'; CREATE TABLE IF NOT EXISTS ll_return_receipt ( id BIGINT NOT NULL COMMENT 'PDA退货签收单ID', return_order_id BIGINT NOT NULL COMMENT '退货订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', receipt_no VARCHAR(128) NOT NULL COMMENT '签收单号', receipt_batch_no VARCHAR(128) NOT NULL COMMENT '签收批次号', tracking_no VARCHAR(128) NULL COMMENT '本次签收包裹的可选快递单号', bound_by VARCHAR(16) NOT NULL COMMENT '开始签收方式,RETURN_NO退货单号或SKU候选', status VARCHAR(32) NOT NULL COMMENT '签收状态,当前SIGNED', received_quantity BIGINT NOT NULL COMMENT '本次实收数量', operator_id VARCHAR(128) NOT NULL COMMENT 'PDA操作人ID', operator_name VARCHAR(128) NULL COMMENT 'PDA操作人名称', idempotency_key VARCHAR(255) NOT NULL COMMENT 'PDA确认幂等键', request_hash CHAR(64) NOT NULL COMMENT 'PDA确认请求SHA-256', signed_at DATETIME(3) NOT NULL COMMENT '签收时间', created_at DATETIME(3) NOT NULL COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_receipt_no(receipt_no), UNIQUE KEY uk_ll_return_receipt_batch(receipt_batch_no), UNIQUE KEY uk_ll_return_receipt_operator_key(operator_id,idempotency_key), KEY idx_ll_return_receipt_order(return_order_id,signed_at), CONSTRAINT chk_ll_return_receipt_quantity CHECK(received_quantity>0), CONSTRAINT chk_ll_return_receipt_bound CHECK(bound_by IN('RETURN_NO','SKU')) ) ENGINE=InnoDB COMMENT='PDA退货实收签收事实'; -- 已创建开发库升级为“客户只预报 SKU,快递单号仅属于签收批次”的最终模型。 SET @ll_return_item_drop_tracking_order_sku = (SELECT IF(COUNT(*) > 0, 'ALTER TABLE ll_return_order_item DROP INDEX uk_ll_return_item_order_tracking_sku', 'SELECT 1') FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_return_order_item' AND index_name='uk_ll_return_item_order_tracking_sku'); PREPARE ll_return_item_drop_tracking_order_sku_stmt FROM @ll_return_item_drop_tracking_order_sku; EXECUTE ll_return_item_drop_tracking_order_sku_stmt; DEALLOCATE PREPARE ll_return_item_drop_tracking_order_sku_stmt; SET @ll_return_item_drop_tracking = (SELECT IF(COUNT(*) > 0, 'ALTER TABLE ll_return_order_item DROP INDEX idx_ll_return_item_tracking', 'SELECT 1') FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_return_order_item' AND index_name='idx_ll_return_item_tracking'); PREPARE ll_return_item_drop_tracking_stmt FROM @ll_return_item_drop_tracking; EXECUTE ll_return_item_drop_tracking_stmt; DEALLOCATE PREPARE ll_return_item_drop_tracking_stmt; SET @ll_return_item_drop_order = (SELECT IF(COUNT(*) > 0, 'ALTER TABLE ll_return_order_item DROP INDEX idx_ll_return_item_order', 'SELECT 1') FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_return_order_item' AND index_name='idx_ll_return_item_order'); PREPARE ll_return_item_drop_order_stmt FROM @ll_return_item_drop_order; EXECUTE ll_return_item_drop_order_stmt; DEALLOCATE PREPARE ll_return_item_drop_order_stmt; SET @ll_return_item_drop_tracking_no = (SELECT IF(COUNT(*) > 0, 'ALTER TABLE ll_return_order_item DROP COLUMN tracking_no', 'SELECT 1') FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order_item' AND column_name='tracking_no'); PREPARE ll_return_item_drop_tracking_no_stmt FROM @ll_return_item_drop_tracking_no; EXECUTE ll_return_item_drop_tracking_no_stmt; DEALLOCATE PREPARE ll_return_item_drop_tracking_no_stmt; SET @ll_return_item_add_order_sku = (SELECT IF(COUNT(*) = 0, 'ALTER TABLE ll_return_order_item ADD UNIQUE KEY uk_ll_return_item_order_sku(return_order_id,sku_code)', 'SELECT 1') FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_return_order_item' AND index_name='uk_ll_return_item_order_sku'); PREPARE ll_return_item_add_order_sku_stmt FROM @ll_return_item_add_order_sku; EXECUTE ll_return_item_add_order_sku_stmt; DEALLOCATE PREPARE ll_return_item_add_order_sku_stmt; SET @ll_return_item_add_sku_idx = (SELECT IF(COUNT(*) = 0, 'ALTER TABLE ll_return_order_item ADD KEY idx_ll_return_item_sku(sku_code,received_quantity)', 'SELECT 1') FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_return_order_item' AND index_name='idx_ll_return_item_sku'); PREPARE ll_return_item_add_sku_idx_stmt FROM @ll_return_item_add_sku_idx; EXECUTE ll_return_item_add_sku_idx_stmt; DEALLOCATE PREPARE ll_return_item_add_sku_idx_stmt; UPDATE ll_return_receipt SET bound_by='RETURN_NO' WHERE bound_by='TRACKING'; SET @ll_return_receipt_drop_bound_check = (SELECT IF(COUNT(*) > 0, 'ALTER TABLE ll_return_receipt DROP CHECK chk_ll_return_receipt_bound', 'SELECT 1') FROM information_schema.table_constraints WHERE constraint_schema=DATABASE() AND table_name='ll_return_receipt' AND constraint_name='chk_ll_return_receipt_bound'); PREPARE ll_return_receipt_drop_bound_check_stmt FROM @ll_return_receipt_drop_bound_check; EXECUTE ll_return_receipt_drop_bound_check_stmt; DEALLOCATE PREPARE ll_return_receipt_drop_bound_check_stmt; SET @ll_return_receipt_alter = 'ALTER TABLE ll_return_receipt MODIFY COLUMN tracking_no VARCHAR(128) NULL COMMENT ''本次签收包裹的可选快递单号'', MODIFY COLUMN bound_by VARCHAR(16) NOT NULL COMMENT ''开始签收方式,RETURN_NO退货单号或SKU候选'', ADD CONSTRAINT chk_ll_return_receipt_bound CHECK(bound_by IN(''RETURN_NO'',''SKU''))'; PREPARE ll_return_receipt_alter_stmt FROM @ll_return_receipt_alter; EXECUTE ll_return_receipt_alter_stmt; DEALLOCATE PREPARE ll_return_receipt_alter_stmt; CREATE TABLE IF NOT EXISTS ll_return_receipt_item ( id BIGINT NOT NULL COMMENT '签收SKU明细ID', receipt_id BIGINT NOT NULL COMMENT 'PDA退货签收单ID', return_order_item_id BIGINT NOT NULL COMMENT '退货预报明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', received_quantity BIGINT NOT NULL COMMENT '本次SKU实收数量', PRIMARY KEY(id), KEY idx_ll_return_receipt_item_receipt(receipt_id), KEY idx_ll_return_receipt_item_order_item(return_order_item_id), CONSTRAINT chk_ll_return_receipt_item_quantity CHECK(received_quantity>0) ) ENGINE=InnoDB COMMENT='PDA退货签收SKU实际数量明细'; CREATE TABLE IF NOT EXISTS ll_return_receipt_batch ( id BIGINT NOT NULL COMMENT '退货仓储计费批次ID', return_order_id BIGINT NOT NULL COMMENT '退货订单ID', receipt_id BIGINT NOT NULL COMMENT 'PDA退货签收单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', batch_no VARCHAR(128) NOT NULL COMMENT '签收批次号', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '操作海外仓ID', storage_billing_status VARCHAR(32) NOT NULL COMMENT '仓储计费状态,初始PENDING_PRICING', storage_started_at DATETIME(3) NOT NULL COMMENT '仓储计费起算时间', created_at DATETIME(3) NOT NULL COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_batch_no(batch_no), UNIQUE KEY uk_ll_return_batch_receipt(receipt_id), KEY idx_ll_return_batch_billing(customer_id,overseas_warehouse_id,storage_billing_status,storage_started_at) ) ENGINE=InnoDB COMMENT='每次退货签收生成的仓储费起算批次'; -- 退货库存:签收即生成箱号,库存按客户、海外仓和SKU汇总;箱内明细保留给合箱与箱唛。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_receipt' AND column_name='carton_mark'), 'SELECT 1', 'ALTER TABLE ll_return_receipt ADD COLUMN carton_mark VARCHAR(128) NULL COMMENT ''签收生成或绑定的退货箱号'' AFTER receipt_batch_no')); PREPARE return_receipt_carton_mark_stmt FROM @ddl; EXECUTE return_receipt_carton_mark_stmt; DEALLOCATE PREPARE return_receipt_carton_mark_stmt; CREATE TABLE IF NOT EXISTS ll_return_inventory_carton ( new_carton_mark VARCHAR(255) NULL COMMENT '换标后新箱唛', id BIGINT NOT NULL COMMENT '退货库存箱ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', source_receipt_id BIGINT NULL COMMENT '来源PDA签收单ID', source_batch_no VARCHAR(128) NULL COMMENT '来源签收批次号', carton_mark VARCHAR(128) NOT NULL COMMENT '退货箱号和箱唛编码', status VARCHAR(32) NOT NULL COMMENT 'AVAILABLE可用或MERGED已合箱', sku_types INT NOT NULL COMMENT '箱内SKU种类数', total_quantity BIGINT NOT NULL COMMENT '箱内总件数', length DECIMAL(12,3) NULL COMMENT '箱长CM', width DECIMAL(12,3) NULL COMMENT '箱宽CM', height DECIMAL(12,3) NULL COMMENT '箱高CM', weight DECIMAL(12,3) NULL COMMENT '箱重KG', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', merged_at DATETIME(3) NULL COMMENT '合箱完成时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_carton_mark(carton_mark), UNIQUE KEY uk_ll_return_inventory_carton_receipt(source_receipt_id), KEY idx_ll_return_inventory_carton_customer(customer_id,overseas_warehouse_id,status,created_at), CONSTRAINT chk_ll_return_inventory_carton_quantity CHECK((status IN('AVAILABLE','OUTBOUNDED') AND sku_types>0 AND total_quantity>0) OR (status='MERGED' AND sku_types=0 AND total_quantity=0)), CONSTRAINT chk_ll_return_inventory_carton_status CHECK(status IN('AVAILABLE','MERGED','OUTBOUNDED')) ) ENGINE=InnoDB COMMENT='退货实物库存箱及箱唛'; -- 已合箱的来源箱保留审计记录,但其箱内库存必须归零;动态 SQL 兼容 Spring 的数据库初始化器。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND constraint_name='chk_ll_return_inventory_carton_quantity'), 'ALTER TABLE ll_return_inventory_carton DROP CHECK chk_ll_return_inventory_carton_quantity', 'SELECT 1')); PREPARE return_inventory_carton_check_drop_stmt FROM @ddl; EXECUTE return_inventory_carton_check_drop_stmt; DEALLOCATE PREPARE return_inventory_carton_check_drop_stmt; ALTER TABLE ll_return_inventory_carton ADD CONSTRAINT chk_ll_return_inventory_carton_quantity CHECK((status IN('AVAILABLE','OUTBOUNDED') AND sku_types>0 AND total_quantity>0) OR (status='MERGED' AND sku_types=0 AND total_quantity=0)); SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND constraint_name='chk_ll_return_inventory_carton_status'), 'ALTER TABLE ll_return_inventory_carton DROP CHECK chk_ll_return_inventory_carton_status', 'SELECT 1')); PREPARE return_inventory_carton_status_drop_stmt FROM @ddl; EXECUTE return_inventory_carton_status_drop_stmt; DEALLOCATE PREPARE return_inventory_carton_status_drop_stmt; ALTER TABLE ll_return_inventory_carton ADD CONSTRAINT chk_ll_return_inventory_carton_status CHECK(status IN('AVAILABLE','MERGED','OUTBOUNDED')); SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND column_name='source_return_no'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_carton ADD COLUMN source_return_no VARCHAR(2000) NULL COMMENT ''来源退货单号'' AFTER source_batch_no')); PREPARE return_inventory_carton_return_no_stmt FROM @ddl; EXECUTE return_inventory_carton_return_no_stmt; DEALLOCATE PREPARE return_inventory_carton_return_no_stmt; ALTER TABLE ll_return_inventory_carton MODIFY COLUMN source_batch_no TEXT NULL COMMENT '实际消耗来源签收批次号,多个批次逗号分隔', MODIFY COLUMN source_return_no TEXT NULL COMMENT '实际消耗来源退货单号,多个单号逗号分隔'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND column_name='fba_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_carton ADD COLUMN fba_carton_mark VARCHAR(255) NULL COMMENT ''FBA箱唛'' AFTER carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND column_name='destination_warehouse_code'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_carton ADD COLUMN destination_warehouse_code VARCHAR(128) NULL COMMENT ''目的仓编码'' AFTER fba_carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND column_name='destination_warehouse_name'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_carton ADD COLUMN destination_warehouse_name VARCHAR(255) NULL COMMENT ''目的仓名称'' AFTER destination_warehouse_code')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND column_name='relabel_application_id'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_carton ADD COLUMN relabel_application_id BIGINT NULL COMMENT ''绑定换标申请单ID'' AFTER destination_warehouse_name')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND column_name='relabel_no'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_carton ADD COLUMN relabel_no VARCHAR(64) NULL COMMENT ''绑定换标单号'' AFTER relabel_application_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND column_name='relabel_status'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_carton ADD COLUMN relabel_status VARCHAR(32) NULL COMMENT ''换标状态'' AFTER relabel_no')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND column_name='relabel_completed_at'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_carton ADD COLUMN relabel_completed_at DATETIME(3) NULL COMMENT ''换标完成时间'' AFTER relabel_status')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_return_inventory_carton_item ( id BIGINT NOT NULL COMMENT '退货库存箱SKU明细ID', carton_id BIGINT NOT NULL COMMENT '退货库存箱ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name_zh VARCHAR(255) NULL COMMENT '中文品名', quantity BIGINT NOT NULL COMMENT '该SKU箱内数量', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_carton_item(carton_id,sku_code), KEY idx_ll_return_inventory_carton_item_customer(customer_id,sku_code), CONSTRAINT chk_ll_return_inventory_carton_item_quantity CHECK(quantity>0) ) ENGINE=InnoDB COMMENT='退货库存箱内SKU和数量'; CREATE TABLE IF NOT EXISTS ll_return_inventory_balance ( id BIGINT NOT NULL COMMENT '退货库存余额ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name_zh VARCHAR(255) NULL COMMENT '中文品名', total_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '实物总库存,仅实际出库扣减', available_quantity BIGINT NOT NULL COMMENT '未合箱可用上架数量', carton_quantity BIGINT NOT NULL COMMENT '包含该SKU的可用箱数', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_balance(customer_id,overseas_warehouse_id,sku_code), CONSTRAINT chk_ll_return_inventory_balance_quantity CHECK(total_quantity>=available_quantity AND available_quantity>=0 AND carton_quantity>=0) ) ENGINE=InnoDB COMMENT='退货库存按客户海外仓SKU汇总余额'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_inventory_balance' AND column_name='total_quantity'), 'SELECT 1', 'ALTER TABLE ll_return_inventory_balance ADD COLUMN total_quantity BIGINT NULL COMMENT ''实物总库存,仅实际出库扣减'' AFTER product_name_zh')); PREPARE return_inventory_balance_total_stmt FROM @ddl; EXECUTE return_inventory_balance_total_stmt; DEALLOCATE PREPARE return_inventory_balance_total_stmt; -- 旧数据的可用量原先包含已合箱库存;升级时一次性拆分为总库存和未合箱可用库存。 UPDATE ll_return_inventory_balance b LEFT JOIN (SELECT c.customer_id,c.overseas_warehouse_id,i.sku_code,SUM(i.quantity) merged_quantity FROM ll_return_inventory_carton c JOIN ll_return_inventory_carton_item i ON i.carton_id=c.id WHERE c.source_batch_no='MERGED' GROUP BY c.customer_id,c.overseas_warehouse_id,i.sku_code) m ON m.customer_id=b.customer_id AND m.overseas_warehouse_id=b.overseas_warehouse_id AND m.sku_code=b.sku_code SET b.total_quantity=b.available_quantity,b.available_quantity=GREATEST(0,b.available_quantity-COALESCE(m.merged_quantity,0)) WHERE b.total_quantity IS NULL; ALTER TABLE ll_return_inventory_balance MODIFY COLUMN total_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '实物总库存,仅实际出库扣减'; CREATE TABLE IF NOT EXISTS ll_return_inventory_operation ( id BIGINT NOT NULL COMMENT '退货库存PDA操作ID', operator_id VARCHAR(128) NOT NULL COMMENT 'PDA操作人ID', idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型,当前MERGE', result_carton_id BIGINT NULL COMMENT '合箱结果退货库存箱ID', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_operation_operator_key(operator_id,idempotency_key), KEY idx_ll_return_inventory_operation_result(result_carton_id) ) ENGINE=InnoDB COMMENT='退货库存PDA合箱幂等操作审计'; -- END INLINE EMPTY-DATABASE BASELINE: LASTLEG -- BEGIN INLINE EMPTY-DATABASE BASELINE: OVERSEAS WAREHOUSE CREATE DATABASE IF NOT EXISTS baiyue_lastlag_warehouse DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE baiyue_lastlag_warehouse; -- This script is run through warehouse-overseas-service's datasource only. -- The datasource guard requires the selected schema to be baiyue_lastlag_warehouse; -- database creation and USE are intentionally forbidden here so a miswired -- service account cannot create or switch schemas during startup. SET NAMES utf8mb4; CREATE TABLE IF NOT EXISTS wh_location ( id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)', customer_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) DEFAULT NULL COMMENT '备注', created_by BIGINT UNSIGNED DEFAULT NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_by BIGINT UNSIGNED DEFAULT NULL COMMENT '最后修改人ID', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', PRIMARY KEY (id), UNIQUE KEY uk_location_code (customer_id, warehouse_id, location_code, deleted), KEY idx_location_query (customer_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)', customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID', warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID', location_id BIGINT UNSIGNED DEFAULT NULL COMMENT '同仓库内绑定的库位ID,可为空', pallet_code VARCHAR(128) NOT NULL COMMENT '仓库内唯一托盘编码', pallet_type VARCHAR(32) NOT NULL COMMENT '托盘类型', capacity_cbm DECIMAL(18,4) NOT NULL DEFAULT 2.0000 COMMENT '托盘容量(立方米)', unit_price DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '托盘单价', status VARCHAR(20) NOT NULL DEFAULT 'IDLE' COMMENT '托盘状态:IDLE闲置、OCCUPIED占用、SCRAPPED废弃', remark VARCHAR(500) DEFAULT NULL COMMENT '备注', fba_warehouse_code VARCHAR(128) DEFAULT NULL COMMENT '所属FBA仓编码', created_by BIGINT UNSIGNED DEFAULT NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_by BIGINT UNSIGNED DEFAULT NULL COMMENT '最后修改人ID', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标记', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', PRIMARY KEY (id), UNIQUE KEY uk_pallet_code (customer_id, warehouse_id, pallet_code, deleted), KEY idx_pallet_query (customer_id, warehouse_id, status, deleted), KEY idx_pallet_location (customer_id, warehouse_id, location_id, deleted) ) ENGINE=InnoDB COMMENT='仓库托盘表:按租户和仓库维护托盘、容量、单价及状态'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='wh_pallet' AND column_name='fba_warehouse_code'), 'SELECT 1', 'ALTER TABLE wh_pallet ADD COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''所属FBA仓编码'' AFTER remark')); PREPARE pallet_fba_warehouse_stmt FROM @ddl; EXECUTE pallet_fba_warehouse_stmt; DEALLOCATE PREPARE pallet_fba_warehouse_stmt; CREATE TABLE IF NOT EXISTS wh_resource_lock ( id BIGINT UNSIGNED NOT NULL COMMENT '主键ID', customer_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 '业务记录ID', reservation_key VARCHAR(160) NOT NULL COMMENT '资源预留幂等键', status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT '资源锁状态', locked_at DATETIME(3) NOT NULL COMMENT '锁定时间', released_at DATETIME(3) DEFAULT NULL COMMENT '释放时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_resource_lock_reservation (customer_id, reservation_key), KEY idx_resource_lock_pallet (customer_id, warehouse_id, pallet_id, status), KEY idx_resource_lock_location (customer_id, warehouse_id, location_id, status), KEY idx_resource_lock_business (customer_id, business_type, business_id) ) ENGINE=InnoDB COMMENT='仓储资源锁定记录'; -- warehouse_id references the domestic warehouse-service authority. This overseas database does -- not duplicate warehouse master, address or capability tables and has no cross-database FK. -- 修复既有数据库中因历史脚本编码错误或英文初始化产生的表与字段注释。 ALTER TABLE wh_location COMMENT='仓库库位表:按租户和仓库维护库位及承重信息'; ALTER TABLE wh_location MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)', MODIFY COLUMN customer_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 '乐观锁版本号'; CREATE TABLE IF NOT EXISTS wh_pallet_business_binding ( id BIGINT NOT NULL COMMENT '主键ID', customer_id BIGINT NOT NULL COMMENT '客户租户ID', warehouse_id BIGINT NOT NULL COMMENT '仓库ID', business_type VARCHAR(32) NOT NULL COMMENT '业务类型', business_id VARCHAR(128) NOT NULL COMMENT '绑定业务记录ID', pallet_id BIGINT NOT NULL COMMENT '托盘ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_wh_pallet_binding (customer_id,warehouse_id,business_type,business_id), KEY idx_wh_pallet_binding_pallet (pallet_id) ) ENGINE=InnoDB COMMENT='托盘业务绑定关系'; CREATE TABLE IF NOT EXISTS wh_pallet_operation ( id BIGINT NOT NULL COMMENT '托盘状态操作ID', operation_key VARCHAR(128) NOT NULL COMMENT '跨服务幂等操作键', request_hash VARCHAR(128) NOT NULL COMMENT '状态变更请求摘要', warehouse_id BIGINT NOT NULL COMMENT '实际海外仓ID', pallet_id BIGINT NOT NULL COMMENT '实物托盘ID', pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照', before_status VARCHAR(20) NOT NULL COMMENT '变更前托盘状态', after_status VARCHAR(20) NOT NULL COMMENT '变更后托盘状态', before_location_id BIGINT NULL COMMENT '变更前库位ID,无库位托盘为空', after_location_id BIGINT NULL COMMENT '变更后库位ID,无库位托盘为空', before_version INT NOT NULL COMMENT '变更前托盘版本', after_version INT NOT NULL COMMENT '变更后托盘版本', operation_status VARCHAR(32) NOT NULL COMMENT '操作状态:APPLIED已应用、COMPENSATED已补偿', reason VARCHAR(500) NULL COMMENT '操作原因', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_wh_pallet_operation_key (operation_key), KEY idx_wh_pallet_operation_pallet (warehouse_id,pallet_id,created_at) ) ENGINE=InnoDB COMMENT='实物托盘状态幂等变更与补偿记录'; ALTER TABLE wh_pallet_operation MODIFY COLUMN before_location_id BIGINT NULL COMMENT '变更前库位ID,无库位托盘为空', MODIFY COLUMN after_location_id BIGINT NULL COMMENT '变更后库位ID,无库位托盘为空'; CREATE TABLE IF NOT EXISTS wh_pallet_batch ( id BIGINT NOT NULL COMMENT '批量托盘预留ID', warehouse_id BIGINT NOT NULL COMMENT '实际海外仓ID', batch_key VARCHAR(160) NOT NULL COMMENT '柜级入库计划批次稳定业务键', request_hash CHAR(64) NOT NULL COMMENT '规范化批量请求SHA-256摘要', status VARCHAR(32) NOT NULL COMMENT '批次状态:RESERVED、CONFIRMED、COMPENSATED', attempt_no INT NOT NULL DEFAULT 1 COMMENT '同批次重新预留尝试次数', confirm_command_key VARCHAR(160) NULL COMMENT '确认命令幂等键', confirm_command_hash CHAR(64) NULL COMMENT '确认命令规范化SHA-256摘要', compensate_command_key VARCHAR(160) NULL COMMENT '补偿命令幂等键', compensate_command_hash CHAR(64) NULL COMMENT '补偿命令规范化SHA-256摘要', compensate_reason VARCHAR(500) NULL COMMENT '补偿原因', confirmed_at DATETIME(3) NULL COMMENT '确认绑定时间', compensated_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_wh_pallet_batch_key (warehouse_id,batch_key), KEY idx_wh_pallet_batch_status (warehouse_id,status,updated_at) ) ENGINE=InnoDB COMMENT='柜级入库计划批量托盘预留与确认记录'; CREATE TABLE IF NOT EXISTS wh_pallet_batch_item ( id BIGINT NOT NULL COMMENT '批量托盘明细ID', batch_id BIGINT NOT NULL COMMENT '所属批量托盘预留ID', customer_id BIGINT NOT NULL COMMENT '实际占用客户ID', warehouse_id BIGINT NOT NULL COMMENT '实际海外仓ID', business_key VARCHAR(100) NOT NULL COMMENT '柜号入库计划序号组成的稳定业务键', inbound_plan_no VARCHAR(128) NOT NULL COMMENT '入库计划号快照', sequence_no INT NOT NULL COMMENT '计划内托盘序号', pallet_id BIGINT NOT NULL COMMENT '公共实物托盘ID', pallet_code VARCHAR(64) NOT NULL COMMENT '资源服务生成的规范托盘码快照', location_id BIGINT NOT NULL COMMENT '公共托盘当前预留库位ID', resource_lock_id BIGINT NOT NULL COMMENT '按客户隔离的资源锁ID', status VARCHAR(32) NOT NULL COMMENT '明细状态:RESERVED、CONFIRMED、RELEASED', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_wh_pallet_batch_item_business (customer_id,warehouse_id,business_key), UNIQUE KEY uk_wh_pallet_batch_item_sequence (batch_id,sequence_no), KEY idx_wh_pallet_batch_item_pallet (pallet_id), KEY idx_wh_pallet_batch_item_batch (batch_id,status) ) ENGINE=InnoDB COMMENT='柜级入库计划批量托盘明细与资源锁关联'; ALTER TABLE wh_pallet COMMENT='仓库托盘表:按租户和仓库维护托盘、容量、单价及状态'; ALTER TABLE wh_pallet MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '托盘ID(雪花ID)', MODIFY COLUMN customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID', MODIFY COLUMN warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID', MODIFY COLUMN location_id BIGINT UNSIGNED NULL COMMENT '同仓库内绑定的库位ID,可为空', MODIFY COLUMN pallet_code VARCHAR(128) NOT NULL COMMENT '仓库内唯一托盘编码', MODIFY COLUMN pallet_type VARCHAR(32) NOT NULL COMMENT '托盘类型', MODIFY COLUMN capacity_cbm DECIMAL(18,4) NOT NULL DEFAULT 2.0000 COMMENT '托盘容量(立方米)', MODIFY COLUMN unit_price DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '托盘单价', MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'IDLE' COMMENT '托盘状态:IDLE闲置、OCCUPIED占用、SCRAPPED废弃', MODIFY COLUMN remark VARCHAR(500) NULL COMMENT '备注', MODIFY COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT '所属FBA仓编码', 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 '乐观锁版本号'; -- END INLINE EMPTY-DATABASE BASELINE: OVERSEAS WAREHOUSE -- BEGIN UNIFIED OVERSEAS INCREMENTAL AND FINAL ASSERTIONS DELIMITER $$ CREATE PROCEDURE assert_overseas_event_bridge_schema() BEGIN IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_event_bridge_overseas' AND table_name IN ('bridge_outbox','bridge_inbox','bridge_delivery_attempt')) <> 3 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外区域初始化失败:Event Bridge 三张表未完整创建'; END IF; IF (SELECT COUNT(DISTINCT CONCAT(table_name, ':', index_name)) FROM information_schema.statistics WHERE table_schema='baiyue_event_bridge_overseas' AND ((table_name='bridge_outbox' AND index_name IN ('PRIMARY','uk_bridge_outbox_idempotency','idx_bridge_outbox_schedule')) OR (table_name='bridge_inbox' AND index_name IN ('PRIMARY','uk_bridge_inbox_idempotency','idx_bridge_inbox_consume')) OR (table_name='bridge_delivery_attempt' AND index_name IN ('PRIMARY','uk_bridge_attempt','idx_bridge_attempt_event')))) <> 9 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外区域初始化失败:Event Bridge 索引未完整创建'; END IF; END$$ DELIMITER ; CALL assert_overseas_event_bridge_schema(); DROP PROCEDURE IF EXISTS assert_overseas_event_bridge_schema; CREATE DATABASE IF NOT EXISTS baiyue_lastleg DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE baiyue_lastleg; CREATE TABLE IF NOT EXISTS ll_order_source_pallet ( id BIGINT NOT NULL COMMENT '来源托盘快照ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', source_pallet_no VARCHAR(128) NOT NULL COMMENT '头程冻结托盘码', sequence_no INT NOT NULL COMMENT '订单内稳定顺序', source_event_id VARCHAR(128) NOT NULL COMMENT '来源装柜完成事件ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_source_pallet_no(source_pallet_no), UNIQUE KEY uk_ll_source_pallet_sequence(customer_id,order_id,sequence_no), KEY idx_ll_source_pallet_order(customer_id,order_id), CONSTRAINT fk_ll_source_pallet_order FOREIGN KEY(order_id) REFERENCES ll_order(id) ) ENGINE=InnoDB COMMENT='头程交接的不可变托盘码快照'; CREATE TABLE IF NOT EXISTS ll_event_outbox ( id BIGINT NOT NULL COMMENT '事件主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', aggregate_type VARCHAR(64) NOT NULL COMMENT '聚合类型', aggregate_id VARCHAR(128) NOT NULL COMMENT '聚合标识', event_type VARCHAR(64) NOT NULL COMMENT '事件类型', event_version INT NOT NULL COMMENT '事件版本', event_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', payload_json LONGTEXT NOT NULL COMMENT '事件载荷JSON', status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '发布状态', retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数', next_retry_at DATETIME(3) NULL COMMENT '下次重试时间', published_at DATETIME(3) NULL COMMENT '发布时间', locked_at DATETIME(3) NULL COMMENT '投递租约获取时间', locked_by VARCHAR(128) NULL COMMENT '投递租约持有者', last_error VARCHAR(1000) NULL COMMENT '最后一次发布错误', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_event_outbox_key (event_key), KEY idx_ll_event_outbox_publish (status,next_retry_at,created_at) ) ENGINE=InnoDB COMMENT='尾程跨区业务事件发件箱'; CREATE TABLE IF NOT EXISTS ll_overseas_quote ( id BIGINT NOT NULL COMMENT '报价ID', name VARCHAR(128) NOT NULL COMMENT '报价名称', warehouse_id BIGINT NOT NULL COMMENT '国内平台海外合作仓ID', warehouse_code VARCHAR(64) NOT NULL COMMENT '合作仓编码快照', warehouse_name VARCHAR(128) NOT NULL COMMENT '合作仓名称快照', country_code VARCHAR(2) NOT NULL COMMENT '国家二字码快照', provider_name VARCHAR(128) NOT NULL COMMENT '报价方', currency CHAR(3) NOT NULL COMMENT '币种', effective_start DATE NOT NULL COMMENT '生效开始日期', effective_end DATE NOT NULL COMMENT '生效结束日期', version_code VARCHAR(64) NOT NULL COMMENT '业务版本号', status VARCHAR(16) NOT NULL DEFAULT 'INACTIVE' COMMENT '状态:ACTIVE/INACTIVE', remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_warehouse_provider_version (warehouse_id,provider_name,version_code), KEY idx_ll_quote_page (status,updated_at,id), KEY idx_ll_quote_effective (warehouse_id,provider_name,currency,effective_start,effective_end) ) ENGINE=InnoDB COMMENT='海外仓报价主表'; CREATE TABLE IF NOT EXISTS ll_overseas_quote_fee ( id BIGINT NOT NULL COMMENT '费用明细ID', quote_id BIGINT NOT NULL COMMENT '报价ID', sequence_no INT NOT NULL COMMENT '显示顺序', item VARCHAR(128) NOT NULL COMMENT '费用项目', billing_unit VARCHAR(64) NOT NULL COMMENT '计费单位', unit_price DECIMAL(18,4) NOT NULL COMMENT '单价', minimum_charge DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '最低收费', remark VARCHAR(500) NULL COMMENT '备注', PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_fee_sequence (quote_id,sequence_no), KEY idx_ll_quote_fee_quote (quote_id) ) ENGINE=InnoDB COMMENT='海外仓报价仓库费用'; CREATE TABLE IF NOT EXISTS ll_overseas_quote_transit_price ( id BIGINT NOT NULL COMMENT '中转价格ID', quote_id BIGINT NOT NULL COMMENT '报价ID', sequence_no INT NOT NULL COMMENT '显示顺序', fba_warehouse_code VARCHAR(64) NOT NULL COMMENT 'FBA仓编码', delivery_method VARCHAR(64) NOT NULL COMMENT '报价运输方式', estimated_miles DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '预估英里数', price DECIMAL(18,4) NOT NULL COMMENT '报价金额', minimum_charge DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '最低收费', remark VARCHAR(500) NULL COMMENT '备注', PRIMARY KEY (id), UNIQUE KEY uk_ll_quote_transit_sequence (quote_id,sequence_no), KEY idx_ll_quote_transit_quote (quote_id) ) ENGINE=InnoDB COMMENT='海外仓报价中转价格明细'; CREATE TABLE IF NOT EXISTS ll_monthly_exchange_rate ( id BIGINT NOT NULL COMMENT '月度汇率ID', rate_month CHAR(7) NOT NULL COMMENT '汇率月份,格式yyyy-MM', base_currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '基准币种', quote_currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '报价币种', usd_to_cny_average DECIMAL(18,8) NOT NULL COMMENT '美元兑人民币月平均汇率', status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态:ACTIVE/INACTIVE', remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_exchange_rate_month (rate_month), KEY idx_ll_exchange_rate_page (status,rate_month) ) ENGINE=InnoDB COMMENT='美元兑人民币月度平均汇率'; CREATE TABLE IF NOT EXISTS ll_monthly_exchange_rate_history ( id BIGINT NOT NULL COMMENT '汇率变更历史ID', exchange_rate_id BIGINT NOT NULL COMMENT '月度汇率ID', before_rate DECIMAL(18,8) NULL COMMENT '变更前汇率', after_rate DECIMAL(18,8) NOT NULL COMMENT '变更后汇率', before_status VARCHAR(16) NULL COMMENT '变更前状态', after_status VARCHAR(16) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NOT NULL COMMENT '操作人', remark VARCHAR(1000) NULL COMMENT '变更说明', created_at DATETIME(3) NOT NULL COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_exchange_rate_history (exchange_rate_id,created_at) ) ENGINE=InnoDB COMMENT='月度汇率变更历史'; CREATE TABLE IF NOT EXISTS ll_vehicle ( id BIGINT NOT NULL COMMENT '车辆档案ID', plate_number VARCHAR(64) NOT NULL COMMENT '车牌号', model VARCHAR(128) NOT NULL COMMENT '车型', fuel_consumption_per100_km DECIMAL(10,2) NOT NULL COMMENT '百公里油耗,单位升', mileage_km BIGINT NOT NULL COMMENT '当前公里码,单位公里', driver_or_dispatch_company VARCHAR(128) NULL COMMENT '司机姓名或外派单位', phone VARCHAR(64) NULL COMMENT '司机或外派单位联系电话', region VARCHAR(16) NOT NULL COMMENT '区域:DOMESTIC/OVERSEAS', ownership VARCHAR(16) NOT NULL COMMENT '车辆归属:OWNED/DISPATCHED', status VARCHAR(32) NOT NULL COMMENT '状态:IN_SERVICE/DISPATCHED/MAINTENANCE/INACTIVE/RETURNED', remark VARCHAR(1000) NULL COMMENT '备注', record_version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_by VARCHAR(128) NOT NULL COMMENT '创建人', updated_by VARCHAR(128) NOT NULL COMMENT '更新人', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_vehicle_plate (plate_number), KEY idx_ll_vehicle_page (ownership,region,status,updated_at,id) ) ENGINE=InnoDB COMMENT='平台车辆主数据'; CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', customer_name VARCHAR(255) NULL COMMENT '客户名称快照', order_no VARCHAR(64) NOT NULL COMMENT '订单号', purchase_category VARCHAR(128) NOT NULL COMMENT '采购品类', product_name VARCHAR(255) NOT NULL COMMENT '产品名称', product_specification VARCHAR(500) NULL COMMENT '产品规格', product_url VARCHAR(2000) NULL COMMENT '产品链接', purchase_quantity BIGINT NOT NULL COMMENT '采购数量', budget_unit_price DECIMAL(18,2) NULL COMMENT '预算单价', currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', receiving_address VARCHAR(1000) NULL COMMENT '收货地址', contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_phone VARCHAR(64) NOT NULL COMMENT '联系人电话', purchase_warehouse_id VARCHAR(128) NULL COMMENT '采购入仓仓库ID', purchase_warehouse_name VARCHAR(255) NULL COMMENT '采购入仓仓库名称', outbound_details JSON NULL COMMENT '出库明细', inbound_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '采购单据累计入库数量', domestic_carrier VARCHAR(128) NULL COMMENT '境内承运商', domestic_tracking_no VARCHAR(128) NULL COMMENT '境内物流单号', overseas_carrier VARCHAR(128) NULL COMMENT '海外承运商', overseas_tracking_no VARCHAR(128) NULL COMMENT '海外物流单号', estimated_arrival_at DATETIME(3) NULL COMMENT '预计到达时间', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '业务状态', remark VARCHAR(1000) NULL COMMENT '备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', reviewed_by VARCHAR(128) NULL COMMENT '审核人ID', review_remark VARCHAR(1000) NULL COMMENT '审核备注', review_idempotency_key VARCHAR(255) NULL COMMENT '审核幂等键', review_request_hash CHAR(64) NULL COMMENT '审核请求内容哈希', reviewed_at DATETIME(3) NULL COMMENT '审核时间', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_overseas_procurement_order_no(customer_id,order_no), UNIQUE KEY uk_ll_overseas_procurement_order_key(customer_id,idempotency_key), KEY idx_ll_overseas_procurement_list(customer_id,status,created_at), KEY idx_ll_overseas_procurement_warehouse(customer_id,purchase_warehouse_id,created_at) ) ENGINE=InnoDB COMMENT='海外采购订单'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='outbound_details'), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN outbound_details JSON NULL COMMENT ''出库明细'' AFTER inbound_quantity')); PREPARE procurement_outbound_stmt FROM @ddl; EXECUTE procurement_outbound_stmt; DEALLOCATE PREPARE procurement_outbound_stmt; SET @ddl = (SELECT IF(EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='review_idempotency_key' ), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_idempotency_key VARCHAR(255) NULL COMMENT ''审核幂等键'' AFTER review_remark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='review_request_hash' ), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_request_hash CHAR(64) NULL COMMENT ''审核请求内容哈希'' AFTER review_idempotency_key')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_overseas_procurement_status_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型:CREATE、REVIEW或UPDATE', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_overseas_procurement_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='海外采购操作流水'; SET @ddl = (SELECT IF(EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_status_history' AND column_name='idempotency_key' ), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_status_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_us_truck_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_no VARCHAR(64) NOT NULL COMMENT '订单号', transport_type VARCHAR(32) NOT NULL COMMENT '运输类型', origin VARCHAR(255) NOT NULL COMMENT '起运地', origin_address VARCHAR(500) NULL COMMENT '起运地址', destination VARCHAR(255) NOT NULL COMMENT '目的地', destination_address VARCHAR(500) NULL COMMENT '目的地址', container_type VARCHAR(32) NULL COMMENT '历史兼容设备类型,零担托盘业务不采集', pallet_count INT NOT NULL DEFAULT 1 COMMENT '客户申报托盘数', package_count INT NULL COMMENT '可选箱数,零或空值均有效', received_pallet_count INT NOT NULL DEFAULT 0 COMMENT 'PDA实收托盘数', allocated_pallet_count INT NOT NULL DEFAULT 0 COMMENT '已分配到合车行程的托盘数', shipped_pallet_count INT NOT NULL DEFAULT 0 COMMENT '已出库托盘数', total_weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '总重量(千克)', total_volume_cbm DECIMAL(18,6) NOT NULL DEFAULT 0 COMMENT '总体积(立方米)', budget_amount DECIMAL(18,2) NULL COMMENT '预算金额', currency VARCHAR(3) NOT NULL DEFAULT 'USD' COMMENT '币种', contact_name VARCHAR(128) NOT NULL COMMENT '联系人姓名', contact_info VARCHAR(128) NOT NULL COMMENT '联系人联系方式', requested_date DATE NOT NULL COMMENT '要求服务日期', status VARCHAR(32) NOT NULL COMMENT '美国卡车订单状态', remark VARCHAR(1000) NULL COMMENT '备注', receipt_idempotency_key VARCHAR(255) NULL COMMENT '实物收货幂等键', receipt_request_hash CHAR(64) NULL COMMENT '实物收货请求哈希', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_us_truck_order_no(customer_id,order_no), UNIQUE KEY uk_ll_us_truck_order_key(customer_id,idempotency_key), UNIQUE KEY uk_ll_us_truck_receipt_key(customer_id,receipt_idempotency_key), KEY idx_ll_us_truck_order_list(customer_id,status,created_at), KEY idx_ll_us_truck_order_date(customer_id,requested_date,created_at) ) ENGINE=InnoDB COMMENT='美国卡车运输订单'; CREATE TABLE IF NOT EXISTS ll_us_truck_order_pallet ( id BIGINT NOT NULL COMMENT '托盘记录ID', order_id BIGINT NOT NULL COMMENT '美国卡车订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', pallet_no VARCHAR(128) NOT NULL COMMENT '业务托盘号', sequence_no INT NOT NULL COMMENT '订单内托盘序号', source VARCHAR(32) NOT NULL COMMENT '托盘来源:订单计划或PDA超收', status VARCHAR(32) NOT NULL COMMENT '托盘状态:待收、已收或超收待审核', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘资源ID', package_count INT NULL COMMENT '托盘箱数', received_at DATETIME(3) NULL COMMENT '实收时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_us_truck_order_pallet_no(customer_id,order_id,pallet_no), UNIQUE KEY uk_ll_us_truck_order_pallet_seq(customer_id,order_id,sequence_no), KEY idx_ll_us_truck_order_pallet_list(customer_id,order_id,status) ) ENGINE=InnoDB COMMENT='美国卡车订单托盘实收记录'; CREATE TABLE IF NOT EXISTS ll_us_truck_order_status_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(64) NOT NULL COMMENT '具名操作类型', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_us_truck_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='美国卡车订单状态历史'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_us_truck_order_status_history' AND column_name='operation_type'), 'SELECT 1', 'ALTER TABLE ll_us_truck_order_status_history ADD COLUMN operation_type VARCHAR(64) NOT NULL DEFAULT ''UPDATE'' COMMENT ''具名操作类型'' AFTER customer_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_us_truck_order_status_history' AND column_name='idempotency_key'), 'SELECT 1', 'ALTER TABLE ll_us_truck_order_status_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_us_truck_order_operation ( id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '美国卡车订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(64) NOT NULL COMMENT '具名操作类型', idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '操作请求内容哈希', result_version BIGINT NOT NULL COMMENT '操作完成后的订单版本', created_by VARCHAR(128) NULL COMMENT '操作人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_us_truck_operation_key(customer_id,order_id,idempotency_key), KEY idx_ll_us_truck_operation_order(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='美国卡车订单幂等操作账'; CREATE TABLE IF NOT EXISTS ll_local_looseboard_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', lastleg_order_id BIGINT NULL COMMENT '关联尾程主订单ID', order_no VARCHAR(64) NOT NULL COMMENT '本土散板订单号', transport_mode VARCHAR(32) NOT NULL COMMENT '运输方式:拼车或优先拼载', pallet_required VARCHAR(8) NOT NULL COMMENT '是否需要打盘:YES或NO', transport_type VARCHAR(32) NOT NULL COMMENT '运输类型', origin VARCHAR(255) NOT NULL COMMENT '起运地', origin_address VARCHAR(500) NULL COMMENT '起运详细地址', destination VARCHAR(255) NOT NULL COMMENT '目的地', destination_address VARCHAR(500) NULL COMMENT '目的详细地址、码头或仓号', container_type VARCHAR(32) NULL COMMENT '柜型', package_count INT NOT NULL DEFAULT 0 COMMENT '货物件数', total_weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '总重量(千克)', total_volume_cbm DECIMAL(18,6) NOT NULL DEFAULT 0 COMMENT '总体积(立方米)', budget_amount DECIMAL(18,2) NULL COMMENT '预算总价', currency CHAR(3) NOT NULL DEFAULT 'USD' COMMENT '预算币种', contact_name VARCHAR(128) NULL COMMENT '联系人姓名', contact_info VARCHAR(128) NULL COMMENT '联系人联系方式', requested_date DATE NULL COMMENT '要求服务日期', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ACCEPTANCE' COMMENT '本土散板订单状态', remark VARCHAR(1000) NULL COMMENT '备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '创建幂等键', request_hash CHAR(64) NOT NULL COMMENT '创建请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_local_looseboard_no(customer_id,order_no), UNIQUE KEY uk_ll_local_looseboard_key(customer_id,idempotency_key), UNIQUE KEY uk_ll_local_looseboard_lastleg(lastleg_order_id), KEY idx_ll_local_looseboard_list(customer_id,status,created_at), KEY idx_ll_local_looseboard_date(customer_id,requested_date,created_at) ) ENGINE=InnoDB COMMENT='本土散板订单'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_local_looseboard_order' AND column_name='lastleg_order_id'), 'SELECT 1', 'ALTER TABLE ll_local_looseboard_order ADD COLUMN lastleg_order_id BIGINT NULL COMMENT ''关联尾程主订单ID'' AFTER customer_id')); PREPARE phase4_looseboard_tail_stmt FROM @ddl; EXECUTE phase4_looseboard_tail_stmt; DEALLOCATE PREPARE phase4_looseboard_tail_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_local_looseboard_order' AND index_name='uk_ll_local_looseboard_lastleg'), 'SELECT 1', 'ALTER TABLE ll_local_looseboard_order ADD UNIQUE KEY uk_ll_local_looseboard_lastleg(lastleg_order_id)')); PREPARE phase4_looseboard_tail_stmt FROM @ddl; EXECUTE phase4_looseboard_tail_stmt; DEALLOCATE PREPARE phase4_looseboard_tail_stmt; CREATE TABLE IF NOT EXISTS ll_local_looseboard_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '本土散板订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型:CREATE、UPDATE或STATUS', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '操作备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_local_looseboard_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='本土散板操作流水'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_local_looseboard_history' AND column_name='idempotency_key'), 'SELECT 1', 'ALTER TABLE ll_local_looseboard_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_local_looseboard_operation ( id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '本土散板订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型', idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '操作请求内容哈希', result_version BIGINT NOT NULL COMMENT '操作完成后的订单版本', created_by VARCHAR(128) NULL COMMENT '操作人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_local_looseboard_operation_key(customer_id,order_id,idempotency_key), KEY idx_ll_local_looseboard_operation_order(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='本土散板订单幂等操作账'; -- 尾程主订单状态历史补齐客户隔离键。代码写入 customer_id,已有表需显式升级; -- 先允许 NULL 以便从主订单回填,再收紧为 NOT NULL,脚本可重复执行。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_loading_order_status_history' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_loading_order_status_history ADD COLUMN customer_id VARCHAR(128) NULL COMMENT ''客户数据隔离键'' AFTER id')); PREPARE phase4_loading_history_customer_stmt FROM @ddl; EXECUTE phase4_loading_history_customer_stmt; DEALLOCATE PREPARE phase4_loading_history_customer_stmt; UPDATE ll_loading_order_status_history history JOIN ll_order orders ON orders.id=history.order_id SET history.customer_id=orders.customer_id WHERE history.customer_id IS NULL; ALTER TABLE ll_loading_order_status_history MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_loading_order_status_history' AND index_name='idx_ll_loading_history_customer_order'), 'SELECT 1', 'ALTER TABLE ll_loading_order_status_history ADD KEY idx_ll_loading_history_customer_order(customer_id,order_id,created_at)')); PREPARE phase4_loading_history_customer_stmt FROM @ddl; EXECUTE phase4_loading_history_customer_stmt; DEALLOCATE PREPARE phase4_loading_history_customer_stmt; -- 尾程订单明细实体、事件消费者和详情查询均使用 customer_id;已有开发库需从主订单回填。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order_detail' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_order_detail ADD COLUMN customer_id VARCHAR(128) NULL COMMENT ''客户数据隔离键'' AFTER id')); PREPARE phase4_order_detail_customer_stmt FROM @ddl; EXECUTE phase4_order_detail_customer_stmt; DEALLOCATE PREPARE phase4_order_detail_customer_stmt; UPDATE ll_order_detail detail JOIN ll_order orders ON orders.id=detail.order_id SET detail.customer_id=orders.customer_id WHERE detail.customer_id IS NULL; ALTER TABLE ll_order_detail MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order_detail' AND index_name='idx_ll_detail_customer_order'), 'SELECT 1', 'ALTER TABLE ll_order_detail ADD KEY idx_ll_detail_customer_order(customer_id,order_id,id)')); PREPARE phase4_order_detail_customer_stmt FROM @ddl; EXECUTE phase4_order_detail_customer_stmt; DEALLOCATE PREPARE phase4_order_detail_customer_stmt; -- 四期平台排车查询、智能预排与草稿锁;不开放编辑、发车、PDA 出库或派送。 CREATE TABLE IF NOT EXISTS ll_dispatch_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', dispatch_no VARCHAR(64) NOT NULL COMMENT '派车单号', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', vehicle_plate VARCHAR(64) NULL COMMENT '车牌号', driver_name VARCHAR(128) NULL COMMENT '司机姓名', driver_phone VARCHAR(64) NULL COMMENT '司机电话', carrier_name VARCHAR(255) NULL COMMENT '承运商名称', route VARCHAR(255) NULL COMMENT '运输路线', depart_at DATETIME(3) NULL COMMENT '发车时间', fba_appointment_no VARCHAR(64) NULL COMMENT 'FBA预约号', fba_appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT 'FBA预约状态', vehicle_appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT '车辆预约状态', estimated_arrival_at DATETIME(3) NULL COMMENT '预计到达时间', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_DEPARTURE' COMMENT '业务状态', item_count INT NOT NULL DEFAULT 0 COMMENT '明细数量', pallet_count INT NOT NULL DEFAULT 0 COMMENT '托盘数', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', picked_package_count INT NOT NULL DEFAULT 0 COMMENT 'PDA累计已拣箱数', shipped_package_count INT NOT NULL DEFAULT 0 COMMENT '累计已出库箱数', partial_completion_reason VARCHAR(1000) NULL COMMENT '部分完成原因', created_by VARCHAR(128) NULL COMMENT '创建人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_dispatch_order_no(dispatch_no), KEY idx_ll_dispatch_order_list(customer_id,status,depart_at), KEY idx_ll_dispatch_order_vehicle(customer_id,vehicle_plate) ) ENGINE=InnoDB COMMENT='尾程派车单'; CREATE TABLE IF NOT EXISTS ll_dispatch_item ( id BIGINT NOT NULL COMMENT '主键ID', dispatch_order_id BIGINT NOT NULL COMMENT '派车单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', plan_id BIGINT NULL COMMENT '入仓计划ID', plan_pallet_id BIGINT NULL COMMENT '计划托盘ID', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID', order_id BIGINT NULL COMMENT '订单ID', order_no VARCHAR(64) NULL COMMENT '订单号', order_refs VARCHAR(2000) NULL COMMENT '关联订单信息', inbound_code VARCHAR(128) NULL COMMENT '入仓单号快照', pallet_no VARCHAR(128) NOT NULL COMMENT '托盘号', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', fba_warehouse_code VARCHAR(128) NULL COMMENT 'FBA仓库编码', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数', volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '体积(立方米)', source_stage VARCHAR(32) NOT NULL COMMENT '数据来源阶段', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_dispatch_item_source(dispatch_order_id,plan_pallet_id,warehouse_pallet_id), KEY idx_ll_dispatch_item_order(customer_id,order_id), KEY idx_ll_dispatch_item_inbound(customer_id,inbound_code), KEY idx_ll_dispatch_item_pallet(customer_id,plan_pallet_id,warehouse_pallet_id) ) ENGINE=InnoDB COMMENT='派车货物冻结明细'; CREATE TABLE IF NOT EXISTS ll_dispatch_pallet_lock ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', source_pallet_key VARCHAR(160) NOT NULL COMMENT '来源托盘业务键', active_key VARCHAR(160) NULL COMMENT '生效中的资源排他键', plan_id BIGINT NULL COMMENT '入仓计划ID', plan_pallet_id BIGINT NULL COMMENT '计划托盘ID', warehouse_pallet_id BIGINT NULL COMMENT '仓库实物托盘ID', dispatch_order_id BIGINT NULL COMMENT '正式派车单ID,草稿锁阶段为空', draft_container_id BIGINT NULL COMMENT '智能排车草稿装车托盘ID', draft_token VARCHAR(64) NULL COMMENT '智能排车草稿随机标识', operator_id VARCHAR(128) NULL COMMENT '草稿锁操作人ID', status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '业务状态', locked_at DATETIME(3) NOT NULL COMMENT '锁定时间', expires_at DATETIME(3) NULL COMMENT '草稿锁失效时间,正式派车锁为空', released_at DATETIME(3) NULL COMMENT '释放时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_dispatch_active_pallet(customer_id,active_key), KEY idx_ll_dispatch_pallet_lock_order(customer_id,dispatch_order_id,status), KEY idx_ll_dispatch_pallet_lock_source(customer_id,source_pallet_key,status) ) ENGINE=InnoDB COMMENT='派车托盘排他锁'; CREATE TABLE IF NOT EXISTS ll_dispatch_draft ( id BIGINT NOT NULL COMMENT '主键ID', draft_token VARCHAR(64) NOT NULL COMMENT '智能排车草稿随机标识', customer_id VARCHAR(128) NULL COMMENT '客户租户ID', operator_id VARCHAR(128) NULL COMMENT '草稿操作人ID', plan_ids_json VARCHAR(4000) NULL COMMENT '所选入仓计划ID列表JSON', containers_json LONGTEXT NULL COMMENT '草稿装车布局JSON快照', status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '草稿状态', expires_at DATETIME(3) NULL COMMENT '草稿失效时间', released_at DATETIME(3) NULL COMMENT '草稿释放时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_dispatch_draft_token(draft_token), KEY idx_ll_dispatch_draft_operator(operator_id,status) ) ENGINE=InnoDB COMMENT='智能排车草稿'; CREATE TABLE IF NOT EXISTS ll_dispatch_draft_container ( id BIGINT NOT NULL COMMENT '主键ID', draft_id BIGINT NOT NULL COMMENT '智能排车草稿ID', draft_token VARCHAR(64) NOT NULL COMMENT '智能排车草稿随机标识', sequence_no INT NOT NULL COMMENT '草稿车厢顺序号', capacity INT NOT NULL COMMENT '草稿车厢托盘容量', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), KEY idx_ll_dispatch_draft_container_token(draft_token) ) ENGINE=InnoDB COMMENT='智能排车草稿装车托盘'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_item' AND column_name='order_refs'), 'SELECT 1', 'ALTER TABLE ll_dispatch_item ADD COLUMN order_refs VARCHAR(2000) NULL COMMENT ''关联订单信息'' AFTER order_no')); PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='draft_container_id'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN draft_container_id BIGINT NULL COMMENT ''智能排车草稿装车托盘ID'' AFTER dispatch_order_id')); PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='draft_token'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN draft_token VARCHAR(64) NULL COMMENT ''智能排车草稿随机标识'' AFTER draft_container_id')); PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='operator_id'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN operator_id VARCHAR(128) NULL COMMENT ''草稿锁操作人ID'' AFTER draft_token')); PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='expires_at'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN expires_at DATETIME(3) NULL COMMENT ''草稿锁失效时间,正式派车锁为空'' AFTER locked_at')); PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='dispatch_order_id' AND is_nullable='YES'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock MODIFY COLUMN dispatch_order_id BIGINT NULL COMMENT ''正式派车单ID,草稿锁阶段为空''')); PREPARE phase4_dispatch_stmt FROM @ddl; EXECUTE phase4_dispatch_stmt; DEALLOCATE PREPARE phase4_dispatch_stmt; -- 入仓库存按 SKU 冻结维度;旧环境只补结构,不由部署自动执行。 CREATE TABLE IF NOT EXISTS ll_inbound_plan_carton ( id BIGINT NOT NULL COMMENT '箱唛作业主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_id BIGINT NULL COMMENT '海外首扫确权后的尾程订单ID', source_inbound_detail_id VARCHAR(128) NOT NULL COMMENT '来源入库明细ID', sku_code VARCHAR(128) NULL COMMENT 'SKU编码快照', carton_mark VARCHAR(128) NOT NULL COMMENT '国内冻结箱唛', destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID快照', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', plan_id BIGINT NULL COMMENT '海外入库计划ID', line_id BIGINT NULL COMMENT '入库计划明细ID', plan_pallet_id BIGINT NULL COMMENT '海外计划托盘ID', warehouse_pallet_id BIGINT NULL COMMENT '海外实物托盘ID', warehouse_location_id BIGINT NULL COMMENT '海外库位ID', pda_task_id BIGINT NULL COMMENT '首次扫码PDA任务ID', status VARCHAR(32) NOT NULL COMMENT '箱唛状态:UNASSIGNED、ON_PALLET、BULK_RECEIVED、AVAILABLE', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', bound_at DATETIME(3) NULL COMMENT '绑定托盘时间', received_at DATETIME(3) NULL COMMENT '完成入库时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_inbound_carton_mark(customer_id,carton_mark), KEY idx_ll_inbound_carton_plan(plan_id,status), KEY idx_ll_inbound_carton_pallet(plan_pallet_id,status), KEY idx_ll_inbound_carton_order(order_id,status) ) ENGINE=InnoDB COMMENT='柜次冻结箱唛及海外入库箱级作业账'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_container_booking_id'), 'ALTER TABLE ll_order MODIFY COLUMN source_container_booking_id VARCHAR(128) NULL COMMENT ''来源头程货柜预订ID''', 'ALTER TABLE ll_order ADD COLUMN source_container_booking_id VARCHAR(128) NULL COMMENT ''来源头程货柜预订ID'' AFTER source_loading_plan_id')); PREPARE phase4_event_stmt FROM @ddl; EXECUTE phase4_event_stmt; DEALLOCATE PREPARE phase4_event_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='idx_ll_order_pending_container'), 'ALTER TABLE ll_order DROP INDEX idx_ll_order_pending_container','SELECT 1')); PREPARE phase4_container_progress_idx_stmt FROM @ddl; EXECUTE phase4_container_progress_idx_stmt; DEALLOCATE PREPARE phase4_container_progress_idx_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='idx_ll_order_container_progress'), 'SELECT 1','ALTER TABLE ll_order ADD INDEX idx_ll_order_container_progress(source_container_booking_id,estimated_warehouse_at,created_at,id)')); PREPARE phase4_container_progress_idx_stmt FROM @ddl; EXECUTE phase4_container_progress_idx_stmt; DEALLOCATE PREPARE phase4_container_progress_idx_stmt; DROP PROCEDURE IF EXISTS assert_container_progress_index_ready; DELIMITER $$ CREATE PROCEDURE assert_container_progress_index_ready() BEGIN IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_order' AND index_name='idx_ll_order_container_progress') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外区域初始化失败:柜级入库计划进度索引缺失'; END IF; END$$ DELIMITER ; CALL assert_container_progress_index_ready(); DROP PROCEDURE assert_container_progress_index_ready; -- 头程 V2 事件冻结目的类型;只补结构,不由部署脚本自动执行历史数据回填。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='destination_type'), 'ALTER TABLE ll_order MODIFY COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码''', 'ALTER TABLE ll_order ADD COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER order_type')); PREPARE phase4_destination_type_stmt FROM @ddl; EXECUTE phase4_destination_type_stmt; DEALLOCATE PREPARE phase4_destination_type_stmt; ALTER TABLE ll_order MODIFY COLUMN inbound_code VARCHAR(128) NULL COMMENT '真实来源入仓码;无入仓关系的海外本土业务为空'; CREATE TABLE IF NOT EXISTS ll_order_no_daily_sequence ( business_date DATE NOT NULL COMMENT '业务日期(Asia/Shanghai)', last_sequence INT NOT NULL COMMENT '当日已分配尾程单流水号', PRIMARY KEY(business_date) ) ENGINE=InnoDB COMMENT='尾程单号按日原子流水'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_line ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id')); PREPARE phase4_receiving_line_stmt FROM @ddl; EXECUTE phase4_receiving_line_stmt; DEALLOCATE PREPARE phase4_receiving_line_stmt; UPDATE ll_inbound_plan_line l JOIN ll_inbound_plan p ON p.id=l.plan_id SET l.customer_id=p.customer_id WHERE l.customer_id IS NULL OR l.customer_id=''; ALTER TABLE ll_inbound_plan_line MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND index_name='idx_ll_inbound_line_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_line ADD KEY idx_ll_inbound_line_customer_plan(customer_id,plan_id)')); PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id')); PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt; UPDATE ll_inbound_plan_pallet v JOIN ll_inbound_plan p ON p.id=v.plan_id SET v.customer_id=p.customer_id WHERE v.customer_id IS NULL OR v.customer_id=''; ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND index_name='idx_ll_inbound_pallet_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD KEY idx_ll_inbound_pallet_customer_plan(customer_id,plan_id)')); PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet_allocation' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD COLUMN customer_id VARCHAR(128) NOT NULL DEFAULT '''' COMMENT ''客户账号标识'' AFTER id')); PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt; UPDATE ll_inbound_plan_pallet_allocation a JOIN ll_inbound_plan p ON p.id=a.plan_id SET a.customer_id=p.customer_id WHERE a.customer_id IS NULL OR a.customer_id=''; ALTER TABLE ll_inbound_plan_pallet_allocation MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet_allocation' AND index_name='idx_ll_inbound_allocation_customer_plan'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet_allocation ADD KEY idx_ll_inbound_allocation_customer_plan(customer_id,plan_id)')); PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt; DROP PROCEDURE IF EXISTS assert_phase4_inbound_plan_customer_scope_ready; DELIMITER $$ CREATE PROCEDURE assert_phase4_inbound_plan_customer_scope_ready() BEGIN IF EXISTS (SELECT 1 FROM ll_inbound_plan_line l LEFT JOIN ll_inbound_plan p ON p.id=l.plan_id WHERE l.customer_id IS NULL OR l.customer_id='' OR p.id IS NULL OR l.customer_id<>p.customer_id) OR EXISTS (SELECT 1 FROM ll_inbound_plan_pallet v LEFT JOIN ll_inbound_plan p ON p.id=v.plan_id WHERE v.customer_id IS NULL OR v.customer_id='' OR p.id IS NULL OR v.customer_id<>p.customer_id) OR EXISTS (SELECT 1 FROM ll_inbound_plan_pallet_allocation a LEFT JOIN ll_inbound_plan p ON p.id=a.plan_id WHERE a.customer_id IS NULL OR a.customer_id='' OR p.id IS NULL OR a.customer_id<>p.customer_id) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Inbound plan child customer scope migration is incomplete'; END IF; END$$ DELIMITER ; CALL assert_phase4_inbound_plan_customer_scope_ready(); DROP PROCEDURE assert_phase4_inbound_plan_customer_scope_ready; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='fba_warehouse_code'), 'ALTER TABLE ll_inbound_plan_line MODIFY COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''FBA仓库编码''', 'ALTER TABLE ll_inbound_plan_line ADD COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''FBA仓库编码'' AFTER inbound_code')); PREPARE phase4_receiving_line_stmt FROM @ddl; EXECUTE phase4_receiving_line_stmt; DEALLOCATE PREPARE phase4_receiving_line_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_line' AND column_name='destination_type'), 'ALTER TABLE ll_inbound_plan_line MODIFY COLUMN destination_type VARCHAR(32) NOT NULL DEFAULT ''OVERSEAS'' COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码''', 'ALTER TABLE ll_inbound_plan_line ADD COLUMN destination_type VARCHAR(32) NOT NULL DEFAULT ''OVERSEAS'' COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER inbound_code')); PREPARE phase4_receiving_line_stmt FROM @ddl; EXECUTE phase4_receiving_line_stmt; DEALLOCATE PREPARE phase4_receiving_line_stmt; UPDATE ll_inbound_plan_line l JOIN ll_order o ON o.id=l.order_id SET l.destination_type=COALESCE(NULLIF(o.destination_type,''),CASE WHEN NULLIF(l.fba_warehouse_code,'') IS NULL THEN 'OVERSEAS' ELSE 'FBA' END) WHERE l.destination_type IS NULL OR l.destination_type='' OR l.destination_type='OVERSEAS'; SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_warehouse_id'), 'SELECT 1','ALTER TABLE ll_order ADD COLUMN source_warehouse_id VARCHAR(128) NULL COMMENT ''来源国内装柜仓ID快照'' AFTER customer_name')); PREPARE phase4_source_warehouse_id_stmt FROM @ddl; EXECUTE phase4_source_warehouse_id_stmt; DEALLOCATE PREPARE phase4_source_warehouse_id_stmt; SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='source_warehouse_name'), 'SELECT 1','ALTER TABLE ll_order ADD COLUMN source_warehouse_name VARCHAR(255) NULL COMMENT ''来源国内装柜仓名称快照'' AFTER source_warehouse_id')); PREPARE phase4_source_warehouse_name_stmt FROM @ddl; EXECUTE phase4_source_warehouse_name_stmt; DEALLOCATE PREPARE phase4_source_warehouse_name_stmt; SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='overseas_warehouse_id'), 'SELECT 1','ALTER TABLE ll_inbound_plan ADD COLUMN overseas_warehouse_id BIGINT NULL COMMENT ''海外实际收货共享物理仓ID,由PDA认领柜号时冻结'' AFTER container_no')); PREPARE phase4_plan_receiving_warehouse_stmt FROM @ddl; EXECUTE phase4_plan_receiving_warehouse_stmt; DEALLOCATE PREPARE phase4_plan_receiving_warehouse_stmt; UPDATE ll_order o JOIN ll_loading_event_inbox i ON i.event_id=o.source_event_id SET o.source_warehouse_id=COALESCE(o.source_warehouse_id,JSON_UNQUOTE(JSON_EXTRACT(i.payload_json,'$.warehouseId'))), o.source_warehouse_name=COALESCE(o.source_warehouse_name,JSON_UNQUOTE(JSON_EXTRACT(i.payload_json,'$.warehouseName'))), o.overseas_warehouse_id=NULL,o.overseas_warehouse_name=NULL WHERE o.current_status<>'INBOUND_COMPLETED' AND o.overseas_warehouse_id=JSON_UNQUOTE(JSON_EXTRACT(i.payload_json,'$.warehouseId')); DROP PROCEDURE IF EXISTS assert_pending_orders_do_not_use_source_warehouse; DELIMITER $$ CREATE PROCEDURE assert_pending_orders_do_not_use_source_warehouse() BEGIN IF EXISTS(SELECT 1 FROM ll_order o JOIN ll_loading_event_inbox i ON i.event_id=o.source_event_id WHERE o.current_status<>'INBOUND_COMPLETED' AND o.overseas_warehouse_id IS NOT NULL AND o.overseas_warehouse_id=JSON_UNQUOTE(JSON_EXTRACT(i.payload_json,'$.warehouseId'))) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='未完成尾程单仍将国内来源仓冒充海外实际收货仓'; END IF; END$$ DELIMITER ; CALL assert_pending_orders_do_not_use_source_warehouse(); DROP PROCEDURE assert_pending_orders_do_not_use_source_warehouse; CREATE TABLE IF NOT EXISTS ll_receiving_container_session ( id BIGINT NOT NULL COMMENT '柜号签收会话ID', source_container_booking_id VARCHAR(128) NOT NULL COMMENT '稳定来源柜预订ID', container_fact_hash VARCHAR(64) NOT NULL COMMENT '领取时整柜订单与计划事实摘要', container_no VARCHAR(64) NOT NULL COMMENT '集装箱号', overseas_warehouse_id BIGINT NOT NULL COMMENT '操作员Token绑定并冻结的海外实际收货共享物理仓ID', overseas_warehouse_name VARCHAR(255) NOT NULL COMMENT '仓库服务校验后的海外实际收货共享物理仓名称快照', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号唯一标识', operator_name VARCHAR(255) NULL COMMENT '操作账号名称', active_operator_key VARCHAR(255) NULL COMMENT '未完成会话平台操作账号全局唯一锁键', active_container_key VARCHAR(255) NULL COMMENT '未完成会话柜号全局唯一锁键', status VARCHAR(32) NOT NULL DEFAULT 'WAIT_SIGN' COMMENT '会话状态:WAIT_SIGN、SIGNED、RECEIVING、COMPLETED、COMPLETED_WITH_DIFFERENCE', sign_photos JSON NULL COMMENT '签收卸柜照片角色与文件ID列表', prepared_at DATETIME(3) NULL COMMENT '选择柜号时间', signed_at DATETIME(3) NULL COMMENT '签收时间', receiving_at DATETIME(3) NULL COMMENT '首次收货时间', completed_at DATETIME(3) NULL COMMENT '完成时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_active_operator(active_operator_key), UNIQUE KEY uk_ll_receiving_active_container(active_container_key), KEY idx_ll_receiving_container(container_no,status), KEY idx_ll_receiving_operator(operator_key,created_at) ) ENGINE=InnoDB COMMENT='海外PDA柜号签收收货会话'; SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='source_container_booking_id'), 'SELECT 1','ALTER TABLE ll_receiving_container_session ADD COLUMN source_container_booking_id VARCHAR(128) NULL COMMENT ''稳定来源柜预订ID'' AFTER id')); PREPARE phase4_receiving_fact_stmt FROM @ddl; EXECUTE phase4_receiving_fact_stmt; DEALLOCATE PREPARE phase4_receiving_fact_stmt; SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='container_fact_hash'), 'SELECT 1','ALTER TABLE ll_receiving_container_session ADD COLUMN container_fact_hash VARCHAR(64) NULL COMMENT ''领取时整柜订单与计划事实摘要'' AFTER source_container_booking_id')); PREPARE phase4_receiving_fact_stmt FROM @ddl; EXECUTE phase4_receiving_fact_stmt; DEALLOCATE PREPARE phase4_receiving_fact_stmt; SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='overseas_warehouse_id'), 'SELECT 1','ALTER TABLE ll_receiving_container_session ADD COLUMN overseas_warehouse_id BIGINT NULL COMMENT ''操作员Token绑定并冻结的海外实际收货共享物理仓ID'' AFTER container_no')); PREPARE phase4_session_receiving_warehouse_stmt FROM @ddl; EXECUTE phase4_session_receiving_warehouse_stmt; DEALLOCATE PREPARE phase4_session_receiving_warehouse_stmt; SET @ddl = (SELECT IF(EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='overseas_warehouse_name'), 'SELECT 1','ALTER TABLE ll_receiving_container_session ADD COLUMN overseas_warehouse_name VARCHAR(255) NULL COMMENT ''仓库服务校验后的海外实际收货共享物理仓名称快照'' AFTER overseas_warehouse_id')); PREPARE phase4_session_receiving_warehouse_name_stmt FROM @ddl; EXECUTE phase4_session_receiving_warehouse_name_stmt; DEALLOCATE PREPARE phase4_session_receiving_warehouse_name_stmt; DROP PROCEDURE IF EXISTS assert_active_receiving_session_has_warehouse; DELIMITER $$ CREATE PROCEDURE assert_active_receiving_session_has_warehouse() BEGIN IF EXISTS(SELECT 1 FROM ll_receiving_container_session WHERE active_container_key IS NOT NULL AND (overseas_warehouse_id IS NULL OR overseas_warehouse_name IS NULL OR overseas_warehouse_name='')) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='存在无法安全推断海外实际收货仓的未完成PDA柜会话'; END IF; END$$ DELIMITER ; CALL assert_active_receiving_session_has_warehouse(); DROP PROCEDURE assert_active_receiving_session_has_warehouse; ALTER TABLE ll_receiving_container_session MODIFY COLUMN overseas_warehouse_id BIGINT NOT NULL COMMENT '操作员Token绑定并冻结的海外实际收货共享物理仓ID', MODIFY COLUMN overseas_warehouse_name VARCHAR(255) NOT NULL COMMENT '仓库服务校验后的海外实际收货共享物理仓名称快照'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='sign_photos'), 'ALTER TABLE ll_receiving_container_session MODIFY COLUMN sign_photos JSON NULL COMMENT ''签收卸柜照片角色与文件ID列表''', 'ALTER TABLE ll_receiving_container_session ADD COLUMN sign_photos JSON NULL COMMENT ''签收卸柜照片角色与文件ID列表'' AFTER status')); PREPARE phase4_receiving_sign_photos_stmt FROM @ddl; EXECUTE phase4_receiving_sign_photos_stmt; DEALLOCATE PREPARE phase4_receiving_sign_photos_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='photo_file_ids'), 'ALTER TABLE ll_receiving_container_session DROP COLUMN photo_file_ids', 'SELECT 1')); PREPARE phase4_receiving_drop_raw_photos_stmt FROM @ddl; EXECUTE phase4_receiving_drop_raw_photos_stmt; DEALLOCATE PREPARE phase4_receiving_drop_raw_photos_stmt; DROP PROCEDURE IF EXISTS assert_receiving_global_locks_migratable; UPDATE ll_receiving_container_session SET active_operator_key=NULL,active_container_key=NULL WHERE status IN ('COMPLETED','COMPLETED_WITH_DIFFERENCE') AND (active_operator_key IS NOT NULL OR active_container_key IS NOT NULL); DELIMITER $$ CREATE PROCEDURE assert_receiving_global_locks_migratable() BEGIN IF EXISTS (SELECT operator_key FROM ll_receiving_container_session WHERE active_operator_key IS NOT NULL GROUP BY operator_key HAVING COUNT(*) > 1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA全局账号锁迁移失败:同一账号存在多个未完成柜'; END IF; IF EXISTS (SELECT UPPER(TRIM(container_no)) FROM ll_receiving_container_session WHERE active_container_key IS NOT NULL GROUP BY UPPER(TRIM(container_no)) HAVING COUNT(*) > 1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA全局柜号锁迁移失败:同一柜存在多个未完成会话'; END IF; END$$ DELIMITER ; CALL assert_receiving_global_locks_migratable(); DROP PROCEDURE assert_receiving_global_locks_migratable; UPDATE ll_receiving_container_session SET active_operator_key=CONCAT('OPERATOR:',operator_key), active_container_key=CONCAT('CONTAINER:',UPPER(TRIM(container_no))) WHERE active_operator_key IS NOT NULL OR active_container_key IS NOT NULL; ALTER TABLE ll_receiving_container_session MODIFY COLUMN active_operator_key VARCHAR(255) NULL COMMENT '未完成会话平台操作账号全局唯一锁键', MODIFY COLUMN active_container_key VARCHAR(255) NULL COMMENT '未完成会话柜号全局唯一锁键'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND index_name='idx_ll_receiving_container'), 'ALTER TABLE ll_receiving_container_session DROP INDEX idx_ll_receiving_container', 'SELECT 1')); PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND index_name='idx_ll_receiving_operator'), 'ALTER TABLE ll_receiving_container_session DROP INDEX idx_ll_receiving_operator', 'SELECT 1')); PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt; ALTER TABLE ll_receiving_container_session ADD KEY idx_ll_receiving_container(container_no,status), ADD KEY idx_ll_receiving_operator(operator_key,created_at); SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='customer_id'), 'ALTER TABLE ll_receiving_container_session DROP COLUMN customer_id', 'SELECT 1')); PREPARE phase4_receiving_scope_stmt FROM @ddl; EXECUTE phase4_receiving_scope_stmt; DEALLOCATE PREPARE phase4_receiving_scope_stmt; CREATE TABLE IF NOT EXISTS ll_receiving_sku_receipt ( id BIGINT NOT NULL COMMENT 'FBA SKU实收进度ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户账号标识', session_id BIGINT NOT NULL COMMENT '柜号签收会话ID', plan_id BIGINT NOT NULL COMMENT '入仓计划ID', line_id BIGINT NOT NULL COMMENT '入仓计划明细ID', pallet_id BIGINT NOT NULL COMMENT '计划托盘ID', order_id BIGINT NOT NULL COMMENT '尾程订单ID', inbound_code VARCHAR(128) NOT NULL COMMENT '入仓码快照', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码快照', product_name VARCHAR(255) NULL COMMENT '产品名称快照', received_packages INT NOT NULL COMMENT 'SKU实收箱数', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_sku_pallet (customer_id,line_id,pallet_id,sku_code), KEY idx_ll_receiving_sku_session (customer_id,session_id,line_id), KEY idx_ll_receiving_sku_plan (customer_id,plan_id,line_id) ) ENGINE=InnoDB COMMENT='海外PDA柜号FBA SKU实收进度'; CREATE TABLE IF NOT EXISTS ll_receiving_fba_pallet_count ( id BIGINT NOT NULL COMMENT 'FBA托盘现场累计箱数ID', session_id BIGINT NOT NULL COMMENT '柜号签收会话ID', group_key VARCHAR(255) NOT NULL COMMENT '柜号与FBA仓组成的收货组键', pallet_code VARCHAR(128) NOT NULL COMMENT '现有FBA托盘码', actual_packages INT NOT NULL COMMENT '该托现场累计实物箱数', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_fba_count(session_id,group_key,pallet_code), KEY idx_ll_receiving_fba_group(session_id,group_key) ) ENGINE=InnoDB COMMENT='海外PDA普通FBA托盘现场累计与超收标记'; CREATE TABLE IF NOT EXISTS ll_receiving_container_operation ( id BIGINT NOT NULL COMMENT '柜号收货操作ID', session_id BIGINT NOT NULL COMMENT '柜号签收会话ID', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号唯一标识', action VARCHAR(32) NOT NULL COMMENT '操作动作', idempotency_key VARCHAR(255) NOT NULL COMMENT '客户端幂等键', request_hash VARCHAR(128) NOT NULL COMMENT '请求内容哈希', request_json LONGTEXT NOT NULL COMMENT '请求内容快照', result_json LONGTEXT NOT NULL COMMENT '响应内容快照', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_operation(operator_key,idempotency_key), KEY idx_ll_receiving_operation_session(session_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA柜号收货幂等审计记录'; DROP PROCEDURE IF EXISTS assert_receiving_operation_global_key_migratable; DELIMITER $$ CREATE PROCEDURE assert_receiving_operation_global_key_migratable() BEGIN IF EXISTS (SELECT operator_key,idempotency_key FROM ll_receiving_container_operation GROUP BY operator_key,idempotency_key HAVING COUNT(*) > 1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA全局幂等键迁移失败:同一操作账号存在重复幂等键'; END IF; END$$ DELIMITER ; CALL assert_receiving_operation_global_key_migratable(); DROP PROCEDURE assert_receiving_operation_global_key_migratable; SET @receiving_operation_global_index = ( SELECT COUNT(*) FROM ( SELECT index_name FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_operation' AND index_name='uk_ll_receiving_operation' GROUP BY index_name HAVING GROUP_CONCAT(column_name ORDER BY seq_in_index)= 'operator_key,idempotency_key' ) ready_index ); SET @receiving_operation_named_index = ( SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_operation' AND index_name='uk_ll_receiving_operation' ); SET @ddl = IF(@receiving_operation_global_index=1, 'SELECT 1', IF(@receiving_operation_named_index>0, 'ALTER TABLE ll_receiving_container_operation DROP INDEX uk_ll_receiving_operation, ADD UNIQUE KEY uk_ll_receiving_operation(operator_key,idempotency_key)', 'ALTER TABLE ll_receiving_container_operation ADD UNIQUE KEY uk_ll_receiving_operation(operator_key,idempotency_key)')); PREPARE phase4_receiving_operation_index_stmt FROM @ddl; EXECUTE phase4_receiving_operation_index_stmt; DEALLOCATE PREPARE phase4_receiving_operation_index_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_operation' AND column_name='customer_id'), 'ALTER TABLE ll_receiving_container_operation DROP COLUMN customer_id', 'SELECT 1')); PREPARE phase4_receiving_operation_scope_stmt FROM @ddl; EXECUTE phase4_receiving_operation_scope_stmt; DEALLOCATE PREPARE phase4_receiving_operation_scope_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_order' AND column_name='destination_type'), 'ALTER TABLE ll_inbound_order MODIFY COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码''', 'ALTER TABLE ll_inbound_order ADD COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER destination_warehouse_name')); PREPARE phase4_destination_type_stmt FROM @ddl; EXECUTE phase4_destination_type_stmt; DEALLOCATE PREPARE phase4_destination_type_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='sub_order_status'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN sub_order_status VARCHAR(255) NULL COMMENT ''子单据状态汇总'' AFTER current_status')); PREPARE phase4_sub_order_status_stmt FROM @ddl; EXECUTE phase4_sub_order_status_stmt; DEALLOCATE PREPARE phase4_sub_order_status_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='order_type' AND COALESCE(column_comment,'') LIKE '订单类型:%'), 'SELECT 1', 'ALTER TABLE ll_order MODIFY COLUMN order_type VARCHAR(32) NOT NULL DEFAULT ''FIRST_LEG'' COMMENT ''订单类型:FIRST_LEG头程订单、RELABEL_APPLICATION换标下单、WAREHOUSE_TRANSFER仓储转运、LOCAL_LOOSEBOARD本土散板、RETURN_RELABEL退货换标、ONE_CLICK_DROPSHIP一件代发''')); PREPARE phase4_order_type_comment_stmt FROM @ddl; EXECUTE phase4_order_type_comment_stmt; DEALLOCATE PREPARE phase4_order_type_comment_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='current_status' AND COALESCE(column_comment,'') LIKE '当前业务状态:%'), 'SELECT 1', 'ALTER TABLE ll_order MODIFY COLUMN current_status VARCHAR(32) NOT NULL DEFAULT ''PENDING_ASSIGNMENT'' COMMENT ''当前业务状态:PENDING_ASSIGNMENT待分配、PENDING_INBOUND待入库、INBOUND_COMPLETED入库完成、PENDING_DELIVERY待派送、DELIVERING派送中、DELIVERED派送完成''')); PREPARE phase4_order_status_comment_stmt FROM @ddl; EXECUTE phase4_order_status_comment_stmt; DEALLOCATE PREPARE phase4_order_status_comment_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='unload_photo_file_ids'), 'ALTER TABLE ll_inbound_pda_task MODIFY COLUMN unload_photo_file_ids JSON NULL COMMENT ''卸柜照片文件ID列表''', 'ALTER TABLE ll_inbound_pda_task ADD COLUMN unload_photo_file_ids JSON NULL COMMENT ''卸柜照片文件ID列表'' AFTER completed_at')); PREPARE phase4_event_stmt FROM @ddl; EXECUTE phase4_event_stmt; DEALLOCATE PREPARE phase4_event_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='unload_photo_uploaded_at'), 'ALTER TABLE ll_inbound_pda_task MODIFY COLUMN unload_photo_uploaded_at DATETIME(3) NULL COMMENT ''卸柜照片上传成功时间''', 'ALTER TABLE ll_inbound_pda_task ADD COLUMN unload_photo_uploaded_at DATETIME(3) NULL COMMENT ''卸柜照片上传成功时间'' AFTER unload_photo_file_ids')); PREPARE phase4_event_stmt FROM @ddl; EXECUTE phase4_event_stmt; DEALLOCATE PREPARE phase4_event_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_pda_task' AND column_name='estimated_empty_return_at'), 'ALTER TABLE ll_inbound_pda_task MODIFY COLUMN estimated_empty_return_at DATETIME(3) NULL COMMENT ''预计报空时间(卸柜照片上传成功后两天)''', 'ALTER TABLE ll_inbound_pda_task ADD COLUMN estimated_empty_return_at DATETIME(3) NULL COMMENT ''预计报空时间(卸柜照片上传成功后两天)'' AFTER unload_photo_uploaded_at')); PREPARE phase4_event_stmt FROM @ddl; EXECUTE phase4_event_stmt; DEALLOCATE PREPARE phase4_event_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND index_name='uk_ll_inbound_plan_container'), 'ALTER TABLE ll_inbound_plan DROP INDEX uk_ll_inbound_plan_container', 'SELECT 1')); PREPARE phase4_inbound_stmt FROM @ddl; EXECUTE phase4_inbound_stmt; DEALLOCATE PREPARE phase4_inbound_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND index_name='idx_ll_inbound_plan_container'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD KEY idx_ll_inbound_plan_container (customer_id,container_no)')); PREPARE phase4_inbound_stmt FROM @ddl; EXECUTE phase4_inbound_stmt; DEALLOCATE PREPARE phase4_inbound_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND column_name='sku_code'), 'ALTER TABLE ll_inventory_balance MODIFY COLUMN sku_code VARCHAR(128) NOT NULL DEFAULT ''UNSPECIFIED'' COMMENT ''SKU快照;多SKU汇总时为MIXED,不参与当前库存唯一维度''', 'ALTER TABLE ll_inventory_balance ADD COLUMN sku_code VARCHAR(128) NOT NULL DEFAULT ''UNSPECIFIED'' COMMENT ''SKU快照;多SKU汇总时为MIXED,不参与当前库存唯一维度'' AFTER inbound_code')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND column_name='customer_name'), 'ALTER TABLE ll_inventory_balance MODIFY COLUMN customer_name VARCHAR(255) NOT NULL COMMENT ''客户名称不可变快照''', 'ALTER TABLE ll_inventory_balance ADD COLUMN customer_name VARCHAR(255) NOT NULL COMMENT ''客户名称不可变快照'' AFTER customer_id')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_ledger' AND column_name='customer_name'), 'ALTER TABLE ll_inventory_ledger MODIFY COLUMN customer_name VARCHAR(255) NOT NULL COMMENT ''客户名称不可变快照''', 'ALTER TABLE ll_inventory_ledger ADD COLUMN customer_name VARCHAR(255) NOT NULL COMMENT ''客户名称不可变快照'' AFTER customer_id')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND column_name='product_name_zh'), 'SELECT 1', 'ALTER TABLE ll_inventory_balance ADD COLUMN product_name_zh VARCHAR(255) NULL COMMENT ''中文品名快照'' AFTER sku_code')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND column_name='product_name_en'), 'SELECT 1', 'ALTER TABLE ll_inventory_balance ADD COLUMN product_name_en VARCHAR(255) NULL COMMENT ''英文品名快照'' AFTER product_name_zh')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND index_name='uk_ll_inventory_dimension'), 'ALTER TABLE ll_inventory_balance DROP INDEX uk_ll_inventory_dimension', 'SELECT 1')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND index_name='uk_ll_inventory_dimension'), 'SELECT 1', 'ALTER TABLE ll_inventory_balance ADD UNIQUE KEY uk_ll_inventory_dimension (customer_id,overseas_warehouse_id,destination_warehouse_code,inbound_order_id,inbound_code)')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; ALTER TABLE ll_inventory_balance COMMENT='客户入仓单与海外目的仓维度实时库存余额'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inventory_balance' AND index_name='idx_ll_inventory_sku'), 'SELECT 1', 'ALTER TABLE ll_inventory_balance ADD KEY idx_ll_inventory_sku (customer_id,sku_code,updated_at)')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND column_name='sku_code'), 'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN sku_code VARCHAR(128) NOT NULL DEFAULT ''UNSPECIFIED'' COMMENT ''SKU编码快照'' AFTER inbound_code')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND column_name='product_name_zh'), 'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN product_name_zh VARCHAR(255) NULL COMMENT ''中文品名快照'' AFTER sku_code')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND column_name='product_name_en'), 'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN product_name_en VARCHAR(255) NULL COMMENT ''英文品名快照'' AFTER product_name_zh')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND index_name='uk_ll_stock_receipt_task_allocation'), 'ALTER TABLE ll_inbound_stock_receipt DROP INDEX uk_ll_stock_receipt_task_allocation', 'SELECT 1')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_inbound_stock_receipt' AND index_name='uk_ll_stock_receipt_task_allocation_sku'), 'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD UNIQUE KEY uk_ll_stock_receipt_task_allocation_sku (customer_id,task_id,allocation_id,sku_code)')); PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt; -- 海运节点达到可提柜后才允许海外 PDA 认领;装柜完成只建立等待门禁快照。 CREATE TABLE IF NOT EXISTS ll_container_shipping_gate ( container_booking_id VARCHAR(128) NOT NULL COMMENT '来源头程柜预订ID', ocean_booking_id VARCHAR(128) NULL COMMENT '来源海运订舱ID;货柜未关联订舱时为空', container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号', status VARCHAR(32) NOT NULL DEFAULT 'AWAITING_PICKUP_READY' COMMENT '海外收货门禁状态:AWAITING_PICKUP_READY、RECEIVING_AVAILABLE', standard_node VARCHAR(64) NULL COMMENT '最新有效标准船节点', node_sequence INT NOT NULL DEFAULT 0 COMMENT '最新有效节点单调序号', observed_at DATETIME(3) NULL COMMENT '供应商节点观测时间', actual_at DATETIME(3) NULL COMMENT '节点实际发生时间', location_code VARCHAR(128) NULL COMMENT '节点地点编码', location_name VARCHAR(255) NULL COMMENT '节点地点名称', provider_code VARCHAR(64) NULL COMMENT '船节点供应商编码', provider_event_id VARCHAR(128) NULL COMMENT '供应商事件ID', provider_node_code VARCHAR(128) NULL COMMENT '供应商原始节点编码', source_reference VARCHAR(255) NULL COMMENT '供应商来源引用', raw_payload_hash VARCHAR(64) NULL COMMENT '供应商原始负载SHA-256', aggregate_version BIGINT NOT NULL DEFAULT 0 COMMENT '来源查询聚合版本', handover_version BIGINT NOT NULL DEFAULT 1 COMMENT '跨区交接版本', last_event_id VARCHAR(128) NULL COMMENT '最近采纳的跨区事件ID', payload_hash VARCHAR(71) NULL COMMENT '最近采纳事件规范化负载摘要', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(container_booking_id), KEY idx_ll_shipping_gate_candidate(container_no,status), KEY idx_ll_shipping_gate_version(container_booking_id,aggregate_version,node_sequence) ) ENGINE=InnoDB COMMENT='海外PDA柜号船节点收货资格快照'; INSERT IGNORE INTO ll_container_shipping_gate ( container_booking_id,ocean_booking_id,container_no,status, node_sequence,aggregate_version,handover_version,created_at,updated_at ) SELECT source_container_booking_id,'',container_no,'AWAITING_PICKUP_READY', 0,COALESCE(MAX(source_loading_plan_version),0),COALESCE(MAX(source_handover_version),1),NOW(3),NOW(3) FROM ll_order WHERE source_container_booking_id IS NOT NULL AND source_container_booking_id <> '' AND container_no IS NOT NULL AND container_no <> '' GROUP BY source_container_booking_id,container_no; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_container_shipping_gate' AND index_name='idx_ll_shipping_gate_candidate'), 'ALTER TABLE ll_container_shipping_gate DROP INDEX idx_ll_shipping_gate_candidate', 'SELECT 1')); PREPARE phase4_shipping_gate_scope_stmt FROM @ddl; EXECUTE phase4_shipping_gate_scope_stmt; DEALLOCATE PREPARE phase4_shipping_gate_scope_stmt; ALTER TABLE ll_container_shipping_gate ADD KEY idx_ll_shipping_gate_candidate(container_no,status); SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_container_shipping_gate' AND column_name='customer_id'), 'ALTER TABLE ll_container_shipping_gate DROP COLUMN customer_id', 'SELECT 1')); PREPARE phase4_shipping_gate_scope_stmt FROM @ddl; EXECUTE phase4_shipping_gate_scope_stmt; DEALLOCATE PREPARE phase4_shipping_gate_scope_stmt; CREATE TABLE IF NOT EXISTS ll_pda_operation_history ( id BIGINT NOT NULL COMMENT 'PDA作业历史ID', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', customer_id VARCHAR(128) NULL COMMENT '作业涉及的客户标识', operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', operation_type VARCHAR(64) NOT NULL COMMENT '作业类型', business_key VARCHAR(255) NOT NULL COMMENT '作业业务键', status VARCHAR(32) NOT NULL COMMENT '作业结果状态', idempotency_key VARCHAR(255) NULL COMMENT '写操作幂等键', request_hash VARCHAR(128) NULL COMMENT '写请求内容哈希', summary VARCHAR(1000) NULL COMMENT '作业结果摘要', occurred_at DATETIME(3) NOT NULL COMMENT '作业发生时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_history_idempotency(operator_key,idempotency_key), KEY idx_ll_pda_history_operator(overseas_warehouse_id,operator_key,occurred_at), KEY idx_ll_pda_history_business(overseas_warehouse_id,operation_type,business_key) ) ENGINE=InnoDB COMMENT='海外PDA真实作业历史'; CREATE TABLE IF NOT EXISTS ll_pda_pallet_operation ( id BIGINT NOT NULL COMMENT 'PDA托盘作业ID', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', idempotency_key VARCHAR(128) NOT NULL COMMENT '设备幂等键', operation_type VARCHAR(64) NOT NULL COMMENT '托盘作业类型', request_hash VARCHAR(128) NOT NULL COMMENT '请求内容摘要', status VARCHAR(32) NOT NULL COMMENT '处理状态:PROCESSING、COMPLETED、FAILED_COMPENSATED、COMPENSATION_REQUIRED', result_json LONGTEXT NULL COMMENT '成功响应快照', remote_transitions_json LONGTEXT NULL COMMENT '实物托盘状态变更回执', last_error VARCHAR(2000) NULL COMMENT '最后失败原因', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_pallet_idempotency(operator_key,idempotency_key), KEY idx_ll_pda_pallet_warehouse(overseas_warehouse_id,status,updated_at) ) ENGINE=InnoDB COMMENT='海外PDA托盘作业幂等、补偿与结果记录'; CREATE TABLE IF NOT EXISTS ll_pda_stocktake_task ( id BIGINT NOT NULL COMMENT '盘点任务ID', task_no VARCHAR(64) NOT NULL COMMENT '盘点任务号', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', scope_type VARCHAR(16) NOT NULL COMMENT '盘点范围类型LOCATION或PALLET', scope_resource_id BIGINT NOT NULL COMMENT '盘点库位或托盘资源ID', scope_code VARCHAR(128) NOT NULL COMMENT '盘点库位码或托盘码快照', status VARCHAR(32) NOT NULL COMMENT '盘点任务状态', position_count INT NOT NULL COMMENT '库存位置总数', counted_count INT NOT NULL DEFAULT 0 COMMENT '已盘库存位置数', difference_count INT NOT NULL DEFAULT 0 COMMENT '存在差异的库存位置数', created_by VARCHAR(128) NOT NULL COMMENT '创建操作账号标识', submitted_by VARCHAR(128) NULL COMMENT '提交操作账号标识', submit_reason VARCHAR(500) NULL COMMENT '盘点差异提交原因', idempotency_key VARCHAR(128) NOT NULL COMMENT '创建幂等键', request_hash VARCHAR(128) NOT NULL COMMENT '创建请求哈希', version BIGINT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', submitted_at DATETIME(3) NULL COMMENT '提交完成时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_stocktake_no(task_no), UNIQUE KEY uk_ll_pda_stocktake_create(overseas_warehouse_id,created_by,idempotency_key), KEY idx_ll_pda_stocktake_list(overseas_warehouse_id,status,created_at) ) ENGINE=InnoDB COMMENT='海外PDA库存盘点任务'; CREATE TABLE IF NOT EXISTS ll_pda_stocktake_item ( id BIGINT NOT NULL COMMENT '盘点明细ID', task_id BIGINT NOT NULL COMMENT '盘点任务ID', customer_id VARCHAR(128) NOT NULL COMMENT '库存所属客户标识', balance_id BIGINT NOT NULL COMMENT '库存余额ID', position_id BIGINT NOT NULL COMMENT '库存位置ID', sku_code VARCHAR(128) NULL COMMENT 'SKU快照', product_name VARCHAR(255) NULL COMMENT '品名快照', inbound_code VARCHAR(128) NULL COMMENT '入仓码快照', pallet_id BIGINT NOT NULL COMMENT '实物托盘ID', pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照', location_id BIGINT NOT NULL COMMENT '库位ID快照', location_code VARCHAR(128) NOT NULL COMMENT '库位码快照', book_packages BIGINT NOT NULL COMMENT '任务创建时账面总箱数', actual_packages BIGINT NULL COMMENT '现场实盘总箱数', difference_packages BIGINT NULL COMMENT '实盘与账面箱数差异', status VARCHAR(32) NOT NULL COMMENT '盘点明细状态', position_version BIGINT NOT NULL COMMENT '任务创建时库存位置版本', counted_by VARCHAR(128) NULL COMMENT '盘点操作账号标识', version BIGINT NOT NULL DEFAULT 0 COMMENT '明细乐观锁版本', counted_at DATETIME(3) NULL COMMENT '盘点时间', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_stocktake_item(task_id,position_id), KEY idx_ll_pda_stocktake_item_task(task_id,status,id) ) ENGINE=InnoDB COMMENT='海外PDA库存盘点位置明细'; CREATE TABLE IF NOT EXISTS ll_pda_stocktake_action ( id BIGINT NOT NULL COMMENT '盘点动作ID', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', idempotency_key VARCHAR(128) NOT NULL COMMENT '动作幂等键', action_type VARCHAR(32) NOT NULL COMMENT '盘点动作类型', task_id BIGINT NULL COMMENT '盘点任务ID', request_hash VARCHAR(128) NOT NULL COMMENT '动作请求哈希', status VARCHAR(32) NOT NULL COMMENT '动作处理状态', result_json LONGTEXT NULL COMMENT '成功响应JSON', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_stocktake_action(overseas_warehouse_id,operator_key,idempotency_key), KEY idx_ll_pda_stocktake_action_task(task_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA盘点动作幂等记录'; CREATE TABLE IF NOT EXISTS ll_pda_inventory_move ( id BIGINT NOT NULL COMMENT '移库操作ID', move_no VARCHAR(64) NOT NULL COMMENT '移库操作单号', overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID', pallet_id BIGINT NOT NULL COMMENT '整托移库的实物托盘ID', pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照', source_location_id BIGINT NOT NULL COMMENT '来源库位ID', source_location_code VARCHAR(128) NOT NULL COMMENT '来源库位码快照', target_location_id BIGINT NOT NULL COMMENT '目标库位ID', target_location_code VARCHAR(128) NOT NULL COMMENT '目标库位码快照', customer_count INT NOT NULL COMMENT '托盘涉及客户数', position_count INT NOT NULL COMMENT '迁移库存位置数', package_count BIGINT NOT NULL COMMENT '迁移总箱数', pallet_version_before INT NOT NULL COMMENT '迁移前托盘版本', pallet_version_after INT NULL COMMENT '迁移后托盘版本', operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识', reason VARCHAR(500) NOT NULL COMMENT '移库原因', idempotency_key VARCHAR(128) NOT NULL COMMENT '移库幂等键', request_hash VARCHAR(128) NOT NULL COMMENT '移库请求哈希', status VARCHAR(32) NOT NULL COMMENT '移库处理状态', result_json LONGTEXT NULL COMMENT '成功响应JSON', created_at DATETIME(3) NOT NULL COMMENT '创建时间', completed_at DATETIME(3) NULL COMMENT '完成时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_pda_inventory_move_no(move_no), UNIQUE KEY uk_ll_pda_inventory_move_key(overseas_warehouse_id,operator_key,idempotency_key), KEY idx_ll_pda_inventory_move_pallet(overseas_warehouse_id,pallet_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA同仓整托移库记录'; CREATE TABLE IF NOT EXISTS ll_relabel_pda_task ( id BIGINT NOT NULL COMMENT '换标PDA任务ID', application_id BIGINT NOT NULL COMMENT '换标申请单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', relabel_no VARCHAR(64) NOT NULL COMMENT '换标申请单号快照', overseas_warehouse_id BIGINT NOT NULL COMMENT 'PDA令牌冻结的海外实际作业仓ID', status VARCHAR(32) NOT NULL COMMENT '任务状态:PROCESSING、WAIT_REVIEW或COMPLETED', operator_key VARCHAR(128) NOT NULL COMMENT '认领操作账号标识', operator_name VARCHAR(255) NOT NULL COMMENT '认领操作员名称快照', reviewer_key VARCHAR(128) NULL COMMENT '复核账号标识', reviewer_name VARCHAR(255) NULL COMMENT '复核员名称快照', expected_packages INT NOT NULL COMMENT '申请单通知的应换标箱数', relabelled_packages INT NOT NULL DEFAULT 0 COMMENT '已正常换标箱数', skipped_packages INT NOT NULL DEFAULT 0 COMMENT '已说明原因跳过箱数', exception_packages INT NOT NULL DEFAULT 0 COMMENT '已登记异常箱数', completion_photo_file_ids JSON NULL COMMENT '换标完成现场照片文件ID列表', completion_remark VARCHAR(1000) NULL COMMENT '完成提交备注', review_decision VARCHAR(16) NULL COMMENT '最近复核结论:APPROVE或REWORK', review_remark VARCHAR(1000) NULL COMMENT '最近复核备注', claimed_at DATETIME(3) NOT NULL COMMENT '任务认领时间', submitted_at DATETIME(3) NULL COMMENT '提交复核时间', reviewed_at DATETIME(3) NULL COMMENT '最近复核时间', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_relabel_pda_task_application (customer_id,application_id), UNIQUE KEY uk_ll_relabel_pda_task_no (relabel_no), KEY idx_ll_relabel_pda_task_warehouse (overseas_warehouse_id,status,updated_at), KEY idx_ll_relabel_pda_task_operator (operator_key,status,updated_at) ) ENGINE=InnoDB COMMENT='海外PDA换标现场作业任务'; CREATE TABLE IF NOT EXISTS ll_relabel_pda_unit_fact ( id BIGINT NOT NULL COMMENT '逐件换标事实ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID', application_id BIGINT NOT NULL COMMENT '换标申请单ID', item_id BIGINT NOT NULL COMMENT '换标申请明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', old_label VARCHAR(255) NULL COMMENT '扫描的实物旧标签或箱标', new_label VARCHAR(255) NULL COMMENT '扫描的换标后新标签', result VARCHAR(32) NOT NULL COMMENT '逐件结果:RELABELLED、SKIPPED或EXCEPTION', exception_code VARCHAR(32) NULL COMMENT '异常编码', reason VARCHAR(1000) NULL COMMENT '跳过或异常原因', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号标识', operator_name VARCHAR(255) NOT NULL COMMENT '操作员名称快照', occurred_at DATETIME(3) NOT NULL COMMENT '逐件事实发生时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_relabel_pda_old_label (old_label), KEY idx_ll_relabel_pda_unit_task (customer_id,task_id,occurred_at,id), KEY idx_ll_relabel_pda_unit_item (customer_id,application_id,item_id) ) ENGINE=InnoDB COMMENT='海外PDA逐件换标扫码与异常事实'; CREATE TABLE IF NOT EXISTS ll_relabel_pda_operation ( id BIGINT NOT NULL COMMENT '换标PDA幂等操作ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', operator_key VARCHAR(128) NOT NULL COMMENT '请求操作账号标识', action VARCHAR(32) NOT NULL COMMENT '幂等操作动作', idempotency_key VARCHAR(255) NOT NULL COMMENT '设备生成的幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', result_json LONGTEXT NOT NULL COMMENT '成功响应快照JSON', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), UNIQUE KEY uk_ll_relabel_pda_operation_key (operator_key,idempotency_key), KEY idx_ll_relabel_pda_operation_task (customer_id,task_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA换标写操作幂等记录'; CREATE TABLE IF NOT EXISTS ll_relabel_pda_history ( id BIGINT NOT NULL COMMENT '换标PDA任务历史ID', task_id BIGINT NOT NULL COMMENT '换标PDA任务ID', application_id BIGINT NOT NULL COMMENT '换标申请单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', action VARCHAR(32) NOT NULL COMMENT '现场动作类型', from_status VARCHAR(32) NULL COMMENT '动作前任务状态', to_status VARCHAR(32) NOT NULL COMMENT '动作后任务状态', operator_key VARCHAR(128) NOT NULL COMMENT '操作账号标识', operator_name VARCHAR(255) NOT NULL COMMENT '操作员名称快照', detail_json LONGTEXT NULL COMMENT '动作详情JSON', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY (id), KEY idx_ll_relabel_pda_history_task (customer_id,task_id,created_at,id), KEY idx_ll_relabel_pda_history_application (customer_id,application_id,created_at) ) ENGINE=InnoDB COMMENT='海外PDA换标任务不可变操作历史'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_application' AND column_name='review_idempotency_key'), 'SELECT 1', 'ALTER TABLE ll_cargo_discard_application ADD COLUMN review_idempotency_key VARCHAR(255) NULL COMMENT ''审核幂等键'' AFTER request_hash')); PREPARE phase4_discard_review_stmt FROM @ddl; EXECUTE phase4_discard_review_stmt; DEALLOCATE PREPARE phase4_discard_review_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_application' AND column_name='review_request_hash'), 'SELECT 1', 'ALTER TABLE ll_cargo_discard_application ADD COLUMN review_request_hash CHAR(64) NULL COMMENT ''审核请求内容哈希'' AFTER review_idempotency_key')); PREPARE phase4_discard_review_stmt FROM @ddl; EXECUTE phase4_discard_review_stmt; DEALLOCATE PREPARE phase4_discard_review_stmt; -- Warehouse Overseas 与 Lastleg 使用同一海外区域发布入口但保持独立数据库。 -- 公共托盘详情实体读取 fba_warehouse_code;旧库缺列时创建可成功但详情会 S0500。 USE baiyue_lastlag_warehouse; -- 仓库主档唯一权威已收口至国内 baiyue_warehouse;海外库只保留 warehouse_id 引用。 -- 当前开发阶段不兼容旧海外主档数据,按依赖顺序移除重复表。 DROP TABLE IF EXISTS wh_service_capability; DROP TABLE IF EXISTS wh_warehouse_address; DROP TABLE IF EXISTS wh_warehouse; CREATE TABLE IF NOT EXISTS wh_pallet_operation ( id BIGINT NOT NULL COMMENT '托盘状态操作ID', operation_key VARCHAR(128) NOT NULL COMMENT '跨服务幂等操作键', request_hash VARCHAR(128) NOT NULL COMMENT '状态变更请求摘要', warehouse_id BIGINT NOT NULL COMMENT '实际海外仓ID', pallet_id BIGINT NOT NULL COMMENT '实物托盘ID', pallet_code VARCHAR(128) NOT NULL COMMENT '实物托盘码快照', before_status VARCHAR(20) NOT NULL COMMENT '变更前托盘状态', after_status VARCHAR(20) NOT NULL COMMENT '变更后托盘状态', before_location_id BIGINT NULL COMMENT '变更前库位ID,无库位托盘为空', after_location_id BIGINT NULL COMMENT '变更后库位ID,无库位托盘为空', before_version INT NOT NULL COMMENT '变更前托盘版本', after_version INT NOT NULL COMMENT '变更后托盘版本', operation_status VARCHAR(32) NOT NULL COMMENT '操作状态:APPLIED已应用、COMPENSATED已补偿', reason VARCHAR(500) NULL COMMENT '操作原因', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_wh_pallet_operation_key (operation_key), KEY idx_wh_pallet_operation_pallet (warehouse_id,pallet_id,created_at) ) ENGINE=InnoDB COMMENT='实物托盘状态幂等变更与补偿记录'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='wh_pallet' AND column_name='fba_warehouse_code'), 'SELECT 1', 'ALTER TABLE wh_pallet ADD COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''所属FBA仓编码'' AFTER remark')); PREPARE phase4_warehouse_pallet_stmt FROM @ddl; EXECUTE phase4_warehouse_pallet_stmt; DEALLOCATE PREPARE phase4_warehouse_pallet_stmt; SET @warehouse_pallet_fba_ready = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastlag_warehouse' AND table_name='wh_pallet' AND column_name='fba_warehouse_code' AND column_type='varchar(128)'); DROP PROCEDURE IF EXISTS assert_phase4_warehouse_pallet_ready; DELIMITER $$ CREATE PROCEDURE assert_phase4_warehouse_pallet_ready() BEGIN IF @warehouse_pallet_fba_ready <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='wh_pallet.fba_warehouse_code migration is incomplete'; END IF; END$$ DELIMITER ; CALL assert_phase4_warehouse_pallet_ready(); DROP PROCEDURE assert_phase4_warehouse_pallet_ready; USE baiyue_lastleg; DROP PROCEDURE IF EXISTS assert_phase4_pda_operations_ready; DELIMITER $$ CREATE PROCEDURE assert_phase4_pda_operations_ready() BEGIN IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name IN ( 'll_pda_pallet_operation','ll_pda_stocktake_task','ll_pda_stocktake_item', 'll_pda_stocktake_action','ll_pda_inventory_move','ll_relabel_pda_task', 'll_relabel_pda_unit_fact','ll_relabel_pda_operation','ll_relabel_pda_history')) <> 9 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA盘点、移库、托盘或换标表未完整部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastlag_warehouse' AND table_name='wh_pallet_operation') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA实物托盘操作表未部署'; END IF; END$$ DELIMITER ; CALL assert_phase4_pda_operations_ready(); DROP PROCEDURE assert_phase4_pda_operations_ready; CREATE TABLE IF NOT EXISTS ll_order_fee ( id BIGINT NOT NULL COMMENT '费用明细主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', fee_item VARCHAR(128) NOT NULL COMMENT '费用项目', currency VARCHAR(3) NOT NULL COMMENT '币种代码', amount DECIMAL(18,2) NOT NULL COMMENT '费用金额', status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '费用状态:PENDING_REVIEW待审核、APPROVED审核通过、REJECTED已驳回', supplier_description VARCHAR(500) NULL COMMENT '供应商或费用说明', created_by VARCHAR(128) NOT NULL COMMENT '创建操作人', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY(id), KEY idx_ll_order_fee_customer_order(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单费用明细'; CREATE TABLE IF NOT EXISTS ll_order_operation_log ( id BIGINT NOT NULL COMMENT '操作记录主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', operation_node VARCHAR(64) NOT NULL COMMENT '操作节点', operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', result VARCHAR(500) NOT NULL COMMENT '处理结果', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间', PRIMARY KEY(id), KEY idx_ll_order_operation_customer_order(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单操作记录'; -- 五期正式结构必须由海外固定入口自行补齐;既有四期库不得依赖当前基线或历史脚本。 -- 收敛曾由历史局部脚本建立的五期中间结构;只补结构,不回填或修复旧数据。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_outbound_order RENAME COLUMN tenant_id TO customer_id')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_outbound_pallet_item RENAME COLUMN tenant_id TO customer_id')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='customer_id'), 'SELECT 1', 'ALTER TABLE ll_delivery_order RENAME COLUMN tenant_id TO customer_id')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='outbound_type'), 'SELECT 1', 'ALTER TABLE ll_outbound_order ADD COLUMN outbound_type VARCHAR(32) NOT NULL DEFAULT ''DISPATCH_DELIVERY'' COMMENT ''出库类型:派送转出库、一件代发'' AFTER status')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='lx_codes'), 'SELECT 1', 'ALTER TABLE ll_outbound_order ADD COLUMN lx_codes VARCHAR(1000) NULL COMMENT ''关联一件代发领星入库单代码汇总'' AFTER outbound_type')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='recipient_info'), 'SELECT 1', 'ALTER TABLE ll_outbound_order ADD COLUMN recipient_info VARCHAR(1000) NULL COMMENT ''一件代发收件信息'' AFTER lx_codes')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='sku_code'), 'SELECT 1', 'ALTER TABLE ll_outbound_pallet_item ADD COLUMN sku_code VARCHAR(128) NULL COMMENT ''一件代发SKU''')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='picked_package_count'), 'SELECT 1', 'ALTER TABLE ll_outbound_pallet_item ADD COLUMN picked_package_count INT NOT NULL DEFAULT 0 COMMENT ''已拣箱数'' AFTER package_count')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='status'), 'SELECT 1', 'ALTER TABLE ll_outbound_pallet_item ADD COLUMN status VARCHAR(32) NOT NULL DEFAULT ''WAIT_PICK'' COMMENT ''拣货状态'' AFTER picked_package_count')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='warehouse_pallet_id' AND is_nullable='NO'), 'ALTER TABLE ll_outbound_pallet_item MODIFY COLUMN warehouse_pallet_id BIGINT NULL COMMENT ''仓库实物托盘ID'', MODIFY COLUMN pallet_no VARCHAR(128) NULL COMMENT ''托盘号''', 'SELECT 1')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='dispatch_order_id' AND is_nullable='YES'), 'SELECT 1', 'ALTER TABLE ll_outbound_order MODIFY COLUMN dispatch_order_id BIGINT NULL COMMENT ''派车单ID,一件代发为空'', MODIFY COLUMN dispatch_no VARCHAR(64) NULL COMMENT ''派车单号,一件代发为空''')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='overseas_warehouse_name'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN overseas_warehouse_name VARCHAR(255) NULL COMMENT ''海外仓名称快照'' AFTER overseas_warehouse_id')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='customer_name'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN customer_name VARCHAR(255) NULL COMMENT ''客户名称快照'' AFTER overseas_warehouse_name')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='waybill_no'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN waybill_no VARCHAR(128) NULL COMMENT ''承运运单号'', ADD COLUMN delivery_method VARCHAR(32) NULL COMMENT ''派送方式'', ADD COLUMN carrier_name VARCHAR(255) NULL COMMENT ''派送承运商'', ADD COLUMN pickup_method VARCHAR(64) NULL COMMENT ''提货方式'', ADD COLUMN loading_type VARCHAR(64) NULL COMMENT ''装车类型'', ADD COLUMN vehicle_type VARCHAR(64) NULL COMMENT ''车辆类型'', ADD COLUMN vehicle_size VARCHAR(64) NULL COMMENT ''车辆大小'', ADD COLUMN vehicle_plate VARCHAR(64) NULL COMMENT ''车牌号'', ADD COLUMN driver_name VARCHAR(128) NULL COMMENT ''司机或车队名称'', ADD COLUMN driver_phone VARCHAR(64) NULL COMMENT ''车队联系电话'', ADD COLUMN appointment_account VARCHAR(128) NULL COMMENT ''预约账号'', ADD COLUMN seller_name VARCHAR(128) NULL COMMENT ''卖家姓名'' AFTER status')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='total_weight_kg'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN total_weight_kg DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''总重量(千克)'', ADD COLUMN total_volume_cbm DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''总体积(立方米)'', ADD COLUMN planned_delivery_at DATETIME(3) NULL COMMENT ''预计派送时间'', ADD COLUMN dispatched_at DATETIME(3) NULL COMMENT ''实际派送时间'', ADD COLUMN expected_arrival_at DATETIME(3) NULL COMMENT ''预计到达时间'', ADD COLUMN signed_at DATETIME(3) NULL COMMENT ''签收时间'', ADD COLUMN remark VARCHAR(1000) NULL COMMENT ''派送备注'' AFTER pallet_count')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='version'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN version BIGINT NOT NULL DEFAULT 0 COMMENT ''派送单乐观锁版本'' AFTER created_by')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_exception_order' AND column_name='handling_result'), 'SELECT 1', 'ALTER TABLE ll_exception_order ADD COLUMN handling_result VARCHAR(2000) NULL COMMENT ''异常处理结果'' AFTER handling_action')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_exception_order' AND column_name='evidence_file_ids_json'), 'SELECT 1', 'ALTER TABLE ll_exception_order ADD COLUMN evidence_file_ids_json JSON NULL COMMENT ''异常处理证据文件ID列表'' AFTER handling_result')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_exception_order' AND column_name='inventory_adjustment_id'), 'SELECT 1', 'ALTER TABLE ll_exception_order ADD COLUMN inventory_adjustment_id BIGINT NULL COMMENT ''退回库存恢复操作ID'' AFTER evidence_file_ids_json')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_exception_order' AND column_name='completed_at'), 'SELECT 1', 'ALTER TABLE ll_exception_order ADD COLUMN completed_at DATETIME(3) NULL COMMENT ''异常处理完成时间'' AFTER exception_at')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_exception_order' AND column_name='version'), 'SELECT 1', 'ALTER TABLE ll_exception_order ADD COLUMN version BIGINT NOT NULL DEFAULT 0 COMMENT ''异常订单乐观锁版本'' AFTER completed_at')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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 ''来源托盘号快照'' AFTER pallet_no')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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='manifest_version'), 'SELECT 1', 'ALTER TABLE ll_dropship_order_profile ADD COLUMN manifest_version INT NOT NULL DEFAULT 1 COMMENT ''整托清单版本'' AFTER source_pallet_no')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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='manifest_package_count'), 'SELECT 1', 'ALTER TABLE ll_dropship_order_profile ADD COLUMN manifest_package_count INT NOT NULL DEFAULT 1 COMMENT ''整托总箱数'' AFTER manifest_version')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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='manifest_fragment_count'), 'SELECT 1', 'ALTER TABLE ll_dropship_order_profile ADD COLUMN manifest_fragment_count INT NOT NULL DEFAULT 1 COMMENT ''整托客户分片总数'' AFTER manifest_package_count')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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='manifest_hash'), 'SELECT 1', 'ALTER TABLE ll_dropship_order_profile ADD COLUMN manifest_hash CHAR(64) NOT NULL DEFAULT ''0000000000000000000000000000000000000000000000000000000000000000'' COMMENT ''整托完整清单摘要'' AFTER manifest_fragment_count')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; ALTER TABLE ll_dropship_order_profile MODIFY COLUMN manifest_version INT NOT NULL COMMENT '整托清单版本', MODIFY COLUMN manifest_package_count INT NOT NULL COMMENT '整托总箱数', MODIFY COLUMN manifest_fragment_count INT NOT NULL COMMENT '整托客户分片总数', MODIFY COLUMN manifest_hash CHAR(64) NOT NULL COMMENT '整托完整清单摘要'; 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_manifest'), 'SELECT 1', 'ALTER TABLE ll_dropship_order_profile ADD KEY idx_ll_dropship_profile_manifest(source_pallet_no,manifest_hash)')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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 phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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 phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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 phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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'), 'ALTER TABLE ll_dropship_sku_inventory DROP INDEX uk_ll_dropship_sku_profile', 'SELECT 1')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @index_ready = (SELECT COUNT(*)=2 AND MIN(non_unique)=0 AND SUM(seq_in_index=1 AND column_name='profile_id')=1 AND SUM(seq_in_index=2 AND column_name='sku_code')=1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_dropship_sku_inventory' AND index_name='uk_ll_dropship_sku_inventory'); SET @index_exists = (SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_dropship_sku_inventory' AND index_name='uk_ll_dropship_sku_inventory'); SET @ddl = IF(@index_ready, 'SELECT 1', IF(@index_exists, 'ALTER TABLE ll_dropship_sku_inventory DROP INDEX uk_ll_dropship_sku_inventory, ADD UNIQUE KEY uk_ll_dropship_sku_inventory(profile_id,sku_code)', 'ALTER TABLE ll_dropship_sku_inventory ADD UNIQUE KEY uk_ll_dropship_sku_inventory(profile_id,sku_code)')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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 phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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='warehouse_pallet_id' AND is_nullable='NO'), 'ALTER TABLE ll_dropship_order_profile MODIFY COLUMN warehouse_pallet_id BIGINT NULL COMMENT ''仓库实物托盘ID'', MODIFY COLUMN pallet_no VARCHAR(128) NULL COMMENT ''托盘号''', 'SELECT 1')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dropship_carton' AND column_name='warehouse_pallet_id' AND is_nullable='NO'), 'ALTER TABLE ll_dropship_carton MODIFY COLUMN warehouse_pallet_id BIGINT NULL COMMENT ''仓库实物托盘ID'', MODIFY COLUMN pallet_no VARCHAR(128) NULL COMMENT ''托盘号''', 'SELECT 1')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; 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='status' AND column_default<>'PENDING_INBOUND'), 'ALTER TABLE ll_dropship_order_profile MODIFY COLUMN status VARCHAR(32) NOT NULL DEFAULT ''PENDING_INBOUND'' COMMENT ''业务状态''', 'SELECT 1')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dropship_carton' AND column_name='status' AND column_default<>'PENDING_INBOUND'), 'ALTER TABLE ll_dropship_carton MODIFY COLUMN status VARCHAR(32) NOT NULL DEFAULT ''PENDING_INBOUND'' COMMENT ''业务状态''', 'SELECT 1')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; -- 五期排车、出库与海外PDA正式业务号/幂等约束。只补结构并 fail-fast 校验开发数据,不回填或修复旧行。 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 COMMENT ''Token绑定的海外仓库ID'' AFTER operator_id')); PREPARE phase5_pda_scope_ddl FROM @ddl; EXECUTE phase5_pda_scope_ddl; DEALLOCATE PREPARE phase5_pda_scope_ddl; SET @ddl = (SELECT IF(EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pda_task' AND column_name='completion_idempotency_key' ), 'SELECT 1', 'ALTER TABLE ll_outbound_pda_task ADD COLUMN completion_idempotency_key VARCHAR(255) NULL COMMENT ''完成命令幂等键'' AFTER status')); PREPARE phase5_pda_scope_ddl FROM @ddl; EXECUTE phase5_pda_scope_ddl; DEALLOCATE PREPARE phase5_pda_scope_ddl; DROP PROCEDURE IF EXISTS assert_phase5_lastleg_identifiers_migratable; DELIMITER $$ CREATE PROCEDURE assert_phase5_lastleg_identifiers_migratable() BEGIN IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name IN ( 'll_dispatch_order','ll_dispatch_item','ll_dispatch_pallet_lock','ll_dispatch_draft','ll_dispatch_draft_container', 'll_dispatch_pda_task','ll_dispatch_pda_pick','ll_dispatch_pda_operation','ll_dispatch_pda_pick_order', 'll_outbound_order','ll_outbound_pallet_item','ll_outbound_pda_task','ll_outbound_pda_pick', 'll_delivery_order','ll_delivery_operation', 'll_dropship_order_profile','ll_dropship_carton','ll_dropship_sku_inventory','ll_dropship_carton_ledger', 'll_exception_order','ll_exception_return_item','ll_exception_order_command','ll_customer_visit')) <> 23 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期排车、出库、派送、一件代发、异常或回访表未完整部署'; END IF; IF EXISTS (SELECT dispatch_no FROM ll_dispatch_order GROUP BY dispatch_no HAVING COUNT(*)>1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_dispatch_order存在跨客户重复dispatch_no,无法收敛全局唯一'; END IF; IF EXISTS (SELECT outbound_no FROM ll_outbound_order GROUP BY outbound_no HAVING COUNT(*)>1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_outbound_order存在跨客户重复outbound_no,无法收敛全局唯一'; END IF; IF EXISTS (SELECT task_no FROM ll_dispatch_pda_task GROUP BY task_no HAVING COUNT(*)>1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_dispatch_pda_task存在跨客户重复task_no,无法收敛全局唯一'; END IF; IF EXISTS (SELECT task_no FROM ll_outbound_pda_task GROUP BY task_no HAVING COUNT(*)>1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_outbound_pda_task存在跨客户重复task_no,无法收敛全局唯一'; END IF; IF EXISTS (SELECT customer_id,completion_idempotency_key FROM ll_outbound_pda_task WHERE completion_idempotency_key IS NOT NULL GROUP BY customer_id,completion_idempotency_key HAVING COUNT(*)>1) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_outbound_pda_task存在重复完成幂等键,无法创建客户范围唯一约束'; END IF; IF EXISTS (SELECT 1 FROM ll_dispatch_pda_task WHERE warehouse_id IS NULL OR TRIM(warehouse_id)='' OR TRIM(warehouse_id)='0') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_dispatch_pda_task存在空或0仓库范围;请重新造数后重跑,脚本不回填旧行'; END IF; IF EXISTS (SELECT 1 FROM ll_dropship_order_profile WHERE source_pallet_no IS NULL OR TRIM(source_pallet_no)='') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_dropship_order_profile存在空来源托盘号;请重新造数后重跑,脚本不回填旧行'; END IF; END$$ DELIMITER ; CALL assert_phase5_lastleg_identifiers_migratable(); DROP PROCEDURE assert_phase5_lastleg_identifiers_migratable; 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' AND is_nullable='NO' AND column_type='varchar(128)' AND column_comment='Token绑定的海外仓库ID' ), 'SELECT 1', 'ALTER TABLE ll_dispatch_pda_task MODIFY COLUMN warehouse_id VARCHAR(128) NOT NULL COMMENT ''Token绑定的海外仓库ID''')); PREPARE phase5_pda_scope_ddl FROM @ddl; EXECUTE phase5_pda_scope_ddl; DEALLOCATE PREPARE phase5_pda_scope_ddl; 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' AND is_nullable='NO' AND column_type='varchar(128)' AND column_comment='来源托盘号快照' ), 'SELECT 1', 'ALTER TABLE ll_dropship_order_profile MODIFY COLUMN source_pallet_no VARCHAR(128) NOT NULL COMMENT ''来源托盘号快照''')); PREPARE phase5_structure_ddl FROM @ddl; EXECUTE phase5_structure_ddl; DEALLOCATE PREPARE phase5_structure_ddl; SET @index_ready = (SELECT COUNT(*)=1 AND MIN(non_unique)=0 AND MAX(seq_in_index=1 AND column_name='dispatch_no')=1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_dispatch_order' AND index_name='uk_ll_dispatch_order_no'); SET @index_exists = (SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_dispatch_order' AND index_name='uk_ll_dispatch_order_no'); SET @ddl = IF(@index_ready, 'SELECT 1', IF(@index_exists, 'ALTER TABLE ll_dispatch_order DROP INDEX uk_ll_dispatch_order_no, ADD UNIQUE KEY uk_ll_dispatch_order_no(dispatch_no)', 'ALTER TABLE ll_dispatch_order ADD UNIQUE KEY uk_ll_dispatch_order_no(dispatch_no)')); PREPARE phase5_identifier_ddl FROM @ddl; EXECUTE phase5_identifier_ddl; DEALLOCATE PREPARE phase5_identifier_ddl; SET @index_ready = (SELECT COUNT(*)=1 AND MIN(non_unique)=0 AND MAX(seq_in_index=1 AND column_name='outbound_no')=1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND index_name='uk_ll_outbound_no'); SET @index_exists = (SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND index_name='uk_ll_outbound_no'); SET @ddl = IF(@index_ready, 'SELECT 1', IF(@index_exists, 'ALTER TABLE ll_outbound_order DROP INDEX uk_ll_outbound_no, ADD UNIQUE KEY uk_ll_outbound_no(outbound_no)', 'ALTER TABLE ll_outbound_order ADD UNIQUE KEY uk_ll_outbound_no(outbound_no)')); PREPARE phase5_identifier_ddl FROM @ddl; EXECUTE phase5_identifier_ddl; DEALLOCATE PREPARE phase5_identifier_ddl; SET @index_ready = (SELECT COUNT(*)=1 AND MIN(non_unique)=0 AND MAX(seq_in_index=1 AND column_name='task_no')=1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pda_task' AND index_name='uk_ll_dispatch_pda_task_no'); SET @index_exists = (SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pda_task' AND index_name='uk_ll_dispatch_pda_task_no'); SET @ddl = IF(@index_ready, 'SELECT 1', IF(@index_exists, 'ALTER TABLE ll_dispatch_pda_task DROP INDEX uk_ll_dispatch_pda_task_no, ADD UNIQUE KEY uk_ll_dispatch_pda_task_no(task_no)', 'ALTER TABLE ll_dispatch_pda_task ADD UNIQUE KEY uk_ll_dispatch_pda_task_no(task_no)')); PREPARE phase5_identifier_ddl FROM @ddl; EXECUTE phase5_identifier_ddl; DEALLOCATE PREPARE phase5_identifier_ddl; SET @index_ready = (SELECT COUNT(*)=1 AND MIN(non_unique)=0 AND MAX(seq_in_index=1 AND column_name='task_no')=1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_task_no'); SET @index_exists = (SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_task_no'); SET @ddl = IF(@index_ready, 'SELECT 1', IF(@index_exists, 'ALTER TABLE ll_outbound_pda_task DROP INDEX uk_ll_outbound_pda_task_no, ADD UNIQUE KEY uk_ll_outbound_pda_task_no(task_no)', 'ALTER TABLE ll_outbound_pda_task ADD UNIQUE KEY uk_ll_outbound_pda_task_no(task_no)')); PREPARE phase5_identifier_ddl FROM @ddl; EXECUTE phase5_identifier_ddl; DEALLOCATE PREPARE phase5_identifier_ddl; SET @index_ready = (SELECT COUNT(*)=2 AND MIN(non_unique)=0 AND SUM(seq_in_index=1 AND column_name='customer_id')=1 AND SUM(seq_in_index=2 AND column_name='completion_idempotency_key')=1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_complete_key'); SET @index_exists = (SELECT COUNT(*)>0 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_complete_key'); SET @ddl = IF(@index_ready, 'SELECT 1', IF(@index_exists, 'ALTER TABLE ll_outbound_pda_task DROP INDEX uk_ll_outbound_pda_complete_key, ADD UNIQUE KEY uk_ll_outbound_pda_complete_key(customer_id,completion_idempotency_key)', 'ALTER TABLE ll_outbound_pda_task ADD UNIQUE KEY uk_ll_outbound_pda_complete_key(customer_id,completion_idempotency_key)')); PREPARE phase5_identifier_ddl FROM @ddl; EXECUTE phase5_identifier_ddl; DEALLOCATE PREPARE phase5_identifier_ddl; DROP PROCEDURE IF EXISTS assert_phase5_lastleg_identifiers_ready; DELIMITER $$ CREATE PROCEDURE assert_phase5_lastleg_identifiers_ready() BEGIN IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name IN ( 'll_dispatch_order','ll_dispatch_item','ll_dispatch_pallet_lock','ll_dispatch_draft','ll_dispatch_draft_container', 'll_dispatch_pda_task','ll_dispatch_pda_pick','ll_dispatch_pda_operation','ll_dispatch_pda_pick_order', 'll_outbound_order','ll_outbound_pallet_item','ll_outbound_pda_task','ll_outbound_pda_pick', 'll_delivery_order','ll_delivery_operation', 'll_dropship_order_profile','ll_dropship_carton','ll_dropship_sku_inventory','ll_dropship_carton_ledger', 'll_exception_order','ll_exception_return_item','ll_exception_order_command','ll_customer_visit')) <> 23 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期完整业务表集合未部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_dispatch_pda_task' AND column_name='warehouse_id' AND is_nullable='NO') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_dispatch_pda_task.warehouse_id未收敛为非空'; END IF; IF EXISTS (SELECT 1 FROM ll_dispatch_pda_task WHERE warehouse_id IS NULL OR TRIM(warehouse_id)='' OR TRIM(warehouse_id)='0') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_dispatch_pda_task仍存在空或0仓库范围'; END IF; IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_dropship_order_profile' AND column_name='source_pallet_no' AND column_type='varchar(128)' AND is_nullable='NO' AND column_comment='来源托盘号快照') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='一件代发来源托盘号字段未收敛'; END IF; IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_dropship_order_profile' AND column_name IN ('manifest_version','manifest_package_count','manifest_fragment_count','manifest_hash') AND is_nullable='NO') <> 4 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='一件代发托盘清单字段未完整收敛'; END IF; IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_dropship_order_profile' AND index_name='idx_ll_dropship_profile_manifest') <> 2 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='一件代发托盘清单索引未部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_outbound_pda_task' AND column_name='completion_idempotency_key' AND column_type='varchar(255)' AND is_nullable='YES') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='ll_outbound_pda_task完成幂等字段未部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_dispatch_order' AND index_name='uk_ll_dispatch_order_no') <> 1 OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_dispatch_order' AND index_name='uk_ll_dispatch_order_no' AND non_unique=0 AND seq_in_index=1 AND column_name='dispatch_no') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='dispatch_no全局唯一索引未部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_outbound_order' AND index_name='uk_ll_outbound_no') <> 1 OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_outbound_order' AND index_name='uk_ll_outbound_no' AND non_unique=0 AND seq_in_index=1 AND column_name='outbound_no') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='outbound_no全局唯一索引未部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_dispatch_pda_task' AND index_name='uk_ll_dispatch_pda_task_no') <> 1 OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_dispatch_pda_task' AND index_name='uk_ll_dispatch_pda_task_no' AND non_unique=0 AND seq_in_index=1 AND column_name='task_no') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='排车PDA task_no全局唯一索引未部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_task_no') <> 1 OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_task_no' AND non_unique=0 AND seq_in_index=1 AND column_name='task_no') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='出库PDA task_no全局唯一索引未部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_complete_key') <> 2 OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_complete_key' AND non_unique=0 AND seq_in_index=1 AND column_name='customer_id') <> 1 OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_outbound_pda_task' AND index_name='uk_ll_outbound_pda_complete_key' AND non_unique=0 AND seq_in_index=2 AND column_name='completion_idempotency_key') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='出库PDA客户范围完成幂等唯一索引未部署'; END IF; END$$ DELIMITER ; CALL assert_phase5_lastleg_identifiers_ready(); DROP PROCEDURE assert_phase5_lastleg_identifiers_ready; USE baiyue_lastleg; SET @ddl = (SELECT IF(EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='version' ), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN version INT NOT NULL DEFAULT 0 COMMENT ''入库计划乐观锁版本'' AFTER updated_at')); PREPARE ll_inbound_plan_version_ddl FROM @ddl; EXECUTE ll_inbound_plan_version_ddl; DEALLOCATE PREPARE ll_inbound_plan_version_ddl; SET @ddl = (SELECT IF(EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='pallet_merge_batch_id' ), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN pallet_merge_batch_id VARCHAR(64) NULL COMMENT ''平台预标记合托分组号'' AFTER pallet_merge_flag')); PREPARE ll_order_merge_batch_ddl FROM @ddl; EXECUTE ll_order_merge_batch_ddl; DEALLOCATE PREPARE ll_order_merge_batch_ddl; CREATE TABLE IF NOT EXISTS ll_security_event_inbox ( event_id VARCHAR(64) NOT NULL COMMENT '跨区安全事件ID', event_type VARCHAR(96) NOT NULL COMMENT 'IAM安全事件类型', payload_hash CHAR(64) NOT NULL COMMENT '规范化载荷SHA-256哈希', payload_json JSON NOT NULL COMMENT '冻结事件载荷JSON', status VARCHAR(16) NOT NULL COMMENT '消费状态:RECEIVED或PROCESSED', result VARCHAR(32) NULL COMMENT '处理结果:APPLIED、STALE、DUPLICATE或DUPLICATE_VERSION', received_at DATETIME(3) NOT NULL COMMENT '接收时间', processed_at DATETIME(3) NULL COMMENT '处理完成时间', PRIMARY KEY (event_id), KEY idx_security_inbox_type_time (event_type,received_at) ) ENGINE=InnoDB COMMENT='海外IAM安全事件消费者收件箱'; CREATE TABLE IF NOT EXISTS ll_security_projection ( aggregate_type VARCHAR(32) NOT NULL COMMENT '聚合类型:USER、TENANT或AUTHORIZATION', aggregate_id VARCHAR(64) NOT NULL COMMENT '用户或客户聚合ID', tenant_id BIGINT NOT NULL COMMENT '平台0或客户ID', security_status VARCHAR(24) NULL COMMENT '当前安全状态:ACTIVE或DISABLED', permission_version BIGINT NULL COMMENT '当前单调权限版本', roles_json JSON NOT NULL COMMENT 'IAM投影的当前角色快照', authorities_json JSON NOT NULL COMMENT 'IAM投影的当前海外权限快照', aggregate_version BIGINT NOT NULL COMMENT '事件聚合单调版本', payload_hash CHAR(64) NOT NULL COMMENT '当前版本载荷哈希', last_event_id VARCHAR(64) NOT NULL COMMENT '最后应用的事件ID', changed_at DATETIME(3) NOT NULL COMMENT '国内IAM事实发生时间', updated_at DATETIME(3) NOT NULL COMMENT '投影更新时间', PRIMARY KEY (aggregate_type,aggregate_id), KEY idx_security_projection_tenant (tenant_id), KEY idx_security_projection_permission (aggregate_id,permission_version) ) ENGINE=InnoDB COMMENT='海外IAM安全状态与权限版本投影'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_security_projection' AND column_name='roles_json'), 'SELECT 1', 'ALTER TABLE ll_security_projection ADD COLUMN roles_json JSON NULL COMMENT ''IAM投影的当前角色快照'' AFTER permission_version')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_security_projection' AND column_name='authorities_json'), 'SELECT 1', 'ALTER TABLE ll_security_projection ADD COLUMN authorities_json JSON NULL COMMENT ''IAM投影的当前海外权限快照'' AFTER roles_json')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; UPDATE ll_security_projection SET roles_json=JSON_ARRAY() WHERE roles_json IS NULL; UPDATE ll_security_projection SET authorities_json=JSON_ARRAY() WHERE authorities_json IS NULL; ALTER TABLE ll_security_projection MODIFY COLUMN roles_json JSON NOT NULL COMMENT 'IAM投影的当前角色快照', MODIFY COLUMN authorities_json JSON NOT NULL COMMENT 'IAM投影的当前海外权限快照'; -- 与国内固定 auth_account.id=1000001、tenant_id=0 的 platform_admin 一致;真实事件从版本1覆盖。 INSERT IGNORE INTO ll_security_projection ( aggregate_type,aggregate_id,tenant_id,security_status,permission_version,roles_json,authorities_json,aggregate_version, payload_hash,last_event_id,changed_at,updated_at ) VALUES ('USER','1000001',0,'ACTIVE',0,JSON_ARRAY(),JSON_ARRAY(),0,SHA2('lastleg-baseline:platform_admin:USER:0',256), 'baseline-platform-admin-user-v0','1970-01-01 00:00:00.000','1970-01-01 00:00:00.000'), ('AUTHORIZATION','1000001',0,NULL,0,@platform_admin_overseas_roles,@platform_admin_overseas_authorities,0, SHA2('lastleg-baseline:platform_admin:AUTHORIZATION:0:current-authorities',256), 'baseline-platform-admin-authorization-v0','1970-01-01 00:00:00.000','1970-01-01 00:00:00.000'); UPDATE ll_security_projection SET roles_json=@platform_admin_overseas_roles, authorities_json=@platform_admin_overseas_authorities, payload_hash=SHA2('lastleg-baseline:platform_admin:AUTHORIZATION:0:current-authorities',256), updated_at=CURRENT_TIMESTAMP(3) WHERE aggregate_type='AUTHORIZATION' AND aggregate_id='1000001' AND tenant_id=0 AND aggregate_version=0 AND last_event_id='baseline-platform-admin-authorization-v0'; DROP PROCEDURE IF EXISTS assert_lastleg_security_projection_ready; DELIMITER $$ CREATE PROCEDURE assert_lastleg_security_projection_ready() BEGIN IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name IN ('ll_security_event_inbox','ll_security_projection')) <> 2 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外IAM安全Inbox或投影表未完整部署'; END IF; IF EXISTS ( SELECT 1 FROM ll_security_projection WHERE aggregate_type='AUTHORIZATION' AND aggregate_id='1000001' AND tenant_id=0 AND aggregate_version=0 AND last_event_id='baseline-platform-admin-authorization-v0' AND (JSON_LENGTH(roles_json) <> 1 OR NOT JSON_CONTAINS(roles_json, JSON_QUOTE('PLATFORM_ADMIN')) OR JSON_LENGTH(authorities_json) <> 106 OR NOT JSON_CONTAINS(authorities_json, JSON_QUOTE('platform:overseas-warehouse:last-mile-order:list')) OR NOT JSON_CONTAINS(authorities_json, JSON_QUOTE('platform:overseas-warehouse:inbound-order:list')) OR NOT JSON_CONTAINS(authorities_json, JSON_QUOTE('platform:overseas-warehouse:dispatch:list')) OR NOT JSON_CONTAINS(authorities_json, JSON_QUOTE('platform:overseas-business:purchase:list')) OR NOT JSON_CONTAINS(authorities_json, JSON_QUOTE('platform:overseas-master-data:quote:list')) OR NOT JSON_CONTAINS(authorities_json, JSON_QUOTE('platform:finance:fee-source:review'))) ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外IAM固定管理员version=0授权快照不完整'; END IF; END$$ DELIMITER ; CALL assert_lastleg_security_projection_ready(); DROP PROCEDURE assert_lastleg_security_projection_ready; CREATE TABLE IF NOT EXISTS ll_finance_fee_source ( id BIGINT NOT NULL COMMENT '费用版本记录ID', source_fee_id BIGINT NOT NULL COMMENT '跨版本稳定费用来源ID', source_version INT NOT NULL COMMENT '费用来源版本,从1递增', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', customer_name VARCHAR(200) NULL COMMENT '客户名称快照', source_type VARCHAR(64) NOT NULL COMMENT '海外费用来源类型', source_no VARCHAR(128) NOT NULL COMMENT '来源业务编号或入仓码快照', business_type VARCHAR(32) NOT NULL COMMENT '来源业务类型', business_id BIGINT NULL COMMENT '来源业务记录ID', business_no VARCHAR(128) NOT NULL COMMENT '来源业务编号', order_id BIGINT NULL COMMENT '关联订单ID', inbound_id BIGINT NULL COMMENT '关联海外入仓计划或入仓记录ID', inbound_code VARCHAR(64) NULL COMMENT '关联入仓码;并非所有费用必填', container_id BIGINT NULL COMMENT '关联柜次ID', container_booking_id BIGINT NULL COMMENT '来源订舱柜ID', container_no VARCHAR(64) NULL COMMENT '真实集装箱号快照', warehouse_id BIGINT NULL COMMENT '关联海外仓ID', fee_item_code VARCHAR(64) NOT NULL COMMENT '费用项目编码快照', fee_item_name VARCHAR(200) NOT NULL COMMENT '费用项目名称快照', direction VARCHAR(16) NOT NULL COMMENT 'RECEIVABLE应收或PAYABLE应付', supplier_id BIGINT NULL COMMENT '应付供应商ID', supplier_name VARCHAR(200) NULL COMMENT '应付供应商名称快照', supplier_category VARCHAR(32) NULL COMMENT '应付供应商类别约束', settlement_mode VARCHAR(16) NULL COMMENT 'ON_ACCOUNT账期应付或DIRECT_PAID业务已付', paid_at DATETIME(3) NULL COMMENT '直接已付时间', payment_method VARCHAR(32) NULL COMMENT '直接已付方式', payment_reference_no VARCHAR(128) NULL COMMENT '直接已付流水号', payment_voucher_file_ids JSON NULL COMMENT '直接已付凭证文件ID快照', business_date DATE NOT NULL COMMENT '费用业务日期', currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '财务结算币种,当前固定CNY', amount DECIMAL(20,6) NOT NULL COMMENT '费用金额', review_status VARCHAR(16) NOT NULL COMMENT 'DRAFT、PENDING、APPROVED或REJECTED', publication_status VARCHAR(16) NOT NULL COMMENT 'UNPUBLISHED或PUBLISHED', source_status VARCHAR(16) NOT NULL COMMENT 'ACTIVE、SUPERSEDED或VOIDED', review_reason VARCHAR(500) NULL COMMENT '审核或作废原因', reviewer_id VARCHAR(128) NULL COMMENT '审核人ID', reviewed_at DATETIME(3) NULL COMMENT '审核时间', created_by VARCHAR(128) NOT NULL COMMENT '创建人ID', updated_by VARCHAR(128) NOT NULL COMMENT '最后更新人ID', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_finance_fee_version(source_fee_id,source_version), KEY idx_ll_finance_fee_customer(customer_id,source_status,created_at), KEY idx_ll_finance_fee_business(business_type,business_no,created_at), CONSTRAINT chk_ll_finance_fee_amount CHECK(amount>0), CONSTRAINT chk_ll_finance_fee_currency CHECK(currency='CNY'), CONSTRAINT chk_ll_finance_fee_direction CHECK(direction IN('RECEIVABLE','PAYABLE')), CONSTRAINT chk_ll_finance_fee_review CHECK(review_status IN('DRAFT','PENDING','APPROVED','REJECTED')), CONSTRAINT chk_ll_finance_fee_publication CHECK(publication_status IN('UNPUBLISHED','PUBLISHED')), CONSTRAINT chk_ll_finance_fee_status CHECK(source_status IN('ACTIVE','SUPERSEDED','VOIDED')) ) ENGINE=InnoDB COMMENT='海外业务不可变费用来源版本;发布后经跨区事件进入Finance'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_finance_fee_source' AND index_name='idx_ll_finance_fee_container_customer'), 'SELECT 1', 'ALTER TABLE ll_finance_fee_source ADD KEY idx_ll_finance_fee_container_customer(container_booking_id,customer_id,source_status,created_at)')); PREPARE ll_finance_fee_ddl FROM @ddl; EXECUTE ll_finance_fee_ddl; DEALLOCATE PREPARE ll_finance_fee_ddl; CREATE TABLE IF NOT EXISTS ll_finance_fee_command ( id BIGINT NOT NULL COMMENT '幂等命令ID', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID', action VARCHAR(16) NOT NULL COMMENT 'CREATE、SUBMIT、REVIEW、ADJUST或VOID', idempotency_key VARCHAR(128) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256', source_fee_id BIGINT NOT NULL COMMENT '稳定费用来源ID', source_version INT NOT NULL COMMENT '命令结果版本', created_at DATETIME(3) NOT NULL COMMENT '命令创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_finance_fee_command(operator_id,action,idempotency_key), KEY idx_ll_finance_fee_command_source(source_fee_id,source_version) ) ENGINE=InnoDB COMMENT='海外费用来源写操作幂等审计'; SELECT 'PASS' AS migration_status, '海外仓业务、海外仓资源与IAM安全投影结构已就绪' AS message; CREATE TABLE IF NOT EXISTS ll_wallet_event_inbox ( event_id VARCHAR(64) NOT NULL COMMENT '国内Finance资金结果事件ID', command_event_id VARCHAR(64) NOT NULL COMMENT '原海外资金指令事件ID', payload_hash VARCHAR(71) NOT NULL COMMENT '规范化载荷SHA-256,包含sha256:前缀', payload_json JSON NOT NULL COMMENT '冻结事件信封', status VARCHAR(16) NOT NULL COMMENT 'RECEIVED或PROCESSED', received_at DATETIME(3) NOT NULL COMMENT '接收时间', processed_at DATETIME(3) NULL COMMENT '处理完成时间', PRIMARY KEY (event_id), UNIQUE KEY uk_ll_wallet_command_result (command_event_id), KEY idx_ll_wallet_event_status (status,received_at) ) ENGINE=InnoDB COMMENT='跨区客户资金结果幂等收件箱'; ALTER TABLE ll_wallet_event_inbox MODIFY COLUMN payload_hash VARCHAR(71) NOT NULL COMMENT '规范化载荷SHA-256,包含sha256:前缀'; CREATE TABLE IF NOT EXISTS ll_procurement_daily_sequence ( customer_id VARCHAR(128) NOT NULL COMMENT '客户ID', business_date DATE NOT NULL COMMENT '北京时间业务日期', sequence_value INT NOT NULL COMMENT '客户当日已分配最大序号', PRIMARY KEY (customer_id,business_date), CONSTRAINT chk_ll_procurement_sequence CHECK (sequence_value BETWEEN 1 AND 9999) ) ENGINE=InnoDB COMMENT='海外采购客户日序列'; CREATE TABLE IF NOT EXISTS ll_overseas_procurement_file ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID', category VARCHAR(16) NOT NULL COMMENT 'RECEIPT签收文件或VOUCHER费用凭证', file_id BIGINT NOT NULL COMMENT 'File服务文件ID', file_name VARCHAR(255) NOT NULL COMMENT '文件名快照', content_type VARCHAR(128) NULL COMMENT '媒体类型', size_bytes BIGINT NOT NULL DEFAULT 0 COMMENT '文件大小', created_by VARCHAR(128) NULL COMMENT '上传人', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '上传时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_procurement_file(order_id,file_id), KEY idx_ll_procurement_file_order(customer_id,order_id,category,created_at), CONSTRAINT chk_ll_procurement_file_category CHECK(category IN ('RECEIPT','VOUCHER')) ) ENGINE=InnoDB COMMENT='海外采购签收文件及费用凭证'; CREATE TABLE IF NOT EXISTS ll_overseas_procurement_fee ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID', fee_no VARCHAR(64) NOT NULL COMMENT '费用业务号', fee_item_code VARCHAR(32) NOT NULL COMMENT '费用项编码', fee_item_name VARCHAR(128) NOT NULL COMMENT '费用项名称', amount DECIMAL(20,2) NOT NULL COMMENT 'CNY金额', currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '费用币种', voucher_file_id BIGINT NOT NULL COMMENT '凭证文件ID', voucher_file_name VARCHAR(255) NOT NULL COMMENT '凭证文件名', remark VARCHAR(500) NULL COMMENT '说明', wallet_status VARCHAR(32) NOT NULL COMMENT '资金状态', wallet_error_code VARCHAR(64) NULL COMMENT '资金错误码', wallet_error_message VARCHAR(500) NULL COMMENT '资金错误说明', wallet_command_event_id VARCHAR(64) NULL COMMENT '当前资金指令事件ID', created_by VARCHAR(128) 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_procurement_fee_no(fee_no), KEY idx_ll_procurement_fee_order(customer_id,order_id,created_at), CONSTRAINT chk_ll_procurement_fee_amount CHECK(amount>0), CONSTRAINT chk_ll_procurement_fee_currency CHECK(currency='CNY') ) ENGINE=InnoDB COMMENT='海外采购费用明细及资金生命周期'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='charge_amount'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN charge_amount DECIMAL(20,2) NOT NULL DEFAULT 0 COMMENT ''换标费用CNY'' AFTER notified_package_count')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='charge_currency'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN charge_currency CHAR(3) NOT NULL DEFAULT ''CNY'' COMMENT ''费用币种'' AFTER charge_amount')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='wallet_status'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN wallet_status VARCHAR(32) NOT NULL DEFAULT ''FREEZE_PENDING'' COMMENT ''资金状态'' AFTER charge_currency')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='wallet_error_code'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN wallet_error_code VARCHAR(64) NULL COMMENT ''资金错误码'' AFTER wallet_status')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='wallet_error_message'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN wallet_error_message VARCHAR(500) NULL COMMENT ''资金错误说明'' AFTER wallet_error_code')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='wallet_command_event_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN wallet_command_event_id VARCHAR(64) NULL COMMENT ''当前资金指令事件ID'' AFTER wallet_error_message')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='remark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN remark VARCHAR(1000) NULL COMMENT ''货物明细备注'' AFTER label_requirement')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN carton_mark VARCHAR(255) NULL COMMENT ''客户自有箱唛'' AFTER relabel_file_url')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='fba_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN fba_carton_mark VARCHAR(255) NULL COMMENT ''关联FBA箱唛'' AFTER carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='destination_warehouse_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT ''该箱目的海外仓ID'' AFTER fba_carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE 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_destination'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD KEY idx_ll_relabel_item_destination (customer_id,destination_warehouse_id,application_id)')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_destuff_pallet_cost ( id BIGINT NOT NULL COMMENT '主键ID', source_container_booking_id VARCHAR(128) NOT NULL COMMENT '来源柜次业务ID', container_no VARCHAR(64) NOT NULL COMMENT '集装箱号', warehouse_id BIGINT NULL COMMENT '海外仓ID', pallet_count INT NOT NULL COMMENT '实际打托数', total_actual_volume_cbm DECIMAL(20,6) NOT NULL COMMENT '客户实收总体积', total_cost DECIMAL(20,2) NOT NULL COMMENT '打托总成本', currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '成本币种', status VARCHAR(16) NOT NULL COMMENT '生成状态', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_destuff_cost_booking(source_container_booking_id), CONSTRAINT chk_ll_destuff_cost CHECK(pallet_count>0 AND total_actual_volume_cbm>0 AND total_cost>0 AND currency='CNY') ) ENGINE=InnoDB COMMENT='拆柜打托实际成本汇总'; CREATE TABLE IF NOT EXISTS ll_destuff_pallet_cost_allocation ( id BIGINT NOT NULL COMMENT '主键ID', cost_id BIGINT NOT NULL COMMENT '打托成本汇总ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID', actual_volume_cbm DECIMAL(20,6) NOT NULL COMMENT '客户实收体积', allocated_amount DECIMAL(20,2) NOT NULL COMMENT '客户分摊金额', fee_source_id BIGINT NOT NULL COMMENT '海外费用来源ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_destuff_customer(cost_id,customer_id), UNIQUE KEY uk_ll_destuff_fee_source(fee_source_id), CONSTRAINT chk_ll_destuff_allocation CHECK(actual_volume_cbm>0 AND allocated_amount>=0) ) ENGINE=InnoDB COMMENT='拆柜打托成本按客户实收体积分摊'; USE baiyue_lastleg; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='destination_fba_warehouse_code'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN destination_fba_warehouse_code VARCHAR(128) NULL COMMENT ''FBA目的仓编码(与海外操作仓分离)''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='operation_type'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN operation_type VARCHAR(32) NOT NULL DEFAULT ''CARTON_LABEL'' COMMENT ''换标模式:箱唛、SKU或组合换标''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='sku_relabel_items_json'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN sku_relabel_items_json JSON NULL COMMENT ''同箱SKU换标子明细快照(数量按件)''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_inventory_balance_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_inventory_balance_id BIGINT NULL COMMENT ''原库存余额ID''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_inventory_position_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_inventory_position_id BIGINT NULL COMMENT ''原库存库位ID''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_inbound_order_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_inbound_order_id BIGINT NULL COMMENT ''原入仓单ID''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_inbound_order_no'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_inbound_order_no VARCHAR(128) NULL COMMENT ''原入仓单号快照''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_inbound_code'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_inbound_code VARCHAR(128) NULL COMMENT ''原进仓编码快照''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_warehouse_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_warehouse_id VARCHAR(128) NULL COMMENT ''原海外中转仓ID''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_warehouse_code'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_warehouse_code VARCHAR(128) NULL COMMENT ''原海外中转仓编码快照''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_warehouse_name'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_warehouse_name VARCHAR(255) NULL COMMENT ''原海外中转仓名称快照''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE 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_source_position'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD KEY idx_ll_relabel_item_source_position (customer_id,source_inventory_position_id)')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='delivery_method'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN delivery_method VARCHAR(32) NULL COMMENT ''派送方式:TRUCK卡车、PICKUP自提、EXPRESS快递;仅涉及箱唛换标时必填''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='print_shipping_label'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN print_shipping_label TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否需要打印面单''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='shipping_label_file_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN shipping_label_file_id VARCHAR(128) NULL COMMENT ''客户上传面单文件ID''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='shipping_label_file_name'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN shipping_label_file_name VARCHAR(255) NULL COMMENT ''客户上传面单文件名''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='shipping_label_file_url'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN shipping_label_file_url VARCHAR(1000) NULL COMMENT ''客户上传面单下载地址''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='fulfillment_status'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN fulfillment_status VARCHAR(32) NOT NULL DEFAULT ''WAIT_RELABEL'' COMMENT ''换标后履约状态''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='outbound_order_no'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN outbound_order_no VARCHAR(64) NULL COMMENT ''自提或快递生成的换标出库单号''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='customer_confirmation_key'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN customer_confirmation_key VARCHAR(255) NULL COMMENT ''客户确认完成幂等键''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='customer_confirmed_at'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN customer_confirmed_at DATETIME(3) NULL COMMENT ''客户确认换标完成时间''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 海外接柜仓由平台在尾程建单时预分配;历史测试数据不回填,缺失事实由业务接口失败关闭。 USE baiyue_lastleg; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='overseas_warehouse_code'), 'ALTER TABLE ll_order MODIFY COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT ''海外接柜仓业务编码快照''', 'ALTER TABLE ll_order ADD COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT ''海外接柜仓业务编码快照'' AFTER overseas_warehouse_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='receiving_warehouse_version'), 'ALTER TABLE ll_order MODIFY COLUMN receiving_warehouse_version INT NOT NULL DEFAULT 0 COMMENT ''柜级接柜仓分配乐观锁版本''', 'ALTER TABLE ll_order ADD COLUMN receiving_warehouse_version INT NOT NULL DEFAULT 0 COMMENT ''柜级接柜仓分配乐观锁版本'' AFTER overseas_warehouse_name')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; ALTER TABLE ll_order MODIFY COLUMN overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外接柜仓ID;新建尾程订单默认洛杉矶仓', MODIFY COLUMN overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外接柜仓名称快照'; ALTER TABLE ll_inbound_plan MODIFY COLUMN overseas_warehouse_id BIGINT NULL COMMENT '从尾程订单继承的平台预分配海外接柜仓ID'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_receiving_container_session' AND column_name='overseas_warehouse_code'), 'ALTER TABLE ll_receiving_container_session MODIFY COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT ''海外接柜仓业务编码快照''', 'ALTER TABLE ll_receiving_container_session ADD COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT ''海外接柜仓业务编码快照'' AFTER overseas_warehouse_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; ALTER TABLE ll_receiving_container_session MODIFY COLUMN overseas_warehouse_id BIGINT NOT NULL COMMENT '平台预分配并由操作员Token匹配的海外接柜仓ID', MODIFY COLUMN overseas_warehouse_name VARCHAR(255) NOT NULL COMMENT '仓库服务校验后的海外接柜仓名称快照'; CREATE TABLE IF NOT EXISTS ll_receiving_warehouse_operation ( id BIGINT NOT NULL COMMENT '柜级接柜仓修改操作ID', source_container_booking_id VARCHAR(128) NOT NULL COMMENT '稳定来源柜预订ID', idempotency_key VARCHAR(255) NOT NULL COMMENT '平台请求幂等键', request_hash VARCHAR(64) NOT NULL COMMENT '规范化修改请求SHA-256摘要', result_version INT NOT NULL COMMENT '修改成功后的柜级分配版本', operator_name VARCHAR(128) NOT NULL COMMENT '平台操作人名称', remark VARCHAR(500) NULL COMMENT '接柜仓修改备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_receiving_warehouse_idempotency(idempotency_key), KEY idx_ll_receiving_warehouse_container(source_container_booking_id,created_at) ) ENGINE=InnoDB COMMENT='柜级海外接柜仓修改幂等审计记录'; DROP PROCEDURE IF EXISTS assert_receiving_warehouse_assignment_ready; DELIMITER $$ CREATE PROCEDURE assert_receiving_warehouse_assignment_ready() BEGIN IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_order' AND column_name IN ('overseas_warehouse_code','receiving_warehouse_version')) <> 2 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程订单海外接柜仓字段未完整部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_receiving_container_session' AND column_name='overseas_warehouse_code') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA接柜会话仓库编码字段未部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_receiving_warehouse_operation') <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='柜级海外接柜仓修改幂等审计表未部署'; END IF; END$$ DELIMITER ; CALL assert_receiving_warehouse_assignment_ready(); DROP PROCEDURE assert_receiving_warehouse_assignment_ready; SELECT 'PASS' AS migration_status, '海外接柜仓预分配与柜级修改结构已就绪' AS message; -- 一件代发来源托盘与海外仓实物托盘分离,实物绑定不得覆盖来源身份。 USE baiyue_lastleg; 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='source_pallet_no'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN source_pallet_no VARCHAR(128) NULL COMMENT ''一件代发不可变来源托盘号快照'' AFTER pallet_no')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN pallet_no VARCHAR(64) NOT NULL COMMENT '当前托盘编号:分配前为计划占位码,分配后为海外仓实物托盘码'; 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='source_pallet_no'), 'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN source_pallet_no VARCHAR(128) NULL COMMENT ''一件代发不可变来源托盘号快照'' AFTER pallet_no')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; ALTER TABLE ll_inbound_stock_receipt MODIFY COLUMN pallet_no VARCHAR(64) NOT NULL COMMENT '海外仓实物托盘码'; -- 尾程单票人工计划、暂扣与人工展示节点。 USE baiyue_lastleg; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='hold_chargeable'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN hold_chargeable TINYINT NOT NULL DEFAULT 0 COMMENT ''当前暂扣是否计费:0否1是'' AFTER detained')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='hold_reason'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN hold_reason VARCHAR(500) NULL COMMENT ''当前暂扣原因;解除后为空'' AFTER hold_chargeable')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='manual_node_override'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN manual_node_override TINYINT NOT NULL DEFAULT 0 COMMENT ''是否启用单票人工计划节点覆盖:0否1是'' AFTER hold_reason')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='version'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN version INT NOT NULL DEFAULT 0 COMMENT ''尾程订单命令乐观锁版本'' AFTER manual_node_override')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; CREATE TABLE IF NOT EXISTS ll_order_command_record ( id BIGINT NOT NULL COMMENT '尾程订单命令幂等记录ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', action VARCHAR(32) NOT NULL COMMENT '命令动作', operator_id VARCHAR(128) NOT NULL COMMENT '平台操作人ID', idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', request_hash VARCHAR(64) NOT NULL COMMENT '规范化请求SHA-256摘要', result_ref VARCHAR(128) NULL COMMENT '结果业务引用', result_json LONGTEXT NOT NULL COMMENT '首次成功响应JSON快照', result_version INT NOT NULL COMMENT '命令成功后的订单版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '首次成功时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_command_key(customer_id,order_id,action,operator_id,idempotency_key), KEY idx_ll_order_command_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单写命令幂等与结果审计记录'; CREATE TABLE IF NOT EXISTS ll_order_hold_history ( id BIGINT NOT NULL COMMENT '尾程订单暂扣历史ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', held TINYINT NOT NULL COMMENT '操作后是否暂扣:0否1是', chargeable TINYINT NOT NULL COMMENT '本次暂扣是否计费:0否1是', reason VARCHAR(500) NOT NULL COMMENT '暂扣或解除原因', order_version INT NOT NULL COMMENT '操作成功后的订单版本', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID', operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', created_at DATETIME(3) NOT NULL COMMENT '操作时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_hold_key(customer_id,order_id,operator_id,idempotency_key), KEY idx_ll_order_hold_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单暂扣与解除不可变历史'; CREATE TABLE IF NOT EXISTS ll_order_manual_node ( id BIGINT NOT NULL COMMENT '尾程订单人工节点ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', node_code VARCHAR(32) NOT NULL COMMENT '八行人工展示节点稳定代码', node_at DATETIME(3) NULL COMMENT '人工填写节点时间,允许为空', source VARCHAR(16) NOT NULL DEFAULT 'MANUAL' COMMENT '节点来源,固定MANUAL', order_version INT NOT NULL COMMENT '最近编辑后的订单版本', updated_by VARCHAR(128) NOT NULL COMMENT '最近操作人ID', updated_at DATETIME(3) NOT NULL COMMENT '最近编辑时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_manual_node(customer_id,order_id,node_code), KEY idx_ll_order_manual_node_order(customer_id,order_id,node_at) ) ENGINE=InnoDB COMMENT='尾程订单当前人工节点覆盖事实'; CREATE TABLE IF NOT EXISTS ll_order_manual_node_history ( id BIGINT NOT NULL COMMENT '尾程订单人工节点历史ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID', nodes_json LONGTEXT NOT NULL COMMENT '本次全量人工节点JSON快照', order_version INT NOT NULL COMMENT '操作成功后的订单版本', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID', operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', created_at DATETIME(3) NOT NULL COMMENT '操作时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_order_manual_node_history_key(customer_id,order_id,operator_id,idempotency_key), KEY idx_ll_order_manual_node_history(customer_id,order_id,created_at) ) ENGINE=InnoDB COMMENT='尾程订单人工节点覆盖不可变历史'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='planned_arrival_date'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN planned_arrival_date DATE NULL COMMENT ''人工计划预计到仓日期'' AFTER overseas_warehouse_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='pallet_type'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN pallet_type VARCHAR(32) NULL COMMENT ''人工计划托盘类型'' AFTER planned_arrival_date')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='assigned_flag'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN assigned_flag TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否已分配:0否1是'' AFTER pallet_type')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='merge_required'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN merge_required TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否要求合托:0否1是'' AFTER assigned_flag')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='urgent_flag'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN urgent_flag TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否加急:0否1是'' AFTER merge_required')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='creation_mode'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN creation_mode VARCHAR(16) NOT NULL DEFAULT ''AUTO'' COMMENT ''计划生成方式:AUTO柜级自动、MANUAL单票人工'' AFTER urgent_flag')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='plan_remark'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN plan_remark VARCHAR(1000) NULL COMMENT ''入仓计划备注'' AFTER creation_mode')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND column_name='pallet_type'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN pallet_type VARCHAR(32) NULL COMMENT ''人工计划托盘类型'' AFTER pallet_no')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 换标总资料、派送资料与退货当前结构;仅结构定义,不回填业务记录。 USE baiyue_lastleg; CREATE TABLE IF NOT EXISTS ll_return_order ( id BIGINT NOT NULL COMMENT '退货订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', return_no VARCHAR(128) NOT NULL COMMENT '退货订单号', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '操作海外仓ID', customer_reference_no VARCHAR(128) NULL COMMENT '客户参考号', status VARCHAR(32) NOT NULL COMMENT 'PENDING_RECEIPT、PARTIALLY_RECEIVED或COMPLETED', expected_sku_types INT NOT NULL COMMENT '预报SKU种类数', expected_quantity BIGINT NOT NULL COMMENT '预报总数量', received_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '累计实收总数量', remark VARCHAR(1000) NULL COMMENT '客户备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '创建幂等键', request_hash CHAR(64) NOT NULL COMMENT '创建请求SHA-256', created_by VARCHAR(128) NULL COMMENT '创建操作人ID', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', need_relabel TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否需要换标', relabel_application_id BIGINT NULL COMMENT '绑定换标申请单ID', relabel_no VARCHAR(64) NULL COMMENT '绑定换标单号', relabel_status VARCHAR(32) NULL COMMENT '换标状态', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_order_customer_no(customer_id,return_no), UNIQUE KEY uk_ll_return_order_customer_key(customer_id,idempotency_key), KEY idx_ll_return_order_warehouse_status(overseas_warehouse_id,status,created_at), CONSTRAINT chk_ll_return_order_quantity CHECK(expected_sku_types>0 AND expected_quantity>0 AND received_quantity>=0 AND received_quantity<=expected_quantity) ) ENGINE=InnoDB COMMENT='客户退货订单及SKU实收汇总'; CREATE TABLE IF NOT EXISTS ll_return_order_item ( id BIGINT NOT NULL COMMENT '退货预报明细ID', return_order_id BIGINT NOT NULL COMMENT '退货订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name_zh VARCHAR(255) NULL COMMENT '中文品名', expected_quantity BIGINT NOT NULL COMMENT 'SKU预报数量', received_quantity BIGINT NOT NULL DEFAULT 0 COMMENT 'SKU累计实收数量', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_item_order_sku(return_order_id,sku_code), KEY idx_ll_return_item_sku(sku_code,received_quantity), CONSTRAINT chk_ll_return_item_quantity CHECK(expected_quantity>0 AND received_quantity>=0 AND received_quantity<=expected_quantity) ) ENGINE=InnoDB COMMENT='客户退货订单的SKU预报与实收明细'; CREATE TABLE IF NOT EXISTS ll_return_receipt ( id BIGINT NOT NULL COMMENT 'PDA退货签收单ID', return_order_id BIGINT NOT NULL COMMENT '退货订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', receipt_no VARCHAR(128) NOT NULL COMMENT '签收单号', receipt_batch_no VARCHAR(128) NOT NULL COMMENT '签收批次号', tracking_no VARCHAR(128) NULL COMMENT '本次签收包裹的可选快递单号', bound_by VARCHAR(16) NOT NULL COMMENT '开始签收方式,RETURN_NO退货单号或SKU候选', status VARCHAR(32) NOT NULL COMMENT '签收状态,当前SIGNED', received_quantity BIGINT NOT NULL COMMENT '本次实收数量', operator_id VARCHAR(128) NOT NULL COMMENT 'PDA操作人ID', operator_name VARCHAR(128) NULL COMMENT 'PDA操作人名称', idempotency_key VARCHAR(255) NOT NULL COMMENT 'PDA确认幂等键', request_hash CHAR(64) NOT NULL COMMENT 'PDA确认请求SHA-256', signed_at DATETIME(3) NOT NULL COMMENT '签收时间', created_at DATETIME(3) NOT NULL COMMENT '创建时间', carton_mark VARCHAR(128) NULL COMMENT '签收生成或绑定的退货箱号', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_receipt_no(receipt_no), UNIQUE KEY uk_ll_return_receipt_batch(receipt_batch_no), UNIQUE KEY uk_ll_return_receipt_operator_key(operator_id,idempotency_key), KEY idx_ll_return_receipt_order(return_order_id,signed_at), CONSTRAINT chk_ll_return_receipt_quantity CHECK(received_quantity>0), CONSTRAINT chk_ll_return_receipt_bound CHECK(bound_by IN('RETURN_NO','SKU')) ) ENGINE=InnoDB COMMENT='PDA退货实收签收事实'; CREATE TABLE IF NOT EXISTS ll_return_receipt_item ( id BIGINT NOT NULL COMMENT '签收SKU明细ID', receipt_id BIGINT NOT NULL COMMENT 'PDA退货签收单ID', return_order_item_id BIGINT NOT NULL COMMENT '退货预报明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', received_quantity BIGINT NOT NULL COMMENT '本次SKU实收数量', PRIMARY KEY(id), KEY idx_ll_return_receipt_item_receipt(receipt_id), KEY idx_ll_return_receipt_item_order_item(return_order_item_id), CONSTRAINT chk_ll_return_receipt_item_quantity CHECK(received_quantity>0) ) ENGINE=InnoDB COMMENT='PDA退货签收SKU实际数量明细'; CREATE TABLE IF NOT EXISTS ll_return_receipt_batch ( id BIGINT NOT NULL COMMENT '退货仓储计费批次ID', return_order_id BIGINT NOT NULL COMMENT '退货订单ID', receipt_id BIGINT NOT NULL COMMENT 'PDA退货签收单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', batch_no VARCHAR(128) NOT NULL COMMENT '签收批次号', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '操作海外仓ID', storage_billing_status VARCHAR(32) NOT NULL COMMENT '仓储计费状态,初始PENDING_PRICING', storage_started_at DATETIME(3) NOT NULL COMMENT '仓储计费起算时间', created_at DATETIME(3) NOT NULL COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_batch_no(batch_no), UNIQUE KEY uk_ll_return_batch_receipt(receipt_id), KEY idx_ll_return_batch_billing(customer_id,overseas_warehouse_id,storage_billing_status,storage_started_at) ) ENGINE=InnoDB COMMENT='每次退货签收生成的仓储费起算批次'; CREATE TABLE IF NOT EXISTS ll_return_inventory_carton ( id BIGINT NOT NULL COMMENT '退货库存箱ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', source_receipt_id BIGINT NULL COMMENT '来源PDA签收单ID', source_batch_no VARCHAR(128) NULL COMMENT '来源签收批次号', carton_mark VARCHAR(128) NOT NULL COMMENT '退货箱号和箱唛编码', status VARCHAR(32) NOT NULL COMMENT 'AVAILABLE可用或MERGED已合箱', sku_types INT NOT NULL COMMENT '箱内SKU种类数', total_quantity BIGINT NOT NULL COMMENT '箱内总件数', length DECIMAL(12,3) NULL COMMENT '箱长CM', width DECIMAL(12,3) NULL COMMENT '箱宽CM', height DECIMAL(12,3) NULL COMMENT '箱高CM', weight DECIMAL(12,3) NULL COMMENT '箱重KG', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', merged_at DATETIME(3) NULL COMMENT '合箱完成时间', source_return_no VARCHAR(2000) NULL COMMENT '来源退货单号', fba_carton_mark VARCHAR(255) NULL COMMENT 'FBA箱唛', new_carton_mark VARCHAR(255) NULL COMMENT '换标后新箱唛', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码', destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称', relabel_application_id BIGINT NULL COMMENT '绑定换标申请单ID', relabel_no VARCHAR(64) NULL COMMENT '绑定换标单号', relabel_status VARCHAR(32) NULL COMMENT '换标状态', relabel_completed_at DATETIME(3) NULL COMMENT '换标完成时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_carton_mark(carton_mark), UNIQUE KEY uk_ll_return_inventory_carton_receipt(source_receipt_id), KEY idx_ll_return_inventory_carton_customer(customer_id,overseas_warehouse_id,status,created_at), CONSTRAINT chk_ll_return_inventory_carton_quantity CHECK((status='AVAILABLE' AND sku_types>0 AND total_quantity>0) OR (status='MERGED' AND sku_types=0 AND total_quantity=0)), CONSTRAINT chk_ll_return_inventory_carton_status CHECK(status IN('AVAILABLE','MERGED')) ) ENGINE=InnoDB COMMENT='退货实物库存箱及箱唛'; CREATE TABLE IF NOT EXISTS ll_return_inventory_carton_item ( id BIGINT NOT NULL COMMENT '退货库存箱SKU明细ID', carton_id BIGINT NOT NULL COMMENT '退货库存箱ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name_zh VARCHAR(255) NULL COMMENT '中文品名', quantity BIGINT NOT NULL COMMENT '该SKU箱内数量', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_carton_item(carton_id,sku_code), KEY idx_ll_return_inventory_carton_item_customer(customer_id,sku_code), CONSTRAINT chk_ll_return_inventory_carton_item_quantity CHECK(quantity>0) ) ENGINE=InnoDB COMMENT='退货库存箱内SKU和数量'; CREATE TABLE IF NOT EXISTS ll_return_inventory_balance ( id BIGINT NOT NULL COMMENT '退货库存余额ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓ID', sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码', product_name_zh VARCHAR(255) NULL COMMENT '中文品名', total_quantity BIGINT NOT NULL DEFAULT 0 COMMENT '实物总库存,仅实际出库扣减', available_quantity BIGINT NOT NULL COMMENT '未合箱可用上架数量', carton_quantity BIGINT NOT NULL COMMENT '包含该SKU的可用箱数', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_balance(customer_id,overseas_warehouse_id,sku_code), CONSTRAINT chk_ll_return_inventory_balance_quantity CHECK(total_quantity>=available_quantity AND available_quantity>=0 AND carton_quantity>=0) ) ENGINE=InnoDB COMMENT='退货库存按客户海外仓SKU汇总余额'; CREATE TABLE IF NOT EXISTS ll_return_inventory_operation ( id BIGINT NOT NULL COMMENT '退货库存PDA操作ID', operator_id VARCHAR(128) NOT NULL COMMENT 'PDA操作人ID', idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型,当前MERGE', result_carton_id BIGINT NULL COMMENT '合箱结果退货库存箱ID', created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_return_inventory_operation_operator_key(operator_id,idempotency_key), KEY idx_ll_return_inventory_operation_result(result_carton_id) ) ENGINE=InnoDB COMMENT='退货库存PDA合箱幂等操作审计'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='bol_no'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN bol_no VARCHAR(128) NULL COMMENT ''派送资料BOL号,不作为文件归属标识''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='documents_json'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN documents_json JSON NULL COMMENT ''派送三类资料当前绑定及权威文件元数据快照''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_id VARCHAR(128) NULL COMMENT ''换标申请总资料文件ID''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_name'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_name VARCHAR(255) NULL COMMENT ''换标申请总资料文件名''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='total_file_url'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN total_file_url VARCHAR(1000) NULL COMMENT ''换标申请总资料下载地址''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND column_name='pallet_no' AND column_type='varchar(128)' AND is_nullable='NO'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN pallet_no VARCHAR(128) NOT NULL COMMENT ''海外仓资源服务返回的真实托盘码''')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; DROP PROCEDURE IF EXISTS assert_tail_order_commands_ready; DELIMITER $$ CREATE PROCEDURE assert_tail_order_commands_ready() BEGIN IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_order' AND column_name IN ('hold_chargeable','hold_reason','manual_node_override','version')) <> 4 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程订单人工计划、暂扣与人工节点字段未完整部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name IN ('ll_order_command_record','ll_order_hold_history','ll_order_manual_node','ll_order_manual_node_history')) <> 4 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程订单命令审计表未完整部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_inbound_plan' AND column_name IN ('planned_arrival_date','pallet_type','assigned_flag','merge_required','urgent_flag','creation_mode','plan_remark')) <> 7 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程人工计划字段未完整部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_order_command_record' AND index_name='uk_ll_order_command_key' AND non_unique=0) <> 5 OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_order_manual_node' AND index_name='uk_ll_order_manual_node' AND non_unique=0) <> 3 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程订单命令幂等或人工节点唯一约束未完整部署'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_document_revision') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_delivery_document_revision'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_order') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_order'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_order_item') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_order_item'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_receipt'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt_item') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_receipt_item'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt_batch') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_receipt_batch'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_inventory_carton'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton_item') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_inventory_carton_item'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_balance') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_inventory_balance'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_operation') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少表 ll_return_inventory_operation'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_order' AND column_name='bol_no' AND column_type='varchar(128)') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少字段 ll_delivery_order.bol_no'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_order' AND column_name='documents_json' AND column_type='json') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少字段 ll_delivery_order.documents_json'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='total_file_id' AND column_type='varchar(128)') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少字段 ll_relabel_application.total_file_id'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='total_file_name' AND column_type='varchar(255)') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少字段 ll_relabel_application.total_file_name'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='total_file_url' AND column_type='varchar(1000)') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少字段 ll_relabel_application.total_file_url'; END IF; IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_inbound_plan_pallet' AND column_name IN ('pallet_no','version')) <> 2 OR NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_inbound_plan_pallet' AND column_name='pallet_no' AND column_type='varchar(128)' AND is_nullable='NO') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='入仓计划托盘码或乐观锁版本字段未就绪'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_document_revision' AND index_name='uk_delivery_document_command') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_delivery_document_command'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_document_revision' AND index_name='uk_delivery_document_version') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_delivery_document_version'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_order' AND index_name='uk_ll_return_order_customer_no') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_order_customer_no'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_order' AND index_name='uk_ll_return_order_customer_key') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_order_customer_key'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_order' AND index_name='idx_ll_return_order_warehouse_status') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_order_warehouse_status'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_order' AND constraint_name='chk_ll_return_order_quantity' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_order_quantity'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_order_item' AND index_name='uk_ll_return_item_order_sku') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_item_order_sku'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_order_item' AND index_name='idx_ll_return_item_sku') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_item_sku'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_order_item' AND constraint_name='chk_ll_return_item_quantity' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_item_quantity'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt' AND index_name='uk_ll_return_receipt_no') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_receipt_no'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt' AND index_name='uk_ll_return_receipt_batch') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_receipt_batch'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt' AND index_name='uk_ll_return_receipt_operator_key') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_receipt_operator_key'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt' AND index_name='idx_ll_return_receipt_order') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_receipt_order'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_receipt' AND constraint_name='chk_ll_return_receipt_quantity' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_receipt_quantity'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_receipt' AND constraint_name='chk_ll_return_receipt_bound' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_receipt_bound'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt_item' AND index_name='idx_ll_return_receipt_item_receipt') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_receipt_item_receipt'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt_item' AND index_name='idx_ll_return_receipt_item_order_item') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_receipt_item_order_item'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_receipt_item' AND constraint_name='chk_ll_return_receipt_item_quantity' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_receipt_item_quantity'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt_batch' AND index_name='uk_ll_return_batch_no') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_batch_no'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt_batch' AND index_name='uk_ll_return_batch_receipt') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_batch_receipt'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_receipt_batch' AND index_name='idx_ll_return_batch_billing') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_batch_billing'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton' AND index_name='uk_ll_return_inventory_carton_mark') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_inventory_carton_mark'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton' AND index_name='uk_ll_return_inventory_carton_receipt') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_inventory_carton_receipt'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton' AND index_name='idx_ll_return_inventory_carton_customer') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_inventory_carton_customer'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton' AND constraint_name='chk_ll_return_inventory_carton_quantity' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_inventory_carton_quantity'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton' AND constraint_name='chk_ll_return_inventory_carton_status' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_inventory_carton_status'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton_item' AND index_name='uk_ll_return_inventory_carton_item') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_inventory_carton_item'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton_item' AND index_name='idx_ll_return_inventory_carton_item_customer') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_inventory_carton_item_customer'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_inventory_carton_item' AND constraint_name='chk_ll_return_inventory_carton_item_quantity' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_inventory_carton_item_quantity'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_balance' AND index_name='uk_ll_return_inventory_balance') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_inventory_balance'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema='baiyue_lastleg' AND table_name='ll_return_inventory_balance' AND constraint_name='chk_ll_return_inventory_balance_quantity' AND constraint_type='CHECK') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少检查约束 chk_ll_return_inventory_balance_quantity'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_operation' AND index_name='uk_ll_return_inventory_operation_operator_key') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 uk_ll_return_inventory_operation_operator_key'; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema='baiyue_lastleg' AND table_name='ll_return_inventory_operation' AND index_name='idx_ll_return_inventory_operation_result') THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='缺少索引 idx_ll_return_inventory_operation_result'; END IF; END$$ DELIMITER ; CALL assert_tail_order_commands_ready(); DROP PROCEDURE IF EXISTS assert_tail_order_commands_ready; CREATE TABLE IF NOT EXISTS ll_container_plan_conversion_command ( id BIGINT NOT NULL COMMENT '柜级转换命令ID', source_container_booking_id VARCHAR(128) NOT NULL COMMENT '稳定来源柜预订ID', idempotency_key VARCHAR(128) NOT NULL COMMENT '首次调用幂等键', request_hash CHAR(64) NOT NULL COMMENT '确认请求SHA-256摘要', snapshot_version BIGINT NOT NULL COMMENT '确认的柜级快照版本', snapshot_hash CHAR(64) NOT NULL COMMENT '确认的柜级快照SHA-256', warehouse_id BIGINT NOT NULL COMMENT '海外接柜仓ID', batch_key VARCHAR(160) NOT NULL COMMENT '海外仓托盘批次幂等键', status VARCHAR(32) NOT NULL COMMENT '命令状态:PREPARED/APPLYING/FAILED/LOCAL_COMMITTED/COMPLETED', lease_token VARCHAR(64) NULL COMMENT '当前执行租约令牌,用于陈旧执行者隔离', preparation_json JSON NOT NULL COMMENT '稳定计划号与托盘业务键快照', result_json JSON NULL COMMENT '本地计划提交结果', last_error VARCHAR(1000) 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_container_conversion_command(source_container_booking_id), UNIQUE KEY uk_ll_container_conversion_batch(warehouse_id,batch_key), KEY idx_ll_container_conversion_status(status,updated_at) ) ENGINE=InnoDB COMMENT='柜级入库计划转换Saga与幂等命令'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_container_plan_conversion_command' AND column_name='lease_token'), 'SELECT 1', 'ALTER TABLE ll_container_plan_conversion_command ADD COLUMN lease_token VARCHAR(64) NULL COMMENT ''当前执行租约令牌,用于陈旧执行者隔离'' AFTER status')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; ALTER TABLE ll_inbound_plan_pallet MODIFY COLUMN pallet_no VARCHAR(128) NOT NULL COMMENT 'Warehouse权威实物托盘码'; SELECT 'PASS' AS migration_status, '海外尾程人工计划、暂扣与人工节点结构已就绪' AS message; -- 2026-09-09 / 035 为历史退货订单补充尾程主订单关联,并回填已生成的 RETURN_RELABEL 尾程订单。 USE baiyue_lastleg; -- 2026-09-09 / 036 为派送单补充 BOL 号字段(不改原始 CREATE TABLE)。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='bol_no'), 'SELECT 1', 'ALTER TABLE ll_delivery_order ADD COLUMN bol_no VARCHAR(128) NULL COMMENT ''派送资料BOL号,不作为文件归属标识''')); PREPARE ll_delivery_order_bol_no_stmt FROM @ddl; EXECUTE ll_delivery_order_bol_no_stmt; DEALLOCATE PREPARE ll_delivery_order_bol_no_stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='lastleg_order_id'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN lastleg_order_id BIGINT NULL COMMENT ''关联尾程主订单ID'' AFTER customer_reference_no')); PREPARE ll_return_order_lastleg_id_stmt FROM @ddl; EXECUTE ll_return_order_lastleg_id_stmt; DEALLOCATE PREPARE ll_return_order_lastleg_id_stmt; UPDATE ll_return_order r JOIN ll_order o ON o.source_order_id COLLATE utf8mb4_unicode_ci = CAST(r.id AS CHAR) COLLATE utf8mb4_unicode_ci AND o.source_order_no COLLATE utf8mb4_unicode_ci = r.return_no COLLATE utf8mb4_unicode_ci AND o.order_type = 'RETURN_RELABEL' SET r.lastleg_order_id = o.id WHERE r.lastleg_order_id IS NULL; -- 柜级入库计划跨客户批量托盘预留、确认与失败补偿。 USE baiyue_lastlag_warehouse; CREATE TABLE IF NOT EXISTS wh_pallet_batch ( id BIGINT NOT NULL COMMENT '批量托盘预留ID', warehouse_id BIGINT NOT NULL COMMENT '实际海外仓ID', batch_key VARCHAR(160) NOT NULL COMMENT '柜级入库计划批次稳定业务键', request_hash CHAR(64) NOT NULL COMMENT '规范化批量请求SHA-256摘要', status VARCHAR(32) NOT NULL COMMENT '批次状态:RESERVED、CONFIRMED、COMPENSATED', attempt_no INT NOT NULL DEFAULT 1 COMMENT '同批次重新预留尝试次数', confirm_command_key VARCHAR(160) NULL COMMENT '确认命令幂等键', confirm_command_hash CHAR(64) NULL COMMENT '确认命令规范化SHA-256摘要', compensate_command_key VARCHAR(160) NULL COMMENT '补偿命令幂等键', compensate_command_hash CHAR(64) NULL COMMENT '补偿命令规范化SHA-256摘要', compensate_reason VARCHAR(500) NULL COMMENT '补偿原因', confirmed_at DATETIME(3) NULL COMMENT '确认绑定时间', compensated_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_wh_pallet_batch_key (warehouse_id,batch_key), KEY idx_wh_pallet_batch_status (warehouse_id,status,updated_at) ) ENGINE=InnoDB COMMENT='柜级入库计划批量托盘预留与确认记录'; CREATE TABLE IF NOT EXISTS wh_pallet_batch_item ( id BIGINT NOT NULL COMMENT '批量托盘明细ID', batch_id BIGINT NOT NULL COMMENT '所属批量托盘预留ID', customer_id BIGINT NOT NULL COMMENT '实际占用客户ID', warehouse_id BIGINT NOT NULL COMMENT '实际海外仓ID', business_key VARCHAR(100) NOT NULL COMMENT '柜号入库计划序号组成的稳定业务键', inbound_plan_no VARCHAR(128) NOT NULL COMMENT '入库计划号快照', sequence_no INT NOT NULL COMMENT '计划内托盘序号', pallet_id BIGINT NOT NULL COMMENT '公共实物托盘ID', pallet_code VARCHAR(64) NOT NULL COMMENT '资源服务生成的规范托盘码快照', location_id BIGINT NOT NULL COMMENT '公共托盘当前预留库位ID', resource_lock_id BIGINT NOT NULL COMMENT '按客户隔离的资源锁ID', status VARCHAR(32) NOT NULL COMMENT '明细状态:RESERVED、CONFIRMED、RELEASED', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', PRIMARY KEY (id), UNIQUE KEY uk_wh_pallet_batch_item_business (customer_id,warehouse_id,business_key), UNIQUE KEY uk_wh_pallet_batch_item_sequence (batch_id,sequence_no), KEY idx_wh_pallet_batch_item_pallet (pallet_id), KEY idx_wh_pallet_batch_item_batch (batch_id,status) ) ENGINE=InnoDB COMMENT='柜级入库计划批量托盘明细与资源锁关联'; -- 2026-09-10 / 037 仓储转运以入中转仓为主流程,FBA 去向可后补;预入仓换标无需先绑定库存仓位。 USE baiyue_lastleg; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order') AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='fba_warehouse_code' AND is_nullable='NO'), 'ALTER TABLE ll_warehouse_transfer_order MODIFY COLUMN fba_warehouse_code VARCHAR(128) NULL COMMENT ''可选FBA目的仓编码'', MODIFY COLUMN fba_shipment_no VARCHAR(128) NULL COMMENT ''可选FBA货件编号'', MODIFY COLUMN delivery_address VARCHAR(1000) NOT NULL COMMENT ''提货地址或中转仓收货地址'', MODIFY COLUMN delivery_method VARCHAR(64) NOT NULL COMMENT ''入仓方式'', MODIFY COLUMN estimated_arrival_at DATETIME(3) NOT NULL COMMENT ''预计入仓时间''', 'SELECT 1')); PREPARE ll_transfer_optional_fba_stmt FROM @ddl; EXECUTE ll_transfer_optional_fba_stmt; DEALLOCATE PREPARE ll_transfer_optional_fba_stmt; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_carton ( id BIGINT NOT NULL COMMENT '预报箱主键', transfer_order_id BIGINT NOT NULL COMMENT '转运单ID', transfer_item_id BIGINT NOT NULL COMMENT '转运申报明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', carton_mark VARCHAR(255) NOT NULL COMMENT '系统生成的一箱一码箱唛', carton_index INT NOT NULL COMMENT '全单箱序号', total_cartons INT NOT NULL COMMENT '首次生成时全单总箱数', status VARCHAR(32) NOT NULL DEFAULT 'EXPECTED' COMMENT '箱状态:EXPECTED待实收', 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_wh_transfer_carton_mark (customer_id,carton_mark), UNIQUE KEY uk_ll_wh_transfer_carton_index (transfer_order_id,carton_index), KEY idx_ll_wh_transfer_carton_list (customer_id,transfer_order_id,status) ) ENGINE=InnoDB COMMENT='仓储转运系统箱唛预报'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='customer_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN customer_carton_mark VARCHAR(255) NULL COMMENT ''客户原箱唛,用于换标现场绑定'' AFTER carton_mark')); PREPARE transfer_customer_carton_stmt FROM @ddl; EXECUTE transfer_customer_carton_stmt; DEALLOCATE PREPARE transfer_customer_carton_stmt; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_pallet ( id BIGINT NOT NULL COMMENT '打托事实ID', transfer_order_id BIGINT NOT NULL COMMENT '转运单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', sequence_no INT NOT NULL COMMENT '托序号', warehouse_pallet_id BIGINT NOT NULL COMMENT '海外仓真实托盘ID', pallet_no VARCHAR(128) NOT NULL COMMENT '真实托盘码', warehouse_location_id BIGINT NOT NULL COMMENT '真实库位ID', warehouse_location_code VARCHAR(128) NULL COMMENT '真实库位码', warehouse_resource_lock_id BIGINT NOT NULL COMMENT '仓储资源锁ID', carton_count INT NOT NULL COMMENT '本托实收箱数', length_cm DECIMAL(12,2) NOT NULL COMMENT '实测长cm', width_cm DECIMAL(12,2) NOT NULL COMMENT '实测宽cm', height_cm DECIMAL(12,2) NOT NULL COMMENT '实测高cm', gross_weight_kg DECIMAL(12,3) NOT NULL COMMENT '实测毛重kg', volume_cbm DECIMAL(18,6) NOT NULL COMMENT '实测体积CBM', status VARCHAR(32) NOT NULL COMMENT '打托状态', completed_at DATETIME(3) NOT NULL COMMENT 'PDA打托完成时间', 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_transfer_pallet_seq(transfer_order_id,sequence_no), UNIQUE KEY uk_ll_transfer_pallet_physical(customer_id,warehouse_pallet_id), KEY idx_ll_transfer_pallet_order(customer_id,transfer_order_id,status) ) ENGINE=InnoDB COMMENT='仓储转运PDA实测打托事实'; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_pallet_item ( id BIGINT NOT NULL COMMENT '主键ID', transfer_order_id BIGINT NOT NULL COMMENT '转运单ID', transfer_pallet_id BIGINT NOT NULL COMMENT '转运托盘事实ID', transfer_item_id BIGINT NOT NULL COMMENT '转运申报明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', package_count INT NOT NULL COMMENT '本托该SKU实收箱数', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_transfer_pallet_item(transfer_pallet_id,transfer_item_id), KEY idx_ll_transfer_pallet_item_order(customer_id,transfer_order_id) ) ENGINE=InnoDB COMMENT='仓储转运每托SKU箱数回填'; CREATE TABLE IF NOT EXISTS ll_warehouse_transfer_relabel_binding ( id BIGINT NOT NULL COMMENT '主键ID', transfer_order_id BIGINT NOT NULL COMMENT '转运单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '换标类型', customer_carton_mark VARCHAR(255) NOT NULL COMMENT '客户原箱唛', original_sku VARCHAR(128) NOT NULL COMMENT '旧SKU', new_sku VARCHAR(128) NULL COMMENT '新SKU', quantity INT NOT NULL COMMENT '换标件数', fba_carton_mark VARCHAR(255) NULL COMMENT '新FBA箱唛', destination_warehouse_code VARCHAR(128) NULL COMMENT 'FBA目的仓', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), UNIQUE KEY uk_ll_transfer_relabel_mark(transfer_order_id,customer_carton_mark), KEY idx_ll_transfer_relabel_order(customer_id,transfer_order_id) ) ENGINE=InnoDB COMMENT='仓储转运换标预绑定明细'; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='ll_relabel_item') AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name IN ('shipment_no','destination_fba_warehouse_code','source_inventory_balance_id','source_inventory_position_id','source_inbound_order_id') AND is_nullable='NO'), 'ALTER TABLE ll_relabel_item MODIFY COLUMN shipment_no VARCHAR(128) NULL COMMENT ''货件编号(无FBA去向时为空)'', MODIFY COLUMN destination_fba_warehouse_code VARCHAR(128) NULL COMMENT ''可选FBA目的仓编码(与海外操作仓分离)'', MODIFY COLUMN source_inventory_balance_id BIGINT NULL COMMENT ''原库存余额ID(预入仓换标任务可为空)'', MODIFY COLUMN source_inventory_position_id BIGINT NULL COMMENT ''原库存库位ID(预入仓换标任务可为空)'', MODIFY COLUMN source_inbound_order_id BIGINT NULL COMMENT ''原入仓单ID(预入仓换标任务可为空)''', 'SELECT 1')); PREPARE ll_relabel_pre_inbound_stmt FROM @ddl; EXECUTE ll_relabel_pre_inbound_stmt; DEALLOCATE PREPARE ll_relabel_pre_inbound_stmt; -- 2026-09-10 / 038 补齐跨服务列表查询依赖的历史库字段,重复执行安全。 USE baiyue_warehouse; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='wh_warehouse' AND column_name='internal_code'), 'SELECT 1', 'ALTER TABLE wh_warehouse ADD COLUMN internal_code VARCHAR(16) NULL COMMENT ''FBA内部编号,仅FBA仓可配置'' AFTER warehouse_code')); PREPARE warehouse_internal_code_stmt FROM @ddl; EXECUTE warehouse_internal_code_stmt; DEALLOCATE PREPARE warehouse_internal_code_stmt; USE baiyue_lastleg; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_order' AND column_name='lastleg_order_no'), 'SELECT 1', 'ALTER TABLE ll_return_order ADD COLUMN lastleg_order_no VARCHAR(128) NULL COMMENT ''关联尾程订单号'' AFTER lastleg_order_id')); PREPARE return_order_lastleg_no_stmt FROM @ddl; EXECUTE return_order_lastleg_no_stmt; DEALLOCATE PREPARE return_order_lastleg_no_stmt; -- 财务 P0:海外费用保留原币、月度汇率和计费依据。 USE baiyue_lastleg; DROP PROCEDURE IF EXISTS add_delivery_fee_currency_columns; DELIMITER $$ CREATE PROCEDURE add_delivery_fee_currency_columns() BEGIN IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_fee') THEN IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_fee' AND column_name='original_currency') THEN ALTER TABLE ll_delivery_fee ADD COLUMN original_currency VARCHAR(8) NOT NULL DEFAULT 'CNY' COMMENT '原币币种' AFTER amount; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_fee' AND column_name='original_amount') THEN ALTER TABLE ll_delivery_fee ADD COLUMN original_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '原币金额' AFTER original_currency; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_delivery_fee' AND column_name='exchange_rate') THEN ALTER TABLE ll_delivery_fee ADD COLUMN exchange_rate DECIMAL(18,8) NOT NULL DEFAULT 1 COMMENT '原币折算CNY汇率' AFTER original_amount; END IF; END IF; END$$ DELIMITER ; CALL add_delivery_fee_currency_columns(); DROP PROCEDURE IF EXISTS add_delivery_fee_currency_columns; DROP PROCEDURE IF EXISTS add_overseas_finance_p0_column; DELIMITER $$ CREATE PROCEDURE add_overseas_finance_p0_column(IN p_column VARCHAR(64), IN p_definition TEXT) BEGIN IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_finance_fee_source' AND column_name=p_column) THEN SET @ddl = CONCAT('ALTER TABLE ll_finance_fee_source ADD COLUMN ', p_column, ' ', p_definition); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; END$$ DELIMITER ; CALL add_overseas_finance_p0_column('original_currency', "VARCHAR(8) NOT NULL DEFAULT 'CNY' COMMENT '原币币种'"); CALL add_overseas_finance_p0_column('original_amount', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '原币金额'"); CALL add_overseas_finance_p0_column('exchange_rate', "DECIMAL(18,8) NOT NULL DEFAULT 1 COMMENT '原币折算CNY汇率'"); CALL add_overseas_finance_p0_column('exchange_rate_month', "CHAR(7) NULL COMMENT '汇率月份YYYY-MM'"); CALL add_overseas_finance_p0_column('chargeable_quantity', "DECIMAL(18,4) NULL COMMENT '计费数量'"); CALL add_overseas_finance_p0_column('quantity_unit', "VARCHAR(32) NULL COMMENT '计费单位'"); CALL add_overseas_finance_p0_column('unit_price', "DECIMAL(18,4) NULL COMMENT '原币单价'"); CALL add_overseas_finance_p0_column('period_start', "DATE NULL COMMENT '周期费用开始日期'"); CALL add_overseas_finance_p0_column('period_end', "DATE NULL COMMENT '周期费用结束日期'"); DROP PROCEDURE IF EXISTS add_overseas_finance_p0_column; DROP PROCEDURE IF EXISTS assert_overseas_finance_p0_ready; DELIMITER $$ CREATE PROCEDURE assert_overseas_finance_p0_ready() BEGIN IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_finance_fee_source' AND column_name IN ('original_currency','original_amount','exchange_rate','exchange_rate_month', 'chargeable_quantity','quantity_unit','unit_price','period_start','period_end')) <> 9 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外财务P0原币、汇率和计费依据字段未完整部署'; END IF; END$$ DELIMITER ; CALL assert_overseas_finance_p0_ready(); DROP PROCEDURE IF EXISTS assert_overseas_finance_p0_ready; SELECT 'PASS' AS migration_status, '海外财务P0费用来源字段已就绪' AS message; -- 人工货柜节点独立于订舱:货柜尚未关联海运订舱时仍可同步当前节点。 ALTER TABLE ll_container_shipping_gate MODIFY ocean_booking_id VARCHAR(128) NULL COMMENT '来源海运订舱ID;货柜未关联订舱时为空'; -- 2026-09-12 退货换箱唛、转运换标回写及派车箱唛快照增量。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='return_carton_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN return_carton_id BIGINT NULL COMMENT ''退货换箱唛来源退货库存箱ID'' AFTER carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='source_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN source_carton_mark VARCHAR(255) NULL COMMENT ''退货换箱唛原箱唛快照'' AFTER return_carton_id')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='new_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN new_carton_mark VARCHAR(255) NULL COMMENT ''退货换箱唛新箱唛'' AFTER source_carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='relabel_completed_at'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_order ADD COLUMN relabel_completed_at DATETIME(3) NULL COMMENT ''关联贴标完成时间'' AFTER relabel_no')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SELECT 'PASS' AS migration_status, '退货换箱唛及转运换标关联字段已就绪' AS message; -- 2026-09-14 海外尾程按托盘维度作业,无库位托盘允许正常流转及补偿。 USE baiyue_lastlag_warehouse; ALTER TABLE wh_pallet_operation MODIFY COLUMN before_location_id BIGINT NULL COMMENT '变更前库位ID,无库位托盘为空', MODIFY COLUMN after_location_id BIGINT NULL COMMENT '变更后库位ID,无库位托盘为空'; USE baiyue_lastleg; SELECT 'PASS' AS migration_status, '无库位托盘状态流转结构已就绪' AS message; -- 2026-09-14 贴标申请区分箱唛总文件、SKU总文件;明细文件沿用ll_relabel_item.relabel_file_*。 DROP PROCEDURE IF EXISTS add_relabel_total_document_columns; DELIMITER $$ CREATE PROCEDURE add_relabel_total_document_columns() BEGIN IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='carton_total_file_id') THEN ALTER TABLE ll_relabel_application ADD COLUMN carton_total_file_id VARCHAR(128) NULL COMMENT '箱唛总文件ID' AFTER total_file_url; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='carton_total_file_name') THEN ALTER TABLE ll_relabel_application ADD COLUMN carton_total_file_name VARCHAR(255) NULL COMMENT '箱唛总文件名' AFTER carton_total_file_id; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='carton_total_file_url') THEN ALTER TABLE ll_relabel_application ADD COLUMN carton_total_file_url VARCHAR(1000) NULL COMMENT '箱唛总文件地址' AFTER carton_total_file_name; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='sku_total_file_id') THEN ALTER TABLE ll_relabel_application ADD COLUMN sku_total_file_id VARCHAR(128) NULL COMMENT 'SKU总文件ID' AFTER carton_total_file_url; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='sku_total_file_name') THEN ALTER TABLE ll_relabel_application ADD COLUMN sku_total_file_name VARCHAR(255) NULL COMMENT 'SKU总文件名' AFTER sku_total_file_id; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name='sku_total_file_url') THEN ALTER TABLE ll_relabel_application ADD COLUMN sku_total_file_url VARCHAR(1000) NULL COMMENT 'SKU总文件地址' AFTER sku_total_file_name; END IF; END$$ DELIMITER ; CALL add_relabel_total_document_columns(); DROP PROCEDURE IF EXISTS add_relabel_total_document_columns; DROP PROCEDURE IF EXISTS assert_relabel_document_columns_ready; DELIMITER $$ CREATE PROCEDURE assert_relabel_document_columns_ready() BEGIN IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_application' AND column_name IN ('carton_total_file_id','carton_total_file_name','carton_total_file_url', 'sku_total_file_id','sku_total_file_name','sku_total_file_url')) <> 6 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='贴标申请箱唛/SKU总文件字段未完整部署'; END IF; IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg' AND table_name='ll_relabel_item' AND column_name IN ('relabel_file_id','relabel_file_name','relabel_file_url')) <> 3 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='贴标申请明细文件字段未完整部署'; END IF; END$$ DELIMITER ; CALL assert_relabel_document_columns_ready(); DROP PROCEDURE IF EXISTS assert_relabel_document_columns_ready; SELECT 'PASS' AS migration_status, '贴标申请箱唛总文件、SKU总文件及明细文件字段已就绪' AS message;