184 lines
11 KiB
YAML
184 lines
11 KiB
YAML
openapi: 3.0.3
|
||
info:
|
||
title: Cargo discard PDA photo evidence
|
||
version: 1.0.0
|
||
description: >-
|
||
Each approved pallet requires 1–20 JPG/PNG photos before actual disposal confirmation.
|
||
Uploads persist as drafts and recover through the PDA list endpoint. Confirmation binds
|
||
selected photos in the same transaction as inventory deduction. Completed quantities and
|
||
photo sets are immutable; identical replay does not deduct stock or create evidence again.
|
||
Platform and merchant details expose only submitted photos, including photos of completed
|
||
pallets while other pallets are still pending. Historic applications are not backfilled.
|
||
Approval atomically creates one DISCARD_OUTBOUND document and planned SKU/pallet snapshots.
|
||
Platform/merchant summary and PDA pallet task include nullable outboundNo. PDA completion
|
||
synchronizes actual quantities and OUTBOUNDED status without a second inventory deduction.
|
||
Cancellation must use the discard application workflow. PDA resolve optionally accepts
|
||
discardNo together with palletNo; ambiguous scans require selection of a discard application.
|
||
Candidates include INVENTORY positions from every document type with available warehouse stock,
|
||
plus RETURN_CARTON sources; one-click dropship orders and positions are excluded.
|
||
Create items identify exactly one of returnCartonId or inventoryPositionId and carry selected cartonIds for partial whole-carton disposal; quantities must match those IDs.
|
||
RETURN_CARTON selections consume every SKU in the selected physical carton.
|
||
Candidates return cartons, cartonSelectionSupported and cartonSelectionBlockReason.
|
||
Stock without complete carton/pallet ownership remains available for full disposal only.
|
||
PDA tasks with real cartonMarks use CARTON scanMode, including full bound-pallet tasks.
|
||
Every distinct selected carton mark must be scanned; confirmAllCartons cannot bypass this check.
|
||
Ordinary stock without selected carton marks uses PALLET mode and actual carton quantities.
|
||
Each SKU returns allowedCartonMarks from the source inbound cartons or net stock-in ledger;
|
||
PDA scans must match this allowlist immediately and confirmation revalidates ownership.
|
||
The loose group uses 散箱 as its API path key, never as a scan code.
|
||
The application may select a subset of available cartons. PDA must finish every selected carton;
|
||
short actual quantities are rejected. At least one photo remains required.
|
||
Partial bound-pallet tasks use CARTON scanMode with the real palletNo and selected cartonMarks.
|
||
PDA completion leaves the application in PDA_COMPLETED (waiting for customer confirmation).
|
||
Only the authenticated merchant may confirm completion after reviewing submitted PDA photos.
|
||
Confirmation changes the application to COMPLETED, records customerConfirmedAt, and never deducts
|
||
inventory again. Identical repeated confirmation preserves the first timestamp and history.
|
||
Platform users cannot close the application on behalf of the customer.
|
||
security:
|
||
- bearerAuth: []
|
||
paths:
|
||
/api/pda/v1/last-leg/cargo-discards:
|
||
get:
|
||
summary: 查询当前绑定仓已审核废弃任务
|
||
description: 返回 PalletTask 数组;skus.allowedCartonMarks 为当前申请明细原入仓库存允许扫描的箱唛,无归属的箱唛不得计数或确认;未知箱唛不降级为自由扫码。
|
||
responses:
|
||
'200': { description: 当前绑定仓废弃任务及明细箱唛白名单 }
|
||
/api/pda/v1/last-leg/cargo-discards/resolve:
|
||
post:
|
||
summary: 按废弃单及托盘定位任务
|
||
description: 返回 PalletTask,包括各明细的 allowedCartonMarks 供即时扫码归属校验;提交确认时服务端再次核验。
|
||
responses:
|
||
'200': { description: 当前废弃单托盘任务及明细箱唛白名单 }
|
||
/api/merchant/v1/last-leg/cargo-discards/{discardNo}/confirm-completion:
|
||
parameters:
|
||
- $ref: '#/components/parameters/DiscardNo'
|
||
post:
|
||
summary: 客户确认废弃完结
|
||
description: >-
|
||
Customer scope is taken only from the authenticated merchant token.
|
||
Requires PDA_COMPLETED; repeated COMPLETED calls return the existing detail.
|
||
No request customerId, stock adjustment, or new photo upload is accepted.
|
||
The client shows submitted PDA photos before the customer confirms.
|
||
x-permissions: [merchant:overseas-warehouse:discard:confirm]
|
||
responses:
|
||
'200': { description: ApiResponse with updated Detail; summary contains customerConfirmedAt }
|
||
/api/pda/v1/last-leg/cargo-discards/{discardNo}/pallets/{palletNo}/photos/files:
|
||
parameters:
|
||
- $ref: '#/components/parameters/DiscardNo'
|
||
- $ref: '#/components/parameters/PalletNo'
|
||
post:
|
||
summary: Upload an approved, unfinished pallet photo (PDA bound warehouse only)
|
||
x-permissions: [lastleg:pda:operate, ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
required: [file]
|
||
properties:
|
||
file: { type: string, format: binary, description: Non-empty JPG/PNG up to 10 MiB with image signature validation }
|
||
responses:
|
||
'200': { description: ApiResponse with uploaded Photo metadata; business errors use body code }
|
||
get:
|
||
summary: Recover all uploaded photos for this application and pallet
|
||
x-permissions: [lastleg:pda:operate, ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR]
|
||
responses:
|
||
'200': { description: ApiResponse with a Photo array, including unsubmitted uploads }
|
||
/api/pda/v1/last-leg/cargo-discards/{discardNo}/pallets/{palletNo}/photos/files/{fileId}/download:
|
||
parameters:
|
||
- $ref: '#/components/parameters/DiscardNo'
|
||
- $ref: '#/components/parameters/PalletNo'
|
||
- $ref: '#/components/parameters/FileId'
|
||
get:
|
||
summary: Download a photo associated with this pallet in the PDA bound warehouse
|
||
x-permissions: [lastleg:pda:operate, ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR]
|
||
responses:
|
||
'200': { description: Inline JPG/PNG bytes with Cache-Control no-store }
|
||
/api/pda/v1/last-leg/cargo-discards/{discardNo}/pallets/{palletNo}/confirm:
|
||
parameters:
|
||
- $ref: '#/components/parameters/DiscardNo'
|
||
- $ref: '#/components/parameters/PalletNo'
|
||
post:
|
||
summary: Confirm actual disposal with owned pallet photos
|
||
description: PalletTask.skus返回actualQuantityEditable布尔值。仅普通库存未保存具体箱唛时为true(表示现场扫码计数,不能手填数量),PDA展示备注和相关托盘,扫描现场箱唛自动累计实际废弃箱数;库存和费用按实际数结算,未废弃预留释放。已完成任务相同数量重放不重复扣减,修改数量拒绝。
|
||
x-permissions: [lastleg:pda:operate, ROLE_OVERSEAS_WAREHOUSE_PDA_OPERATOR]
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
required: [lines, photoFileIds]
|
||
properties:
|
||
lines:
|
||
type: array
|
||
minItems: 1
|
||
items:
|
||
type: object
|
||
required: [itemId, actualPackages]
|
||
properties:
|
||
itemId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||
scannedCartonMarks: { type: array, uniqueItems: true, items: { type: string, minLength: 1, maxLength: 128 }, description: 无关联库存现场箱唛清单,数量须与actualPackages一致,整单跨托盘不重复;每个箱唛必须能溯源到本单明细原入仓库存,未知或外单箱唛拒绝;详情以actualCartonMarks回显 }
|
||
actualPackages: { type: integer, minimum: 0, description: 无精确箱唛对应关系的普通库存允许0至plannedPackages的实际箱数,剩余预留释放;有具体选箱的明细必须等于plannedPackages }
|
||
scannedCartonMarks:
|
||
type: array
|
||
uniqueItems: true
|
||
items: { type: string }
|
||
description: All task cartonMarks must be scanned exactly once, regardless of confirmAllCartons.
|
||
confirmAllCartons:
|
||
type: boolean
|
||
default: false
|
||
deprecated: true
|
||
description: Compatibility field only; does not bypass individual carton scans. Photos remain mandatory.
|
||
photoFileIds:
|
||
type: array
|
||
minItems: 1
|
||
maxItems: 20
|
||
uniqueItems: true
|
||
items: { type: string, pattern: '^[1-9][0-9]*$' }
|
||
responses:
|
||
'200': { description: ApiResponse containing the completed PalletTask; skus.allowedCartonMarks provides the source-scoped scan allowlist for immediate PDA validation; conflicts use business body code }
|
||
/api/platform/v1/last-leg/cargo-discards/{discardNo}/photos/files/{fileId}/download:
|
||
parameters:
|
||
- $ref: '#/components/parameters/DiscardNo'
|
||
- $ref: '#/components/parameters/FileId'
|
||
- name: customerId
|
||
in: query
|
||
required: true
|
||
schema: { type: string, pattern: '^[1-9][0-9]*$' }
|
||
get:
|
||
summary: Download a submitted photo after application/customer ownership validation
|
||
x-permissions: [platform:overseas-warehouse:discard:list]
|
||
responses:
|
||
'200': { description: Inline JPG/PNG bytes with Cache-Control no-store }
|
||
/api/merchant/v1/last-leg/cargo-discards/{discardNo}/photos/files/{fileId}/download:
|
||
parameters:
|
||
- $ref: '#/components/parameters/DiscardNo'
|
||
- $ref: '#/components/parameters/FileId'
|
||
get:
|
||
summary: Download a submitted photo belonging to the authenticated customer only
|
||
x-permissions: [merchant:overseas-warehouse:discard:list]
|
||
responses:
|
||
'200': { description: Inline JPG/PNG bytes with Cache-Control no-store; no customer override allowed }
|
||
components:
|
||
securitySchemes:
|
||
bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
|
||
parameters:
|
||
DiscardNo: { name: discardNo, in: path, required: true, schema: { type: string } }
|
||
PalletNo: { name: palletNo, in: path, required: true, schema: { type: string } }
|
||
FileId: { name: fileId, in: path, required: true, schema: { type: string, pattern: '^[1-9][0-9]*$' } }
|
||
schemas:
|
||
Photo:
|
||
type: object
|
||
required: [fileId, palletNo, fileName, contentType, sizeBytes, operatorId, createdAt]
|
||
properties:
|
||
fileId: { type: string }
|
||
palletNo: { type: string }
|
||
fileName: { type: string }
|
||
contentType: { type: string, enum: [image/jpeg, image/png] }
|
||
sizeBytes: { type: integer, format: int64, maximum: 10485760 }
|
||
operatorId: { type: string }
|
||
createdAt: { type: string, format: date-time }
|
||
submittedAt: { type: string, format: date-time, nullable: true }
|