feat: add self-operated analytics and enforce Lastleg module boundaries
This commit is contained in:
@@ -2,14 +2,77 @@ openapi: 3.0.3
|
||||
info:
|
||||
title: Lingxing WMS Internal Read API
|
||||
version: 1.0.0
|
||||
description: Read-only provider adapter. No business scheduling, persistence, inventory mutation or public Gateway route.
|
||||
description: >-
|
||||
Single-page or single-order adapter. No scheduling, business persistence or public Gateway route.
|
||||
Source times remain uninterpreted strings; warehouse timeZone does not certify source timezone.
|
||||
Server-side collection mode defaults to OFF. VALIDATION requires an externally confirmed exclusive
|
||||
account window; BUSINESS requires environmentLabel exactly production. All five endpoints apply the same gate.
|
||||
Missing exclusive proof, persistent account budget authorization or control context fails closed before egress.
|
||||
At most one account request is in flight and HTTP request starts are separated by at least 5 seconds.
|
||||
A JVM lock is only local protection and is not proof of cross-environment account exclusivity.
|
||||
Each invocation performs at most one supplier HTTP attempt. No mode uses implicit HTTP retries;
|
||||
429 is never retried, immediately pauses the account and returns persistent cooldown metadata.
|
||||
VALIDATION page size must not exceed 10. Lastleg owns root/session budgets and cooldown persistence.
|
||||
External server configuration supplies externalExclusiveGrantId and externalExclusiveUntil;
|
||||
the grant must match context.exclusiveGrantId and remain valid. A BUSINESS rate-limit pause is
|
||||
recoverable only within the original valid exclusive window, after both the persistently returned
|
||||
cooldown and the local minimum fallback cooldown have elapsed, and after the authority issues a new
|
||||
strictly valid single-attempt permit confirming account budget, cooldown, stop limits and root state.
|
||||
Time alone never permits egress. VALIDATION 429 does not automatically recover. Unavailable, lost
|
||||
or malformed authorization and uncertain completion hold an unrecoverable local pause until
|
||||
operations verify persistent account state. Completion failure never automatically recovers.
|
||||
A well-formed explicit authorization denial is deterministic and does not cause a permanent pause.
|
||||
sourceAccount defaults to lingxing-primary and budgetAuthorityBaseUri defaults internally to
|
||||
http://lastleg-service:9303; neither default enables egress.
|
||||
x-lastleg-egress-coordination:
|
||||
description: >-
|
||||
Integration calls these Lastleg endpoints with X-Internal-Service-Token. These are dependencies,
|
||||
not Integration Controller paths. Lastleg prepares attemptId server-side and binds context and operation
|
||||
before authorization. authorize only consumes an already prepared attempt, first binds the opaque
|
||||
requestHash and atomically consumes persistent account/root/session budget. Duplicate authorization
|
||||
is refused; arbitrary client-created attempts are refused. complete verifies the same bindings.
|
||||
A permit is bound to its full context, operation and requestHash, requires exclusiveConfirmed=true
|
||||
and budgetConsumed=true, expires after now but no later than now plus 30 seconds or externalExclusiveUntil,
|
||||
and cannot be reused. Explicit denial uses HTTP 200 with ApiResponse code string B0001 and
|
||||
AuthorizationDenial data. A valid denial is not an uncertain authorization and does not impose
|
||||
a permanent local pause. Unavailable, lost or malformed authorization or an unconfirmed callback blocks further egress;
|
||||
pending or ambiguous attempts remain conservatively consumed, including after restart.
|
||||
authorize:
|
||||
method: POST
|
||||
path: /internal/lastleg/self-operated-analytics/egress/authorize
|
||||
requestSchema: '#/components/schemas/AuthorizationRequest'
|
||||
responseSchema: '#/components/schemas/AttemptPermitResponse'
|
||||
complete:
|
||||
method: POST
|
||||
path: /internal/lastleg/self-operated-analytics/egress/complete
|
||||
requestSchema: '#/components/schemas/CompletionRequest'
|
||||
responseSchema: '#/components/schemas/CompletionResponse'
|
||||
security:
|
||||
- InternalServiceToken: []
|
||||
paths:
|
||||
/internal/integrations/lingxing/wms/warehouses/query:
|
||||
post:
|
||||
summary: Query one page of normal warehouses
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
||||
description: Calls /openapi/v2/warehouse/page without filters. Maps page/pageSize into current/size; preserves original metadata.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/WarehouseQueryRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: Standard envelope with WarehousePage or sanitized ProviderFailure.
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/WarehouseResponse'}
|
||||
/internal/integrations/lingxing/wms/outbound-orders/query:
|
||||
post:
|
||||
summary: Query one page of completed WMS outbound summaries by outbound time
|
||||
description: Calls OMP /openapi/v2/order/delivery/page with timeType=outboundTime and status=100. Source time strings are preserved. This is a single page, not a complete sales report. It uses the self-developed-system API authorization in the WMS management console.
|
||||
summary: Query one page of completed outbound orders by source outbound time
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
||||
description: Calls /openapi/v2/order/delivery/page with timeType=outboundTime and status=100. No external warehouse filter. At current=1,size=100 only, records=[],total=0,pages=0,sourceCurrent=1,sourceSize=10 is accepted and internal size remains 100. All other pagination metadata is strictly required. No completeness claim across pages.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -17,65 +80,363 @@ paths:
|
||||
schema: {$ref: '#/components/schemas/QueryRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: Standard envelope; code 200 for success, A0401 for rejected internal identity, A0422 for bean validation, B0001 or S0503 for provider/configuration failures. Failures never return a successful empty page.
|
||||
description: Standard envelope with OrderPage or sanitized ProviderFailure.
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/Response'}
|
||||
schema: {$ref: '#/components/schemas/OrderResponse'}
|
||||
/internal/integrations/lingxing/wms/outbound-orders/locate:
|
||||
post:
|
||||
summary: Locate one page by delivery number without time or status filters
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
||||
description: Sends only current,size,deliveryNo to delivery/page. Every returned deliveryNo must match exactly. Caller reads all required pages and verifies original customer identity and uniqueness before accepting the current warehouse. Missing results do not prove cancellation.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/LocateRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: Standard envelope with OrderPage or sanitized ProviderFailure.
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/OrderResponse'}
|
||||
/internal/integrations/lingxing/wms/outbound-orders/detail:
|
||||
post:
|
||||
summary: Read one order using warehouse, customer and delivery identifiers
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
||||
description: Maps warehouseCode to whCode for delivery/detail. All three returned identifiers must match. Returns only skuVOList; packageList is never added to quantities. Duplicate SKU lines remain separate for caller normalization. Missing quantities remain null; no quantity unit is inferred.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/DetailRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: Standard envelope with OrderDetail or sanitized ProviderFailure.
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/DetailResponse'}
|
||||
/internal/integrations/lingxing/wms/product-inventory/query:
|
||||
post:
|
||||
summary: Query one page of all qualities and customers in a required warehouse
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
||||
description: Calls stock/stockSku/page with whCode and isHideInventory=0. No SKU, quality, customer or quantity filters. Warehouse mismatch and duplicate business keys within a page fail closed. Caller validates cross-page keys and counts. Unknown quantities stay null, negative quantities remain evidence, stockCompare is not accumulated.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/InventoryQueryRequest'}
|
||||
responses:
|
||||
'200':
|
||||
description: Standard envelope with InventoryPage or sanitized ProviderFailure.
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/InventoryResponse'}
|
||||
components:
|
||||
parameters:
|
||||
LingxingEgressContext:
|
||||
name: X-Lingxing-Egress-Context
|
||||
in: header
|
||||
required: true
|
||||
description: >-
|
||||
JSON control context; no credentials. Maximum 2048 characters, all printable ASCII (32 through 126).
|
||||
Unknown fields, duplicate fields and trailing JSON are rejected. Identifiers are strings supplied
|
||||
by the server-side coordinator and do not confer authorization by themselves.
|
||||
content:
|
||||
application/json:
|
||||
schema: {$ref: '#/components/schemas/EgressContext'}
|
||||
securitySchemes:
|
||||
InternalServiceToken:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-Internal-Service-Token
|
||||
schemas:
|
||||
EgressContext:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [sourceAccount, executionPurpose, rootTaskId, sessionId, attemptId, exclusiveGrantId]
|
||||
properties:
|
||||
sourceAccount: {type: string, minLength: 1, maxLength: 64, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]*$', description: Server-configured account alias, never App Key or Secret.}
|
||||
executionPurpose: {type: string, enum: [VALIDATION, BUSINESS]}
|
||||
rootTaskId: {type: string, minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]*$', description: Stable root control identifier; child tasks share root budget.}
|
||||
sessionId: {type: string, minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]*$', description: Stable session control identifier; reopening or restart does not reset it.}
|
||||
attemptId: {type: string, minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]*$', description: Prepared unique single-attempt control identifier; duplicate authorization is refused.}
|
||||
exclusiveGrantId: {type: string, minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]*$', description: Must equal the valid externalExclusiveGrantId configured server-side.}
|
||||
EgressRequestHash:
|
||||
type: string
|
||||
pattern: '^[0-9a-f]{64}$'
|
||||
description: >-
|
||||
Lowercase hexadecimal SHA256 of UTF-8 bytes of OMP path, one LF character and compact
|
||||
insertion-ordered external business JSON. Lastleg treats this digest as opaque and binds
|
||||
it on the first authorization of an already prepared attempt.
|
||||
example: fa60a92c78b4803878930e5914e6db03591acc31b7c09abad53c91912fa3d627
|
||||
x-preimage-example: |-
|
||||
/openapi/v2/stock/stockSku/page
|
||||
{"current":1,"size":2,"whCode":"WH-DEMO","isHideInventory":0}
|
||||
EgressOperation:
|
||||
type: string
|
||||
enum: [WAREHOUSES, OUTBOUND_QUERY, OUTBOUND_LOCATE, OUTBOUND_DETAIL, PRODUCT_INVENTORY]
|
||||
EgressMetadata:
|
||||
type: object
|
||||
required: [attemptId, actualHttpAttempts, accountPaused]
|
||||
properties:
|
||||
attemptId: {type: string, nullable: true, description: Null only if no valid control context was accepted.}
|
||||
actualHttpAttempts: {type: integer, minimum: 0, maximum: 1, description: Supplier HTTP attempts actually started, including failed calls; authorization callbacks do not count.}
|
||||
accountPaused: {type: boolean}
|
||||
cooldownUntil: {type: string, format: date-time, nullable: true, description: Account cooldown deadline to persist; valid supplier retry time must not be shortened.}
|
||||
AuthorizationRequest:
|
||||
type: object
|
||||
required: [context, operation, requestHash]
|
||||
properties:
|
||||
context: {$ref: '#/components/schemas/EgressContext'}
|
||||
operation: {$ref: '#/components/schemas/EgressOperation'}
|
||||
requestHash: {$ref: '#/components/schemas/EgressRequestHash'}
|
||||
AuthorizationDenial:
|
||||
type: object
|
||||
required: [errorCode, sampleDone]
|
||||
properties:
|
||||
errorCode: {type: string, pattern: '^[A-Z][A-Z0-9_]{0,63}$'}
|
||||
sampleDone: {type: boolean, description: Strict JSON boolean; validation budget normal completion is distinct from a failure.}
|
||||
waitUntil: {type: string, format: date-time, nullable: true, description: Nullable ISO-8601 Instant from the persistent authority.}
|
||||
AuthorizationDenialResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
code: {type: string, enum: [B0001]}
|
||||
data: {$ref: '#/components/schemas/AuthorizationDenial'}
|
||||
AttemptPermit:
|
||||
type: object
|
||||
required: [context, operation, requestHash, allowedAttempts, expiresAt, exclusiveConfirmed, budgetConsumed]
|
||||
properties:
|
||||
context: {$ref: '#/components/schemas/EgressContext'}
|
||||
operation: {$ref: '#/components/schemas/EgressOperation'}
|
||||
requestHash: {$ref: '#/components/schemas/EgressRequestHash'}
|
||||
allowedAttempts: {type: integer, enum: [1]}
|
||||
expiresAt: {type: string, format: date-time, description: Must be after now and no later than now plus 30 seconds and configured externalExclusiveUntil.}
|
||||
exclusiveConfirmed: {type: boolean, enum: [true]}
|
||||
budgetConsumed: {type: boolean, enum: [true], description: Lastleg has atomically consumed persistent account and root/session budget before returning this permit.}
|
||||
CompletionRequest:
|
||||
type: object
|
||||
required: [context, operation, requestHash, actualHttpAttempts, accountPaused]
|
||||
properties:
|
||||
context: {$ref: '#/components/schemas/EgressContext'}
|
||||
operation: {$ref: '#/components/schemas/EgressOperation'}
|
||||
requestHash: {$ref: '#/components/schemas/EgressRequestHash'}
|
||||
actualHttpAttempts: {type: integer, minimum: 0, maximum: 1}
|
||||
errorCode: {type: string, nullable: true, description: Sanitized local error code; null on success.}
|
||||
upstreamStatus: {type: integer, nullable: true}
|
||||
sourceCode: {type: integer, nullable: true}
|
||||
accountPaused: {type: boolean, description: True on 429 or explicit provider rate limiting; all account request families must pause.}
|
||||
cooldownUntil: {type: string, format: date-time, nullable: true}
|
||||
AttemptPermitResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
code: {type: string, enum: ['200', B0001]}
|
||||
data:
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/AttemptPermit'}
|
||||
- {$ref: '#/components/schemas/AuthorizationDenial'}
|
||||
description: Code 200 requires AttemptPermit; code B0001 requires AuthorizationDenial. Lost or malformed responses are uncertain and fail closed with a local pause.
|
||||
CompletionResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data: {type: boolean, enum: [true], description: Successful acknowledgement confirms durable completion and cooldown persistence; any other result fails closed.}
|
||||
WarehouseQueryRequest:
|
||||
type: object
|
||||
required: [current, size]
|
||||
properties:
|
||||
current: {type: integer, minimum: 1}
|
||||
size: {type: integer, minimum: 1, maximum: 1000}
|
||||
QueryRequest:
|
||||
type: object
|
||||
required: [startTime, endTime, current, size]
|
||||
properties:
|
||||
startTime: {type: string, example: '2026-09-12T08:00:00', description: Source local datetime; must precede endTime and must not be earlier than endTime minus one calendar month. This is a local guard.}
|
||||
endTime: {type: string, example: '2026-10-12T08:00:00', description: Source local datetime.}
|
||||
startTime: {type: string, example: '2026-09-12T08:00:00', description: Source local datetime. Must precede endTime and be no earlier than endTime minus one calendar month. No source timezone inference.}
|
||||
endTime: {type: string, example: '2026-10-12T08:00:00'}
|
||||
current: {type: integer, minimum: 1}
|
||||
size: {type: integer, minimum: 1, maximum: 100, description: Local request cap; not a claim about the provider quota. Use 1 for connectivity verification.}
|
||||
size: {type: integer, minimum: 1, maximum: 100, description: Local request cap, not supplier quota.}
|
||||
LocateRequest:
|
||||
type: object
|
||||
required: [deliveryNo, current, size]
|
||||
properties:
|
||||
deliveryNo: {type: string, minLength: 1, maxLength: 128}
|
||||
current: {type: integer, minimum: 1}
|
||||
size: {type: integer, minimum: 1, maximum: 1000}
|
||||
DetailRequest:
|
||||
type: object
|
||||
required: [warehouseCode, customerCode, deliveryNo]
|
||||
properties:
|
||||
warehouseCode: {type: string, minLength: 1, maxLength: 64}
|
||||
customerCode: {type: string, minLength: 1, maxLength: 64}
|
||||
deliveryNo: {type: string, minLength: 1, maxLength: 128}
|
||||
InventoryQueryRequest:
|
||||
type: object
|
||||
required: [warehouseCode, current, size]
|
||||
properties:
|
||||
warehouseCode: {type: string, minLength: 1, maxLength: 64}
|
||||
current: {type: integer, minimum: 1}
|
||||
size: {type: integer, minimum: 1, maximum: 1000}
|
||||
Pagination:
|
||||
type: object
|
||||
required: [total, current, size, pages, sourceCurrent, sourceSize, sourceCode, observedAt, egress]
|
||||
properties:
|
||||
egress: {$ref: '#/components/schemas/EgressMetadata'}
|
||||
total: {type: string, pattern: '^[0-9]+$', description: Required provider total. Long follows platform string serialization.}
|
||||
current: {type: integer}
|
||||
size: {type: integer}
|
||||
pages: {type: integer, minimum: 0}
|
||||
sourceCurrent: {type: integer}
|
||||
sourceSize: {type: integer}
|
||||
sourceCode: {type: integer, enum: [200]}
|
||||
observedAt: {type: string, format: date-time}
|
||||
OrderSummary:
|
||||
type: object
|
||||
required: [deliveryNo]
|
||||
required: [deliveryNo, customerCode, whCode, status]
|
||||
properties:
|
||||
deliveryNo: {type: string}
|
||||
sourceNo: {type: string, nullable: true}
|
||||
customerCode: {type: string, nullable: true}
|
||||
whCode: {type: string, nullable: true}
|
||||
status: {type: integer, nullable: true}
|
||||
customerCode: {type: string}
|
||||
whCode: {type: string}
|
||||
status: {type: integer}
|
||||
createTime: {type: string, nullable: true}
|
||||
outboundTime: {type: string, nullable: true}
|
||||
PageResult:
|
||||
Warehouse:
|
||||
type: object
|
||||
required: [records, current, size, sourceCode, observedAt]
|
||||
required: [whCode, warehouseType, status]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/OrderSummary'}}
|
||||
total: {type: string, pattern: '^[0-9]+$', nullable: true, description: Provider total only when supplied. Java Long follows the platform JSON string convention.}
|
||||
current: {type: integer}
|
||||
size: {type: integer}
|
||||
sourceCode: {type: integer}
|
||||
whCode: {type: string}
|
||||
whNameCn: {type: string, nullable: true}
|
||||
warehouseType: {type: integer}
|
||||
status: {type: integer}
|
||||
timeZone: {type: string, nullable: true, description: Warehouse metadata only.}
|
||||
SkuLine:
|
||||
type: object
|
||||
required: [productSku]
|
||||
properties:
|
||||
productSku: {type: string}
|
||||
productName: {type: string, nullable: true}
|
||||
actualDeliveryQty: {type: number, nullable: true, description: BigDecimal actual quantity, unknown is null.}
|
||||
deliveryQty: {type: number, nullable: true, description: Forecast only; never a replacement for actual quantity.}
|
||||
OrderDetail:
|
||||
type: object
|
||||
required: [deliveryNo, customerCode, whCode, status, skuVOList, sourceCode, observedAt, egress]
|
||||
properties:
|
||||
egress: {$ref: '#/components/schemas/EgressMetadata'}
|
||||
deliveryNo: {type: string}
|
||||
sourceNo: {type: string, nullable: true}
|
||||
customerCode: {type: string}
|
||||
whCode: {type: string}
|
||||
status: {type: integer}
|
||||
orderCreateTime: {type: string, nullable: true}
|
||||
outboundTime: {type: string, nullable: true}
|
||||
skuVOList: {type: array, minItems: 1, items: {$ref: '#/components/schemas/SkuLine'}}
|
||||
sourceCode: {type: integer, enum: [200]}
|
||||
observedAt: {type: string, format: date-time}
|
||||
ProductStock:
|
||||
type: object
|
||||
required: [customerCode, whCode, productSku, productQuality]
|
||||
properties:
|
||||
customerCode: {type: string}
|
||||
whCode: {type: string}
|
||||
productSku: {type: string}
|
||||
productName: {type: string, nullable: true}
|
||||
productQuality: {type: integer}
|
||||
stkQty: {type: number, nullable: true}
|
||||
freezeQty: {type: number, nullable: true}
|
||||
useStkQty: {type: number, nullable: true}
|
||||
transitQty: {type: number, nullable: true}
|
||||
innerBatchNo: {type: string, nullable: true}
|
||||
outBatchNo: {type: string, nullable: true}
|
||||
uniqueKey4tenant: {type: string, nullable: true}
|
||||
OrderPage:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Pagination'}
|
||||
- type: object
|
||||
required: [records]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/OrderSummary'}}
|
||||
WarehousePage:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Pagination'}
|
||||
- type: object
|
||||
required: [records]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/Warehouse'}}
|
||||
InventoryPage:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Pagination'}
|
||||
- type: object
|
||||
required: [records]
|
||||
properties:
|
||||
records: {type: array, items: {$ref: '#/components/schemas/ProductStock'}}
|
||||
ProviderFailure:
|
||||
type: object
|
||||
required: [errorCode, retryable]
|
||||
required: [errorCode, retryable, egress]
|
||||
properties:
|
||||
egress: {$ref: '#/components/schemas/EgressMetadata'}
|
||||
denial:
|
||||
nullable: true
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/AuthorizationDenial'}
|
||||
description: Well-formed deterministic authority denial, alongside egress; null for other failures.
|
||||
errorCode: {type: string}
|
||||
retryable: {type: boolean}
|
||||
retryable: {type: boolean, description: Caller scheduling hint only; never authorizes implicit retries or reuse of an attempt. False for 429 and validation session failure.}
|
||||
upstreamStatus: {type: integer, nullable: true}
|
||||
sourceCode: {type: integer, nullable: true}
|
||||
Response:
|
||||
Envelope:
|
||||
type: object
|
||||
required: [code, message, data, timestamp]
|
||||
properties:
|
||||
code: {type: string}
|
||||
message: {type: string, description: Sanitized local message; never the raw provider response.}
|
||||
data:
|
||||
nullable: true
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/PageResult'}
|
||||
- {$ref: '#/components/schemas/ProviderFailure'}
|
||||
code: {type: string, description: '200 success; A0401 identity; A0422 validation; B0001 or S0503 provider/configuration failure.'}
|
||||
message: {type: string, description: Sanitized fixed local message, never raw supplier content.}
|
||||
requestId: {type: string, nullable: true}
|
||||
traceId: {type: string, nullable: true}
|
||||
timestamp: {type: string, format: date-time}
|
||||
OrderResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
nullable: true
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/OrderPage'}
|
||||
- {$ref: '#/components/schemas/ProviderFailure'}
|
||||
WarehouseResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
nullable: true
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/WarehousePage'}
|
||||
- {$ref: '#/components/schemas/ProviderFailure'}
|
||||
DetailResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
nullable: true
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/OrderDetail'}
|
||||
- {$ref: '#/components/schemas/ProviderFailure'}
|
||||
InventoryResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/Envelope'}
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
nullable: true
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/InventoryPage'}
|
||||
- {$ref: '#/components/schemas/ProviderFailure'}
|
||||
|
||||
Reference in New Issue
Block a user