diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index 67d5f8c5d..670b44041 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -9918,19 +9918,19 @@ SET NAMES utf8mb4; USE baiyue_firstleg; CREATE TABLE IF NOT EXISTS fl_customs_container ( - id BIGINT UNSIGNED NOT NULL, + id BIGINT UNSIGNED NOT NULL COMMENT '整柜报关聚合ID', loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '已完成装柜计划ID;报关柜级聚合唯一键', container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '物理货柜ID', - status VARCHAR(40) NOT NULL COMMENT 'WAITING_CUSTOMER_DOCUMENTS、READY_TO_START、DECLARING、COMPLETED', - started_by BIGINT UNSIGNED NULL, - started_by_name VARCHAR(64) NULL, - started_at DATETIME(3) NULL, - completed_by BIGINT UNSIGNED NULL, - completed_by_name VARCHAR(64) NULL, - completed_at DATETIME(3) NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), - version INT UNSIGNED NOT NULL DEFAULT 0, + status VARCHAR(40) NOT NULL COMMENT '报关状态:WAITING_CUSTOMER_DOCUMENTS待客户资料、READY_TO_START待开始、DECLARING报关中、COMPLETED已完成', + started_by BIGINT UNSIGNED NULL COMMENT '开始报关操作人ID', + started_by_name VARCHAR(64) NULL COMMENT '开始报关操作人姓名快照', + started_at DATETIME(3) NULL COMMENT '开始报关时间', + completed_by BIGINT UNSIGNED NULL COMMENT '完成报关操作人ID', + completed_by_name VARCHAR(64) 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 UNSIGNED NOT NULL DEFAULT 0 COMMENT '报关聚合乐观锁版本', PRIMARY KEY(id), UNIQUE KEY uk_customs_container_plan(loading_plan_id), UNIQUE KEY uk_customs_container_booking(container_booking_id), @@ -9940,24 +9940,24 @@ CREATE TABLE IF NOT EXISTS fl_customs_container ( ) ENGINE=InnoDB COMMENT='装柜完成后的整柜出口报关聚合'; CREATE TABLE IF NOT EXISTS fl_customs_customer_document ( - id BIGINT UNSIGNED NOT NULL, - customs_container_id BIGINT UNSIGNED NOT NULL, + id BIGINT UNSIGNED NOT NULL COMMENT '客户报关资料ID', + customs_container_id BIGINT UNSIGNED NOT NULL COMMENT '所属整柜报关聚合ID', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户隔离键;只允许关联同客户退税票', - file_id BIGINT UNSIGNED NOT NULL, - file_name VARCHAR(255) NOT NULL, - file_hash CHAR(64) NOT NULL, - content_type VARCHAR(128) NULL, - size_bytes BIGINT UNSIGNED NOT NULL, - status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', - uploaded_by BIGINT UNSIGNED NOT NULL, - uploaded_at DATETIME(3) NOT NULL, - frozen_version INT UNSIGNED NULL, - frozen_at DATETIME(3) NULL, - deleted_by BIGINT UNSIGNED NULL, - deleted_at DATETIME(3) NULL, - version INT UNSIGNED NOT NULL DEFAULT 1, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + file_id BIGINT UNSIGNED NOT NULL COMMENT 'File服务文件ID', + file_name VARCHAR(255) NOT NULL COMMENT '客户资料文件名快照', + file_hash CHAR(64) NOT NULL COMMENT '客户资料文件SHA-256摘要', + content_type VARCHAR(128) NULL COMMENT '客户资料文件内容类型', + size_bytes BIGINT UNSIGNED NOT NULL COMMENT '客户资料文件大小(字节)', + status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '资料状态:ACTIVE有效、DELETED已删除', + uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '上传操作人ID', + uploaded_at DATETIME(3) NOT NULL COMMENT '上传时间', + frozen_version INT UNSIGNED NULL COMMENT '开始报关时冻结的资料版本', + frozen_at DATETIME(3) NULL COMMENT '资料冻结时间', + deleted_by BIGINT UNSIGNED NULL COMMENT '删除操作人ID', + deleted_at DATETIME(3) NULL COMMENT '逻辑删除时间', + version INT UNSIGNED NOT NULL DEFAULT 1 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_customs_customer_document_container(customs_container_id,status,tenant_id), CONSTRAINT fk_customs_customer_document_container FOREIGN KEY(customs_container_id) REFERENCES fl_customs_container(id), @@ -9967,30 +9967,30 @@ CREATE TABLE IF NOT EXISTS fl_customs_customer_document ( ) ENGINE=InnoDB COMMENT='客户整份退税报送资料逻辑根'; CREATE TABLE IF NOT EXISTS fl_customs_customer_document_inbound ( - document_id BIGINT UNSIGNED NOT NULL, - inbound_id BIGINT UNSIGNED NOT NULL, - tenant_id BIGINT UNSIGNED NOT NULL, - order_id BIGINT UNSIGNED NOT NULL, - inbound_code VARCHAR(40) NOT NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + document_id BIGINT UNSIGNED NOT NULL COMMENT '客户报关资料ID', + inbound_id BIGINT UNSIGNED NOT NULL COMMENT '覆盖的入仓单ID', + tenant_id BIGINT UNSIGNED NOT NULL COMMENT '入仓单客户隔离键', + order_id BIGINT UNSIGNED NOT NULL COMMENT '入仓单所属订单ID', + inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '资料覆盖关系创建时间', PRIMARY KEY(document_id,inbound_id), KEY idx_customs_document_inbound(inbound_id,tenant_id), CONSTRAINT fk_customs_document_inbound_document FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id) ) ENGINE=InnoDB COMMENT='客户报送资料与当前柜退税入仓码多对多关系'; CREATE TABLE IF NOT EXISTS fl_customs_customer_document_version ( - id BIGINT UNSIGNED NOT NULL, - document_id BIGINT UNSIGNED NOT NULL, - document_version INT UNSIGNED NOT NULL, - file_id BIGINT UNSIGNED NOT NULL, - file_name VARCHAR(255) NOT NULL, - file_hash CHAR(64) NOT NULL, - content_type VARCHAR(128) NULL, - size_bytes BIGINT UNSIGNED NOT NULL, - scope_snapshot_json JSON NOT NULL, - action VARCHAR(24) NOT NULL COMMENT 'UPLOAD、REPLACE、SCOPE_CHANGE、DELETE', - operator_id BIGINT UNSIGNED NOT NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + id BIGINT UNSIGNED NOT NULL COMMENT '客户资料版本记录ID', + document_id BIGINT UNSIGNED NOT NULL COMMENT '客户报关资料ID', + document_version INT UNSIGNED NOT NULL COMMENT '客户资料版本号', + file_id BIGINT UNSIGNED NOT NULL COMMENT '该版本File服务文件ID', + file_name VARCHAR(255) NOT NULL COMMENT '该版本文件名快照', + file_hash CHAR(64) NOT NULL COMMENT '该版本文件SHA-256摘要', + content_type VARCHAR(128) NULL COMMENT '该版本文件内容类型', + size_bytes BIGINT UNSIGNED NOT NULL COMMENT '该版本文件大小(字节)', + scope_snapshot_json JSON NOT NULL COMMENT '该版本覆盖入仓码范围快照', + action VARCHAR(24) NOT NULL COMMENT '版本动作:UPLOAD上传、REPLACE替换、SCOPE_CHANGE调整范围、DELETE删除', + operator_id BIGINT UNSIGNED NOT NULL COMMENT '版本操作人ID', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '版本记录创建时间', PRIMARY KEY(id), UNIQUE KEY uk_customs_customer_document_version(document_id,document_version), CONSTRAINT fk_customs_customer_document_version FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id), @@ -9998,77 +9998,77 @@ CREATE TABLE IF NOT EXISTS fl_customs_customer_document_version ( ) ENGINE=InnoDB COMMENT='客户报送资料文件与覆盖范围不可变版本'; CREATE TABLE IF NOT EXISTS fl_customs_frozen_document_inbound ( - document_id BIGINT UNSIGNED NOT NULL, - inbound_id BIGINT UNSIGNED NOT NULL, - tenant_id BIGINT UNSIGNED NOT NULL, - order_id BIGINT UNSIGNED NOT NULL, - inbound_code VARCHAR(40) NOT NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + document_id BIGINT UNSIGNED NOT NULL COMMENT '冻结的客户报关资料ID', + inbound_id BIGINT UNSIGNED NOT NULL COMMENT '冻结覆盖的入仓单ID', + tenant_id BIGINT UNSIGNED NOT NULL COMMENT '冻结入仓单客户隔离键', + order_id BIGINT UNSIGNED NOT NULL COMMENT '冻结入仓单所属订单ID', + inbound_code VARCHAR(40) NOT NULL COMMENT '冻结入仓码快照', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '覆盖范围冻结时间', PRIMARY KEY(document_id,inbound_id), CONSTRAINT fk_customs_frozen_document FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id) ) ENGINE=InnoDB COMMENT='开始报关时冻结的客户资料覆盖范围'; CREATE TABLE IF NOT EXISTS fl_customs_completion_document ( - id BIGINT UNSIGNED NOT NULL, + id BIGINT UNSIGNED NOT NULL COMMENT '报关完成文件ID', source_document_id BIGINT UNSIGNED NOT NULL COMMENT '一份冻结客户资料严格对应一份完成文件逻辑根', - file_id BIGINT UNSIGNED NOT NULL, - file_name VARCHAR(255) NOT NULL, - file_hash CHAR(64) NOT NULL, - content_type VARCHAR(128) NULL, - size_bytes BIGINT UNSIGNED NOT NULL, - uploaded_by BIGINT UNSIGNED NOT NULL, - uploaded_by_name VARCHAR(64) NULL, - uploaded_at DATETIME(3) NOT NULL, - version INT UNSIGNED NOT NULL DEFAULT 1, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + file_id BIGINT UNSIGNED NOT NULL COMMENT '完成文件的File服务文件ID', + file_name VARCHAR(255) NOT NULL COMMENT '完成文件名快照', + file_hash CHAR(64) NOT NULL COMMENT '完成文件SHA-256摘要', + content_type VARCHAR(128) NULL COMMENT '完成文件内容类型', + size_bytes BIGINT UNSIGNED NOT NULL COMMENT '完成文件大小(字节)', + uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '完成文件上传操作人ID', + uploaded_by_name VARCHAR(64) NULL COMMENT '完成文件上传操作人姓名快照', + uploaded_at DATETIME(3) NOT NULL COMMENT '完成文件上传时间', + version INT UNSIGNED NOT NULL DEFAULT 1 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_customs_completion_source(source_document_id), CONSTRAINT fk_customs_completion_source FOREIGN KEY(source_document_id) REFERENCES fl_customs_customer_document(id) ) ENGINE=InnoDB COMMENT='报关完成文件当前版本'; CREATE TABLE IF NOT EXISTS fl_customs_completion_document_version ( - id BIGINT UNSIGNED NOT NULL, - completion_document_id BIGINT UNSIGNED NOT NULL, - document_version INT UNSIGNED NOT NULL, - file_id BIGINT UNSIGNED NOT NULL, - file_name VARCHAR(255) NOT NULL, - file_hash CHAR(64) NOT NULL, - content_type VARCHAR(128) NULL, - size_bytes BIGINT UNSIGNED NOT NULL, - operator_id BIGINT UNSIGNED NOT NULL, - operator_name VARCHAR(64) NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + id BIGINT UNSIGNED NOT NULL COMMENT '完成文件版本记录ID', + completion_document_id BIGINT UNSIGNED NOT NULL COMMENT '报关完成文件ID', + document_version INT UNSIGNED NOT NULL COMMENT '完成文件版本号', + file_id BIGINT UNSIGNED NOT NULL COMMENT '该版本File服务文件ID', + file_name VARCHAR(255) NOT NULL COMMENT '该版本文件名快照', + file_hash CHAR(64) NOT NULL COMMENT '该版本文件SHA-256摘要', + content_type VARCHAR(128) NULL COMMENT '该版本文件内容类型', + size_bytes BIGINT UNSIGNED NOT 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), UNIQUE KEY uk_customs_completion_version(completion_document_id,document_version), CONSTRAINT fk_customs_completion_version FOREIGN KEY(completion_document_id) REFERENCES fl_customs_completion_document(id) ) ENGINE=InnoDB COMMENT='报关完成文件不可变覆盖版本'; CREATE TABLE IF NOT EXISTS fl_customs_container_history ( - id BIGINT UNSIGNED NOT NULL, - customs_container_id BIGINT UNSIGNED NOT NULL, - action VARCHAR(40) NOT NULL, - from_status VARCHAR(40) NULL, - to_status VARCHAR(40) NULL, - remark VARCHAR(500) NULL, - operator_id BIGINT UNSIGNED NOT NULL, - operator_name VARCHAR(64) NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + id BIGINT UNSIGNED NOT NULL COMMENT '整柜报关历史ID', + customs_container_id BIGINT UNSIGNED NOT NULL COMMENT '所属整柜报关聚合ID', + action VARCHAR(40) NOT NULL COMMENT '报关状态或系统触发动作', + from_status VARCHAR(40) NULL COMMENT '动作前报关状态', + to_status VARCHAR(40) 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_customs_container_history(customs_container_id,created_at,id), CONSTRAINT fk_customs_container_history FOREIGN KEY(customs_container_id) REFERENCES fl_customs_container(id) ) ENGINE=InnoDB COMMENT='整柜报关状态与系统触发历史'; CREATE TABLE IF NOT EXISTS fl_customs_command ( - id BIGINT UNSIGNED NOT NULL, - actor_id BIGINT UNSIGNED NOT NULL, - action VARCHAR(80) NOT NULL, - idempotency_key VARCHAR(128) NOT NULL, - request_hash CHAR(64) NOT NULL, - status VARCHAR(16) NOT NULL, - result_id BIGINT UNSIGNED NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - completed_at DATETIME(3) NULL, + id BIGINT UNSIGNED NOT NULL COMMENT '报关写命令ID', + actor_id BIGINT UNSIGNED NOT NULL COMMENT '命令发起操作人ID', + action VARCHAR(80) NOT NULL COMMENT '报关写命令动作', + idempotency_key VARCHAR(128) NOT NULL COMMENT '调用方幂等键', + request_hash CHAR(64) NOT NULL COMMENT '规范化请求SHA-256摘要', + status VARCHAR(16) NOT NULL COMMENT '命令状态:PROCESSING处理中、SUCCESS成功', + result_id BIGINT UNSIGNED NULL COMMENT '命令成功生成的业务结果ID', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '命令创建时间', + completed_at DATETIME(3) NULL COMMENT '命令成功完成时间', PRIMARY KEY(id), UNIQUE KEY uk_customs_command(actor_id,action,idempotency_key), CONSTRAINT chk_customs_command_status CHECK(status IN('PROCESSING','SUCCESS')) diff --git a/firstleg/src/main/resources/db/phase3-container-customs-schema.sql b/firstleg/src/main/resources/db/phase3-container-customs-schema.sql index 5f86e3d2b..3da35accc 100644 --- a/firstleg/src/main/resources/db/phase3-container-customs-schema.sql +++ b/firstleg/src/main/resources/db/phase3-container-customs-schema.sql @@ -2,19 +2,19 @@ SET NAMES utf8mb4; USE baiyue_firstleg; CREATE TABLE IF NOT EXISTS fl_customs_container ( - id BIGINT UNSIGNED NOT NULL, + id BIGINT UNSIGNED NOT NULL COMMENT '整柜报关聚合ID', loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '已完成装柜计划ID;报关柜级聚合唯一键', container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '物理货柜ID', - status VARCHAR(40) NOT NULL COMMENT 'WAITING_CUSTOMER_DOCUMENTS、READY_TO_START、DECLARING、COMPLETED', - started_by BIGINT UNSIGNED NULL, - started_by_name VARCHAR(64) NULL, - started_at DATETIME(3) NULL, - completed_by BIGINT UNSIGNED NULL, - completed_by_name VARCHAR(64) NULL, - completed_at DATETIME(3) NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), - version INT UNSIGNED NOT NULL DEFAULT 0, + status VARCHAR(40) NOT NULL COMMENT '报关状态:WAITING_CUSTOMER_DOCUMENTS待客户资料、READY_TO_START待开始、DECLARING报关中、COMPLETED已完成', + started_by BIGINT UNSIGNED NULL COMMENT '开始报关操作人ID', + started_by_name VARCHAR(64) NULL COMMENT '开始报关操作人姓名快照', + started_at DATETIME(3) NULL COMMENT '开始报关时间', + completed_by BIGINT UNSIGNED NULL COMMENT '完成报关操作人ID', + completed_by_name VARCHAR(64) 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 UNSIGNED NOT NULL DEFAULT 0 COMMENT '报关聚合乐观锁版本', PRIMARY KEY(id), UNIQUE KEY uk_customs_container_plan(loading_plan_id), UNIQUE KEY uk_customs_container_booking(container_booking_id), @@ -24,24 +24,24 @@ CREATE TABLE IF NOT EXISTS fl_customs_container ( ) ENGINE=InnoDB COMMENT='装柜完成后的整柜出口报关聚合'; CREATE TABLE IF NOT EXISTS fl_customs_customer_document ( - id BIGINT UNSIGNED NOT NULL, - customs_container_id BIGINT UNSIGNED NOT NULL, + id BIGINT UNSIGNED NOT NULL COMMENT '客户报关资料ID', + customs_container_id BIGINT UNSIGNED NOT NULL COMMENT '所属整柜报关聚合ID', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户隔离键;只允许关联同客户退税票', - file_id BIGINT UNSIGNED NOT NULL, - file_name VARCHAR(255) NOT NULL, - file_hash CHAR(64) NOT NULL, - content_type VARCHAR(128) NULL, - size_bytes BIGINT UNSIGNED NOT NULL, - status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', - uploaded_by BIGINT UNSIGNED NOT NULL, - uploaded_at DATETIME(3) NOT NULL, - frozen_version INT UNSIGNED NULL, - frozen_at DATETIME(3) NULL, - deleted_by BIGINT UNSIGNED NULL, - deleted_at DATETIME(3) NULL, - version INT UNSIGNED NOT NULL DEFAULT 1, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + file_id BIGINT UNSIGNED NOT NULL COMMENT 'File服务文件ID', + file_name VARCHAR(255) NOT NULL COMMENT '客户资料文件名快照', + file_hash CHAR(64) NOT NULL COMMENT '客户资料文件SHA-256摘要', + content_type VARCHAR(128) NULL COMMENT '客户资料文件内容类型', + size_bytes BIGINT UNSIGNED NOT NULL COMMENT '客户资料文件大小(字节)', + status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '资料状态:ACTIVE有效、DELETED已删除', + uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '上传操作人ID', + uploaded_at DATETIME(3) NOT NULL COMMENT '上传时间', + frozen_version INT UNSIGNED NULL COMMENT '开始报关时冻结的资料版本', + frozen_at DATETIME(3) NULL COMMENT '资料冻结时间', + deleted_by BIGINT UNSIGNED NULL COMMENT '删除操作人ID', + deleted_at DATETIME(3) NULL COMMENT '逻辑删除时间', + version INT UNSIGNED NOT NULL DEFAULT 1 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_customs_customer_document_container(customs_container_id,status,tenant_id), CONSTRAINT fk_customs_customer_document_container FOREIGN KEY(customs_container_id) REFERENCES fl_customs_container(id), @@ -51,30 +51,30 @@ CREATE TABLE IF NOT EXISTS fl_customs_customer_document ( ) ENGINE=InnoDB COMMENT='客户整份退税报送资料逻辑根'; CREATE TABLE IF NOT EXISTS fl_customs_customer_document_inbound ( - document_id BIGINT UNSIGNED NOT NULL, - inbound_id BIGINT UNSIGNED NOT NULL, - tenant_id BIGINT UNSIGNED NOT NULL, - order_id BIGINT UNSIGNED NOT NULL, - inbound_code VARCHAR(40) NOT NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + document_id BIGINT UNSIGNED NOT NULL COMMENT '客户报关资料ID', + inbound_id BIGINT UNSIGNED NOT NULL COMMENT '覆盖的入仓单ID', + tenant_id BIGINT UNSIGNED NOT NULL COMMENT '入仓单客户隔离键', + order_id BIGINT UNSIGNED NOT NULL COMMENT '入仓单所属订单ID', + inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '资料覆盖关系创建时间', PRIMARY KEY(document_id,inbound_id), KEY idx_customs_document_inbound(inbound_id,tenant_id), CONSTRAINT fk_customs_document_inbound_document FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id) ) ENGINE=InnoDB COMMENT='客户报送资料与当前柜退税入仓码多对多关系'; CREATE TABLE IF NOT EXISTS fl_customs_customer_document_version ( - id BIGINT UNSIGNED NOT NULL, - document_id BIGINT UNSIGNED NOT NULL, - document_version INT UNSIGNED NOT NULL, - file_id BIGINT UNSIGNED NOT NULL, - file_name VARCHAR(255) NOT NULL, - file_hash CHAR(64) NOT NULL, - content_type VARCHAR(128) NULL, - size_bytes BIGINT UNSIGNED NOT NULL, - scope_snapshot_json JSON NOT NULL, - action VARCHAR(24) NOT NULL COMMENT 'UPLOAD、REPLACE、SCOPE_CHANGE、DELETE', - operator_id BIGINT UNSIGNED NOT NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + id BIGINT UNSIGNED NOT NULL COMMENT '客户资料版本记录ID', + document_id BIGINT UNSIGNED NOT NULL COMMENT '客户报关资料ID', + document_version INT UNSIGNED NOT NULL COMMENT '客户资料版本号', + file_id BIGINT UNSIGNED NOT NULL COMMENT '该版本File服务文件ID', + file_name VARCHAR(255) NOT NULL COMMENT '该版本文件名快照', + file_hash CHAR(64) NOT NULL COMMENT '该版本文件SHA-256摘要', + content_type VARCHAR(128) NULL COMMENT '该版本文件内容类型', + size_bytes BIGINT UNSIGNED NOT NULL COMMENT '该版本文件大小(字节)', + scope_snapshot_json JSON NOT NULL COMMENT '该版本覆盖入仓码范围快照', + action VARCHAR(24) NOT NULL COMMENT '版本动作:UPLOAD上传、REPLACE替换、SCOPE_CHANGE调整范围、DELETE删除', + operator_id BIGINT UNSIGNED NOT NULL COMMENT '版本操作人ID', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '版本记录创建时间', PRIMARY KEY(id), UNIQUE KEY uk_customs_customer_document_version(document_id,document_version), CONSTRAINT fk_customs_customer_document_version FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id), @@ -82,77 +82,77 @@ CREATE TABLE IF NOT EXISTS fl_customs_customer_document_version ( ) ENGINE=InnoDB COMMENT='客户报送资料文件与覆盖范围不可变版本'; CREATE TABLE IF NOT EXISTS fl_customs_frozen_document_inbound ( - document_id BIGINT UNSIGNED NOT NULL, - inbound_id BIGINT UNSIGNED NOT NULL, - tenant_id BIGINT UNSIGNED NOT NULL, - order_id BIGINT UNSIGNED NOT NULL, - inbound_code VARCHAR(40) NOT NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + document_id BIGINT UNSIGNED NOT NULL COMMENT '冻结的客户报关资料ID', + inbound_id BIGINT UNSIGNED NOT NULL COMMENT '冻结覆盖的入仓单ID', + tenant_id BIGINT UNSIGNED NOT NULL COMMENT '冻结入仓单客户隔离键', + order_id BIGINT UNSIGNED NOT NULL COMMENT '冻结入仓单所属订单ID', + inbound_code VARCHAR(40) NOT NULL COMMENT '冻结入仓码快照', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '覆盖范围冻结时间', PRIMARY KEY(document_id,inbound_id), CONSTRAINT fk_customs_frozen_document FOREIGN KEY(document_id) REFERENCES fl_customs_customer_document(id) ) ENGINE=InnoDB COMMENT='开始报关时冻结的客户资料覆盖范围'; CREATE TABLE IF NOT EXISTS fl_customs_completion_document ( - id BIGINT UNSIGNED NOT NULL, + id BIGINT UNSIGNED NOT NULL COMMENT '报关完成文件ID', source_document_id BIGINT UNSIGNED NOT NULL COMMENT '一份冻结客户资料严格对应一份完成文件逻辑根', - file_id BIGINT UNSIGNED NOT NULL, - file_name VARCHAR(255) NOT NULL, - file_hash CHAR(64) NOT NULL, - content_type VARCHAR(128) NULL, - size_bytes BIGINT UNSIGNED NOT NULL, - uploaded_by BIGINT UNSIGNED NOT NULL, - uploaded_by_name VARCHAR(64) NULL, - uploaded_at DATETIME(3) NOT NULL, - version INT UNSIGNED NOT NULL DEFAULT 1, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + file_id BIGINT UNSIGNED NOT NULL COMMENT '完成文件的File服务文件ID', + file_name VARCHAR(255) NOT NULL COMMENT '完成文件名快照', + file_hash CHAR(64) NOT NULL COMMENT '完成文件SHA-256摘要', + content_type VARCHAR(128) NULL COMMENT '完成文件内容类型', + size_bytes BIGINT UNSIGNED NOT NULL COMMENT '完成文件大小(字节)', + uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '完成文件上传操作人ID', + uploaded_by_name VARCHAR(64) NULL COMMENT '完成文件上传操作人姓名快照', + uploaded_at DATETIME(3) NOT NULL COMMENT '完成文件上传时间', + version INT UNSIGNED NOT NULL DEFAULT 1 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_customs_completion_source(source_document_id), CONSTRAINT fk_customs_completion_source FOREIGN KEY(source_document_id) REFERENCES fl_customs_customer_document(id) ) ENGINE=InnoDB COMMENT='报关完成文件当前版本'; CREATE TABLE IF NOT EXISTS fl_customs_completion_document_version ( - id BIGINT UNSIGNED NOT NULL, - completion_document_id BIGINT UNSIGNED NOT NULL, - document_version INT UNSIGNED NOT NULL, - file_id BIGINT UNSIGNED NOT NULL, - file_name VARCHAR(255) NOT NULL, - file_hash CHAR(64) NOT NULL, - content_type VARCHAR(128) NULL, - size_bytes BIGINT UNSIGNED NOT NULL, - operator_id BIGINT UNSIGNED NOT NULL, - operator_name VARCHAR(64) NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + id BIGINT UNSIGNED NOT NULL COMMENT '完成文件版本记录ID', + completion_document_id BIGINT UNSIGNED NOT NULL COMMENT '报关完成文件ID', + document_version INT UNSIGNED NOT NULL COMMENT '完成文件版本号', + file_id BIGINT UNSIGNED NOT NULL COMMENT '该版本File服务文件ID', + file_name VARCHAR(255) NOT NULL COMMENT '该版本文件名快照', + file_hash CHAR(64) NOT NULL COMMENT '该版本文件SHA-256摘要', + content_type VARCHAR(128) NULL COMMENT '该版本文件内容类型', + size_bytes BIGINT UNSIGNED NOT 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), UNIQUE KEY uk_customs_completion_version(completion_document_id,document_version), CONSTRAINT fk_customs_completion_version FOREIGN KEY(completion_document_id) REFERENCES fl_customs_completion_document(id) ) ENGINE=InnoDB COMMENT='报关完成文件不可变覆盖版本'; CREATE TABLE IF NOT EXISTS fl_customs_container_history ( - id BIGINT UNSIGNED NOT NULL, - customs_container_id BIGINT UNSIGNED NOT NULL, - action VARCHAR(40) NOT NULL, - from_status VARCHAR(40) NULL, - to_status VARCHAR(40) NULL, - remark VARCHAR(500) NULL, - operator_id BIGINT UNSIGNED NOT NULL, - operator_name VARCHAR(64) NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + id BIGINT UNSIGNED NOT NULL COMMENT '整柜报关历史ID', + customs_container_id BIGINT UNSIGNED NOT NULL COMMENT '所属整柜报关聚合ID', + action VARCHAR(40) NOT NULL COMMENT '报关状态或系统触发动作', + from_status VARCHAR(40) NULL COMMENT '动作前报关状态', + to_status VARCHAR(40) 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_customs_container_history(customs_container_id,created_at,id), CONSTRAINT fk_customs_container_history FOREIGN KEY(customs_container_id) REFERENCES fl_customs_container(id) ) ENGINE=InnoDB COMMENT='整柜报关状态与系统触发历史'; CREATE TABLE IF NOT EXISTS fl_customs_command ( - id BIGINT UNSIGNED NOT NULL, - actor_id BIGINT UNSIGNED NOT NULL, - action VARCHAR(80) NOT NULL, - idempotency_key VARCHAR(128) NOT NULL, - request_hash CHAR(64) NOT NULL, - status VARCHAR(16) NOT NULL, - result_id BIGINT UNSIGNED NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - completed_at DATETIME(3) NULL, + id BIGINT UNSIGNED NOT NULL COMMENT '报关写命令ID', + actor_id BIGINT UNSIGNED NOT NULL COMMENT '命令发起操作人ID', + action VARCHAR(80) NOT NULL COMMENT '报关写命令动作', + idempotency_key VARCHAR(128) NOT NULL COMMENT '调用方幂等键', + request_hash CHAR(64) NOT NULL COMMENT '规范化请求SHA-256摘要', + status VARCHAR(16) NOT NULL COMMENT '命令状态:PROCESSING处理中、SUCCESS成功', + result_id BIGINT UNSIGNED NULL COMMENT '命令成功生成的业务结果ID', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '命令创建时间', + completed_at DATETIME(3) NULL COMMENT '命令成功完成时间', PRIMARY KEY(id), UNIQUE KEY uk_customs_command(actor_id,action,idempotency_key), CONSTRAINT chk_customs_command_status CHECK(status IN('PROCESSING','SUCCESS')) diff --git a/firstleg/src/test/java/com/baiyue/firstleg/customs/repository/CustomsSqlContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/customs/repository/CustomsSqlContractTest.java index 7a8b5240c..50edf3a3d 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/customs/repository/CustomsSqlContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/customs/repository/CustomsSqlContractTest.java @@ -4,10 +4,32 @@ import org.junit.jupiter.api.Test; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.assertj.core.api.Assertions.assertThat; class CustomsSqlContractTest { + private static final Set CUSTOMS_TABLES = Set.of( + "fl_customs_container", + "fl_customs_customer_document", + "fl_customs_customer_document_inbound", + "fl_customs_customer_document_version", + "fl_customs_frozen_document_inbound", + "fl_customs_completion_document", + "fl_customs_completion_document_version", + "fl_customs_container_history", + "fl_customs_command"); + private static final Pattern CREATE_TABLE = Pattern.compile( + "(?i)CREATE\\s+TABLE\\s+IF\\s+NOT\\s+EXISTS\\s+`?([a-zA-Z0-9_]+)`?\\s*\\("); + private static final Pattern COLUMN = Pattern.compile( + "(?i)^\\s*`?([a-zA-Z0-9_]+)`?\\s+(bigint|char|datetime|int|json|tinyint|varchar)\\b"); + private static final Pattern CHINESE_COMMENT = Pattern.compile( + "(?i)\\bCOMMENT\\s*=?\\s*'(?:(?:''|\\\\'|[^'])*[\\u3400-\\u9fff](?:''|\\\\'|[^'])*)'"); + @Test void moduleSqlContainsContainerStateManyToManyFreezeVersionAndIdempotencyContracts() throws Exception { String sql = Files.readString(Path.of("src/main/resources/db/phase3-container-customs-schema.sql")); @@ -19,4 +41,76 @@ class CustomsSqlContractTest { .contains("fl_customs_command", "uk_customs_command(actor_id,action,idempotency_key)") .doesNotContain("platform:firstleg:loading-list:export"); } + + @Test + void everyCustomsColumnHasAnAccurateChineseComment() throws Exception { + String sql = Files.readString(Path.of("src/main/resources/db/phase3-container-customs-schema.sql")); + Matcher tableMatcher = CREATE_TABLE.matcher(sql); + Set found = new java.util.HashSet<>(); + List missingComments = new ArrayList<>(); + + while (tableMatcher.find()) { + String table = tableMatcher.group(1); + if (!CUSTOMS_TABLES.contains(table)) continue; + found.add(table); + int open = tableMatcher.end() - 1; + int close = matchingParen(sql, open); + for (String definition : splitDefinitions(sql.substring(open + 1, close))) { + Matcher columnMatcher = COLUMN.matcher(definition); + if (columnMatcher.find() && !CHINESE_COMMENT.matcher(definition).find()) { + missingComments.add(table + "." + columnMatcher.group(1)); + } + } + } + + assertThat(found).containsExactlyInAnyOrderElementsOf(CUSTOMS_TABLES); + assertThat(missingComments).isEmpty(); + } + + private static int matchingParen(String sql, int open) { + int depth = 0; + char quote = 0; + for (int index = open; index < sql.length(); index++) { + char current = sql.charAt(index); + if (quote != 0) { + if (current == '\\') index++; + else if (current == quote) { + if (index + 1 < sql.length() && sql.charAt(index + 1) == quote) index++; + else quote = 0; + } + continue; + } + if (current == '\'' || current == '"' || current == '`') quote = current; + else if (current == '(') depth++; + else if (current == ')' && --depth == 0) return index; + } + throw new AssertionError("unclosed CREATE TABLE at " + open); + } + + private static List splitDefinitions(String body) { + List definitions = new ArrayList<>(); + int start = 0; + int depth = 0; + char quote = 0; + for (int index = 0; index < body.length(); index++) { + char current = body.charAt(index); + if (quote != 0) { + if (current == '\\') index++; + else if (current == quote) { + if (index + 1 < body.length() && body.charAt(index + 1) == quote) index++; + else quote = 0; + } + continue; + } + if (current == '\'' || current == '"' || current == '`') quote = current; + else if (current == '(') depth++; + else if (current == ')') depth--; + else if (current == ',' && depth == 0) { + definitions.add(body.substring(start, index)); + start = index + 1; + } + } + definitions.add(body.substring(start)); + return definitions; + } }