-- Phase 3 domestic outbound aggregate and dispatch gate. MySQL 8, idempotent. USE baiyue_firstleg; CREATE TABLE IF NOT EXISTS fl_outbound_dispatch ( id BIGINT UNSIGNED NOT NULL COMMENT '国内出仓调度记录ID', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键', order_id BIGINT UNSIGNED NOT NULL COMMENT 'Order服务订单逻辑ID,不复制订单主数据', inbound_id BIGINT UNSIGNED NOT NULL COMMENT '关联入库单逻辑ID', container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '关联柜次逻辑ID', status VARCHAR(32) NOT NULL DEFAULT 'READY_FOR_DISPATCH' COMMENT '出仓状态:READY_FOR_DISPATCH待确认出仓、WAITING_FOR_LOADING等待装柜', version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号,每次更新递增', confirmed_by BIGINT UNSIGNED NULL COMMENT '确认国内出仓的操作人ID', confirmed_by_name VARCHAR(64) NULL COMMENT '确认国内出仓的操作人姓名快照', confirmed_at DATETIME(3) NULL COMMENT '国内出仓确认时间', reversed_by BIGINT UNSIGNED NULL COMMENT '撤销国内出仓的操作人ID', reversed_by_name VARCHAR(64) NULL COMMENT '撤销国内出仓的操作人姓名快照', reversed_at DATETIME(3) NULL COMMENT '国内出仓撤销时间', remark VARCHAR(500) NULL COMMENT '国内出仓调度备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '出仓调度记录创建时间', updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '出仓调度记录最后更新时间', PRIMARY KEY (id), UNIQUE KEY uk_outbound_dispatch_owner (tenant_id,inbound_id,container_booking_id), KEY idx_outbound_dispatch_order (tenant_id,order_id,updated_at), KEY idx_outbound_dispatch_container (container_booking_id,status,updated_at), CONSTRAINT fk_outbound_dispatch_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order(id), CONSTRAINT fk_outbound_dispatch_container FOREIGN KEY (container_booking_id) REFERENCES fl_container_booking(id), CONSTRAINT chk_outbound_dispatch_status CHECK (status IN ('READY_FOR_DISPATCH','WAITING_FOR_LOADING')) ) ENGINE=InnoDB COMMENT='三期国内出仓派车状态,不重复创建出仓单'; CREATE TABLE IF NOT EXISTS fl_outbound_dispatch_history ( id BIGINT UNSIGNED NOT NULL COMMENT '出仓状态历史记录ID', dispatch_id BIGINT UNSIGNED NOT NULL COMMENT '关联国内出仓调度记录ID', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键', inbound_id BIGINT UNSIGNED NOT NULL COMMENT '关联入库单逻辑ID快照', container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '关联柜次逻辑ID快照', action VARCHAR(32) NOT NULL COMMENT '出仓状态变更动作', from_status VARCHAR(32) NULL COMMENT '变更前出仓状态;首次创建时为空', to_status VARCHAR(32) NOT NULL COMMENT '变更后出仓状态', remark VARCHAR(500) NULL COMMENT '状态变更原因或备注', operator_id BIGINT UNSIGNED NOT NULL COMMENT '执行状态变更的平台用户ID', operator_name VARCHAR(64) NULL COMMENT '执行状态变更的平台用户姓名快照', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '状态历史创建时间', PRIMARY KEY (id), KEY idx_outbound_dispatch_history (tenant_id,inbound_id,container_booking_id,created_at,id), CONSTRAINT fk_outbound_dispatch_history FOREIGN KEY (dispatch_id) REFERENCES fl_outbound_dispatch(id) ) ENGINE=InnoDB COMMENT='国内出仓追加式审计历史'; CREATE TABLE IF NOT EXISTS fl_outbound_dispatch_operation ( id BIGINT UNSIGNED NOT NULL COMMENT '出仓幂等操作记录ID', dispatch_id BIGINT UNSIGNED NULL COMMENT '首次声明幂等键时允许为空', operator_id BIGINT UNSIGNED NOT NULL COMMENT '执行写操作的平台用户ID', operation VARCHAR(32) NOT NULL COMMENT '国内出仓写操作类型', idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键,同一操作重试复用', request_hash CHAR(64) NOT NULL COMMENT '规范化请求内容SHA-256摘要', status VARCHAR(16) NOT NULL DEFAULT 'PROCESSING' COMMENT '幂等处理状态:PROCESSING处理中、SUCCESS成功', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '幂等声明创建时间', completed_at DATETIME(3) NULL COMMENT '幂等操作完成时间', PRIMARY KEY (id), UNIQUE KEY uk_outbound_dispatch_operation (operator_id,operation,idempotency_key), KEY idx_outbound_dispatch_operation_resource (dispatch_id,created_at), CONSTRAINT fk_outbound_dispatch_operation FOREIGN KEY (dispatch_id) REFERENCES fl_outbound_dispatch(id), CONSTRAINT chk_outbound_dispatch_operation_status CHECK (status IN ('PROCESSING','SUCCESS')) ) ENGINE=InnoDB COMMENT='国内出仓写操作幂等声明'; USE baiyue_iam; DROP PROCEDURE IF EXISTS assert_outbound_dispatch_permission_ids_available; DELIMITER $$ CREATE PROCEDURE assert_outbound_dispatch_permission_ids_available() BEGIN IF EXISTS ( SELECT 1 FROM iam_permission WHERE (id BETWEEN 5102160 AND 5102164 AND permission_code <> CASE id WHEN 5102160 THEN 'platform:firstleg:outbound-dispatch:list' WHEN 5102161 THEN 'platform:firstleg:outbound-dispatch:view' WHEN 5102162 THEN 'platform:firstleg:outbound-dispatch:check' WHEN 5102163 THEN 'platform:firstleg:outbound-dispatch:confirm' WHEN 5102164 THEN 'platform:firstleg:outbound-dispatch:reverse' END) OR (permission_code LIKE 'platform:firstleg:outbound-dispatch:%' AND (tenant_id <> 0 OR app_code <> 'PLATFORM' OR id NOT BETWEEN 5102160 AND 5102164)) ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '三期出仓权限迁移失败:5102160-5102164 ID 或权限码被其他语义占用'; END IF; END$$ DELIMITER ; CALL assert_outbound_dispatch_permission_ids_available(); DROP PROCEDURE IF EXISTS assert_outbound_dispatch_permission_ids_available; INSERT INTO iam_permission (id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name, route_path,http_method,sort_no,status,built_in,deleted) VALUES (5102160,0,'PLATFORM','MENU',5102000,'platform:firstleg:outbound-dispatch:list','国内出仓','/first-leg/outbound-dispatches','GET',95,'ACTIVE',1,0), (5102161,0,'PLATFORM','BUTTON',5102160,'platform:firstleg:outbound-dispatch:view','查看出仓聚合',NULL,'GET',10,'ACTIVE',1,0), (5102162,0,'PLATFORM','BUTTON',5102160,'platform:firstleg:outbound-dispatch:check','检查出仓门禁',NULL,'GET',20,'ACTIVE',1,0), (5102163,0,'PLATFORM','BUTTON',5102160,'platform:firstleg:outbound-dispatch:confirm','确认国内出仓',NULL,'POST',30,'ACTIVE',1,0), (5102164,0,'PLATFORM','BUTTON',5102160,'platform:firstleg:outbound-dispatch:reverse','撤销国内出仓',NULL,'POST',40,'ACTIVE',1,0) ON DUPLICATE KEY UPDATE tenant_id=0,app_code='PLATFORM',permission_type=VALUES(permission_type), permission_code=VALUES(permission_code),permission_name=VALUES(permission_name),parent_id=VALUES(parent_id), route_path=VALUES(route_path),http_method=VALUES(http_method),sort_no=VALUES(sort_no),status='ACTIVE',built_in=1,deleted=0; INSERT IGNORE INTO iam_role_permission(role_id,permission_id,tenant_id) SELECT role.id,permission.id,0 FROM iam_role role JOIN iam_permission permission ON permission.tenant_id=0 AND permission.app_code='PLATFORM' AND permission.permission_code LIKE 'platform:firstleg:outbound-dispatch:%' WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR'); USE baiyue_firstleg;