fix(consignment): 拼单份额验收收官补寄卖结算钩子 + 手动匹配弹窗三处复核遗留
- acceptWorkOrderShareAndSettle 最后一个份额把母单转 accepted 的分支, 此前不释放发布押金也不结算供货货款(两钩子只在统一验收里): 现在同口径补上;供货货款传 assignedWorkerId=0(拼单母单无单一接单人, 份额打手已各自按 share_reward 结算,不会重复付款) - 手动匹配弹窗:race_condition/unavailable/spec_mismatch/partial_requires_confirm 四个错误码清空已选并自动重拉列表,数据过期不再死循环撞错 - 手动匹配弹窗库存侧:keyword+pageSize100 透传后端(原来 keyword 是死参数、 只拉 50 条),300ms 防抖后端搜索;无供货打手时禁用指派选项并在提交前 再拦一道(原来必 400 死路);选中订单回显 workerId/workerName - 凭证核销反馈抽共享 utils/voucher-consume,WorkOrdersPanel 与弹窗共用, 口径不再漂移(弹窗顺带获得"已提前核销 N 张"提示) - docs/寄卖系统优化方案.md 记录批次 V 后端 477(+4)/ 前端 50(+1)测试全绿,typecheck / lint / format / check:sql 通过
This commit is contained in:
@@ -647,6 +647,42 @@ export async function acceptWorkOrderShareAndSettle(input: {
|
||||
`UPDATE work_orders SET status = 'accepted', accepted_at = $1, updated_at = $1 WHERE id = $2`,
|
||||
[input.now, input.workOrderId],
|
||||
)
|
||||
|
||||
// 最后一个份额把母单转成已验收时,必须与统一验收(acceptWorkOrderAndSettle)同口径补寄卖钩子,
|
||||
// 否则这条路径下发布押金永久挂死、供货卖家拿不到货款。
|
||||
const shareMaterial =
|
||||
typeof workOrder.material_json === 'string'
|
||||
? (() => {
|
||||
try {
|
||||
return JSON.parse(workOrder.material_json) as Record<string, unknown>
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
})()
|
||||
: workOrder.material_json && typeof workOrder.material_json === 'object'
|
||||
? (workOrder.material_json as Record<string, unknown>)
|
||||
: {}
|
||||
const shareConsignment =
|
||||
shareMaterial.consignment && typeof shareMaterial.consignment === 'object'
|
||||
? (shareMaterial.consignment as Record<string, unknown>)
|
||||
: null
|
||||
const shareSourceSubmissionId = shareConsignment?.sourceSubmissionId
|
||||
if (shareSourceSubmissionId) {
|
||||
await releaseConsignmentPublishDepositBySubmissionWithClient(client, {
|
||||
submissionId: String(shareSourceSubmissionId),
|
||||
note: `寄卖拼单份额全部验收完成释放发布押金 #${input.workOrderId}`,
|
||||
now: input.now,
|
||||
})
|
||||
}
|
||||
// 拼单母单没有单一接单人(份额打手已在上面各自按 share_reward 结算),
|
||||
// 传 0 让供货货款必走本渠道,不会与份额报酬重复。
|
||||
await settleConsignmentSupplierPayoutByWorkOrderWithClient(client, {
|
||||
workOrderId: input.workOrderId,
|
||||
assignedWorkerId: 0,
|
||||
rewardUnfreezeEnabled: input.rewardUnfreezeEnabled,
|
||||
unfreezeDays: input.unfreezeDays,
|
||||
now: input.now,
|
||||
})
|
||||
}
|
||||
await createWorkOrderEventWithClient(client, {
|
||||
workOrderId: input.workOrderId,
|
||||
|
||||
@@ -107,3 +107,24 @@ test('指派链路必须按“指派对象===供货卖家”判定报酬渠道
|
||||
'指派报酬必须传 assigneeIsSupplier,且与供货卖家(inventory.worker_id)比对',
|
||||
)
|
||||
})
|
||||
|
||||
test('拼单份额全部验收(母单转已验收)也必须补寄卖钩子,否则货款漏付、押金挂死', async () => {
|
||||
const source = await readFile(SETTLEMENT_REPO, 'utf8')
|
||||
const start = source.indexOf('export async function acceptWorkOrderShareAndSettle')
|
||||
assert.ok(start > 0, '未找到份额单独验收函数')
|
||||
const body = source.slice(start)
|
||||
// 只看"最后一个份额把母单转 accepted"的分支,别被统一验收函数里的同名调用误判
|
||||
const acceptedBranch = body.slice(
|
||||
body.indexOf("nextOrderStatus === 'accepted'"),
|
||||
body.indexOf('sharing_share_accepted'),
|
||||
)
|
||||
assert.ok(acceptedBranch.length > 0, '未找到母单转已验收的分支')
|
||||
assert.ok(
|
||||
acceptedBranch.includes('releaseConsignmentPublishDepositBySubmissionWithClient('),
|
||||
'份额验收收官时必须释放卖家发布押金',
|
||||
)
|
||||
assert.ok(
|
||||
acceptedBranch.includes('settleConsignmentSupplierPayoutByWorkOrderWithClient('),
|
||||
'份额验收收官时必须结算供货货款(拼单母单无接单人,传 0 走供货渠道)',
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user