merge: preserve TEST finance and rent changes with fleet photo updates

This commit is contained in:
2026-10-26 17:21:43 +08:00
181 changed files with 9007 additions and 396 deletions
@@ -880,7 +880,8 @@ CREATE TABLE IF NOT EXISTS ll_finance_fee_source (
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应付',
fee_item_name VARCHAR(200) NOT NULL COMMENT '费用项目名称快照', fee_remark VARCHAR(500) 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 '直接已付方式',
@@ -888,19 +889,20 @@ CREATE TABLE IF NOT EXISTS ll_finance_fee_source (
wallet_settlement JSON NULL COMMENT '已实扣应收的Finance资金命令、冻结和消费流水引用',
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',
original_amount DECIMAL(20,6) NOT NULL COMMENT '业务原币金额', exchange_rate DECIMAL(20,6) 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 '审核时间',
review_reason VARCHAR(500) NULL COMMENT '审核或作废原因', reviewer_id VARCHAR(128) NULL COMMENT '审核人ID', reviewer_name VARCHAR(255) NULL COMMENT '审核人名称快照', 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_exchange_rate CHECK((exchange_rate IS NOT NULL AND exchange_rate>0) OR (exchange_rate IS NULL AND amount=0 AND original_amount=0 AND created_by='STORAGE_RENT' AND fee_item_code='FEE_TYPE_077' AND direction='RECEIVABLE')),
CONSTRAINT chk_ll_finance_fee_amount CHECK(amount>0 OR (amount=0 AND original_amount=0 AND created_by='STORAGE_RENT' AND fee_item_code='FEE_TYPE_077' AND direction='RECEIVABLE')), 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')),
@@ -2926,6 +2928,7 @@ CREATE TABLE IF NOT EXISTS ll_cargo_discard_status_history (
) ENGINE=InnoDB COMMENT='货物废弃审批历史';
CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order (
procurement_direction VARCHAR(32) NOT NULL DEFAULT 'OVERSEAS_TO_DOMESTIC' COMMENT '采购方向:海外采购回国内/国内采购发海外',
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 '产品名称',
@@ -3261,7 +3264,7 @@ CREATE TABLE IF NOT EXISTS ll_destuff_pallet_cost (
) 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 '创建时间',
allocated_amount DECIMAL(20,2) NOT NULL COMMENT '客户分摊金额', fee_source_id BIGINT 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='拆柜打托成本按客户实收体积分摊';
@@ -3923,6 +3926,7 @@ CREATE TABLE IF NOT EXISTS ll_return_sku_conversion (
quantity BIGINT NOT NULL COMMENT '实际完成转换件数',
status VARCHAR(32) NOT NULL COMMENT 'APPLIED待客户确认/CONFIRMED已确认/REVERSED退回冲回',
ownership_json LONGTEXT NOT NULL COMMENT '本次转换件数的来源退货单快照,供精确冲回',
storage_rent_shares_json LONGTEXT NULL COMMENT '原仓租批次迁移快照',
completed_at DATETIME(3) NOT NULL COMMENT '实物SKU转换时间',
confirmed_at DATETIME(3) NULL COMMENT '客户确认时间',
reversed_at DATETIME(3) NULL COMMENT '退回冲回时间',
@@ -4672,3 +4676,126 @@ CREATE TABLE IF NOT EXISTS ll_fleet_resource_photo (
PRIMARY KEY (resource_kind, resource_id, record_version),
UNIQUE KEY uk_fleet_resource_photo_file (resource_kind, resource_id, file_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆及司机档案照片版本记录';
-- 海外人工费用资金编排。金额与余额以 Finance 钱包为唯一事实,本表仅记录指令及回执状态。
CREATE TABLE IF NOT EXISTS ll_finance_fee_funding (
source_fee_id BIGINT NOT NULL COMMENT '关联海外费用稳定来源ID',
customer_id VARCHAR(128) NOT NULL COMMENT '费用所属客户隔离标识',
collection_mode VARCHAR(16) NOT NULL COMMENT '客户收费方式:BILL账单结算,WALLET余额及授信',
wallet_status VARCHAR(32) NOT NULL COMMENT '资金进度:待冻结、已冻结、待扣款、已扣款、待释放及失败状态',
wallet_business_no VARCHAR(128) NULL COMMENT '本次冻结使用的独立业务编号,重提使用新编号',
command_event_id VARCHAR(64) NULL COMMENT '当前待处理资金指令事件ID',
wallet_hold_id VARCHAR(64) NULL COMMENT 'Finance确认的资金冻结记录ID',
wallet_ledger_id VARCHAR(64) NULL COMMENT 'Finance确认的已扣资金流水ID',
command_version BIGINT NOT NULL DEFAULT 0 COMMENT '资金指令单调递增版本,防止重试重复入账',
error_message VARCHAR(500) NULL COMMENT '最新资金失败原因,成功后清空',
command_history JSON NOT NULL COMMENT '已发资金指令及核验结果哈希,识别重复和错序回执',
created_at DATETIME(3) NOT NULL COMMENT '资金编排创建UTC时间',
updated_at DATETIME(3) NOT NULL COMMENT '资金编排最近变更UTC时间',
PRIMARY KEY (source_fee_id),
KEY idx_ll_fee_funding_customer_state (customer_id, wallet_status),
KEY idx_ll_fee_funding_command (command_event_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='海外人工费用资金冻结、审核扣款及释放编排';
-- 实收仓租原批次、份额与资金预占。
CREATE TABLE IF NOT EXISTS ll_storage_rent_inbound (
receipt_id bigint NOT NULL COMMENT '实际入库凭证主键,防止重复累计计租数量',
lot_id bigint NOT NULL COMMENT '头程同单同仓计租批次主键',
quantity decimal(24,12) NOT NULL COMMENT '本次实收追加计租箱数',
created_at datetime(3) NOT NULL COMMENT '计租登记时间,采用协调世界时',
PRIMARY KEY (receipt_id),
KEY idx_storage_rent_inbound_lot (lot_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='头程实收计租幂等登记';
CREATE TABLE IF NOT EXISTS ll_storage_rent_lot (
id bigint NOT NULL COMMENT '原批次主键',
source_key varchar(80) NOT NULL COMMENT '实收来源幂等键',
customer_id varchar(32) NOT NULL COMMENT '客户标识',
customer_name varchar(255) DEFAULT NULL COMMENT '客户名称',
warehouse_id varchar(32) NOT NULL COMMENT '海外仓标识',
warehouse_name varchar(255) DEFAULT NULL COMMENT '海外仓名称',
business_type varchar(32) NOT NULL COMMENT '原入库业务类型',
business_id bigint NOT NULL COMMENT '原入库业务主键',
business_no varchar(128) NOT NULL COMMENT '原入库业务单号',
order_id bigint DEFAULT NULL COMMENT '尾程订单主键',
inbound_code varchar(128) DEFAULT NULL COMMENT '入仓码',
balance_id bigint DEFAULT NULL COMMENT '普通库存余额主键',
batch_no varchar(128) DEFAULT NULL COMMENT '原实收批次',
sku_code varchar(128) DEFAULT NULL COMMENT '商品编码',
rule_code varchar(32) NOT NULL COMMENT '仓租规则',
original_quantity decimal(24,12) NOT NULL COMMENT '实收原始数量',
remaining_quantity decimal(24,12) NOT NULL COMMENT '未出库原始数量',
original_units decimal(24,12) DEFAULT NULL COMMENT '原批次计费体积或托数',
inbound_at datetime(3) NOT NULL COMMENT '实际入库时间',
created_at datetime(3) NOT NULL COMMENT '创建时间',
updated_at datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_storage_rent_lot_source (source_key),
KEY idx_storage_rent_stock (balance_id,batch_no),
KEY idx_storage_rent_customer (customer_id,warehouse_id,inbound_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='实收计租原批次';
CREATE TABLE IF NOT EXISTS ll_storage_rent_share (
balance_id bigint DEFAULT NULL COMMENT '普通库存当前余额,退货箱份额为空',
batch_no varchar(128) DEFAULT NULL COMMENT '普通库存当前批次,换标搬移保持原计租批次引用',
id bigint NOT NULL COMMENT '份额主键',
lot_id bigint NOT NULL COMMENT '原计租批次主键',
customer_id varchar(32) NOT NULL COMMENT '客户标识',
warehouse_id varchar(32) NOT NULL COMMENT '海外仓标识',
carton_mark varchar(255) DEFAULT NULL COMMENT '当前箱唛',
sku_code varchar(128) DEFAULT NULL COMMENT '商品编码',
quantity decimal(24,12) NOT NULL COMMENT '剩余商品数量',
PRIMARY KEY (id),
UNIQUE KEY uk_storage_rent_return_share (lot_id,carton_mark,sku_code),
UNIQUE KEY uk_storage_rent_stock_share (lot_id,balance_id,batch_no),
KEY idx_storage_rent_carton (customer_id,warehouse_id,carton_mark),
KEY idx_storage_rent_share_stock (customer_id,warehouse_id,balance_id,batch_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='当前库存与原计租批次份额';
CREATE TABLE IF NOT EXISTS ll_storage_rent_preparation (
id bigint NOT NULL COMMENT '预校验主键',
warehouse_id varchar(32) NOT NULL COMMENT '作业海外仓',
customer_id varchar(32) NOT NULL COMMENT '费用客户',
mode varchar(32) NOT NULL COMMENT '扫码类型',
execution_no varchar(128) NOT NULL COMMENT '实际作业单号',
request_key varchar(255) NOT NULL COMMENT '原扫码幂等键',
request_hash varchar(64) NOT NULL COMMENT '原扫码内容哈希',
attempt int NOT NULL COMMENT '冻结尝试次数',
business_type varchar(32) NOT NULL COMMENT '本次应收业务类型',
business_id bigint NOT NULL COMMENT '本次应收业务主键',
business_no varchar(128) NOT NULL COMMENT '本次应收业务单号',
status varchar(32) NOT NULL COMMENT '资金与扫码状态',
plan_json json NOT NULL COMMENT '原批次计费不可变快照',
original_amount decimal(24,12) NOT NULL COMMENT '原币仓租金额,币种见计费快照',
amount decimal(24,12) NOT NULL COMMENT '人民币结算金额',
exchange_rate decimal(24,12) NULL COMMENT '冻结确认汇率,免费出库为空',
exchange_rate_month varchar(7) NOT NULL COMMENT '汇率月份',
freeze_event_id varchar(128) DEFAULT NULL COMMENT '冻结指令事件',
settle_event_id varchar(128) DEFAULT NULL COMMENT '扣款指令事件',
release_event_id varchar(128) DEFAULT NULL COMMENT '解冻指令事件',
release_status varchar(32) DEFAULT NULL COMMENT '解冻回执状态,失败后由恢复任务重发',
wallet_version bigint NOT NULL COMMENT '同一预占资金命令版本,重试使用新版本保留审计',
hold_id varchar(128) DEFAULT NULL COMMENT '财务冻结主键',
ledger_id varchar(128) DEFAULT NULL COMMENT '财务扣款流水',
error_message varchar(1000) DEFAULT NULL COMMENT '资金处理结果',
source_fee_id bigint DEFAULT NULL COMMENT '财务费用来源主键',
created_at datetime(3) NOT NULL COMMENT '预校验时间',
consumed_at datetime(3) DEFAULT NULL COMMENT '实际扫描出库时间',
updated_at datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_storage_rent_request (warehouse_id,mode,request_key,attempt),
KEY idx_storage_rent_execution (mode,execution_no,status),
KEY idx_storage_rent_business (customer_id,business_no),
KEY idx_storage_rent_recovery (status,updated_at),
KEY idx_storage_rent_release (release_status,updated_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='仓租扫码资金预占与结算快照';
-- SKU 换标原计租份额快照,存量数据库可重复执行。
SET @storage_rent_sku_column = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_sku_conversion' AND column_name='storage_rent_shares_json');
SET @storage_rent_sku_ddl = IF(@storage_rent_sku_column=0, 'ALTER TABLE ll_return_sku_conversion ADD COLUMN storage_rent_shares_json LONGTEXT NULL COMMENT ''原仓租批次迁移快照'' AFTER ownership_json', 'SELECT 1');
PREPARE storage_rent_sku_stmt FROM @storage_rent_sku_ddl;
EXECUTE storage_rent_sku_stmt;
DEALLOCATE PREPARE storage_rent_sku_stmt;
-- 首版拆柜成本只记录分摊依据,客户应收另行人工登记审核;重复执行保持相同定义。
ALTER TABLE ll_destuff_pallet_cost_allocation MODIFY COLUMN fee_source_id BIGINT NULL COMMENT '人工审核后关联的海外费用来源ID';
@@ -0,0 +1,22 @@
-- 海外人工费用资金编排。金额与余额以 Finance 钱包为唯一事实,本表仅记录指令及回执状态。
CREATE TABLE IF NOT EXISTS ll_finance_fee_funding (
source_fee_id BIGINT NOT NULL COMMENT '关联海外费用稳定来源ID',
customer_id VARCHAR(128) NOT NULL COMMENT '费用所属客户隔离标识',
collection_mode VARCHAR(16) NOT NULL COMMENT '客户收费方式:BILL账单结算,WALLET余额及授信',
wallet_status VARCHAR(32) NOT NULL COMMENT '资金进度:待冻结、已冻结、待扣款、已扣款、待释放及失败状态',
wallet_business_no VARCHAR(128) NULL COMMENT '本次冻结使用的独立业务编号,重提使用新编号',
command_event_id VARCHAR(64) NULL COMMENT '当前待处理资金指令事件ID',
wallet_hold_id VARCHAR(64) NULL COMMENT 'Finance确认的资金冻结记录ID',
wallet_ledger_id VARCHAR(64) NULL COMMENT 'Finance确认的已扣资金流水ID',
command_version BIGINT NOT NULL DEFAULT 0 COMMENT '资金指令单调递增版本,防止重试重复入账',
error_message VARCHAR(500) NULL COMMENT '最新资金失败原因,成功后清空',
command_history JSON NOT NULL COMMENT '已发资金指令及核验结果哈希,识别重复和错序回执',
created_at DATETIME(3) NOT NULL COMMENT '资金编排创建UTC时间',
updated_at DATETIME(3) NOT NULL COMMENT '资金编排最近变更UTC时间',
PRIMARY KEY (source_fee_id),
KEY idx_ll_fee_funding_customer_state (customer_id, wallet_status),
KEY idx_ll_fee_funding_command (command_event_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='海外人工费用资金冻结、审核扣款及释放编排';
-- 首版拆柜成本只记录分摊依据,客户应收另行人工登记审核;重复执行保持相同定义。
ALTER TABLE ll_destuff_pallet_cost_allocation MODIFY COLUMN fee_source_id BIGINT NULL COMMENT '人工审核后关联的海外费用来源ID';
@@ -17,6 +17,7 @@ CREATE TABLE IF NOT EXISTS ll_return_sku_conversion (
quantity BIGINT NOT NULL COMMENT '实际完成转换件数',
status VARCHAR(32) NOT NULL COMMENT 'APPLIED待客户确认/CONFIRMED已确认/REVERSED退回冲回',
ownership_json LONGTEXT NOT NULL COMMENT '本次转换件数的来源退货单快照,供精确冲回',
storage_rent_shares_json LONGTEXT NULL COMMENT '原仓租批次迁移快照',
completed_at DATETIME(3) NOT NULL COMMENT '实物SKU转换时间',
confirmed_at DATETIME(3) NULL COMMENT '客户确认时间',
reversed_at DATETIME(3) NULL COMMENT '退回冲回时间',
@@ -0,0 +1,98 @@
CREATE TABLE IF NOT EXISTS ll_storage_rent_inbound (
receipt_id bigint NOT NULL COMMENT '实际入库凭证主键,防止重复累计计租数量',
lot_id bigint NOT NULL COMMENT '头程同单同仓计租批次主键',
quantity decimal(24,12) NOT NULL COMMENT '本次实收追加计租箱数',
created_at datetime(3) NOT NULL COMMENT '计租登记时间,采用协调世界时',
PRIMARY KEY (receipt_id),
KEY idx_storage_rent_inbound_lot (lot_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='头程实收计租幂等登记';
CREATE TABLE IF NOT EXISTS ll_storage_rent_lot (
id bigint NOT NULL COMMENT '原批次主键',
source_key varchar(80) NOT NULL COMMENT '实收来源幂等键',
customer_id varchar(32) NOT NULL COMMENT '客户标识',
customer_name varchar(255) DEFAULT NULL COMMENT '客户名称',
warehouse_id varchar(32) NOT NULL COMMENT '海外仓标识',
warehouse_name varchar(255) DEFAULT NULL COMMENT '海外仓名称',
business_type varchar(32) NOT NULL COMMENT '原入库业务类型',
business_id bigint NOT NULL COMMENT '原入库业务主键',
business_no varchar(128) NOT NULL COMMENT '原入库业务单号',
order_id bigint DEFAULT NULL COMMENT '尾程订单主键',
inbound_code varchar(128) DEFAULT NULL COMMENT '入仓码',
balance_id bigint DEFAULT NULL COMMENT '普通库存余额主键',
batch_no varchar(128) DEFAULT NULL COMMENT '原实收批次',
sku_code varchar(128) DEFAULT NULL COMMENT '商品编码',
rule_code varchar(32) NOT NULL COMMENT '仓租规则',
original_quantity decimal(24,12) NOT NULL COMMENT '实收原始数量',
remaining_quantity decimal(24,12) NOT NULL COMMENT '未出库原始数量',
original_units decimal(24,12) DEFAULT NULL COMMENT '原批次计费体积或托数',
inbound_at datetime(3) NOT NULL COMMENT '实际入库时间',
created_at datetime(3) NOT NULL COMMENT '创建时间',
updated_at datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_storage_rent_lot_source (source_key),
KEY idx_storage_rent_stock (balance_id,batch_no),
KEY idx_storage_rent_customer (customer_id,warehouse_id,inbound_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='实收计租原批次';
CREATE TABLE IF NOT EXISTS ll_storage_rent_share (
balance_id bigint DEFAULT NULL COMMENT '普通库存当前余额,退货箱份额为空',
batch_no varchar(128) DEFAULT NULL COMMENT '普通库存当前批次,换标搬移保持原计租批次引用',
id bigint NOT NULL COMMENT '份额主键',
lot_id bigint NOT NULL COMMENT '原计租批次主键',
customer_id varchar(32) NOT NULL COMMENT '客户标识',
warehouse_id varchar(32) NOT NULL COMMENT '海外仓标识',
carton_mark varchar(255) DEFAULT NULL COMMENT '当前箱唛',
sku_code varchar(128) DEFAULT NULL COMMENT '商品编码',
quantity decimal(24,12) NOT NULL COMMENT '剩余商品数量',
PRIMARY KEY (id),
UNIQUE KEY uk_storage_rent_return_share (lot_id,carton_mark,sku_code),
UNIQUE KEY uk_storage_rent_stock_share (lot_id,balance_id,batch_no),
KEY idx_storage_rent_carton (customer_id,warehouse_id,carton_mark),
KEY idx_storage_rent_share_stock (customer_id,warehouse_id,balance_id,batch_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='当前库存与原计租批次份额';
CREATE TABLE IF NOT EXISTS ll_storage_rent_preparation (
id bigint NOT NULL COMMENT '预校验主键',
warehouse_id varchar(32) NOT NULL COMMENT '作业海外仓',
customer_id varchar(32) NOT NULL COMMENT '费用客户',
mode varchar(32) NOT NULL COMMENT '扫码类型',
execution_no varchar(128) NOT NULL COMMENT '实际作业单号',
request_key varchar(255) NOT NULL COMMENT '原扫码幂等键',
request_hash varchar(64) NOT NULL COMMENT '原扫码内容哈希',
attempt int NOT NULL COMMENT '冻结尝试次数',
business_type varchar(32) NOT NULL COMMENT '本次应收业务类型',
business_id bigint NOT NULL COMMENT '本次应收业务主键',
business_no varchar(128) NOT NULL COMMENT '本次应收业务单号',
status varchar(32) NOT NULL COMMENT '资金与扫码状态',
plan_json json NOT NULL COMMENT '原批次计费不可变快照',
original_amount decimal(24,12) NOT NULL COMMENT '原币仓租金额,币种见计费快照',
amount decimal(24,12) NOT NULL COMMENT '人民币结算金额',
exchange_rate decimal(24,12) NULL COMMENT '冻结确认汇率,免费出库为空',
exchange_rate_month varchar(7) NOT NULL COMMENT '汇率月份',
freeze_event_id varchar(128) DEFAULT NULL COMMENT '冻结指令事件',
settle_event_id varchar(128) DEFAULT NULL COMMENT '扣款指令事件',
release_event_id varchar(128) DEFAULT NULL COMMENT '解冻指令事件',
release_status varchar(32) DEFAULT NULL COMMENT '解冻回执状态,失败后由恢复任务重发',
wallet_version bigint NOT NULL COMMENT '同一预占资金命令版本,重试使用新版本保留审计',
hold_id varchar(128) DEFAULT NULL COMMENT '财务冻结主键',
ledger_id varchar(128) DEFAULT NULL COMMENT '财务扣款流水',
error_message varchar(1000) DEFAULT NULL COMMENT '资金处理结果',
source_fee_id bigint DEFAULT NULL COMMENT '财务费用来源主键',
created_at datetime(3) NOT NULL COMMENT '预校验时间',
consumed_at datetime(3) DEFAULT NULL COMMENT '实际扫描出库时间',
updated_at datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_storage_rent_request (warehouse_id,mode,request_key,attempt),
KEY idx_storage_rent_execution (mode,execution_no,status),
KEY idx_storage_rent_business (customer_id,business_no),
KEY idx_storage_rent_recovery (status,updated_at),
KEY idx_storage_rent_release (release_status,updated_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='仓租扫码资金预占与结算快照';
-- SKU 换标原计租份额快照,存量数据库可重复执行。
SET @storage_rent_sku_column = (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_return_sku_conversion' AND column_name='storage_rent_shares_json');
SET @storage_rent_sku_ddl = IF(@storage_rent_sku_column=0, 'ALTER TABLE ll_return_sku_conversion ADD COLUMN storage_rent_shares_json LONGTEXT NULL COMMENT ''原仓租批次迁移快照'' AFTER ownership_json', 'SELECT 1');
PREPARE storage_rent_sku_stmt FROM @storage_rent_sku_ddl;
EXECUTE storage_rent_sku_stmt;
DEALLOCATE PREPARE storage_rent_sku_stmt;
@@ -2404,8 +2404,10 @@ paths:
content: { application/json: { schema: { $ref: '#/components/schemas/CustomerOptionResponse' } } }
/api/platform/v1/last-leg/overseas-procurements/warehouse-options:
get:
summary: 查询有效公共海外收货仓候选
description: 权限 platform:overseas-business:purchase:list;固定国内权威公共 OVERSEAS、ACTIVE、RECEIVING 仓,浏览器不访问内部 API。
summary: 按采购方向查询有效公共起运收货仓候选
description: 权限 platform:overseas-business:purchase:list;海外采购取 OVERSEAS、ACTIVE、RECEIVING 公共仓,国内采购取 DOMESTIC、ACTIVE 公共仓,均以 Warehouse 为准。
parameters:
- { name: procurementDirection, in: query, schema: { $ref: '#/components/schemas/ProcurementDirection' } }
security: [{ bearerAuth: [] }]
responses:
'200':
@@ -3731,6 +3733,7 @@ components:
properties:
feeItemCode: { type: string, minLength: 1, maxLength: 64 }
feeItemName: { type: string, minLength: 1, maxLength: 128 }
feeRemark: { type: string, maxLength: 500, nullable: true, description: 费用说明;同单同方向已有相同项目时须填写补收或重复作业原因 }
direction: { type: string, enum: [RECEIVABLE, PAYABLE] }
currency: { type: string, enum: [CNY, USD] }
amount: { type: number, format: decimal, minimum: 0.01 }
@@ -3738,7 +3741,7 @@ components:
supplierId: { type: string, pattern: '^[1-9][0-9]*$' }
supplierName: { type: string, maxLength: 200 }
supplierCategory: { type: string, maxLength: 32 }
settlementMode: { type: string, enum: [ON_ACCOUNT, DIRECT_PAID] }
settlementMode: { type: string, enum: [BILL, WALLET, ON_ACCOUNT, DIRECT_PAID], nullable: true, description: 应收可选推送结算或余额扣费;应付使用账期或已付 }
chargeableQuantity: { type: number, minimum: 0, exclusiveMinimum: true }
quantityUnit: { type: string, maxLength: 32 }
unitPrice: { type: number, minimum: 0, exclusiveMinimum: true }
@@ -3755,6 +3758,7 @@ components:
orderId: { type: string, pattern: '^[1-9][0-9]*$' }
feeItemCode: { type: string }
feeItemName: { type: string }
feeRemark: { type: string, maxLength: 500, nullable: true, description: 业务费用说明,与审核原因分开保存 }
direction: { type: string, enum: [RECEIVABLE, PAYABLE] }
currency: { type: string, enum: [CNY] }
amount: { type: number, format: decimal }
@@ -4227,7 +4231,7 @@ components:
supplierId: { type: string, pattern: '^[1-9][0-9]*$' }
supplierName: { type: string, maxLength: 200 }
supplierCategory: { type: string, maxLength: 32 }
settlementMode: { type: string, enum: [ON_ACCOUNT, DIRECT_PAID] }
settlementMode: { type: string, enum: [BILL, WALLET, ON_ACCOUNT, DIRECT_PAID], nullable: true, description: 应收可选推送结算或余额扣费;应付使用账期或已付 }
chargeableQuantity: { type: number, minimum: 0, exclusiveMinimum: true }
quantityUnit: { type: string, maxLength: 32 }
unitPrice: { type: number, minimum: 0, exclusiveMinimum: true }
@@ -4533,7 +4537,7 @@ components:
labelDeadline: { type: string, format: date-time }
contactName: { type: string, maxLength: 128 }
contactPhone: { type: string, maxLength: 64 }
chargeAmount: { type: number, nullable: true, minimum: 0.01, description: 本次贴标费用(CNY);未传时不冻结或结算资金 }
chargeAmount: { type: number, nullable: true, minimum: 0.01, description: 换标报价快照(CNY);不自动冻结或收费,应收由海外费用登记审核 }
remark: { type: string, nullable: true, maxLength: 1000 }
idempotencyKey: { type: string, maxLength: 255 }
deliveryMethod: { type: string, nullable: true, enum: [TRUCK, EXPRESS, AMAZON_PICKUP, CUSTOMER_PICKUP, PICKUP], description: 只换箱唛或SKU与箱唛同时换时必填;只换SKU时不传;仅TRUCK进入平台预排车,其余方式直接创建出库任务 }
@@ -4700,10 +4704,16 @@ components:
- type: object
required: [records]
properties: { records: { type: array, items: { $ref: '#/components/schemas/ProcurementSummary' } } }
ProcurementDirection:
type: string
enum: [OVERSEAS_TO_DOMESTIC, DOMESTIC_TO_OVERSEAS]
default: OVERSEAS_TO_DOMESTIC
description: 海外采购回国内或国内采购发海外;创建可选,待审核时可核定,通过后锁定。历史运输段编码保持不变,区域文案按方向展示。
ProcurementSummary:
type: object
required: [id, orderNo, customerId, purchaseCategory, productName, purchaseQuantity, status, version, createdAt, updatedAt]
properties:
procurementDirection: { $ref: '#/components/schemas/ProcurementDirection' }
id: { type: string, pattern: '^[0-9]+$' }
orderNo: { type: string }
customerId: { type: string }
@@ -5067,12 +5077,13 @@ components:
actualVolumeCbm: { type: number, nullable: true }
status: { type: string }
version: { type: integer }
ProcurementStatus: { type: string, enum: [PENDING_REVIEW, WAIT_PURCHASE, WAIT_OVERSEAS_RECEIPT, OVERSEAS_RECEIVING, WAIT_PACKING, WAIT_LABELS, WAIT_OVERSEAS_DISPATCH, INTERNATIONAL_TRANSIT, DOMESTIC_RECEIVING, WAIT_CHARGES, WAIT_CUSTOMER_DISPATCH, SHIPPED_TO_CUSTOMER, REJECTED, CANCELLED, EXCEPTION_CLOSED] }
ProcurementStatus: { type: string, enum: [PENDING_REVIEW, WAIT_PURCHASE, WAIT_OVERSEAS_RECEIPT, OVERSEAS_RECEIVING, WAIT_PACKING, WAIT_LABELS, WAIT_OVERSEAS_DISPATCH, WAIT_OVERSEAS_SHIPMENT, INTERNATIONAL_TRANSIT, DOMESTIC_RECEIVING, WAIT_CHARGES, WAIT_CUSTOMER_DISPATCH, WAIT_CUSTOMER_SHIPMENT, SHIPPED_TO_CUSTOMER, REJECTED, CANCELLED, EXCEPTION_CLOSED] }
ProcurementReview:
type: object
required: [version, decision, idempotencyKey]
description: 审核通过必须选择有效公共海外收货仓;拒绝不要求仓库。
description: 审核通过必须选择与采购方向匹配的有效公共收货仓;国内采购选择国内仓,海外采购选择海外收货仓;拒绝不要求仓库,但 remark 必须填写非空白拒绝原因。审核不得修改客户下单采购方向。
properties:
procurementDirection: { $ref: '#/components/schemas/ProcurementDirection' }
version: { type: integer, format: int64, minimum: 0 }
decision: { type: string, enum: [APPROVE, REJECT] }
idempotencyKey: { type: string, minLength: 1, maxLength: 255 }
@@ -5082,6 +5093,7 @@ components:
type: object
required: [productName, purchaseQuantity, budgetUnitPrice, currency, receivingAddress, contactName, contactPhone, idempotencyKey]
properties:
procurementDirection: { $ref: '#/components/schemas/ProcurementDirection' }
customerName: { type: string, nullable: true, maxLength: 255 }
purchaseCategory: { type: string, maxLength: 128 }
productName: { type: string, maxLength: 255 }
@@ -5090,7 +5102,7 @@ components:
purchaseQuantity: { type: integer, format: int64, minimum: 1 }
budgetUnitPrice: { type: number, minimum: 0, multipleOf: 0.01, description: 客户授权的货款预算单价;零表示仅授权免费样品 }
currency: { type: string, enum: [CNY, USD] }
receivingAddress: { type: string, minLength: 1, maxLength: 1000, description: 最终客户国内收件完整地址 }
receivingAddress: { type: string, minLength: 1, maxLength: 1000, description: 最终客户目的地完整地址;国内采购发海外时填写海外地址 }
contactName: { type: string, maxLength: 128 }
contactPhone: { type: string, maxLength: 64 }
remark: { type: string, nullable: true, maxLength: 1000 }
@@ -7709,6 +7721,7 @@ components:
nullable: true
DispatchFeeItem:
type: object
description: 派送应付费用。客户应收费用统一到海外费用登记并审核,派送完成不自动生成应收。
x-java-record: DispatchDeliveryModels.FeeItem
properties:
feeType:
@@ -7719,6 +7732,7 @@ components:
nullable: true
direction:
type: string
enum: [PAYABLE]
nullable: true
currency:
type: string
@@ -0,0 +1,21 @@
openapi: 3.0.3
info: { title: 海外录费公共费用项目, version: 1.0.0 }
security: [{ bearerAuth: [] }]
paths:
/api/platform/v1/last-leg/finance-fee-sources/fee-items:
get:
summary: 按收付方向选择当前启用的海外费用项目
description: '仅平台主体;需要platform:overseas-fee:list或platform:finance:customer-arap:list。复用Firstleg目录,不建立独立目录。录费时重新校验当前编码和名称。'
parameters:
- name: direction
in: query
required: false
schema: { type: string, enum: [RECEIVABLE, PAYABLE], default: RECEIVABLE }
responses:
'400': { description: 收付方向无效 }
'200': { description: '统一响应data为数组;每项code、name、defaultPrice。默认价仅CNY,USD录费不得直接套用。' }
'403': { description: 身份或查询权限不满足 }
'409': { description: 费用目录未就绪或响应无效 }
components:
securitySchemes:
bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
@@ -1,6 +1,13 @@
openapi: 3.0.3
info: { title: Overseas Business Fee Source API, version: 1.0.0 }
info: { title: Overseas Business Fee Source API, version: 1.1.0, description: '首版除仓租外均人工登记审核;换标报价、外接运费及拆柜成本不自动收费;旧资金链同项目已锁款或收取时拒绝重复登记。' }
paths:
/api/platform/v1/last-leg/finance-fee-sources/{sourceFeeId}/retries:
get:
summary: 查询该费用每次人工重试的时间、操作人和实际结果
description: 与费用详情使用相同列表权限。按客户及稳定费用身份隔离,包含各版本的推送重试和资金重试。SUCCESS依据投递接收或实际资金成功回执;FAILED保留失败原因;SUBMITTED只代表请求已提交。多次重试分别保留,后一次成功不覆盖前一次失败。
security: [{ bearerAuth: [] }]
parameters: [{ in: path, name: sourceFeeId, required: true, schema: { type: string } }]
responses: { '200': { description: 'data为RetryRecord数组,按重试时间倒序' } }
/api/platform/v1/last-leg/finance-fee-sources:
get:
summary: 查询海外业务费用来源当前版本
@@ -12,12 +19,56 @@ paths:
- { in: query, name: containerBookingId, description: 精确查询真实来源柜下全部客户的费用;可再传customerId收窄到单个客户, schema: { type: string, pattern: '^[1-9][0-9]*$' } }
responses: { '200': { description: '当前版本列表;voidStatus为NOT_REQUESTED、PENDING_FINANCE、FINANCE_ATTENTION或CONFIRMED,批量查询作废确认状态,不逐行读取。等待或拒绝时sourceStatus保留ACTIVE,只有Finance持久化确认后为VOIDED。' } }
post:
summary: 创建海外业务费用来源草稿
description: 采购费用仅由采购履约或财务节点实扣后自动发布,本入口拒绝采购来源或采购业务类型。客户和业务编号必填;入仓ID、入仓码均按业务事实选填,不得为补字段伪造。海外货柜费用必须以相同的businessId和containerBookingId引用真实来源柜,且businessNo与containerNo均为该柜真实集装箱号。
summary: 创建人工费用并锁定资金
description: 需platform:finance:fee-source:edit。创建即PENDING。应收仅当前LASTLEG_ORDER且orderType=FIRST_LEG采用BILL,其余业务(含ONE_CLICK_DROPSHIP、退货、转运、柜级费用)为WALLET,发送异步FREEZE,本土卡车、本土散板应收同采购一样使用客户余额及授信扣款;余额及授信不足显示FREEZE_FAILED,不可审核通过。原USD按业务月有效汇率固化为CNY后冻结;原币与汇率快照保留。采购来源仍只允许采购业务节点处理。业务ID、客户、单号与补充订单/入仓关联由服务端核对;真实柜要求businessId=containerBookingId且businessNo=containerNo。调用重放不重复冻结。
security: [{ bearerAuth: [] }]
parameters: [{ in: header, name: Idempotency-Key, required: true, schema: { type: string, maxLength: 128 } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/SaveRequest' } } } }
responses: { '200': { description: 草稿费用来源 }, '400': { description: 业务归属或付款事实无效 } }
responses: { '200': { description: 待审核费用,含collectionMode、walletStatus、allowedActions }, '400': { description: 业务归属或付款事实无效 } }
/api/platform/v1/last-leg/finance-fee-sources/page:
get:
summary: 分页查询海外费用
description: 需platform:overseas-fee:list或platform:finance:customer-arap:list。只返回各稳定来源最新版本,按创建时间及ID倒序;应收是默认方向。资金状态批量加载。
security: [{ bearerAuth: [] }]
parameters:
- { in: query, name: page, schema: { type: integer, minimum: 1, default: 1 } }
- { in: query, name: size, schema: { type: integer, minimum: 1, maximum: 200, default: 20 } }
- { in: query, name: customerId, schema: { type: string } }
- { in: query, name: businessType, schema: { $ref: '#/components/schemas/BusinessType' } }
- { in: query, name: businessNo, schema: { type: string } }
- { in: query, name: feeItemCode, schema: { type: string } }
- { in: query, name: storageRentOnly, description: 只查询已实际出库生成的仓租费用,分页总数使用相同口径, schema: { type: boolean, default: false } }
- { in: query, name: reviewStatus, schema: { type: string, enum: [DRAFT, PENDING, APPROVED, REJECTED] } }
- { in: query, name: walletStatus, schema: { type: string } }
- { in: query, name: processingStatus, description: 业务费用状态,按当前版本事件及资金状态统一筛选并统计分页, schema: { type: string, enum: [WAITING, PROCESSING, COMPLETED, FAILED, CLOSED] } }
- { in: query, name: direction, schema: { type: string, enum: [RECEIVABLE, PAYABLE], default: RECEIVABLE } }
responses:
'200':
description: data为PageResult,包含records、page、size、total、pages
/api/platform/v1/last-leg/finance-fee-sources/{sourceFeeId}:
get:
summary: 费用详情及服务端可执行动作
security: [{ bearerAuth: [] }]
parameters: [{ in: path, name: sourceFeeId, required: true, schema: { type: string } }]
responses: { '200': { description: 当前费用及资金、审核、作废确认状态 }, '404': { description: 费用不存在 } }
/api/platform/v1/last-leg/finance-fee-sources/customer-options:
get:
summary: 查询已有海外业务或费用的客户候选
security: [{ bearerAuth: [] }]
responses: { '200': { description: data为ContainerCustomerOption数组 } }
/api/platform/v1/last-leg/finance-fee-sources/business-options:
get:
summary: 查询真实服务业务单候选
description: 只查Lastleg自有实体,每次最多50条;LASTLEG_ORDER保留真实orderType,区分FIRST_LEG与ONE_CLICK_DROPSHIP等业务。
security: [{ bearerAuth: [] }]
parameters:
- { in: query, name: businessType, required: true, schema: { type: string, enum: [LASTLEG_ORDER, RELABEL_ORDER, WAREHOUSE_TRANSFER, RETURN_ORDER, US_TRUCK, LOCAL_LOOSEBOARD, DISCARD_ORDER, OVERSEAS_INBOUND, DELIVERY_ORDER] } }
- { in: query, name: customerId, schema: { type: string } }
- { in: query, name: keyword, schema: { type: string } }
responses:
'200':
description: 真实订单候选
content: { application/json: { schema: { type: object, properties: { data: { type: array, items: { $ref: '#/components/schemas/BusinessOption' } } } } } }
/api/platform/v1/last-leg/finance-fee-sources/container-customers:
get:
summary: 查询真实来源柜内客户选项
@@ -33,16 +84,132 @@ paths:
schema: { $ref: '#/components/schemas/ContainerCustomerListResponse' }
/api/platform/v1/last-leg/finance-fee-sources/{sourceFeeId}/{action}:
post:
summary: 提交、审核、调整或作废海外业务费用来源
description: 采购来源不接受通用提交、审核、调整或作废,须回到采购财务节点处理。审核通过与作废均事务性写入Outbox;此处作废仅指申请,直接可靠投递至独立Finance;action为submit、review、adjust、void。作废申请不立即更改sourceStatus,voidStatus为PENDING_FINANCE;等待原发布成功后才投递作废,收到匹配APPLIED/DUPLICATE确认时在投递审计事务内更新VOIDED。失败/结果未知仍保留原来源,拒绝或投递耗尽显示FINANCE_ATTENTION,禁止未决作废期间调整版本。
summary: 提交、审核、调整、作废或处理资金
x-headleg-delivery-review: 首版头程派送费由审核员核对原报价是否已包含;当前未实现自动识别。已含费用不应再建单或通过审核,另收费用人工添加后审核进入头程账单。
description: 编辑动作需platform:finance:fee-source:edit,review与void需platform:finance:fee-source:review。WALLET通过审核只发送SETTLE,实际匹配成功回执含冻结与账本引用后才PUBLISHED,此时仅本地费用完成、不推送财务账单;失败为SETTLE_FAILED,保持未收。驳回释放冻结,冻结在途时回执成功后自动释放。驳回后的费用只读,不能继续操作;如需重新收费应在业务单据中新增费用。头程BILL审核通过推送结算;已发布BILL作废等待Finance持久化确认才VOIDED。历史无资金记录的海外费用必须重新提交完成冻结,不允许审核绕过。采购来源仍由采购节点处理。
security: [{ bearerAuth: [] }]
parameters:
- { in: path, name: sourceFeeId, required: true, schema: { type: string } }
- { in: path, name: action, required: true, schema: { type: string, enum: [submit, review, adjust, void] } }
- { in: path, name: action, required: true, schema: { type: string, enum: [submit, review, adjust, void, retry-funding, retry-delivery] } }
requestBody:
required: true
content:
application/json:
schema:
description: 请求格式随路径action选择;submit、cancel、retry-funding用ActionRequest,其他动作使用同名请求。
anyOf:
- { $ref: '#/components/schemas/ActionRequest' }
- { $ref: '#/components/schemas/ReviewRequest' }
- { $ref: '#/components/schemas/AdjustRequest' }
- { $ref: '#/components/schemas/VoidRequest' }
- { $ref: '#/components/schemas/RetryDeliveryRequest' }
examples:
review: { value: { decision: APPROVE, idempotencyKey: review-unique-key } }
funding: { value: { idempotencyKey: retry-unique-key } }
responses: { '200': { description: 当前费用来源版本 }, '409': { description: 状态、版本或幂等冲突 } }
components:
schemas:
BusinessType: { type: string, enum: [OVERSEAS_INBOUND, OVERSEAS_PROCUREMENT, PROCUREMENT_FEE, US_TRUCK, LOCAL_LOOSEBOARD, WAREHOUSE_SERVICE, OVERSEAS_CONTAINER, LASTLEG_ORDER, DELIVERY_ORDER, RELABEL_ORDER] }
RetryRecord:
type: object
properties:
requestId: { type: string }
requestedAt: { type: string, format: date-time, description: 系统 UTC 时间,明确携带 Z 时区 }
operatorName: { type: string, description: 认证操作人名称及ID,非客户端提交 }
action: { type: string }
result: { type: string, enum: [SUBMITTED, SUCCESS, FAILED] }
errorMessage: { type: string, nullable: true }
RetryDeliveryRequest:
type: object
description: 需platform:finance:fee-source:edit。可重试当前费用对应的DEAD事件或已有失败原因的PENDING事件,校验费用版本、原事件ID及载荷摘要;沿用原事件及资金幂等身份,不创建费用或资金指令。同一请求UUID重复提交仅返回原操作,跨费用或事件复用拒绝。无失败原因的PENDING、PROCESSING和PUBLISHED不可新发起人工重试;每次重试失败后可再次提交新的请求UUID继续重推。写入既有event_delivery_retry_audit审计。
required: [expectedVersion, eventId, idempotencyKey]
properties:
expectedVersion: { type: integer, minimum: 1 }
eventId: { type: string, maxLength: 64 }
idempotencyKey: { type: string, format: uuid }
ActionRequest:
type: object
description: submit、cancel、retry-funding共用;标识需按费用及单次操作生成,重试原操作沿用。
required: [idempotencyKey]
properties:
idempotencyKey: { type: string, minLength: 1, maxLength: 128 }
ReviewRequest:
type: object
required: [decision, idempotencyKey]
properties:
decision: { type: string, enum: [APPROVE, REJECT] }
expectedVersion: { type: integer, minimum: 1, description: 仓租审核必填,必须为审核人看到的当前费用版本;调价后旧版审核被拒绝。 }
reason: { type: string, maxLength: 500, nullable: true }
idempotencyKey: { type: string, minLength: 1, maxLength: 128 }
AdjustRequest:
type: object
required: [expectedVersion, fee, idempotencyKey]
properties:
expectedVersion: { type: integer, minimum: 1 }
fee: { $ref: '#/components/schemas/SaveRequest' }
idempotencyKey: { type: string, minLength: 1, maxLength: 128 }
VoidRequest:
type: object
required: [expectedVersion, reason, idempotencyKey]
properties:
expectedVersion: { type: integer, minimum: 1 }
reason: { type: string, minLength: 1, maxLength: 500 }
idempotencyKey: { type: string, minLength: 1, maxLength: 128 }
BusinessType: { type: string, enum: [OVERSEAS_INBOUND, OVERSEAS_PROCUREMENT, PROCUREMENT_FEE, US_TRUCK, LOCAL_LOOSEBOARD, WAREHOUSE_SERVICE, OVERSEAS_CONTAINER, LASTLEG_ORDER, DELIVERY_ORDER, RELABEL_ORDER, WAREHOUSE_TRANSFER, RETURN_ORDER, DISCARD_ORDER] }
BusinessOption:
type: object
properties:
businessId: { type: string }
businessType: { $ref: '#/components/schemas/BusinessType' }
businessNo: { type: string }
customerId: { type: string }
customerName: { type: string, nullable: true, description: 查询显示按客户ID读取IAM当前名称;主档不可用时回退历史名称,查询不回写费用或结算快照。 }
warehouseId: { type: string, nullable: true }
orderId: { type: string, nullable: true }
orderType: { type: string, nullable: true }
FundingDescription:
type: object
description: 海外费用来源返回值的资金补充字段。amount及currency始终为CNY结算快照;originalAmount、originalCurrency、exchangeRate、exchangeRateMonth保留原币依据。
properties:
displayBusinessType:
allOf: [{ $ref: '#/components/schemas/BusinessType' }]
readOnly: true
description: 按真实业务事实解析的展示分类;分页业务类型筛选使用此分类。换标履约费用显示RELABEL_ORDER,原businessType/businessId保留收费凭据的关联身份。新登记换标履约费用以真实换标申请作为主业务关联。
storageRent:
type: object
nullable: true
readOnly: true
description: 自动仓租的原始计费与实际出入库明细;审核前可通过仓租adjust入口留说明调价。chargedAmount仅成功实扣或确认零元后返回。
properties:
outboundNo: {type: string}
outboundAt: {type: string, format: date-time}
calculatedAmount: {type: number, description: 原快照计算金额,币种为originalCurrency}
chargedAmount: {type: number, nullable: true, description: 实际扣费CNY,未成功时为null}
lines:
type: array
items:
type: object
properties:
lotId: {type: string}
sourceBusinessType: {type: string, nullable: true, description: 原计租入库来源类型,头程为LASTLEG_ORDER,退货为RETURN_ORDER}
sourceBusinessNo: {type: string, nullable: true, description: 原计租来源单号,头程展示对应尾程订单号,退货展示退货单号;不以换标出库单替代}
batchNo: {type: string, nullable: true, description: 原计租入库批次}
inboundAt: {type: string, format: date-time}
quantity: {type: number}
days: {type: integer}
calculatedAmount: {type: number, description: 本原批次原币计费依据}
collectionMode: { type: string, enum: [BILL, WALLET] }
walletStatus: { type: string, enum: [NOT_REQUIRED, FREEZE_PENDING, FROZEN, FREEZE_FAILED, SETTLE_PENDING, SETTLED, SETTLE_FAILED, RELEASE_PENDING, RELEASED, RELEASE_FAILED] }
walletErrorMessage: { type: string, nullable: true }
deliveryStatus: { type: string, nullable: true, enum: [PENDING, PROCESSING, PUBLISHED, DEAD], description: 当前版本原事件的实际投递状态;账单费用publicationStatus=PUBLISHED仅表示已入队,不代表Finance已接收;余额应收实扣成功即完成且deliveryStatus为空。 }
deliveryKind: { type: string, nullable: true, enum: [FEE, FUNDING] }
deliveryEventId: { type: string, nullable: true, description: 当前原事件ID,重试时必须原样提交 }
deliveryErrorMessage: { type: string, nullable: true }
allowedActions: { type: array, items: { type: string, enum: [SUBMIT, APPROVE, REJECT, ADJUST, ADJUST_RENT, VOID, RETRY_FREEZE, RETRY_SETTLE, RETRY_RELEASE, RETRY_PUBLISH, RETRY_FUNDING_DELIVERY] } }
reviewerId: { type: string, nullable: true, description: 审核人ID }
reviewerName: { type: string, nullable: true, description: 审核人名称快照 }
reviewedAt: { type: string, format: date-time, nullable: true, description: 审核时间,UTC 且携带 Z 时区 }
createdAt: { type: string, format: date-time, nullable: true, description: 创建时间,UTC 且携带 Z 时区 }
updatedAt: { type: string, format: date-time, nullable: true, description: 更新时间,UTC 且携带 Z 时区 }
OverseasContainerFeeItem:
type: string
description: 海外阶段柜级费用项目:港口费、堆存费、修箱费、吊机费、码头拖车费、其他。
@@ -67,12 +234,12 @@ components:
timestamp: { type: string, format: date-time }
SaveRequest:
type: object
required: [customerId, sourceType, businessType, businessNo, feeItemCode, feeItemName, direction, businessDate, currency, amount]
required: [customerId, sourceType, businessType, businessId, businessNo, feeItemCode, feeItemName, direction, businessDate, currency, amount]
properties:
customerId: { type: string }
sourceType: { type: string, enum: [OVERSEAS_INBOUND_FEE, OVERSEAS_TRUCK_FEE, OVERSEAS_LOOSEBOARD_FEE, OVERSEAS_WAREHOUSE_FEE, OVERSEAS_CONTAINER_FEE, OVERSEAS_ORDER_FEE, OVERSEAS_DELIVERY_FEE, OVERSEAS_RELABEL_FEE] }
businessType: { type: string, enum: [OVERSEAS_INBOUND, US_TRUCK, LOCAL_LOOSEBOARD, WAREHOUSE_SERVICE, OVERSEAS_CONTAINER, LASTLEG_ORDER, DELIVERY_ORDER, RELABEL_ORDER] }
businessId: { type: string, pattern: '^[1-9][0-9]*$', nullable: true }
businessType: { type: string, enum: [OVERSEAS_INBOUND, US_TRUCK, LOCAL_LOOSEBOARD, OVERSEAS_CONTAINER, LASTLEG_ORDER, DELIVERY_ORDER, RELABEL_ORDER, WAREHOUSE_TRANSFER, RETURN_ORDER, DISCARD_ORDER] }
businessId: { type: string, pattern: '^[1-9][0-9]*$' }
businessNo: { type: string, maxLength: 128 }
containerBookingId: { type: string, pattern: '^[1-9][0-9]*$', nullable: true }
containerNo: { type: string, maxLength: 64, nullable: true }
@@ -81,8 +248,9 @@ components:
inboundCode: { type: string, maxLength: 64, nullable: true }
feeItemCode:
type: string
description: OVERSEAS_CONTAINER时必须取OverseasContainerFeeItem枚举;其他业务类型沿用各自费用项目编码。
description: 必须选择共享费用目录的有效编码,人工录费禁止自动仓租项目FEE_TYPE_077。OVERSEAS_CONTAINER时同时符合OverseasContainerFeeItem枚举。
feeItemName: { type: string }
feeRemark: { type: string, maxLength: 500, nullable: true, description: 费用说明;同单同方向已有相同项目时必填,允许实际作业分次收费。已驳回原费用终结,只能重新新增。 }
direction: { type: string, enum: [RECEIVABLE, PAYABLE] }
businessDate: { type: string, format: date }
currency: { type: string, enum: [CNY, USD], description: 业务原币;USD由服务端按业务月份有效汇率折算为CNY入池 }
@@ -2,7 +2,7 @@ openapi: 3.0.3
info:
title: 采购样品履约节点 API
version: 1.0.0
description: 客户范围、节点资格、版本与幂等由服务端校验;购买事实与资金结果分开保存。
description: 客户范围、节点资格、版本与幂等由服务端校验;购买事实与资金结果分开保存。采购双方向复用两段技术编码:OVERSEAS 为起运段,DOMESTIC 为目的地段;按 procurementDirection 解释实际区域。
security:
- bearerAuth: []
paths:
@@ -2310,7 +2310,6 @@ components:
maxLength: 500
ChargeSelection:
type: object
required: []
properties:
feeId:
type: string
@@ -2977,6 +2976,8 @@ components:
- status
- version
properties:
procurementDirection:
$ref: 'overseas-business-v1.yaml#/components/schemas/ProcurementDirection'
orderNo:
type: string
nullable: true
@@ -0,0 +1,227 @@
openapi: 3.0.3
info:
title: 海外仓租与出库资金预校验
version: 1.0.0
description: |
仅仓租自动计费。中转按CBM/天、退货按原托份额/天累进,首次或重建预校验读取客户当前仓租配置。
未配置客户使用仓库服务明确返回的两张默认报价表;网络、无效配置或不支持币种均阻断出库,不降级免费。
PlanJson保存配置ID、版本、币种和完整阶梯。有效预占重放与consume使用原快照及冻结金额,不受期间改价影响。
后续部分出库采用客户最新配置,原入库时间与原托份额保持不变。原币支持USD/CNY,结算币为CNY。
实际PDA入库开始计租,实际出库按本次数量生成待审核费用,审核通过后按确认金额扣款;所有海外仓租从余额及有效授信扣除。
头程同单同仓多次入库合并计租,统一沿用首次实际入库时间;其他业务按各批实际入库时间分别计龄。
每满24小时一天,不足24小时向上取整。公开时间均为ISO8601 UTC时间,携带Z,客户端按本地时区显示。
普通业务错误沿用HTTP 200及非200业务code。平台接口要求平台tenant_id=0。
security:
- bearerAuth: []
paths:
/api/platform/v1/last-leg/storage-rent:
get:
summary: 原计租批次分页
description: 权限platform:overseas-fee:list。一个原始实收批次一行。
parameters:
- {in: query, name: customerId, schema: {type: string}}
- {in: query, name: businessNo, schema: {type: string}}
- {in: query, name: warehouseId, schema: {type: string}}
- {in: query, name: businessType, schema: {type: string, enum: [LASTLEG_ORDER, WAREHOUSE_TRANSFER, RETURN_ORDER]}}
- {in: query, name: status, schema: {type: string, enum: [IN_STOCK, CLEARED]}}
- {in: query, name: page, schema: {type: integer, minimum: 1, default: 1}}
- {in: query, name: size, schema: {type: integer, minimum: 1, maximum: 200, default: 20}}
responses:
'200':
description: 统一响应data包含records、page、size、total、pages
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/Envelope'}
- properties:
data:
type: object
properties:
records: {type: array, items: {$ref: '#/components/schemas/Lot'}}
page: {type: integer}
size: {type: integer}
total: {type: integer}
pages: {type: integer}
/api/platform/v1/last-leg/storage-rent/warehouse-options:
get:
summary: 计租仓库选项
description: 权限platform:overseas-fee:list,只读取已有仓库快照。
responses:
'200':
description: data为id、warehouseName对象数组
/api/platform/v1/last-leg/storage-rent/{id}:
get:
summary: 原批次及逐次出库仓租
description: 权限platform:overseas-fee:list;只返回已实际出库的收费记录,免费出库保留零金额。
parameters:
- {$ref: '#/components/parameters/id'}
responses:
'200':
description: 统一响应
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/Envelope'}
- properties:
data:
type: object
properties:
lot: {$ref: '#/components/schemas/Lot'}
charges: {type: array, items: {$ref: '#/components/schemas/Charge'}}
/api/platform/v1/last-leg/storage-rent/fees/{sourceFeeId}/adjust:
post:
summary: 审核前调整仓租金额并保存说明
description: 权限platform:finance:fee-source:edit。仅当前待审核且资金已锁定版本可改;金额按原币填写,保留冻结汇率与原计算快照。生成新费用版本。原零元改为非零须先补冻结;原非零费用调高在审核结算时由Finance原子检查差额,余额不足保留原冻结,不登记实扣。
parameters:
- {in: path, name: sourceFeeId, required: true, schema: {type: string}}
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedVersion, amount, reason, idempotencyKey]
properties:
expectedVersion: {type: integer, minimum: 1}
amount: {type: number, minimum: 0, maximum: 999999999999.99, multipleOf: 0.01}
reason: {type: string, minLength: 1, maxLength: 500}
idempotencyKey: {type: string, minLength: 1, maxLength: 128}
responses:
'200': {description: 统一响应,data为调整后的费用版本;状态冲突或缺少说明返回非200业务code}
/api/pda/v1/last-leg/storage-rent/preparations:
post:
summary: 出库前计算仓租并提交余额授信冻结
description: |
权限lastleg:pda:operate及ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR。客户与仓库从绑定身份及真实业务来源解析。
ready=false必须等待资金回执;仅ready=true可提交原扫码。先冻结后扣库存,实际扫码后生成待审核仓租,审核通过后实际扣款。
同一原扫码复用idempotencyKey与全部明细;更改货物或数量必须新键。冻结15分钟有效,变更计费天数或汇率月份需重算。
已实际出库的原键返回CONSUMED,调用原扫码接口恢复其幂等结果。零费用无需汇率及资金指令。
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/PrepareRequest'}
responses:
'200':
description: 统一响应data为预校验状态
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/Envelope'}
- properties:
data: {$ref: '#/components/schemas/Preparation'}
/api/pda/v1/last-leg/storage-rent/preparations/{id}:
parameters:
- {$ref: '#/components/parameters/id'}
get:
summary: 查询原冻结真实回执
description: PDA权限及绑定仓校验同创建。
responses:
'200': {description: 统一响应data为Preparation}
delete:
summary: 取消未使用预占并解冻
description: 已出库不能取消;冻结处理中取消将于迟到成功回执后补解冻。PDA权限及绑定仓校验同创建。
responses:
'200': {description: 统一响应data为Preparation}
components:
securitySchemes:
bearerAuth: {type: http, scheme: bearer, bearerFormat: JWT}
parameters:
id: {in: path, name: id, required: true, schema: {type: string}}
schemas:
Envelope:
type: object
properties:
code: {type: string, example: '200'}
message: {type: string}
data: {type: object}
Lot:
type: object
properties:
id: {type: string}
customerId: {type: string}
customerName: {type: string}
businessType: {type: string}
businessNo: {type: string, description: 原计租来源单号,头程为对应尾程订单号,退货为退货单号}
warehouseId: {type: string}
warehouseName: {type: string}
batchNo: {type: string}
inboundAt: {type: string, format: date-time, description: 实际入库UTC时间,带Z}
storageDays: {type: integer, description: 已清仓按最后实际出库停止}
originalQuantity: {type: number}
remainingQuantity: {type: number}
quantityUnit: {type: string, enum: [PACKAGE, PIECE]}
billingQuantity: {type: number}
billingUnit: {type: string, enum: [CBM, PALLET]}
ruleCode: {type: string, enum: [TRANSIT_V1, RETURN_V1]}
status: {type: string, enum: [IN_STOCK, CLEARED]}
settledAmount: {type: number, description: 本原批次已成功扣款的CNY合计,不含处理中及失败记录}
chargeCount: {type: integer, description: 本原批次实际出库仓租记录数,包含免租记录}
settledChargeCount: {type: integer, description: 已完成结算的仓租记录数,包含免租记录}
generatedAmount: {type: number, nullable: true, description: 单币种合计;无记录为0,多币种为null}
generatedCurrency: {type: string, nullable: true, enum: [USD, CNY], description: 无记录或多币种为null}
generatedAmounts:
type: array
description: 按原币分别汇总,禁止跨币相加;无记录为空数组
items:
type: object
properties:
currency: {type: string, enum: [USD, CNY]}
amount: {type: number}
Charge:
type: object
properties:
id: {type: string}
outboundNo: {type: string}
businessNo: {type: string}
quantity: {type: number}
storageDays: {type: integer}
originalAmount: {type: number}
currency: {type: string, enum: [USD, CNY]}
settlementAmount: {type: number, description: CNY结算金额}
currencyRate: {type: number, nullable: true}
status: {type: string, enum: [PENDING_REVIEW, REVIEW_FREEZE_PENDING, REVIEW_FREEZE_FAILED, REJECTED, CONSUMED, SETTLE_FAILED, SETTLED]}
createdAt: {type: string, format: date-time}
outboundAt: {type: string, format: date-time}
PrepareRequest:
type: object
required: [mode, businessNo, idempotencyKey]
properties:
mode: {type: string, enum: [DISPATCH, OUTBOUND, OUTBOUND_PALLET, DISCARD]}
businessNo: {type: string, maxLength: 128}
itemId: {type: string}
positionId: {type: string}
packages: {type: integer, minimum: 1}
cartonMark: {type: string}
palletNo: {type: string}
idempotencyKey: {type: string, maxLength: 255}
cartonMarks: {type: array, items: {type: string}}
skuCode: {type: string}
productQuantity: {type: integer, minimum: 0}
lines:
type: array
items:
type: object
required: [itemId, actualPackages]
properties:
itemId: {type: string}
actualPackages: {type: integer, minimum: 0}
photoFileIds: {type: array, items: {type: string}}
scannedCartonMarks: {type: array, items: {type: string}}
confirmAllCartons: {type: boolean}
Preparation:
type: object
properties:
preparationId: {type: string, nullable: true}
status: {type: string, enum: [NOT_REQUIRED, FREEZE_PENDING, READY, FAILED, EXPIRED, CANCELLED, CONSUMED]}
ready: {type: boolean}
amount: {type: number}
currency: {type: string, enum: [CNY]}
originalAmount: {type: number, nullable: true, description: 整托包含多种原币时为null,CNY amount始终可合计}
originalCurrency: {type: string, nullable: true, enum: [USD, CNY]}
exchangeRate: {type: number, nullable: true}
exchangeRateMonth: {type: string, nullable: true}
message: {type: string, nullable: true}