This commit is contained in:
2026-08-12 14:08:29 +08:00
parent 4375beaa13
commit aaa38f825a
5 changed files with 485 additions and 7 deletions
+158 -5
View File
@@ -43,7 +43,11 @@ paths:
- $ref: '#/components/parameters/UnifiedPage'
- $ref: '#/components/parameters/UnifiedSize'
responses:
'200': {description: 成功或业务失败,响应体 code 为字符串 200 时成功}
'200':
description: 成功或业务失败,响应体 code 为字符串 200 时成功
content:
application/json:
schema: {$ref: '#/components/schemas/UnifiedOrderPageEnvelope'}
'403': {description: 需要平台身份和 platform:order:list 权限}
/api/platform/v1/orders/{orderId}:
get:
@@ -53,7 +57,11 @@ paths:
- $ref: '#/components/parameters/UnifiedOrderId'
- $ref: '#/components/parameters/UnifiedTenantId'
responses:
'200': {description: 成功或业务失败,按响应体 code 判断}
'200':
description: 成功或业务失败,按响应体 code 判断
content:
application/json:
schema: {$ref: '#/components/schemas/UnifiedOrderDetailEnvelope'}
'403': {description: 需要平台身份和 platform:order:list 权限}
/api/platform/v1/orders/{orderId}/internal-notes:
post:
@@ -105,7 +113,11 @@ paths:
- $ref: '#/components/parameters/UnifiedPage'
- $ref: '#/components/parameters/UnifiedSize'
responses:
'200': {description: 成功或业务失败,按响应体 code 判断}
'200':
description: 成功或业务失败,按响应体 code 判断
content:
application/json:
schema: {$ref: '#/components/schemas/UnifiedOrderPageEnvelope'}
'403': {description: 需要 merchant:order:list 权限}
/api/merchant/v1/orders/{orderId}:
get:
@@ -118,7 +130,7 @@ paths:
description: 成功或业务失败,按响应体 code 判断
content:
application/json:
schema: {$ref: '#/components/schemas/FirstLegOrderSummary'}
schema: {$ref: '#/components/schemas/UnifiedOrderDetailEnvelope'}
'403': {description: 需要 merchant:order:view 权限}
/api/merchant/v1/orders/first-leg:
get:
@@ -295,6 +307,146 @@ components:
scheme: bearer
bearerFormat: JWT
schemas:
UnifiedMainStatus:
type: string
enum: [PENDING_REVIEW, WAIT_MEASURE, INBOUNDED, LOADING, LOADED, DELIVERED]
description: >-
统一订单产品主状态。历史内部状态 WAIT_SPLIT 仅作为查询入参兼容,所有列表、详情和时间线响应均归并为 INBOUNDED。
UnifiedOrderPageEnvelope:
type: object
properties:
code: {type: string, example: '200'}
message: {type: string}
data: {$ref: '#/components/schemas/UnifiedOrderPage'}
UnifiedOrderPage:
type: object
properties:
records: {type: array, items: {$ref: '#/components/schemas/UnifiedOrderRow'}}
page: {type: integer, format: int64, minimum: 1}
size: {type: integer, format: int64, minimum: 1}
total: {type: integer, format: int64, minimum: 0}
pages: {type: integer, format: int64, minimum: 0}
UnifiedOrderDetailEnvelope:
type: object
properties:
code: {type: string, example: '200'}
message: {type: string}
data: {$ref: '#/components/schemas/UnifiedOrderDetail'}
UnifiedOrderDetail:
type: object
properties:
summary: {$ref: '#/components/schemas/UnifiedOrderRow'}
order:
type: object
properties:
order: {type: object, description: Order 服务订单主实体}
cargoes: {type: array, items: {type: object}}
parties: {type: array, items: {type: object}}
internalNotes: {type: array, items: {type: object}, description: 客户详情始终为空数组}
statusHistory: {type: array, items: {type: object}}
timeline: {type: array, items: {$ref: '#/components/schemas/UnifiedOrderTimelineEvent'}}
UnifiedOrderRow:
type: object
properties:
orderId: {type: integer, format: int64}
tenantId: {type: integer, format: int64}
orderNo: {type: string}
mainStatus: {$ref: '#/components/schemas/UnifiedMainStatus'}
nextAction: {type: string, nullable: true}
relation: {$ref: '#/components/schemas/UnifiedOrderRelation'}
internalOrderStatus: {type: string, enum: [DRAFT, SUBMITTED, APPROVED, ACCEPTED, REJECTED, CANCELLED, PROCESSING, COMPLETED], nullable: true}
customerId: {type: integer, format: int64, nullable: true}
customerName: {type: string, nullable: true}
channelName: {type: string, nullable: true}
receivingWarehouseId: {type: integer, format: int64, nullable: true}
receivingWarehouseName: {type: string, nullable: true}
destinationWarehouseId: {type: integer, format: int64, nullable: true}
destinationWarehouseName: {type: string, nullable: true}
inboundId: {type: integer, format: int64, nullable: true}
inboundVersion: {type: integer, nullable: true, description: C04 loading/complete 的 expectedVersion}
inboundCode: {type: string, nullable: true}
expectedShipDate: {type: string, format: date, nullable: true}
totalPackageCount: {type: integer, nullable: true}
recommendedPalletType: {type: string, nullable: true}
locationCodes: {type: string, nullable: true}
actualGrossWeightKg: {type: number, nullable: true}
actualVolumeCbm: {type: number, nullable: true}
measurement: {$ref: '#/components/schemas/UnifiedMeasurementSummary'}
preload: {$ref: '#/components/schemas/UnifiedPreloadSummary'}
loading: {$ref: '#/components/schemas/UnifiedLoadingSummary'}
delivery: {$ref: '#/components/schemas/UnifiedDeliverySummary'}
transport: {$ref: '#/components/schemas/UnifiedTransportSummary'}
customerRemark: {type: string, nullable: true}
latestInternalNote: {type: string, nullable: true, description: 客户详情不返回平台内部备注}
createdAt: {type: string, format: date-time, nullable: true}
updatedAt: {type: string, format: date-time, nullable: true}
UnifiedOrderRelation:
type: object
nullable: true
properties:
role: {type: string, enum: [PARENT, CHILD]}
rootOrderId: {type: integer, format: int64, nullable: true}
parentOrderId: {type: integer, format: int64, nullable: true}
splitSequence: {type: integer, nullable: true}
childCount: {type: integer, nullable: true}
UnifiedMeasurementSummary:
type: object
nullable: true
properties:
reviewStatus: {type: string, nullable: true}
actualGrossWeightKg: {type: number, nullable: true}
actualVolumeCbm: {type: number, nullable: true}
chargeableWeightKg: {type: number, nullable: true}
completedAt: {type: string, format: date-time, nullable: true}
UnifiedPreloadSummary:
type: object
nullable: true
properties:
status: {type: string, nullable: true}
version: {type: integer, nullable: true}
itemCount: {type: integer, nullable: true}
updatedAt: {type: string, format: date-time, nullable: true}
UnifiedLoadingSummary:
type: object
nullable: true
properties:
status: {type: string, nullable: true}
loadingVersion: {type: integer, nullable: true, description: 当前为 pickingVersion 兼容别名}
pickingVersion: {type: integer, nullable: true}
expectedCount: {type: integer, nullable: true}
pickedCount: {type: integer, nullable: true}
evidenceCount: {type: integer, nullable: true}
sealNo: {type: string, nullable: true}
updatedAt: {type: string, format: date-time, nullable: true}
UnifiedDeliverySummary:
type: object
nullable: true
properties:
status: {type: string, nullable: true}
completedAt: {type: string, format: date-time, nullable: true}
trackingNo: {type: string, nullable: true}
UnifiedTransportSummary:
type: object
nullable: true
properties:
loadingStatus: {type: string, nullable: true}
containerNo: {type: string, nullable: true}
cabinetNo: {type: string, nullable: true}
vesselName: {type: string, nullable: true}
voyageNo: {type: string, nullable: true}
sailingAt: {type: string, format: date-time, nullable: true}
portArrivalAt: {type: string, format: date-time, nullable: true}
UnifiedOrderTimelineEvent:
type: object
properties:
source: {type: string}
eventType: {type: string}
mainStatus: {$ref: '#/components/schemas/UnifiedMainStatus'}
action: {type: string, nullable: true}
remark: {type: string, nullable: true}
operatorId: {type: integer, format: int64, nullable: true}
operatorName: {type: string, nullable: true}
occurredAt: {type: string, format: date-time, nullable: true}
FulfillmentSplitQuantityLine:
type: object
required: [sourceDetailId, packageCount]
@@ -459,9 +611,10 @@ components:
name: mainStatus
in: query
required: false
description: 历史值 WAIT_SPLIT 仍可作为兼容筛选传入,但响应 mainStatus 始终归并为 INBOUNDED
schema:
type: string
enum: [PENDING_REVIEW, WAIT_MEASURE, INBOUNDED, LOADING, LOADED, DELIVERED]
enum: [PENDING_REVIEW, WAIT_MEASURE, INBOUNDED, LOADING, LOADED, DELIVERED, WAIT_SPLIT]
UnifiedInboundCode:
{name: inboundCode, in: query, required: false, description: 客户提交后生成的入仓码,待审核订单同样可查询, schema: {type: string, maxLength: 40}}
UnifiedInternalOrderStatus:
@@ -39,7 +39,24 @@ class UnifiedOrderApiContractTest {
Map<String, Object> mainStatus = stringMap(parameters.get("UnifiedMainStatus"));
Map<String, Object> schema = stringMap(mainStatus.get("schema"));
assertThat(stringList(schema.get("enum"))).containsExactly(
"PENDING_REVIEW", "WAIT_MEASURE", "INBOUNDED", "LOADING", "LOADED", "DELIVERED", "WAIT_SPLIT");
assertThat(mainStatus.get("description").toString())
.contains("WAIT_SPLIT", "INBOUNDED");
Map<String, Object> schemas = stringMap(components.get("schemas"));
Map<String, Object> responseStatus = stringMap(schemas.get("UnifiedMainStatus"));
assertThat(stringList(responseStatus.get("enum"))).containsExactly(
"PENDING_REVIEW", "WAIT_MEASURE", "INBOUNDED", "LOADING", "LOADED", "DELIVERED");
assertThat(responseStatus.get("description").toString()).contains("WAIT_SPLIT", "INBOUNDED");
Map<String, Object> row = stringMap(schemas.get("UnifiedOrderRow"));
assertThat(stringMap(row.get("properties"))).containsKeys(
"orderId", "mainStatus", "inboundId", "inboundVersion", "measurement", "preload",
"loading", "delivery", "transport", "customerRemark", "latestInternalNote");
assertThat(responseSchema(paths, "/api/platform/v1/orders", "get"))
.containsEntry("$ref", "#/components/schemas/UnifiedOrderPageEnvelope");
assertThat(responseSchema(paths, "/api/merchant/v1/orders/{orderId}", "get"))
.containsEntry("$ref", "#/components/schemas/UnifiedOrderDetailEnvelope");
}
@Test
@@ -61,4 +78,11 @@ class UnifiedOrderApiContractTest {
private static List<String> stringList(Object value) {
return (List<String>) value;
}
private static Map<String, Object> responseSchema(Map<String, Object> paths, String path, String method) {
Map<String, Object> operation = stringMap(stringMap(paths.get(path)).get(method));
Map<String, Object> response = stringMap(stringMap(operation.get("responses")).get("200"));
Map<String, Object> content = stringMap(response.get("content"));
return stringMap(stringMap(content.get("application/json")).get("schema"));
}
}