feat(phase3): 收口父子单与全链路验收
This commit is contained in:
@@ -8766,6 +8766,232 @@ DROP PROCEDURE IF EXISTS assert_phase3_pda_item_assignment_schema;
|
||||
ALTER TABLE fl_inbound_pallet_allocation
|
||||
ADD COLUMN IF NOT EXISTS reservation_id BIGINT UNSIGNED NULL COMMENT '仓库预占资源唯一ID,A0共享场景用于区分托盘' AFTER location_code;
|
||||
|
||||
/* Phase 3: six-carrier schedule query tasks, truthful manual fallback and three-day rate limit. */
|
||||
USE baiyue_firstleg;
|
||||
CREATE TABLE IF NOT EXISTS fl_carrier_schedule_query (
|
||||
id BIGINT UNSIGNED NOT NULL,
|
||||
query_no VARCHAR(40) NOT NULL,
|
||||
customer_id BIGINT UNSIGNED NOT NULL COMMENT '当前产品客户ID',
|
||||
ocean_booking_id BIGINT UNSIGNED NOT NULL,
|
||||
container_booking_id BIGINT UNSIGNED NULL,
|
||||
container_scope_id BIGINT UNSIGNED GENERATED ALWAYS AS (COALESCE(container_booking_id,0)) STORED,
|
||||
carrier_code VARCHAR(16) NOT NULL COMMENT 'MATSON/SML/ZIM/COSCO/EMC/HEDE',
|
||||
tracking_type VARCHAR(32) NOT NULL COMMENT 'BOOKING_NO/BILL_OF_LADING/CONTAINER_NO',
|
||||
tracking_no VARCHAR(128) NOT NULL,
|
||||
official_url VARCHAR(500) NOT NULL,
|
||||
access_mode VARCHAR(32) NOT NULL COMMENT 'PUBLIC_FORM/HCAPTCHA/DYNAMIC_IFRAME',
|
||||
status VARCHAR(24) NOT NULL COMMENT 'READY/MANUAL_REQUIRED/SUCCESS',
|
||||
window_started_at DATETIME(3) NOT NULL,
|
||||
attempt_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
next_allowed_at DATETIME(3) NOT NULL,
|
||||
last_attempt_at DATETIME(3) NULL,
|
||||
last_success_at DATETIME(3) NULL,
|
||||
source_updated_at DATETIME(3) NULL,
|
||||
expires_at DATETIME(3) NULL,
|
||||
result_port_schedule_id BIGINT UNSIGNED NULL,
|
||||
last_attempt_status VARCHAR(24) NULL,
|
||||
manual_reason VARCHAR(1000) NULL,
|
||||
last_error_code VARCHAR(64) NULL,
|
||||
last_error_message VARCHAR(1000) NULL,
|
||||
remark VARCHAR(1000) NULL,
|
||||
created_by BIGINT UNSIGNED NOT NULL,
|
||||
created_by_name VARCHAR(64) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
updated_by BIGINT UNSIGNED NOT NULL,
|
||||
updated_by_name VARCHAR(64) NULL,
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
version INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_carrier_schedule_query_no (query_no),
|
||||
UNIQUE KEY uk_carrier_schedule_query_scope
|
||||
(customer_id,ocean_booking_id,container_scope_id,carrier_code,tracking_type,tracking_no),
|
||||
KEY idx_carrier_schedule_query_due (status,next_allowed_at,id),
|
||||
KEY idx_carrier_schedule_query_customer (customer_id,updated_at,id),
|
||||
KEY idx_carrier_schedule_query_expiry (expires_at,id),
|
||||
CONSTRAINT fk_carrier_schedule_query_booking FOREIGN KEY (ocean_booking_id) REFERENCES fl_ocean_booking(id),
|
||||
CONSTRAINT fk_carrier_schedule_query_container FOREIGN KEY (container_booking_id) REFERENCES fl_container_booking(id),
|
||||
CONSTRAINT fk_carrier_schedule_query_result FOREIGN KEY (result_port_schedule_id) REFERENCES fl_port_schedule(id),
|
||||
CONSTRAINT chk_carrier_schedule_query_customer CHECK (customer_id > 0),
|
||||
CONSTRAINT chk_carrier_schedule_query_carrier CHECK
|
||||
(carrier_code IN ('MATSON','SML','ZIM','COSCO','EMC','HEDE')),
|
||||
CONSTRAINT chk_carrier_schedule_query_tracking CHECK
|
||||
(tracking_type IN ('BOOKING_NO','BILL_OF_LADING','CONTAINER_NO')),
|
||||
CONSTRAINT chk_carrier_schedule_query_access CHECK
|
||||
(access_mode IN ('PUBLIC_FORM','HCAPTCHA','DYNAMIC_IFRAME')),
|
||||
CONSTRAINT chk_carrier_schedule_query_status CHECK
|
||||
(status IN ('READY','MANUAL_REQUIRED','SUCCESS')),
|
||||
CONSTRAINT chk_carrier_schedule_query_attempt CHECK (attempt_count BETWEEN 0 AND 3)
|
||||
) ENGINE=InnoDB COMMENT='六家船公司官网查询任务与三天窗口频控';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_carrier_schedule_query_attempt (
|
||||
id BIGINT UNSIGNED NOT NULL,
|
||||
query_id BIGINT UNSIGNED NOT NULL,
|
||||
window_attempt_no INT UNSIGNED NOT NULL,
|
||||
carrier_code VARCHAR(16) NOT NULL,
|
||||
access_mode VARCHAR(32) NOT NULL,
|
||||
official_url VARCHAR(500) NOT NULL,
|
||||
attempt_status VARCHAR(24) NOT NULL,
|
||||
coverage_gap TINYINT(1) NOT NULL DEFAULT 0,
|
||||
coverage_gap_code VARCHAR(64) NULL,
|
||||
manual_reason VARCHAR(1000) NULL,
|
||||
error_code VARCHAR(64) NULL,
|
||||
error_message VARCHAR(1000) NULL,
|
||||
operator_id BIGINT UNSIGNED NOT NULL,
|
||||
operator_name VARCHAR(64) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_carrier_schedule_attempt_query (query_id,created_at,id),
|
||||
CONSTRAINT fk_carrier_schedule_attempt_query FOREIGN KEY (query_id) REFERENCES fl_carrier_schedule_query(id),
|
||||
CONSTRAINT chk_carrier_schedule_attempt_no CHECK (window_attempt_no BETWEEN 1 AND 3),
|
||||
CONSTRAINT chk_carrier_schedule_attempt_status CHECK
|
||||
(attempt_status IN ('MANUAL_REQUIRED','SUCCESS','FAILED'))
|
||||
) ENGINE=InnoDB COMMENT='船司官网查询尝试不可变审计';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_carrier_schedule_query_history (
|
||||
id BIGINT UNSIGNED NOT NULL,
|
||||
query_id BIGINT UNSIGNED NOT NULL,
|
||||
action VARCHAR(24) NOT NULL,
|
||||
from_version INT UNSIGNED NULL,
|
||||
to_version INT UNSIGNED NOT NULL,
|
||||
reason VARCHAR(1000) NULL,
|
||||
before_snapshot JSON NULL,
|
||||
after_snapshot JSON NOT NULL,
|
||||
operator_id BIGINT UNSIGNED NOT NULL,
|
||||
operator_name VARCHAR(64) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_carrier_schedule_history_query (query_id,created_at,id),
|
||||
CONSTRAINT fk_carrier_schedule_history_query FOREIGN KEY (query_id) REFERENCES fl_carrier_schedule_query(id),
|
||||
CONSTRAINT chk_carrier_schedule_history_action CHECK (action IN ('CREATE','ATTEMPT','MANUAL_RESULT'))
|
||||
) ENGINE=InnoDB COMMENT='船司查询任务不可变历史';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_carrier_schedule_query_operation (
|
||||
id BIGINT UNSIGNED NOT NULL,
|
||||
query_id BIGINT UNSIGNED NULL,
|
||||
operator_id BIGINT UNSIGNED NOT NULL,
|
||||
operation VARCHAR(24) NOT NULL,
|
||||
idempotency_key VARCHAR(128) NOT NULL,
|
||||
request_hash CHAR(64) NOT NULL,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'PROCESSING',
|
||||
result_json JSON NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
completed_at DATETIME(3) NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_carrier_schedule_operation (operator_id,idempotency_key),
|
||||
KEY idx_carrier_schedule_operation_query (query_id,created_at,id),
|
||||
CONSTRAINT fk_carrier_schedule_operation_query FOREIGN KEY (query_id) REFERENCES fl_carrier_schedule_query(id),
|
||||
CONSTRAINT chk_carrier_schedule_operation_status CHECK (status IN ('PROCESSING','SUCCESS'))
|
||||
) ENGINE=InnoDB COMMENT='船司查询写操作幂等与请求摘要';
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_carrier_schedule_query_before_insert;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_carrier_schedule_query_before_insert BEFORE INSERT ON fl_carrier_schedule_query FOR EACH ROW
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM fl_ocean_booking booking
|
||||
WHERE booking.id=NEW.ocean_booking_id AND booking.customer_id=NEW.customer_id) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询客户与订舱不一致';
|
||||
END IF;
|
||||
IF NEW.container_booking_id IS NOT NULL AND NOT EXISTS (
|
||||
SELECT 1 FROM fl_ocean_booking_container_allocation allocation
|
||||
WHERE allocation.ocean_booking_id=NEW.ocean_booking_id
|
||||
AND allocation.container_booking_id=NEW.container_booking_id
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询柜次未分配至订舱';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_carrier_schedule_attempt_before_update;
|
||||
DROP TRIGGER IF EXISTS trg_carrier_schedule_attempt_before_delete;
|
||||
DROP TRIGGER IF EXISTS trg_carrier_schedule_history_before_update;
|
||||
DROP TRIGGER IF EXISTS trg_carrier_schedule_history_before_delete;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_carrier_schedule_attempt_before_update BEFORE UPDATE ON fl_carrier_schedule_query_attempt
|
||||
FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询尝试不可修改'; END$$
|
||||
CREATE TRIGGER trg_carrier_schedule_attempt_before_delete BEFORE DELETE ON fl_carrier_schedule_query_attempt
|
||||
FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询尝试不可删除'; END$$
|
||||
CREATE TRIGGER trg_carrier_schedule_history_before_update BEFORE UPDATE ON fl_carrier_schedule_query_history
|
||||
FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询历史不可修改'; END$$
|
||||
CREATE TRIGGER trg_carrier_schedule_history_before_delete BEFORE DELETE ON fl_carrier_schedule_query_history
|
||||
FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询历史不可删除'; END$$
|
||||
DELIMITER ;
|
||||
|
||||
USE baiyue_iam;
|
||||
DROP PROCEDURE IF EXISTS assert_carrier_schedule_query_permission_ids;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE assert_carrier_schedule_query_permission_ids()
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM iam_permission
|
||||
WHERE (id BETWEEN 5102184 AND 5102188
|
||||
AND permission_code <> CASE id
|
||||
WHEN 5102184 THEN 'platform:firstleg:port-schedule-query:list'
|
||||
WHEN 5102185 THEN 'platform:firstleg:port-schedule-query:view'
|
||||
WHEN 5102186 THEN 'platform:firstleg:port-schedule-query:create'
|
||||
WHEN 5102187 THEN 'platform:firstleg:port-schedule-query:attempt'
|
||||
WHEN 5102188 THEN 'platform:firstleg:port-schedule-query:manual'
|
||||
END)
|
||||
OR (permission_code LIKE 'platform:firstleg:port-schedule-query:%'
|
||||
AND (tenant_id<>0 OR app_code<>'PLATFORM' OR id NOT BETWEEN 5102184 AND 5102188))
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT='三期船司查询权限迁移失败:5102184-5102188 ID或权限码被占用';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL assert_carrier_schedule_query_permission_ids();
|
||||
DROP PROCEDURE IF EXISTS assert_carrier_schedule_query_permission_ids;
|
||||
|
||||
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
|
||||
(5102184,0,'PLATFORM','BUTTON',5102180,'platform:firstleg:port-schedule-query:list','查询船司任务',NULL,'GET',40,'ACTIVE',1,0),
|
||||
(5102185,0,'PLATFORM','BUTTON',5102180,'platform:firstleg:port-schedule-query:view','查看船司任务',NULL,'GET',50,'ACTIVE',1,0),
|
||||
(5102186,0,'PLATFORM','BUTTON',5102180,'platform:firstleg:port-schedule-query:create','创建船司任务',NULL,'POST',60,'ACTIVE',1,0),
|
||||
(5102187,0,'PLATFORM','BUTTON',5102180,'platform:firstleg:port-schedule-query:attempt','执行船司查询',NULL,'POST',70,'ACTIVE',1,0),
|
||||
(5102188,0,'PLATFORM','BUTTON',5102180,'platform:firstleg:port-schedule-query:manual','录入人工结果',NULL,'POST',80,'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:port-schedule-query:%'
|
||||
WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR');
|
||||
|
||||
USE baiyue_firstleg;
|
||||
DROP PROCEDURE IF EXISTS assert_carrier_schedule_query_schema;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE assert_carrier_schedule_query_schema()
|
||||
BEGIN
|
||||
IF (SELECT COUNT(*) FROM information_schema.tables
|
||||
WHERE table_schema='baiyue_firstleg' AND table_name IN
|
||||
('fl_carrier_schedule_query','fl_carrier_schedule_query_attempt',
|
||||
'fl_carrier_schedule_query_history','fl_carrier_schedule_query_operation')) <> 4 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询任务表未完整创建';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM baiyue_iam.iam_permission
|
||||
WHERE tenant_id=0 AND id BETWEEN 5102184 AND 5102188
|
||||
AND permission_code LIKE 'platform:firstleg:port-schedule-query:%') <> 5 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询任务权限未完整创建';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*)
|
||||
FROM baiyue_iam.iam_role_permission role_permission
|
||||
JOIN baiyue_iam.iam_role role ON role.id=role_permission.role_id
|
||||
JOIN baiyue_iam.iam_permission permission ON permission.id=role_permission.permission_id
|
||||
WHERE role.tenant_id=0 AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR')
|
||||
AND permission.tenant_id=0
|
||||
AND permission.permission_code LIKE 'platform:firstleg:port-schedule-query:%') <> 10 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='船司查询任务角色授权未完整创建';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL assert_carrier_schedule_query_schema();
|
||||
DROP PROCEDURE IF EXISTS assert_carrier_schedule_query_schema;
|
||||
|
||||
-- 三期仓库常用角色初始化。模块来源:iam/src/main/resources/db/phase3-warehouse-roles.sql。
|
||||
-- 三期仓库常用系统角色:仓库操作员、仓库拣货员、仓库理货员。
|
||||
-- 本脚本只组合已经存在的权限资源,需在三期 Firstleg/IAM 权限脚本之后执行,可重复部署。
|
||||
|
||||
Reference in New Issue
Block a user