fix(consignment): 内部库存候选过滤掉已无可用余量的现货

- 内部库存匹配提醒与订单侧手动指定现货候选都过滤 remaining_quantity = 0 的库存
- 与提交接口 matchConsignmentWorkOrderManually 的可用性口径保持一致,避免「弹窗有货、提交报错」
- 补充源码断言用例
This commit is contained in:
2026-11-15 15:15:29 +08:00
parent 92564cd731
commit 68fa2a575f
2 changed files with 38 additions and 2 deletions
@@ -251,7 +251,11 @@ export async function listWorkOrderInventoryMatchOptions(workOrderId: number | s
return { hasMatch: false, exactCount: 0, partialCount: 0, options: [] } return { hasMatch: false, exactCount: 0, partialCount: 0, options: [] }
} }
const fields = resolveCollectSubmittedFieldValues(workOrder) const fields = resolveCollectSubmittedFieldValues(workOrder)
const inventories = await listActiveConsignmentInventoriesForMatching() // 已被其它工单占用或已用尽的现货不能再出现在候选里:remaining_quantity=0 的库存
// 提交时会被匹配引擎过滤掉,列出来只会让客服点了才知道不可用。
const inventories = (await listActiveConsignmentInventoriesForMatching()).filter(
(inventory) => Number(inventory.remaining_quantity ?? 1) > 0,
)
const ranking = { exact: 0, partial: 1, conflict: 2 } const ranking = { exact: 0, partial: 1, conflict: 2 }
const options = listConsignmentMatchOptions(workOrder.product_name, inventories, { const options = listConsignmentMatchOptions(workOrder.product_name, inventories, {
system: fields.system, system: fields.system,
@@ -389,7 +393,11 @@ export async function checkWorkOrderInventoryMatches(workOrderId: number | strin
const fields = resolveCollectSubmittedFieldValues(workOrder) const fields = resolveCollectSubmittedFieldValues(workOrder)
const inventories = await listActiveConsignmentInventoriesForMatching() // 同上:无可用余量的现货(已被其它工单占用)不能作为「可直接履约」的提醒,
// 否则点进去只会被提交接口拒绝。
const inventories = (await listActiveConsignmentInventoriesForMatching()).filter(
(inventory) => Number(inventory.remaining_quantity ?? 1) > 0,
)
const matches = findMatchingPeacekeeperInventories(workOrder.product_name, inventories, { const matches = findMatchingPeacekeeperInventories(workOrder.product_name, inventories, {
system: fields.system, system: fields.system,
@@ -2511,6 +2511,34 @@ test('寄卖只做整单:拼单工单不得进入寄卖现货履约链路', as
) )
}) })
test('内部库存候选必须过滤掉无可用余量的现货:弹窗与提交口径一致', async () => {
const readFile = await import('node:fs/promises')
const src = await readFile.readFile(
new URL('./consignment-fulfillment-service.ts', import.meta.url),
'utf8',
)
// 订单侧「手动指定现货」全量列表
const optionsBody = src.slice(
src.indexOf('export async function listWorkOrderInventoryMatchOptions'),
src.indexOf('export async function listInventoryMatchableOrders'),
)
assert.ok(
optionsBody.includes('Number(inventory.remaining_quantity ?? 1) > 0'),
'订单侧候选现货必须过滤掉已被其它工单占用/用尽的库存',
)
// 发布时的内部库存提醒:不过滤会出现「弹窗说有货、点履约报请选择可用库存」
const matchesBody = src.slice(
src.indexOf('export async function checkWorkOrderInventoryMatches'),
src.indexOf('export async function fulfillWorkOrderWithConsignment'),
)
assert.ok(
matchesBody.includes('Number(inventory.remaining_quantity ?? 1) > 0'),
'内部库存提醒必须与提交接口使用同一套可用性口径(remaining_quantity > 0)',
)
})
test('寄卖履约必须写入真实 SUB 单号:只能取带 join 的预读库存', async () => { test('寄卖履约必须写入真实 SUB 单号:只能取带 join 的预读库存', async () => {
const readFile = await import('node:fs/promises') const readFile = await import('node:fs/promises')
const src = await readFile.readFile( const src = await readFile.readFile(