fix(outbound): submit selected carton marks for partial PDA picking
This commit is contained in:
@@ -112,6 +112,15 @@ export function pickOutboundTask(taskNo, request) {
|
||||
return overseasRequest('POST', `${OUTBOUND_BASE}/${encoded(taskNo)}/pick`, request)
|
||||
}
|
||||
|
||||
export function outboundPickPayload(item, position, packages) {
|
||||
return {
|
||||
outboundPalletItemId: item.outboundPalletItemId,
|
||||
inventoryPositionId: position.inventoryPositionId,
|
||||
packages: Number(packages),
|
||||
cartonMarks: position.cartonMark ? [position.cartonMark] : []
|
||||
}
|
||||
}
|
||||
|
||||
export function completeOutboundTask(taskNo, request) {
|
||||
return overseasRequest('POST', `${OUTBOUND_BASE}/${encoded(taskNo)}/complete`, request)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<view class="fulfillment-card summary-card"><view class="task-head"><text class="business-code">{{ current.taskNo || '—' }}</text><text class="status-badge">{{ statusLabel(current.status) }}</text></view><text class="task-meta">出库单 {{ current.outboundNo || '—' }} · {{ taskType(current) }}</text><view class="metrics"><view><text class="metric-value">{{ plannedPackages }}</text><text>计划箱数</text></view><view><text class="metric-value success">{{ pickedPackages }}</text><text>已拣箱数</text></view><view><text class="metric-value warning">{{ remainingPackages }}</text><text>待拣箱数</text></view></view><button class="link-button" :disabled="busy" @tap="closeTask">返回任务列表</button></view>
|
||||
|
||||
<view v-if="current.items.length" class="item-list">
|
||||
<view v-for="item in current.items" :key="item.palletNo || item.outboundPalletItemId" class="fulfillment-card item-card">
|
||||
<view v-for="item in current.items" :key="item.outboundPalletItemId" class="fulfillment-card item-card">
|
||||
<view class="task-head"><text class="business-code">{{ item.palletNo || '散件出库' }}</text><text>{{ item.pickedPackages }}/{{ item.plannedPackages }} 箱</text></view>
|
||||
<view v-for="position in item.positions" :key="businessLineKey(position)" class="outbound-line" :class="{ selected: selectedPosition === position }" @tap="selectPosition(item, position)">
|
||||
<text class="line-code">{{ lineBusinessCode(position) }}</text><text class="line-meta">{{ position.inboundCode || '无入仓码' }} · 已拣 {{ position.pickedPackages }} 箱 · 可拣 {{ position.availablePackages }} 箱</text>
|
||||
@@ -49,7 +49,7 @@
|
||||
<script>
|
||||
import PortalHeader from '@/components/PortalHeader.vue'
|
||||
import ScanTargetInput from '@/components/ScanTargetInput.vue'
|
||||
import { completeOutboundTask, getOutboundTask, listOutboundTasks, pickOutboundTask, resolveOutboundTask } from '@/api/fulfillment.js'
|
||||
import { completeOutboundTask, getOutboundTask, listOutboundTasks, outboundPickPayload, pickOutboundTask, resolveOutboundTask } from '@/api/fulfillment.js'
|
||||
import { fulfillment, fulfillmentIdempotencyKey, releaseFulfillmentKey, restoreFulfillmentDraft, updateFulfillmentDraft } from '@/stores/fulfillment.js'
|
||||
import { requireSession, session } from '@/stores/session.js'
|
||||
import { playErrorSound, playSuccessSound } from '@/utils/audio-feedback.js'
|
||||
@@ -105,8 +105,8 @@
|
||||
selectPosition(item, position) { if (!position || position.availablePackages <= 0) return; this.selectedItem = item; this.selectedPosition = position; updateFulfillmentDraft('outbound', { scanCode: this.lineBusinessCode(position), packages: Math.max(1, Math.min(item.plannedPackages - item.pickedPackages, position.availablePackages)) }) },
|
||||
async submitPick() {
|
||||
if (!this.canPick) return
|
||||
const businessCode = this.lineBusinessCode(this.selectedPosition); const payload = { taskNo: this.current.taskNo, businessCode, packages: Number(this.packages) }; const key = fulfillmentIdempotencyKey('outbound', 'pick', payload)
|
||||
await this.run('提交出库拣货', async () => { await pickOutboundTask(this.current.taskNo, { outboundPalletItemId: this.selectedItem.outboundPalletItemId, inventoryPositionId: this.selectedPosition.inventoryPositionId, packages: Number(this.packages), idempotencyKey: key.value }); this.current = await getOutboundTask(this.current.taskNo); releaseFulfillmentKey('outbound', key.signature); this.selectedItem = null; this.selectedPosition = null; updateFulfillmentDraft('outbound', { scanCode: '', packages: 1 }); this.successMessage = '本次出库拣货已记录'; playSuccessSound() })
|
||||
const payload = outboundPickPayload(this.selectedItem, this.selectedPosition, this.packages); const key = fulfillmentIdempotencyKey('outbound', 'pick', { taskNo: this.current.taskNo, ...payload })
|
||||
await this.run('提交出库拣货', async () => { await pickOutboundTask(this.current.taskNo, { ...payload, idempotencyKey: key.value }); this.current = await getOutboundTask(this.current.taskNo); releaseFulfillmentKey('outbound', key.signature); this.selectedItem = null; this.selectedPosition = null; updateFulfillmentDraft('outbound', { scanCode: '', packages: 1 }); this.successMessage = '本次出库拣货已记录'; playSuccessSound() })
|
||||
},
|
||||
async completeTask() {
|
||||
if (!this.canComplete) return
|
||||
|
||||
@@ -6,13 +6,24 @@ import { fulfillment, fulfillmentIdempotencyKey, releaseFulfillmentKey, resetFul
|
||||
import {
|
||||
completeDispatchPicking, completeOutboundTask, departDispatch, getDispatchTask, getOutboundTask,
|
||||
listDispatchTasks, listOutboundTasks, normalizeDispatchTask, normalizeOutboundTask,
|
||||
pickDispatchItem, pickOutboundTask, resolveOutboundTask
|
||||
pickDispatchItem, pickOutboundTask, resolveOutboundTask, outboundPickPayload
|
||||
} from '../src/api/fulfillment.js'
|
||||
import { session } from '../src/stores/session.js'
|
||||
import { toDispatchError } from '../src/utils/dispatch-error.js'
|
||||
|
||||
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8')
|
||||
|
||||
test('outbound partial pick submits the selected carton and distinguishes shared-pallet items', async () => {
|
||||
const first = outboundPickPayload({ outboundPalletItemId: '11' }, { inventoryPositionId: '21', cartonMark: 'BOX-A' }, '1')
|
||||
assert.deepEqual(first, { outboundPalletItemId: '11', inventoryPositionId: '21', packages: 1, cartonMarks: ['BOX-A'] })
|
||||
assert.notDeepEqual(first, outboundPickPayload({ outboundPalletItemId: '12' }, { inventoryPositionId: '22', cartonMark: 'BOX-B' }, 1))
|
||||
assert.deepEqual(outboundPickPayload({ outboundPalletItemId: '13' }, { inventoryPositionId: '23' }, 2).cartonMarks, [])
|
||||
const page = await read('../src/pages/outbound/outbound.vue')
|
||||
assert.match(page, /:key="item.outboundPalletItemId"/)
|
||||
assert.match(page, /outboundPickPayload\(this.selectedItem, this.selectedPosition, this.packages\)/)
|
||||
assert.match(page, /pickOutboundTask\(this.current.taskNo, \{ \.\.\.payload, idempotencyKey: key.value \}\)/)
|
||||
})
|
||||
|
||||
function storageMock() {
|
||||
const values = new Map()
|
||||
globalThis.uni = {
|
||||
|
||||
Reference in New Issue
Block a user