feat(lastleg): add overseas container fee sources

This commit is contained in:
2026-09-08 21:45:57 +08:00
parent 1cf6722d6e
commit e3a5ea7341
9 changed files with 325 additions and 11 deletions
@@ -799,6 +799,7 @@ CREATE TABLE IF NOT EXISTS ll_finance_fee_source (
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_direction CHECK(direction IN('RECEIVABLE','PAYABLE')),
CONSTRAINT chk_ll_finance_fee_review CHECK(review_status IN('DRAFT','PENDING','APPROVED','REJECTED')),
@@ -806,6 +807,9 @@ CREATE TABLE IF NOT EXISTS ll_finance_fee_source (
CONSTRAINT chk_ll_finance_fee_status CHECK(source_status IN('ACTIVE','SUPERSEDED','VOIDED'))
) ENGINE=InnoDB COMMENT='海外业务不可变费用来源版本;发布后经跨区事件进入Finance';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_finance_fee_source' AND index_name='idx_ll_finance_fee_container_customer'), 'SELECT 1', 'ALTER TABLE ll_finance_fee_source ADD KEY idx_ll_finance_fee_container_customer(container_booking_id,customer_id,source_status,created_at)'));
PREPARE ll_finance_fee_ddl FROM @ddl; EXECUTE ll_finance_fee_ddl; DEALLOCATE PREPARE ll_finance_fee_ddl;
CREATE TABLE IF NOT EXISTS ll_finance_fee_command (
id BIGINT NOT NULL COMMENT '幂等命令ID', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID',
action VARCHAR(16) NOT NULL COMMENT 'CREATE、SUBMIT、REVIEW、ADJUST或VOID', idempotency_key VARCHAR(128) NOT NULL COMMENT '操作幂等键',
@@ -9,14 +9,28 @@ paths:
- { 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: containerBookingId, description: 精确查询真实来源柜下全部客户的费用;可再传customerId收窄到单个客户, schema: { type: string, pattern: '^[1-9][0-9]*$' } }
responses: { '200': { description: 当前版本列表 } }
post:
summary: 创建海外业务费用来源草稿
description: 客户和业务编号必填;入仓ID、入仓码均按业务事实选填,不得为补字段伪造。
description: 客户和业务编号必填;入仓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: 业务归属或付款事实无效 } }
/api/platform/v1/last-leg/finance-fee-sources/container-customers:
get:
summary: 查询真实来源柜内客户选项
description: 单次按真实来源柜聚合全部客户,供柜详情维护费用时选择,不逐票查询。
security: [{ bearerAuth: [] }]
parameters:
- { in: query, name: containerBookingId, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }
responses:
'200':
description: 柜内客户选项
content:
application/json:
schema: { $ref: '#/components/schemas/ContainerCustomerListResponse' }
/api/platform/v1/last-leg/finance-fee-sources/{sourceFeeId}/{action}:
post:
summary: 提交、审核、调整或作废海外业务费用来源
@@ -28,23 +42,49 @@ paths:
responses: { '200': { description: 当前费用来源版本 }, '409': { description: 状态、版本或幂等冲突 } }
components:
schemas:
BusinessType: { type: string, enum: [OVERSEAS_INBOUND, OVERSEAS_PROCUREMENT, US_TRUCK, LOCAL_LOOSEBOARD, WAREHOUSE_SERVICE] }
BusinessType: { type: string, enum: [OVERSEAS_INBOUND, OVERSEAS_PROCUREMENT, US_TRUCK, LOCAL_LOOSEBOARD, WAREHOUSE_SERVICE, OVERSEAS_CONTAINER] }
OverseasContainerFeeItem:
type: string
description: 海外阶段柜级费用项目:港口费、堆存费、修箱费、吊机费、码头拖车费、其他。
enum: [PORT_FEE, STORAGE_FEE, CONTAINER_REPAIR_FEE, CRANE_FEE, TERMINAL_DRAYAGE_FEE, OTHER]
ContainerCustomerOption:
type: object
required: [customerId]
properties:
customerId: { type: string }
customerName: { type: string, nullable: true }
ContainerCustomerListResponse:
type: object
required: [data]
properties:
code: { type: string }
message: { type: string }
data:
type: array
items: { $ref: '#/components/schemas/ContainerCustomerOption' }
requestId: { type: string, nullable: true }
traceId: { type: string, nullable: true }
timestamp: { type: string, format: date-time }
SaveRequest:
type: object
required: [customerId, sourceType, businessType, businessNo, feeItemCode, feeItemName, direction, businessDate, currency, amount]
properties:
customerId: { type: string }
sourceType: { type: string, enum: [OVERSEAS_INBOUND_FEE, OVERSEAS_PROCUREMENT_FEE, OVERSEAS_TRUCK_FEE, OVERSEAS_LOOSEBOARD_FEE, OVERSEAS_WAREHOUSE_FEE] }
sourceType: { type: string, enum: [OVERSEAS_INBOUND_FEE, OVERSEAS_PROCUREMENT_FEE, OVERSEAS_TRUCK_FEE, OVERSEAS_LOOSEBOARD_FEE, OVERSEAS_WAREHOUSE_FEE, OVERSEAS_CONTAINER_FEE] }
businessType: { $ref: '#/components/schemas/BusinessType' }
businessId: { type: string, nullable: true }
businessId: { type: string, pattern: '^[1-9][0-9]*$', nullable: true }
businessNo: { type: string, maxLength: 128 }
containerBookingId: { type: string, pattern: '^[1-9][0-9]*$', nullable: true }
containerNo: { type: string, maxLength: 64, nullable: true }
warehouseId: { type: string, nullable: true }
inboundId: { type: string, nullable: true }
inboundCode: { type: string, maxLength: 64, nullable: true }
feeItemCode: { type: string }
feeItemCode:
type: string
description: OVERSEAS_CONTAINER时必须取OverseasContainerFeeItem枚举;其他业务类型沿用各自费用项目编码。
feeItemName: { type: string }
direction: { type: string, enum: [RECEIVABLE, PAYABLE] }
businessDate: { type: string, format: date }
currency: { type: string, enum: [CNY] }
amount: { type: number, format: decimal, exclusiveMinimum: 0 }
amount: { type: number, format: decimal, minimum: 0, exclusiveMinimum: true }
securitySchemes: { bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT } }