fix(dropship): generate pallet numbers atomically and extend full regressions
This commit is contained in:
@@ -260,6 +260,8 @@ CREATE TABLE IF NOT EXISTS ll_delivery_order (
|
||||
customer_name VARCHAR(255) NULL COMMENT '客户名称快照',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'WAIT_DELIVERY' COMMENT '派送状态:WAIT_DELIVERY待派送及后续正式状态',
|
||||
waybill_no VARCHAR(128) NULL COMMENT '承运运单号',
|
||||
bol_no VARCHAR(128) NULL COMMENT '派送资料BOL号,不作为文件归属标识',
|
||||
documents_json JSON NULL COMMENT '派送三类资料当前绑定及权威文件元数据快照',
|
||||
delivery_method VARCHAR(32) NULL COMMENT '派送方式',
|
||||
carrier_name VARCHAR(255) NULL COMMENT '派送承运商',
|
||||
pickup_method VARCHAR(64) NULL COMMENT '提货方式',
|
||||
@@ -306,6 +308,21 @@ CREATE TABLE IF NOT EXISTS ll_delivery_fee (
|
||||
amount DECIMAL(18,2) NOT NULL COMMENT '费用金额', remark VARCHAR(500) NULL COMMENT '费用备注', created_by VARCHAR(128) NULL COMMENT '创建人ID',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_delivery_fee_order(customer_id,delivery_order_id,id)
|
||||
) ENGINE=InnoDB COMMENT='派送单费用明细';
|
||||
CREATE TABLE IF NOT EXISTS ll_delivery_document_revision (
|
||||
id BIGINT NOT NULL COMMENT '派送资料历史ID',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '派送所属客户隔离键',
|
||||
delivery_order_id BIGINT NOT NULL COMMENT '派送单ID',
|
||||
version BIGINT NOT NULL COMMENT '保存成功时派送单版本',
|
||||
idempotency_key VARCHAR(128) NOT NULL COMMENT '资料保存幂等键',
|
||||
request_hash VARCHAR(64) NOT NULL COMMENT '完整保存请求哈希',
|
||||
snapshot_json JSON NOT NULL COMMENT '不可变三类资料及BOL号结果快照',
|
||||
operator_id VARCHAR(128) NOT NULL COMMENT '保存操作人ID',
|
||||
created_at DATETIME(3) NOT NULL COMMENT '资料保存时间',
|
||||
PRIMARY KEY(id),
|
||||
UNIQUE KEY uk_delivery_document_command(customer_id,delivery_order_id,idempotency_key),
|
||||
UNIQUE KEY uk_delivery_document_version(customer_id,delivery_order_id,version)
|
||||
) ENGINE=InnoDB COMMENT='派送资料版本历史与幂等保存记录';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_delivery_operation (
|
||||
id BIGINT NOT NULL COMMENT '派送操作主键', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', delivery_order_id BIGINT NOT NULL COMMENT '派送单ID',
|
||||
operation_node VARCHAR(64) NOT NULL COMMENT '操作节点', operator_id VARCHAR(128) NULL COMMENT '操作人ID', operator_name VARCHAR(128) NULL COMMENT '操作人名称',
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: 派送单三类资料
|
||||
version: 1.0.0
|
||||
description: |
|
||||
所有入口只允许平台,customerId 必须为真实派送所属客户;不得按 BOL 文本查找或复用其他客户/派送单文件。
|
||||
GET /delivery-orders 及 GET /delivery-orders/{deliveryNo} 的 order 行新增 bolNo 和 documentSummary,version/allowedActions 保持原契约。
|
||||
状态 PUT /delivery-orders/{deliveryNo}/status 请求保持 {status,expectedVersion,remark},expectedVersion 必传。
|
||||
START_DELIVERY=DELIVERING(派送中);COMPLETE_DELIVERY=DELIVERED(完成并记录签收时间、生成待回访)。同状态重放不重复副作用。
|
||||
资料不设必传门禁,不以三类齐全作为派送完成条件。业务失败使用统一 ApiResponse(A0422参数、A0409冲突),通常HTTP200。
|
||||
security: [{ bearerAuth: [] }]
|
||||
paths:
|
||||
/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/documents:
|
||||
parameters:
|
||||
- { $ref: '#/components/parameters/DeliveryNo' }
|
||||
- { $ref: '#/components/parameters/CustomerId' }
|
||||
get:
|
||||
summary: 查询已保存三类资料
|
||||
description: 权限 platform:overseas-warehouse:delivery:list;空资料仍返回全部三类MISSING。上传未保存不计入摘要。
|
||||
responses:
|
||||
'200': { description: 当前快照, content: { application/json: { schema: { $ref: '#/components/schemas/DetailResponse' } } } }
|
||||
put:
|
||||
summary: 原子保存全部类别绑定与BOL号
|
||||
description: |
|
||||
权限 platform:overseas-warehouse:delivery:documents。documents为全量快照,遗漏类别清空;Admin须提交完整三类。
|
||||
同一派送单锁下校验expectedVersion、全部文件客户/派送单/类别归属后一起提交,任一失败不写任何绑定。
|
||||
保存增加派送version,与状态修改共享版本;幂等键按客户+派送单限定,同键同请求重放原结果、异请求冲突。
|
||||
替换/删除通过修改fileIds并保存表达,只解除当前绑定,历史对象和版本快照不可变保留。
|
||||
requestBody:
|
||||
required: true
|
||||
content: { application/json: { schema: { $ref: '#/components/schemas/Save' } } }
|
||||
responses:
|
||||
'200': { description: 保存结果或统一业务错误, content: { application/json: { schema: { $ref: '#/components/schemas/DetailResponse' } } } }
|
||||
/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/documents/{category}/files:
|
||||
parameters:
|
||||
- { $ref: '#/components/parameters/DeliveryNo' }
|
||||
- { $ref: '#/components/parameters/CustomerId' }
|
||||
- { $ref: '#/components/parameters/Category' }
|
||||
post:
|
||||
summary: 上传一个待绑定文件
|
||||
description: |
|
||||
权限 platform:overseas-warehouse:delivery:documents。FormData唯一file,无额外幂等头。
|
||||
File沿用ARBITRARY任意格式、非空且不超过52428800字节(50MiB),每类别最多20个文件由保存校验。
|
||||
上传仅产生不可变对象,不修改派送version或摘要;取消弹框/未保存不落绑定,不物理删除File对象。
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema: { type: object, required: [file], properties: { file: { type: string, format: binary } } }
|
||||
responses:
|
||||
'200':
|
||||
description: 单文件权威元数据
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- { $ref: '#/components/schemas/Envelope' }
|
||||
- type: object
|
||||
properties: { data: { $ref: '#/components/schemas/File' } }
|
||||
/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/documents/history:
|
||||
parameters:
|
||||
- { $ref: '#/components/parameters/DeliveryNo' }
|
||||
- { $ref: '#/components/parameters/CustomerId' }
|
||||
get:
|
||||
summary: 查看不可变资料保存历史
|
||||
description: 权限 platform:overseas-warehouse:delivery:list;版本倒序,仅当前客户和派送单。
|
||||
responses:
|
||||
'200':
|
||||
description: 历史快照
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- { $ref: '#/components/schemas/Envelope' }
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
version: { type: integer, format: int64 }
|
||||
operatorId: { type: string }
|
||||
savedAt: { type: string, format: date-time }
|
||||
snapshot: { $ref: '#/components/schemas/Detail' }
|
||||
/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/documents/{category}/files/{fileId}/download:
|
||||
parameters:
|
||||
- { $ref: '#/components/parameters/DeliveryNo' }
|
||||
- { $ref: '#/components/parameters/CustomerId' }
|
||||
- { $ref: '#/components/parameters/Category' }
|
||||
- { in: path, name: fileId, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }
|
||||
- { in: query, name: revisionVersion, required: false, schema: { type: integer, format: int64, minimum: 1 } }
|
||||
get:
|
||||
summary: 下载当前或指定保存版本已绑定文件
|
||||
description: 权限 platform:overseas-warehouse:delivery:list;省略revisionVersion只允许当前绑定。历史版本仍严格校验客户/单据/类别。未保存或跨单文件拒绝;附件响应no-store/nosniff。
|
||||
responses:
|
||||
'200': { description: 文件内容, content: { application/octet-stream: { schema: { type: string, format: binary } } } }
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
|
||||
parameters:
|
||||
DeliveryNo: { in: path, name: deliveryNo, required: true, schema: { type: string } }
|
||||
CustomerId: { in: query, name: customerId, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }
|
||||
Category: { in: path, name: category, required: true, schema: { $ref: '#/components/schemas/CategoryCode' } }
|
||||
schemas:
|
||||
CategoryCode:
|
||||
type: string
|
||||
enum: [LOADING_PHOTO, BOL, RECEIPT]
|
||||
description: 依次为装车照片、BOL文件(含签名)、签收文件(POD签收/快递签收)。BOL签名由用户提供,不进行OCR或电子签署验证。
|
||||
Save:
|
||||
type: object
|
||||
required: [expectedVersion, idempotencyKey, documents]
|
||||
properties:
|
||||
expectedVersion: { type: integer, format: int64, minimum: 0 }
|
||||
idempotencyKey: { type: string, minLength: 1, maxLength: 128 }
|
||||
bolNo: { type: string, nullable: true, maxLength: 128, description: 不作为文件复用或归属匹配依据;空值清空 }
|
||||
documents:
|
||||
type: array
|
||||
maxItems: 3
|
||||
items:
|
||||
type: object
|
||||
required: [category, fileIds]
|
||||
properties:
|
||||
category: { $ref: '#/components/schemas/CategoryCode' }
|
||||
fileIds: { type: array, maxItems: 20, uniqueItems: true, items: { type: string, pattern: '^[1-9][0-9]*$' } }
|
||||
File:
|
||||
type: object
|
||||
required: [fileId, fileName, sizeBytes, uploadedAt]
|
||||
properties:
|
||||
fileId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
fileName: { type: string }
|
||||
contentType: { type: string, nullable: true }
|
||||
sizeBytes: { type: integer, format: int64, minimum: 1, maximum: 52428800 }
|
||||
uploadedAt: { type: string, format: date-time, description: File持久化的真实创建时间 }
|
||||
CategorySummary:
|
||||
type: object
|
||||
required: [category, status, fileCount]
|
||||
properties:
|
||||
category: { $ref: '#/components/schemas/CategoryCode' }
|
||||
status: { type: string, enum: [UPLOADED, MISSING] }
|
||||
fileCount: { type: integer, minimum: 0, maximum: 20 }
|
||||
DocumentSummary:
|
||||
type: object
|
||||
required: [uploadedCategoryCount, totalCategoryCount, categories]
|
||||
properties:
|
||||
uploadedCategoryCount: { type: integer, minimum: 0, maximum: 3 }
|
||||
totalCategoryCount: { type: integer, enum: [3] }
|
||||
categories: { type: array, minItems: 3, maxItems: 3, items: { $ref: '#/components/schemas/CategorySummary' } }
|
||||
Detail:
|
||||
type: object
|
||||
required: [deliveryNo, customerId, version, uploadedCategoryCount, totalCategoryCount, categories, allowedActions, replayed]
|
||||
properties:
|
||||
deliveryNo: { type: string }
|
||||
customerId: { type: string }
|
||||
version: { type: integer, format: int64 }
|
||||
bolNo: { type: string, nullable: true }
|
||||
uploadedCategoryCount: { type: integer, minimum: 0, maximum: 3 }
|
||||
totalCategoryCount: { type: integer, enum: [3] }
|
||||
categories:
|
||||
type: array
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
items:
|
||||
allOf:
|
||||
- { $ref: '#/components/schemas/CategorySummary' }
|
||||
- type: object
|
||||
required: [files]
|
||||
properties: { files: { type: array, maxItems: 20, items: { $ref: '#/components/schemas/File' } } }
|
||||
allowedActions: { type: array, items: { type: string, enum: [MANAGE_DOCUMENTS] }, description: 返回时按当前认证授权裁剪;只读用户为空,历史和幂等重放也不能沿用旧权限 }
|
||||
replayed: { type: boolean }
|
||||
Envelope:
|
||||
type: object
|
||||
properties:
|
||||
code: { type: string }
|
||||
message: { type: string }
|
||||
DetailResponse:
|
||||
allOf:
|
||||
- { $ref: '#/components/schemas/Envelope' }
|
||||
- type: object
|
||||
properties: { data: { $ref: '#/components/schemas/Detail' } }
|
||||
@@ -1,6 +1,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Lastleg Overseas Business API
|
||||
description: 派送资料完整契约见同目录 delivery-documents-v1.yaml;派送列表/详情行返回 bolNo、documentSummary(三类状态与x/3),状态仍使用 version 和 allowedActions。
|
||||
version: 1.0.0
|
||||
paths:
|
||||
/api/platform/v1/last-leg/inventory/balances/{balanceId}:
|
||||
|
||||
Reference in New Issue
Block a user