feat: gate overseas receiving and harden phase4 workflows

This commit is contained in:
2026-08-25 10:31:04 +08:00
parent cb78bc6b41
commit 52b9fc382f
93 changed files with 2779 additions and 201 deletions
@@ -16394,6 +16394,81 @@ DELIMITER ;
CALL baiyue_iam.assert_overseas_pda_picker_permission();
DROP PROCEDURE baiyue_iam.assert_overseas_pda_picker_permission;
-- 四期仓库后台角色严格最小授权:list 同时覆盖列表与详情,只读角色不得获得任何写权限。
DROP TEMPORARY TABLE IF EXISTS tmp_phase4_warehouse_role_permission;
CREATE TEMPORARY TABLE tmp_phase4_warehouse_role_permission (
role_code VARCHAR(64) NOT NULL,
permission_code VARCHAR(160) NOT NULL,
PRIMARY KEY (role_code, permission_code)
);
INSERT INTO tmp_phase4_warehouse_role_permission (role_code, permission_code) VALUES
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:last-mile-order:list'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:inbound-order:list'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:relabel-order:list'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:inventory:list'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:warehouse:list'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:location:list'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:pallet:list'),
('WAREHOUSE_OPERATOR','platform:overseas-business:purchase:list'),
('WAREHOUSE_OPERATOR','platform:overseas-business:truck:list'),
('WAREHOUSE_OPERATOR','platform:overseas-business:looseboard:list'),
('WAREHOUSE_TALLY','platform:overseas-warehouse:last-mile-order:list'),
('WAREHOUSE_TALLY','platform:overseas-warehouse:inbound-order:list'),
('WAREHOUSE_TALLY','platform:overseas-warehouse:relabel-order:list'),
('WAREHOUSE_TALLY','platform:overseas-warehouse:inventory:list'),
('WAREHOUSE_TALLY','platform:overseas-warehouse:warehouse:list'),
('WAREHOUSE_TALLY','platform:overseas-warehouse:location:list'),
('WAREHOUSE_TALLY','platform:overseas-warehouse:pallet:list'),
('WAREHOUSE_TALLY','platform:overseas-business:purchase:list'),
('WAREHOUSE_TALLY','platform:overseas-business:truck:list'),
('WAREHOUSE_TALLY','platform:overseas-business:looseboard:list');
DELETE grant_row FROM baiyue_iam.iam_role_permission grant_row
JOIN baiyue_iam.iam_role role ON role.id=grant_row.role_id AND role.tenant_id=grant_row.tenant_id
JOIN baiyue_iam.iam_permission permission ON permission.id=grant_row.permission_id AND permission.tenant_id=grant_row.tenant_id
LEFT JOIN tmp_phase4_warehouse_role_permission expected
ON expected.role_code=role.role_code AND expected.permission_code=permission.permission_code
WHERE role.tenant_id=0 AND role.app_code='PLATFORM'
AND role.role_code IN ('WAREHOUSE_OPERATOR','WAREHOUSE_PICKER','WAREHOUSE_TALLY')
AND permission.permission_code LIKE 'platform:overseas-%'
AND expected.permission_code IS NULL;
INSERT IGNORE INTO baiyue_iam.iam_role_permission (tenant_id, role_id, permission_id, created_at)
SELECT 0, role.id, permission.id, NOW(3)
FROM tmp_phase4_warehouse_role_permission expected
JOIN baiyue_iam.iam_role role ON role.tenant_id=0 AND role.app_code='PLATFORM'
AND role.role_code=expected.role_code AND role.status='ACTIVE' AND role.deleted=0
JOIN baiyue_iam.iam_permission permission ON permission.tenant_id=0 AND permission.app_code='PLATFORM'
AND permission.permission_code=expected.permission_code
AND permission.status='ACTIVE' AND permission.deleted=0;
DROP PROCEDURE IF EXISTS baiyue_iam.assert_phase4_warehouse_role_minimum;
DELIMITER $$
CREATE PROCEDURE baiyue_iam.assert_phase4_warehouse_role_minimum()
BEGIN
IF (SELECT COUNT(*) FROM tmp_phase4_warehouse_role_permission) <> 20 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='四期仓库角色最小权限矩阵数量异常';
END IF;
IF EXISTS (SELECT 1 FROM tmp_phase4_warehouse_role_permission
WHERE permission_code REGEXP ':(create|edit|status|export|adjust|delete|review)$') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='四期仓库只读角色错误获得写权限';
END IF;
IF EXISTS (SELECT 1 FROM tmp_phase4_warehouse_role_permission expected
LEFT JOIN baiyue_iam.iam_role role ON role.tenant_id=0 AND role.app_code='PLATFORM'
AND role.role_code=expected.role_code AND role.status='ACTIVE' AND role.deleted=0
LEFT JOIN baiyue_iam.iam_permission permission ON permission.tenant_id=0 AND permission.app_code='PLATFORM'
AND permission.permission_code=expected.permission_code AND permission.status='ACTIVE' AND permission.deleted=0
LEFT JOIN baiyue_iam.iam_role_permission grant_row ON grant_row.tenant_id=0
AND grant_row.role_id=role.id AND grant_row.permission_id=permission.id
WHERE grant_row.role_id IS NULL) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='四期仓库角色最小权限授权不完整';
END IF;
END$$
DELIMITER ;
CALL baiyue_iam.assert_phase4_warehouse_role_minimum();
DROP PROCEDURE baiyue_iam.assert_phase4_warehouse_role_minimum;
DROP TEMPORARY TABLE tmp_phase4_warehouse_role_permission;
INSERT IGNORE INTO baiyue_iam.iam_role_permission (tenant_id, role_id, permission_id, created_at)
SELECT 0, role.id, permission.id, NOW(3)
FROM baiyue_iam.iam_role role
@@ -618,6 +618,74 @@ SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE
'SELECT 1', 'ALTER TABLE ll_inbound_stock_receipt ADD UNIQUE KEY uk_ll_stock_receipt_task_allocation_sku (customer_id,task_id,allocation_id,sku_code)'));
PREPARE phase4_inventory_stmt FROM @ddl; EXECUTE phase4_inventory_stmt; DEALLOCATE PREPARE phase4_inventory_stmt;
-- 海运节点达到可提柜后才允许海外 PDA 认领;装柜完成只建立等待门禁快照。
CREATE TABLE IF NOT EXISTS ll_container_shipping_gate (
container_booking_id VARCHAR(128) NOT NULL COMMENT '来源头程柜预订ID',
customer_id VARCHAR(128) NOT NULL COMMENT '客户标识',
ocean_booking_id VARCHAR(128) NOT NULL COMMENT '来源海运订舱ID',
container_no VARCHAR(64) NOT NULL COMMENT '实际集装箱号',
status VARCHAR(32) NOT NULL DEFAULT 'AWAITING_PICKUP_READY' COMMENT '海外收货门禁状态:AWAITING_PICKUP_READY、RECEIVING_AVAILABLE',
standard_node VARCHAR(64) NULL COMMENT '最新有效标准船节点',
node_sequence INT NOT NULL DEFAULT 0 COMMENT '最新有效节点单调序号',
observed_at DATETIME(3) NULL COMMENT '供应商节点观测时间',
actual_at DATETIME(3) NULL COMMENT '节点实际发生时间',
location_code VARCHAR(128) NULL COMMENT '节点地点编码',
location_name VARCHAR(255) NULL COMMENT '节点地点名称',
provider_code VARCHAR(64) NULL COMMENT '船节点供应商编码',
provider_event_id VARCHAR(128) NULL COMMENT '供应商事件ID',
provider_node_code VARCHAR(128) NULL COMMENT '供应商原始节点编码',
source_reference VARCHAR(255) NULL COMMENT '供应商来源引用',
raw_payload_hash VARCHAR(64) NULL COMMENT '供应商原始负载SHA-256',
aggregate_version BIGINT NOT NULL DEFAULT 0 COMMENT '来源查询聚合版本',
handover_version BIGINT NOT NULL DEFAULT 1 COMMENT '跨区交接版本',
last_event_id VARCHAR(128) NULL COMMENT '最近采纳的跨区事件ID',
payload_hash VARCHAR(71) NULL COMMENT '最近采纳事件规范化负载摘要',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
PRIMARY KEY(container_booking_id),
KEY idx_ll_shipping_gate_candidate(customer_id,container_no,status),
KEY idx_ll_shipping_gate_version(container_booking_id,aggregate_version,node_sequence)
) ENGINE=InnoDB COMMENT='海外PDA柜号船节点收货资格快照';
INSERT IGNORE INTO ll_container_shipping_gate (
container_booking_id,customer_id,ocean_booking_id,container_no,status,
node_sequence,aggregate_version,handover_version,created_at,updated_at
)
SELECT source_container_booking_id,customer_id,'',container_no,'AWAITING_PICKUP_READY',
0,COALESCE(MAX(source_loading_plan_version),0),COALESCE(MAX(source_handover_version),1),NOW(3),NOW(3)
FROM ll_order
WHERE source_container_booking_id IS NOT NULL AND source_container_booking_id <> ''
AND container_no IS NOT NULL AND container_no <> ''
GROUP BY source_container_booking_id,customer_id,container_no;
CREATE TABLE IF NOT EXISTS ll_pda_operation_history (
id BIGINT NOT NULL COMMENT 'PDA作业历史ID',
overseas_warehouse_id BIGINT NOT NULL COMMENT 'Token冻结的海外实际仓ID',
customer_id VARCHAR(128) NULL COMMENT '作业涉及的客户标识',
operator_key VARCHAR(128) NOT NULL COMMENT 'PDA操作账号标识',
operation_type VARCHAR(64) NOT NULL COMMENT '作业类型',
business_key VARCHAR(255) NOT NULL COMMENT '作业业务键',
status VARCHAR(32) NOT NULL COMMENT '作业结果状态',
idempotency_key VARCHAR(255) NULL COMMENT '写操作幂等键',
request_hash VARCHAR(128) NULL COMMENT '写请求内容哈希',
summary VARCHAR(1000) NULL COMMENT '作业结果摘要',
occurred_at DATETIME(3) NOT NULL COMMENT '作业发生时间',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
PRIMARY KEY(id),
UNIQUE KEY uk_ll_pda_history_idempotency(operator_key,idempotency_key),
KEY idx_ll_pda_history_operator(overseas_warehouse_id,operator_key,occurred_at),
KEY idx_ll_pda_history_business(overseas_warehouse_id,operation_type,business_key)
) ENGINE=InnoDB COMMENT='海外PDA真实作业历史';
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;