Files
pda-overseas-uniapp/tests/fulfillment-stock-commands.test.mjs

56 lines
3.6 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { pickDispatchItem, pickOutboundTask, pickOutboundPallet, confirmCargoDiscard } from '../src/api/fulfillment.js'
import { session } from '../src/stores/session.js'
// 模拟当前生产:仓租预检查接口不存在,既有库存命令仍正常受理。
function transport(failure) {
const calls = []
session.apiBase = '/api'; session.token = 'overseas-token'
globalThis.uni = { request(options) {
calls.push({ method: options.method, url: options.url, data: options.data })
if (failure?.network) return options.fail({ errMsg: 'network down' })
const error = options.url.includes('/storage-rent/') ? { code: 'A0404', message: 'Resource not found' } : failure
options.success({ statusCode: 200, data: error || { code: '200', data: { success: true } }, header: {} })
} }
return calls
}
const dispatch = { recordVersion: '9007199254740993', positionId: '9007199254740994', packages: 21, cartonMark: null, productQuantity: 0, idempotencyKey: 'dispatch-key' }
const outbound = { outboundPalletItemId: '9007199254740996', inventoryPositionId: null, packages: 1, cartonMarks: ['RETURN-BOX-1'], skuCode: 'SKU-A', productQuantity: 5, idempotencyKey: 'outbound-key' }
const pallet = { idempotencyKey: 'pallet-key' }
const discard = { lines: [{ itemId: '9007199254740993', actualPackages: 2 }], photoFileIds: ['101'], scannedCartonMarks: ['BOX-1'], confirmAllCartons: false, idempotencyKey: 'discard-key' }
const modes = [
{ name: 'dispatch', path: '/dispatches/DSP%2F1/items/9007199254740995/pick', body: dispatch, submit: () => pickDispatchItem('DSP/1', '9007199254740995', dispatch) },
{ name: 'outbound', path: '/outbound-tasks/TASK%2F1/pick', body: outbound, submit: () => pickOutboundTask('TASK/1', outbound) },
{ name: 'pallet', path: '/outbound-tasks/TASK%2F1/pallets/DP%2F1/pick', body: pallet, submit: () => pickOutboundPallet('TASK/1', 'DP/1', pallet) },
{ name: 'discard', path: '/cargo-discards/CD%2F1/pallets/P%2F1/confirm', body: discard, submit: () => confirmCargoDiscard('CD/1', 'P/1', discard.lines, discard.photoFileIds, discard.scannedCartonMarks, false, { idempotencyKey: discard.idempotencyKey }) }
]
for (const mode of modes) {
test(`${mode.name} works without the unpublished rent endpoint and preserves its stock payload`, async () => {
const calls = transport()
await mode.submit()
assert.deepEqual(calls, [{ method: 'POST', url: '/api/pda/v1/last-leg' + mode.path, data: mode.body }])
})
test(`${mode.name} propagates stock failures without fallback or automatic resubmission`, async () => {
for (const failure of [{ code: 'A0404', message: 'missing' }, { code: 'A0409', message: 'conflict' }, { code: 'S0503', message: 'unavailable' }, { network: true }]) {
const calls = transport(failure)
await assert.rejects(mode.submit(), error => failure.network ? error.network === true : error.code === failure.code)
assert.equal(calls.length, 1)
assert.equal(calls[0].url, '/api/pda/v1/last-leg' + mode.path)
assert.deepEqual(calls[0].data, mode.body)
}
})
}
test('invalid dispatch version and missing command keys fail before any request', async () => {
const calls = transport()
await assert.rejects(pickDispatchItem('DSP-1', '11', { idempotencyKey: 'key' }), /版本/)
await assert.rejects(pickDispatchItem('DSP-1', '11', { recordVersion: 1 }), /标识/)
await assert.rejects(pickOutboundTask('TASK-1', {}), /标识/)
await assert.rejects(pickOutboundPallet('TASK-1', 'DP-1', {}), /标识/)
await assert.rejects(confirmCargoDiscard('CD-1', 'P-1', [], [], [], false, {}), /标识/)
assert.equal(calls.length, 0)
})