647 lines
33 KiB
YAML
647 lines
33 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Lingxing WMS Internal Read API
|
|
version: 1.0.0
|
|
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 or test. TEST business task creation is restricted by Lastleg to controlled commands and their legitimate derived work; the adapter does not schedule work. Provider-query 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; request starts obey the bound minStartInterval (VALIDATION 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 a VALIDATION externalExclusiveUntil;
|
|
the nonempty grant must match context.exclusiveGrantId. BUSINESS has no grant, session or root time cutoff;
|
|
explicit stops, persistent account protections and each short single-attempt permit remain enforced.
|
|
A BUSINESS rate-limit pause is recoverable 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 (also within externalExclusiveUntil for VALIDATION),
|
|
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/inventory-flow-page/query:
|
|
post:
|
|
summary: One frozen warehouse inventory-flow page
|
|
description: >-
|
|
Shared INVENTORY_FLOW permit, one upstream request, no automatic retry. Fixed warehouse and
|
|
inclusive Beijing start/end bounds at most one day, current>=1, size 1..1000, sorted by createTime asc.
|
|
Customer/SKU filters are absent. Lastleg validates persisted task/page binding, page counts,
|
|
duplicate IDs and ordering before admitting coverage. Only quantity/identity whitelist fields return.
|
|
Empty first-page current=1,size=10,total=0,pages=0,records=[] is normalized to the requested size.
|
|
parameters:
|
|
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [warehouseCode, startTime, endTime, current, size]
|
|
properties:
|
|
warehouseCode: {type: string, minLength: 1, maxLength: 64}
|
|
startTime: {type: string, format: date-time, description: Beijing local datetime without offset}
|
|
endTime: {type: string, format: date-time, description: Inclusive bound, at most one day after start}
|
|
current: {type: integer, minimum: 1}
|
|
size: {type: integer, minimum: 1, maximum: 1000}
|
|
responses:
|
|
'200':
|
|
description: Envelope of QueryPage with current/size/total/pages/records and source pagination evidence, or sanitized ProviderFailure. Rows retain string id, customerCode, whCode, productSku, cellNo, innerBatchNo, billNo, sourceNo, billType, productQuality, numeric bookQty/closeQty and string bookChangQty/createTime.
|
|
/internal/integrations/lingxing/wms/inventory-flow/query:
|
|
post:
|
|
summary: One SKU inventory-flow diagnostic page
|
|
description: >-
|
|
Calls stock/stockCellBook/page through the existing INVENTORY_FLOW permit. Exact warehouse/customer/SKU,
|
|
at most 31 days, current=1 and size=1000 fixed. No automatic next page or retry. Source quality and signed
|
|
quantities are preserved, not translated to inventory-snapshot quality. Source 11008 only rejects this optional
|
|
operation; authentication, rate-limit and uncertain-result account protection remain effective.
|
|
Source movement IDs must be strings. An empty first response with current=1, size=10, total=0,
|
|
pages=0 and records=[] is normalized to requested size=1000 while retaining sourceSize=10.
|
|
Other pagination mismatches remain errors.
|
|
parameters:
|
|
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [warehouseCode, customerCode, sku, startTime, endTime]
|
|
properties:
|
|
warehouseCode: {type: string, maxLength: 64}
|
|
customerCode: {type: string, maxLength: 64}
|
|
sku: {type: string, maxLength: 128}
|
|
startTime: {type: string, format: date-time, description: Beijing local datetime without offset}
|
|
endTime: {type: string, format: date-time, description: Beijing local datetime without offset}
|
|
responses:
|
|
'200':
|
|
description: Standard envelope with QueryPage or sanitized ProviderFailure. Flow rows retain id as string, customerCode, whCode, productSku, cellNo, innerBatchNo, billNo, sourceNo, billType, productQuality, numeric bookQty/closeQty, string bookChangQty/createTime. Unknown source fields remain null; no calculated inventory is published.
|
|
/internal/integrations/lingxing/wms/customers/query:
|
|
post:
|
|
summary: Query one page of customers using the existing account egress permit
|
|
description: Calls /openapi/v2/customer/list. BUSINESS MASTER_DATA tasks only; no retries or separate egress path. Dimensions and units remain separate; blanks are null.
|
|
parameters:
|
|
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/WarehouseQueryRequest'}
|
|
responses:
|
|
'200':
|
|
description: Standard envelope with one page or sanitized ProviderFailure.
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/CustomerResponse'}
|
|
/internal/integrations/lingxing/wms/products/query:
|
|
post:
|
|
summary: Query one page of products using the existing account egress permit
|
|
description: Calls /openapi/v2/product/page. BUSINESS MASTER_DATA tasks only; no retries or separate egress path. Dimensions and units remain separate; blanks are null.
|
|
parameters:
|
|
- {$ref: '#/components/parameters/LingxingEgressContext'}
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/ProductQueryRequest'}
|
|
responses:
|
|
'200':
|
|
description: Standard envelope with one page or sanitized ProviderFailure.
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/ProductResponse'}
|
|
/internal/integrations/lingxing/wms/egress/runtime:
|
|
get:
|
|
operationId: lingxingEgressRuntime
|
|
summary: Read sanitized configuration from the active egress gate
|
|
description: >-
|
|
Internal token authentication only. No provider, database, budget-authority, permit or persistence side effect.
|
|
Returns actual bound configuration, not a verified claim or a commit identity. Fingerprints use lowercase
|
|
SHA-256 of UTF-8 "selfop-runtime:v1:<domain>\n" plus the exact original nonblank value, without trimming.
|
|
Domains are source-account, grant and budget-authority. Missing/blank values yield null, never an empty-value hash.
|
|
security: [{InternalServiceToken: []}]
|
|
responses:
|
|
'200':
|
|
description: ApiResponse code 200 with runtime snapshot, or A0401 for missing/invalid internal token
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
code: {type: string}
|
|
data: {$ref: '#/components/schemas/EgressRuntimeSnapshot'}
|
|
/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 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:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/QueryRequest'}
|
|
responses:
|
|
'200':
|
|
description: Standard envelope with OrderPage or sanitized ProviderFailure.
|
|
content:
|
|
application/json:
|
|
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:
|
|
CustomerPage:
|
|
allOf:
|
|
- {$ref: '#/components/schemas/Pagination'}
|
|
- type: object
|
|
required: [records]
|
|
properties:
|
|
records: {type: array, items: {$ref: '#/components/schemas/Customer'}}
|
|
CustomerResponse:
|
|
allOf:
|
|
- {$ref: '#/components/schemas/Envelope'}
|
|
- type: object
|
|
properties:
|
|
data:
|
|
nullable: true
|
|
oneOf:
|
|
- {$ref: '#/components/schemas/CustomerPage'}
|
|
- {$ref: '#/components/schemas/ProviderFailure'}
|
|
ProductPage:
|
|
allOf:
|
|
- {$ref: '#/components/schemas/Pagination'}
|
|
- type: object
|
|
required: [records]
|
|
properties:
|
|
records: {type: array, items: {$ref: '#/components/schemas/Product'}}
|
|
ProductResponse:
|
|
allOf:
|
|
- {$ref: '#/components/schemas/Envelope'}
|
|
- type: object
|
|
properties:
|
|
data:
|
|
nullable: true
|
|
oneOf:
|
|
- {$ref: '#/components/schemas/ProductPage'}
|
|
- {$ref: '#/components/schemas/ProviderFailure'}
|
|
ProductQueryRequest:
|
|
type: object
|
|
required: [current, size]
|
|
properties:
|
|
current: {type: integer, minimum: 1}
|
|
size: {type: integer, minimum: 1, maximum: 100}
|
|
Customer:
|
|
type: object
|
|
required: [customerCode]
|
|
properties:
|
|
customerCode: {type: string}
|
|
customerName: {type: string, nullable: true}
|
|
status: {type: string, nullable: true}
|
|
Product:
|
|
type: object
|
|
required: [customerCode, sku]
|
|
properties:
|
|
customerCode: {type: string}
|
|
sku: {type: string}
|
|
productName: {type: string, nullable: true}
|
|
length: {type: number, nullable: true}
|
|
width: {type: number, nullable: true}
|
|
height: {type: number, nullable: true}
|
|
wmsLength: {type: number, nullable: true}
|
|
wmsWidth: {type: number, nullable: true}
|
|
wmsHeight: {type: number, nullable: true}
|
|
sizeUnit: {type: string, nullable: true}
|
|
wmsSizeUnit: {type: string, nullable: true}
|
|
EgressRuntimeSnapshot:
|
|
type: object
|
|
additionalProperties: false
|
|
required: [schemaVersion, service, observedAt, mode, environment, continuousEnabled, grantPresent, intervalMs, permitMaxSeconds, providerEnabled]
|
|
properties:
|
|
schemaVersion: {type: integer, enum: [1]}
|
|
service: {type: string, enum: [integration]}
|
|
observedAt: {type: string, format: date-time}
|
|
mode: {type: string, enum: [OFF, VALIDATION, BUSINESS]}
|
|
environment: {type: string}
|
|
continuousEnabled: {type: boolean}
|
|
sourceAccountFingerprint: {type: string, nullable: true, pattern: '^[a-f0-9]{64}$'}
|
|
grantPresent: {type: boolean}
|
|
grantFingerprint: {type: string, nullable: true, pattern: '^[a-f0-9]{64}$'}
|
|
intervalMs:
|
|
oneOf: [{type: integer, format: int64}, {type: string, pattern: '^[0-9]+$'}]
|
|
description: Actual bound interval; shared long-value JSON serialization may encode it as a decimal string.
|
|
permitMaxSeconds: {type: integer, enum: [30]}
|
|
providerEnabled: {type: boolean}
|
|
budgetAuthorityFingerprint: {type: string, nullable: true, pattern: '^[a-f0-9]{64}$'}
|
|
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, CUSTOMERS, PRODUCTS, INVENTORY_FLOW]
|
|
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 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 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, customerCode, whCode, status]
|
|
properties:
|
|
deliveryNo: {type: string}
|
|
sourceNo: {type: string, nullable: true}
|
|
customerCode: {type: string}
|
|
whCode: {type: string}
|
|
status: {type: integer}
|
|
createTime: {type: string, nullable: true}
|
|
outboundTime: {type: string, nullable: true}
|
|
productList:
|
|
type: array
|
|
nullable: true
|
|
description: Per-SKU list quantities; missing items, SKU or qty require one detail supplement for this order. Zero is a known quantity.
|
|
items:
|
|
type: object
|
|
properties:
|
|
productSku: {type: string, nullable: true}
|
|
productName: {type: string, nullable: true}
|
|
qty: {type: number, nullable: true}
|
|
Warehouse:
|
|
type: object
|
|
required: [whCode, warehouseType, status]
|
|
properties:
|
|
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, 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, 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}
|
|
Envelope:
|
|
type: object
|
|
required: [code, message, data, timestamp]
|
|
properties:
|
|
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'}
|