fix(firstleg): preserve sealed pallet identity in atomic PDA picking

This commit is contained in:
2026-09-09 12:33:31 +08:00
parent 44ac24a9e2
commit ac3ce3703e
12 changed files with 323 additions and 47 deletions
@@ -201,13 +201,17 @@ components:
items: {$ref: '#/components/schemas/PickItem'}
PickItem:
type: object
required: [id, loadingPlanItemId, tenantId, inboundId, inboundDetailId, boxCodes, inventoryResources, plannedPackageCount, pickedPackageCount, itemStatus, version]
required: [id, loadingPlanItemId, tenantId, inboundId, inboundDetailId, unitType, palletId, palletNo, indivisible, boxCodes, inventoryResources, plannedPackageCount, pickedPackageCount, itemStatus, version]
properties:
id: {type: integer, format: int64}
loadingPlanItemId: {type: integer, format: int64}
tenantId: {type: integer, format: int64, description: Hidden isolation key for subsequent PDA evidence calls}
inboundId: {type: integer, format: int64}
inboundDetailId: {type: integer, format: int64}
unitType: {type: string, enum: [PACKAGE, SEALED_PALLET], description: Authoritative loading plan unit; SEALED_PALLET must use the whole-pallet pick command}
palletId: {type: integer, format: int64, nullable: true, description: Dropship sealed pallet identity; not the weighing pallet in inventoryResources}
palletNo: {type: string, nullable: true, description: System-issued DP pallet code from the loading plan item}
indivisible: {type: boolean, description: Whole-pallet indivisibility from the loading plan item}
orderNo: {type: string, nullable: true}
inboundCode: {type: string, nullable: true}
cargoName: {type: string, nullable: true}
@@ -273,14 +277,16 @@ components:
items: {$ref: '#/components/schemas/BatchItemRequest'}
BatchItemRequest:
type: object
description: PICK_PALLET submits every pickItem of the scanned DP pallet with its own version in the same atomic batch. No carton quantities or skip reason are accepted; the server verifies the complete SEALED pallet. Scanning only changes the device draft.
required: [itemId, action, version]
properties:
itemId: {type: integer, format: int64, minimum: 1}
action: {type: string, enum: [PICK, PARTIAL, SKIP]}
action: {type: string, enum: [PICK, PARTIAL, SKIP, PICK_PALLET]}
pickedPackageCount: {type: integer, minimum: 1, description: Incremental count required by PICK}
finalPickedPackageCount: {type: integer, minimum: 1, description: Final actual count required by PARTIAL}
version: {type: integer, minimum: 0}
reason: {type: string, maxLength: 500, description: Required by SKIP}
palletNo: {type: string, nullable: true, pattern: '^DP-[0-9]{6}-[0-9]{4}$', description: Required only by PICK_PALLET; ordinary carton actions must omit it}
ReviewRequest:
type: object
required: [expectedTaskVersion, operationId]
@@ -313,7 +319,7 @@ components:
remark: {type: string, maxLength: 500}
InventorySnapshot:
type: object
required: [taskId, loadingPlanId, containerBookingId, cabinetNo, taskVersion, warehouseId, capturedAt, snapshotToken, inbounds]
required: [taskId, loadingPlanId, containerBookingId, cabinetNo, taskVersion, warehouseId, capturedAt, snapshotToken, inbounds, units]
properties:
taskId: {type: integer, format: int64}
loadingPlanId: {type: integer, format: int64}
@@ -327,6 +333,21 @@ components:
inbounds:
type: array
items: {$ref: '#/components/schemas/InboundInventory'}
units:
type: array
description: Authoritative plan units ordered by pickItemId and included in snapshotToken; one inbound may contain multiple sealed pallets
items: {$ref: '#/components/schemas/InventoryUnit'}
InventoryUnit:
type: object
required: [pickItemId, loadingPlanItemId, inboundId, unitType, palletId, palletNo, indivisible]
properties:
pickItemId: {type: integer, format: int64}
loadingPlanItemId: {type: integer, format: int64}
inboundId: {type: integer, format: int64}
unitType: {type: string, enum: [PACKAGE, SEALED_PALLET]}
palletId: {type: integer, format: int64, nullable: true}
palletNo: {type: string, nullable: true}
indivisible: {type: boolean}
InboundInventory:
type: object
required: [inboundId, availablePackageCount, resources]