费用提交

This commit is contained in:
2026-10-27 17:41:33 +08:00
parent 57cd211973
commit 423e40e6aa
68 changed files with 1856 additions and 166 deletions
@@ -597,11 +597,13 @@
},
"physicalPallets": {
"type": "integer",
"minimum": 0
"minimum": 0,
"nullable": true
},
"palletSpaces": {
"type": "integer",
"minimum": 0
"minimum": 0,
"nullable": true
},
"ownPackages": {
"type": "integer",
@@ -557,6 +557,7 @@ components:
type: "string"
nullable: true
ownership:
nullable: true
type: "string"
enum:
- "OWNED"
@@ -715,6 +716,9 @@ components:
type: "array"
items:
"$ref": "#/components/schemas/Destination"
taskType:
type: string
enum: [DELIVERY, LOCAL_TRUCK, PICKUP]
actualPalletCount:
type: "integer"
minimum: 0
@@ -5077,7 +5077,7 @@ 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, WAIT_OVERSEAS_SHIPMENT, INTERNATIONAL_TRANSIT, DOMESTIC_RECEIVING, WAIT_CHARGES, WAIT_CUSTOMER_DISPATCH, WAIT_CUSTOMER_SHIPMENT, SHIPPED_TO_CUSTOMER, REJECTED, CANCELLED, EXCEPTION_CLOSED] }
ProcurementStatus: { type: string, enum: [PENDING_REVIEW, RECEIVING, WAIT_CUSTOMER_CONFIRM, CONFIRMED, IN_TRANSIT, DELIVERING, COMPLETED, REJECTED, CANCELLED, EXCEPTION_CLOSED, 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] }
ProcurementReview:
type: object
required: [version, decision, idempotencyKey]
@@ -20,7 +20,7 @@ paths:
responses: { '200': { description: '当前版本列表;voidStatus为NOT_REQUESTED、PENDING_FINANCE、FINANCE_ATTENTION或CONFIRMED,批量查询作废确认状态,不逐行读取。等待或拒绝时sourceStatus保留ACTIVE,只有Finance持久化确认后为VOIDED。' } }
post:
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。调用重放不重复冻结。
description: 需platform:finance:fee-source:edit。创建即PENDING。应收仅当前LASTLEG_ORDER且orderType=FIRST_LEG采用BILL,其余业务(含ONE_CLICK_DROPSHIP、退货、转运、柜级费用)为WALLET,发送异步FREEZE,本土卡车、本土散板应收同采购一样使用客户余额及授信扣款;余额及授信不足显示FREEZE_FAILED,不可审核通过。原USD按业务月有效汇率固化为CNY后冻结;原币与汇率快照保留。采购主单OVERSEAS_PROCUREMENT复用本入口,未传结算方式默认WALLET;旧PROCUREMENT_FEE子费用仍只由原采购节点处理。业务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' } } } }
@@ -86,7 +86,7 @@ paths:
post:
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。历史无资金记录的海外费用必须重新提交完成冻结,不允许审核绕过。采购来源仍由采购节点处理。
description: 编辑动作需platform:finance:fee-source:edit,review与void需platform:finance:fee-source:review。WALLET通过审核只发送SETTLE,实际匹配成功回执含冻结与账本引用后才PUBLISHED,此时仅本地费用完成、不推送财务账单;失败为SETTLE_FAILED,保持未收。驳回释放冻结,冻结在途时回执成功后自动释放。驳回后的费用只读,不能继续操作;如需重新收费应在业务单据中新增费用。头程BILL审核通过推送结算;已发布BILL作废等待Finance持久化确认才VOIDED。历史无资金记录的海外费用必须重新提交完成冻结,不允许审核绕过。采购主单费用沿此审核扣款链,旧PROCUREMENT_FEE子费用仍由原采购节点处理。
security: [{ bearerAuth: [] }]
parameters:
- { in: path, name: sourceFeeId, required: true, schema: { type: string } }
@@ -0,0 +1,331 @@
openapi: 3.0.3
info:
title: 简化海外采购批次流程 API
version: 1.0.0
description: 创建采购单后为待审核;审核通过进入收货中。实收可分批登记,客户确认后按采购库存分批出库。库存仅在本批次签收完成时扣减,创建出库单先占用可用库存。
security:
- bearerAuth: []
paths:
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/workflow:
get:
summary: 读取采购实收、库存和出库批次
description: 权限 platform:overseas-business:purchase:list;仅平台主体,必须指定目标客户 customerId。
parameters:
- $ref: '#/components/parameters/OrderNo'
- $ref: '#/components/parameters/CustomerId'
responses:
'200':
$ref: '#/components/responses/WorkflowResponse'
'401':
description: 未认证
'403':
description: 身份或操作权限不允许
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/receipts:
post:
summary: 分批登记实收数量和照片
description: 权限 platform:overseas-business:purchase:receive-overseas;仅平台主体,必须指定目标客户 customerId。仅 RECEIVING;本次数量不得超过未收采购数量。文件须已上传到本采购单,须为图片,分类为 RECEIPT 或 VOUCHER。
parameters:
- $ref: '#/components/parameters/OrderNo'
- $ref: '#/components/parameters/CustomerId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ReceiptCommand'
responses:
'200':
$ref: '#/components/responses/WorkflowResponse'
'401':
description: 未认证
'403':
description: 身份或操作权限不允许
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/request-confirmation:
post:
summary: 采购完成并请求客户确认
description: 权限 platform:overseas-business:purchase:receive-overseas;仅平台主体,必须指定目标客户 customerId。仅 RECEIVING 且已有实收;提交后不再追加收货。
parameters:
- $ref: '#/components/parameters/OrderNo'
- $ref: '#/components/parameters/CustomerId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Command'
responses:
'200':
$ref: '#/components/responses/WorkflowResponse'
'401':
description: 未认证
'403':
description: 身份或操作权限不允许
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/outbounds:
post:
summary: 从采购库存创建出库单
description: 权限 platform:overseas-business:purchase:ship-customer;仅平台主体,必须指定目标客户 customerId。仅 CONFIRMED、IN_TRANSIT 或 DELIVERING;数量不得超过 availableQuantity,物流跟踪号必填。创建后占用数量增加,不实际扣库存。
parameters:
- $ref: '#/components/parameters/OrderNo'
- $ref: '#/components/parameters/CustomerId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/OutboundCommand'
responses:
'200':
$ref: '#/components/responses/WorkflowResponse'
'401':
description: 未认证
'403':
description: 身份或操作权限不允许
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/outbounds/{batchId}/dispatch:
post:
summary: 本批出库开始派送
description: 权限 platform:overseas-business:purchase:ship-customer;仅平台主体,必须指定目标客户 customerId。仅本单 IN_TRANSIT 批次可转为 DELIVERING。
parameters:
- $ref: '#/components/parameters/OrderNo'
- $ref: '#/components/parameters/CustomerId'
- $ref: '#/components/parameters/BatchId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Command'
responses:
'200':
$ref: '#/components/responses/WorkflowResponse'
'401':
description: 未认证
'403':
description: 身份或操作权限不允许
/api/platform/v1/last-leg/overseas-procurements/{orderNo}/outbounds/{batchId}/complete:
post:
summary: 上传凭证并完成本批出库
description: 权限 platform:overseas-business:purchase:ship-customer;仅平台主体,必须指定目标客户 customerId。仅本单 DELIVERING 批次;凭证须属于本单且分类为 RECEIPT 或 VOUCHER,支持文件或图片。批次完成与采购库存扣减同事务,重复请求不重复扣减。
parameters:
- $ref: '#/components/parameters/OrderNo'
- $ref: '#/components/parameters/CustomerId'
- $ref: '#/components/parameters/BatchId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CompletionCommand'
responses:
'200':
$ref: '#/components/responses/WorkflowResponse'
'401':
description: 未认证
'403':
description: 身份或操作权限不允许
/api/merchant/v1/last-leg/overseas-procurements/{orderNo}/workflow:
get:
summary: 客户读取采购实收与出库批次
description: 权限 merchant:cross-border:procurement:list;客户范围只取认证身份,不接收 customerId。仅返回已关联收货或出库批次的文件元信息,不暴露内部文件。
parameters:
- $ref: '#/components/parameters/OrderNo'
responses:
'200':
$ref: '#/components/responses/WorkflowResponse'
'401':
description: 未认证
'403':
description: 身份或操作权限不允许
/api/merchant/v1/last-leg/overseas-procurements/{orderNo}/confirm:
post:
summary: 客户确认采购结果
description: 权限 merchant:cross-border:procurement:create;客户范围只取认证身份,不接收 customerId。仅 WAIT_CUSTOMER_CONFIRM 可确认,成功进入 CONFIRMED。
parameters:
- $ref: '#/components/parameters/OrderNo'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Command'
responses:
'200':
$ref: '#/components/responses/WorkflowResponse'
'401':
description: 未认证
'403':
description: 身份或操作权限不允许
/api/merchant/v1/last-leg/overseas-procurements/{orderNo}/files/{fileId}/content:
get:
summary: 客户下载收货照片或签收凭证
description: 权限 merchant:cross-border:procurement:list;客户范围只取认证身份。fileId 必须已关联本单收货或出库批次,内部文件和其他客户文件均不可下载。成功为原始字节流,响应 Cache-Control 为 no-store。
parameters:
- $ref: '#/components/parameters/OrderNo'
- name: fileId
in: path
required: true
schema:
$ref: '#/components/schemas/Id'
responses:
'200':
description: 原始凭证内容;Content-Type 采用文件真实类型,Content-Disposition 为 attachment 并携带文件名
headers:
Cache-Control:
schema: {type: string, example: no-store}
Content-Disposition:
schema: {type: string}
content:
application/octet-stream:
schema: {type: string, format: binary}
image/*:
schema: {type: string, format: binary}
'401':
description: 未认证
'403':
description: 身份或只读权限不允许
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
OrderNo:
name: orderNo
in: path
required: true
schema: {type: string}
CustomerId:
name: customerId
in: query
required: true
schema: {type: string, pattern: '^[1-9][0-9]*$'}
BatchId:
name: batchId
in: path
required: true
schema:
$ref: '#/components/schemas/Id'
responses:
WorkflowResponse:
description: HTTP 200 业务响应;必须核对 code,版本冲突和非法状态返回非成功业务码
content:
application/json:
schema:
$ref: '#/components/schemas/Response'
schemas:
Id:
type: string
pattern: '^[1-9][0-9]*$'
description: Long 主键在 JSON 中按字符串传输,避免前端精度损失
Status:
type: string
enum: [PENDING_REVIEW, RECEIVING, WAIT_CUSTOMER_CONFIRM, CONFIRMED, IN_TRANSIT, DELIVERING, COMPLETED]
description: 依次为待审核、收货中、待客户确认、已确认、运输中、派送中、签收完成
Command:
type: object
required: [version, idempotencyKey]
description: version 为当前采购单版本;同单原幂等键与相同参数重试不重复执行,跨动作或改参数复用键会被拒绝
properties:
version: {type: integer, format: int64, minimum: 0}
idempotencyKey: {type: string, minLength: 1, maxLength: 128}
FileIds:
type: array
minItems: 1
maxItems: 20
uniqueItems: true
items:
$ref: '#/components/schemas/Id'
ReceiptCommand:
allOf:
- $ref: '#/components/schemas/Command'
- type: object
required: [quantity, fileIds]
properties:
quantity: {type: integer, format: int64, minimum: 1}
fileIds:
$ref: '#/components/schemas/FileIds'
OutboundCommand:
allOf:
- $ref: '#/components/schemas/Command'
- type: object
required: [quantity, trackingNo]
properties:
quantity: {type: integer, format: int64, minimum: 1}
trackingNo: {type: string, minLength: 1, maxLength: 255}
CompletionCommand:
allOf:
- $ref: '#/components/schemas/Command'
- type: object
required: [fileIds]
properties:
fileIds:
$ref: '#/components/schemas/FileIds'
Receipt:
type: object
required: [id, quantity, fileIds, receivedAt]
properties:
id:
$ref: '#/components/schemas/Id'
quantity: {type: integer, format: int64, minimum: 1}
fileIds:
type: array
items:
$ref: '#/components/schemas/Id'
receivedAt: {type: string, format: date-time}
Outbound:
type: object
required: [id, outboundNo, quantity, trackingNo, status, fileIds, createdAt, completedAt]
properties:
id:
$ref: '#/components/schemas/Id'
outboundNo: {type: string}
quantity: {type: integer, format: int64, minimum: 1}
trackingNo: {type: string}
status: {type: string, enum: [IN_TRANSIT, DELIVERING, COMPLETED]}
fileIds:
type: array
items:
$ref: '#/components/schemas/Id'
createdAt: {type: string, format: date-time}
completedAt: {type: string, format: date-time, nullable: true}
FileInfo:
type: object
required: [fileId, fileName, contentType]
properties:
fileId:
$ref: '#/components/schemas/Id'
fileName: {type: string}
contentType: {type: string}
Workflow:
type: object
required: [orderNo, version, status, receivedQuantity, stockQuantity, reservedQuantity, availableQuantity, receipts, outbounds, files]
description: stockQuantity = receivedQuantity - 已完成出库数量;reservedQuantity 为未完成出库占用;availableQuantity = stockQuantity - reservedQuantity。主状态优先显示运输中批次,其次派送中;全部批次完成但仍有库存时回到已确认,无剩余库存才签收完成。
properties:
orderNo: {type: string}
version: {type: integer, format: int64, minimum: 0}
status:
$ref: '#/components/schemas/Status'
receivedQuantity: {type: integer, format: int64, minimum: 0}
stockQuantity: {type: integer, format: int64, minimum: 0}
reservedQuantity: {type: integer, format: int64, minimum: 0}
availableQuantity: {type: integer, format: int64, minimum: 0}
receipts:
type: array
items:
$ref: '#/components/schemas/Receipt'
outbounds:
type: array
items:
$ref: '#/components/schemas/Outbound'
files:
type: array
items:
$ref: '#/components/schemas/FileInfo'
Response:
type: object
required: [code, message, data]
properties:
code: {type: string, example: '200'}
message: {type: string}
data:
$ref: '#/components/schemas/Workflow'