106 lines
4.8 KiB
YAML
106 lines
4.8 KiB
YAML
openapi: 3.0.3
|
|||
|
|
info:
|
||
|
|
title: Internal bounded self-operated quantity diagnostics
|
||
|
|
version: 1.0.0
|
||
|
|
paths:
|
||
|
|
/internal/lastleg/self-operated-analytics/quantity-diagnostics/orders:
|
||
|
|
post:
|
||
|
|
operationId: receiveSelfopQuantityDiagnosticOrder
|
||
|
|
description: >-
|
||
|
|
Internal service-token only; never routed through Gateway. One complete paired order per request.
|
||
|
|
Quantities are evidence only. Session scope and UTC time interval are frozen by server configuration.
|
||
|
|
Maximum 100 orders, 2000 SKU rows and 2097152 canonical UTF8 bytes per session;
|
||
|
|
200 SKU rows and 262144 wire/canonical bytes per request; at most 30 minutes.
|
||
|
|
First known forecast/actual difference closes capture regardless of comparison classification.
|
||
|
|
Same identity and canonical evidence is idempotent, including after closure; changed evidence is 409.
|
||
|
|
security:
|
||
|
|
- internalServiceToken: []
|
||
|
|
requestBody:
|
||
|
|
required: true
|
||
|
|
content:
|
||
|
|
application/json:
|
||
|
|
schema:
|
||
|
|
$ref: '#/components/schemas/PairedOrder'
|
||
|
|
responses:
|
||
|
|
'200':
|
||
|
|
description: Diagnostic receipt in the standard ApiResponse wrapper; code is string 200.
|
||
|
|
content:
|
||
|
|
application/json:
|
||
|
|
schema:
|
||
|
|
type: object
|
||
|
|
properties:
|
||
|
|
code: { type: string, example: '200' }
|
||
|
|
data: { $ref: '#/components/schemas/Receipt' }
|
||
|
|
'400': { description: 'Invalid JSON, unknown fields, invalid scope/evidence, duplicate SKU or request limit.' }
|
||
|
|
'401': { description: Invalid internal service token. }
|
||
|
|
'409': { description: Session configuration changed or order identity reused with different evidence. }
|
||
|
|
'503': { description: Internal service token unconfigured or diagnostic storage unavailable. }
|
||
|
|
components:
|
||
|
|
securitySchemes:
|
||
|
|
internalServiceToken:
|
||
|
|
type: apiKey
|
||
|
|
in: header
|
||
|
|
name: X-Internal-Service-Token
|
||
|
|
schemas:
|
||
|
|
PairedOrder:
|
||
|
|
type: object
|
||
|
|
additionalProperties: false
|
||
|
|
required: [diagnosticSessionId, collectionSessionId, rootTaskId, sourceAccount, warehouseCode, ownerCode, orderNo, listObservation, detailObservation, skus]
|
||
|
|
properties:
|
||
|
|
diagnosticSessionId: { type: string, maxLength: 128 }
|
||
|
|
collectionSessionId: { type: string, maxLength: 128 }
|
||
|
|
rootTaskId: { type: string, maxLength: 128 }
|
||
|
|
sourceAccount: { type: string, maxLength: 64 }
|
||
|
|
warehouseCode: { type: string, maxLength: 64 }
|
||
|
|
ownerCode: { type: string, maxLength: 128 }
|
||
|
|
orderNo: { type: string, maxLength: 128 }
|
||
|
|
listObservation: { $ref: '#/components/schemas/Observation' }
|
||
|
|
detailObservation: { $ref: '#/components/schemas/Observation' }
|
||
|
|
skus:
|
||
|
|
type: array
|
||
|
|
minItems: 1
|
||
|
|
maxItems: 200
|
||
|
|
description: Union of list/detail SKUs; duplicate source lines aggregated, unknown never zero-filled.
|
||
|
|
items: { $ref: '#/components/schemas/Sku' }
|
||
|
|
Observation:
|
||
|
|
type: object
|
||
|
|
additionalProperties: false
|
||
|
|
required: [observedAt, attemptId, skuSetComplete]
|
||
|
|
properties:
|
||
|
|
status: { type: string, nullable: true, maxLength: 32 }
|
||
|
|
outboundTime:
|
||
|
|
type: string
|
||
|
|
nullable: true
|
||
|
|
maxLength: 32
|
||
|
|
description: Original Asia/Shanghai source text, null if absent; not reinterpreted as another timezone.
|
||
|
|
observedAt: { type: string, format: date-time }
|
||
|
|
attemptId: { type: string, maxLength: 128 }
|
||
|
|
skuSetComplete: { type: boolean }
|
||
|
|
Sku:
|
||
|
|
type: object
|
||
|
|
additionalProperties: false
|
||
|
|
required: [sku, listPresent, detailPresent]
|
||
|
|
properties:
|
||
|
|
sku: { type: string, maxLength: 128 }
|
||
|
|
listQty: { type: number, nullable: true, minimum: 0, multipleOf: 0.000001 }
|
||
|
|
forecastQty: { type: number, nullable: true, minimum: 0, multipleOf: 0.000001 }
|
||
|
|
actualQty: { type: number, nullable: true, minimum: 0, multipleOf: 0.000001 }
|
||
|
|
listPresent: { type: boolean }
|
||
|
|
detailPresent: { type: boolean }
|
||
|
|
Receipt:
|
||
|
|
type: object
|
||
|
|
required: [outcome, acceptedOrders, acceptedSkuRows, acceptedBytes]
|
||
|
|
properties:
|
||
|
|
outcome: { type: string, enum: [ACCEPTED, DUPLICATE, STOPPED] }
|
||
|
|
comparison:
|
||
|
|
type: string
|
||
|
|
nullable: true
|
||
|
|
enum: [SKU_SET_MISMATCH, QUANTITY_UNKNOWN, FORECAST_ACTUAL_DIFFERENCE, ALL_EQUAL, LIST_QUANTITY_DIFFERENCE]
|
||
|
|
stopReason:
|
||
|
|
type: string
|
||
|
|
nullable: true
|
||
|
|
enum: [DISABLED, NOT_STARTED, EXPIRED, LIMIT_REACHED, FORECAST_ACTUAL_DIFFERENCE]
|
||
|
|
acceptedOrders: { type: integer }
|
||
|
|
acceptedSkuRows: { type: integer }
|
||
|
|
acceptedBytes: { type: integer, format: int64, description: Canonical whitelist JSON UTF8 bytes persisted in this session. }
|