From 9573acc59da986434e8833c199b6b566b09dbfde Mon Sep 17 00:00:00 2001 From: yml2213 Date: Thu, 1 Oct 2026 12:22:56 +0800 Subject: [PATCH] =?UTF-8?q?fix(consignment):=20=E9=97=AE=E9=A2=98=E5=8D=95?= =?UTF-8?q?=E3=80=8C=E9=80=80=E5=9B=9E=E5=A4=A7=E5=8E=85=E3=80=8D=E4=B9=9F?= =?UTF-8?q?=E8=A6=81=E8=A7=A3=E7=BB=91=E5=AF=84=E5=8D=96=E7=8E=B0=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题单处置的「退回大厅」只把订单置回 open,没有解绑被本工单占用的寄卖现货,也没摘 material 上的 寄售标记。后果是卖家端「我的寄卖」把这张单显示成「履约中 + 关联订单状态已变化,请联系客服核对」 (状态机只认 in_progress / problem / pending_acceptance,open 落到兜底分支),而现货永久停在 consumed 占库不还、既不再参与匹配也没有释放入口。 其余同义路径(后台退回大厅、超时重开、打手退单通过)本来都会解绑,只有问题单这条漏了,属口径不一致。 现在把解绑条件从「仅取消」扩到「取消或退回大厅」;「退回打手重做」保持占用(货还在这一单上履约)。 调用位置仍在状态 UPDATE 之前——该 UPDATE 在 open/cancelled 时会清空 friend_added_at, 清完再解绑会把已确认加好友的货误判成可回池(二次出货)。 验证:真实库跑通两条路径——退回打手重做(现货仍 consumed+绑定的、标记保留、打手端仍「已匹配-待加好友」) 与退回大厅(现货回 in_stock、解绑、标记摘除、打手端变「已通过(在库待匹配)」);后端 520 项单测全绿。 --- .../worker-platform/work-order-issue-repo.ts | 22 +++++++++++++------ .../worker-platform-service.test.ts | 19 ++++++++++------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/backend/src/repositories/worker-platform/work-order-issue-repo.ts b/apps/backend/src/repositories/worker-platform/work-order-issue-repo.ts index 3c776e0e..c31ba6e6 100644 --- a/apps/backend/src/repositories/worker-platform/work-order-issue-repo.ts +++ b/apps/backend/src/repositories/worker-platform/work-order-issue-repo.ts @@ -143,17 +143,25 @@ export async function resolveProblemWorkOrder(input: { input.action === 'reopen' || (input.action === 'return_to_worker' && targetStatus === 'in_progress') - // 取消处置 = 工单终止:被本工单占用的寄卖现货必须解绑(回库;已确认加好友则作废下架), - // 并同步摘掉 material 上的寄售标记。否则会出现两个后果: - // 1) 列表「打手」列继续显示「供货打手 / 内部现货」,看着像打手还挂在这张已取消的单上; - // 2) 现货永久停在 consumed 占库不还,既不参与匹配也没有押金释放入口。 - // ⚠️ 必须放在下面的 UPDATE 之前:那条 UPDATE 在取消时会把 friend_added_at 清空, + // 问题单处置把工单带离履约态(取消 / 退回大厅)时,被本工单占用的寄卖现货必须解绑 + // (回库;已确认加好友则作废下架),并同步摘掉 material 上的寄售标记。 + // 不解绑会出现两个后果: + // 1) 卖家端「我的寄卖」把这张单显示成「履约中 + 关联订单状态已变化,请联系客服核对」 + // ——状态机只认 in_progress / problem / pending_acceptance,open 落到兜底分支; + // 2) 现货永久停在 consumed 占库不还,既不再参与匹配,也没有押金释放入口。 + // 「退回大厅」也必须解绑:后台退回大厅、超时重开、打手退单通过这三条同义路径都会解绑, + // 只有这里漏了(口径不一致,且订单回到大厅后本单已不承担交付)。 + // 退回打手重做(in_progress / pending_acceptance)保持占用:货还在这一单上履约。 + // ⚠️ 必须放在下面的 UPDATE 之前:那条 UPDATE 在 open/cancelled 时会把 friend_added_at 清空, // 而解绑是否需要改成「作废」正是看这个字段——清空后再解绑会把已加好友的货退回在库池, // 等于二次出货。 - if (targetStatus === 'cancelled') { + if (targetStatus === 'cancelled' || targetStatus === 'open') { await releaseConsignmentInventoryBindingForWorkOrderWithClient(client, input.workOrderId, { now: input.now, - reason: `问题单处置取消(${effectiveAction})`, + reason: + targetStatus === 'cancelled' + ? `问题单处置取消(${effectiveAction})` + : `问题单处置退回大厅(${effectiveAction})`, }) } diff --git a/apps/backend/src/services/worker-platform/worker-platform-service.test.ts b/apps/backend/src/services/worker-platform/worker-platform-service.test.ts index f528fe15..22d7110f 100644 --- a/apps/backend/src/services/worker-platform/worker-platform-service.test.ts +++ b/apps/backend/src/services/worker-platform/worker-platform-service.test.ts @@ -240,7 +240,7 @@ test('没解绑到现货时也必须摘掉工单上的寄售标记(老帖 / assert.equal(detach!.values[3], null, '无现货可解绑时应按工单整体摘标记') }) -test('问题单处置取消:先解绑寄卖现货,再改工单状态', async () => { +test('问题单处置离开履约态(取消 / 退回大厅)都要先解绑寄卖现货', async () => { const readFile = await import('node:fs/promises') const src = await readFile.readFile( new URL('../../repositories/worker-platform/work-order-issue-repo.ts', import.meta.url), @@ -253,13 +253,18 @@ test('问题单处置取消:先解绑寄卖现货,再改工单状态', async const releaseIndex = body.indexOf( 'releaseConsignmentInventoryBindingForWorkOrderWithClient(client, input.workOrderId', ) - assert.ok(releaseIndex > 0, '取消问题单必须解绑被本工单占用的寄卖现货,否则现货永久占库不还') - assert.ok( - body.includes("if (targetStatus === 'cancelled')"), - '只对「取消」处置解绑:退回打手重做 / 退回大厅时货还在履约,不能解绑', - ) + assert.ok(releaseIndex > 0, '处置问题单必须解绑被本工单占用的寄卖现货,否则现货永久占库不还') - // 顺序很重要:那条 UPDATE 会在取消时把 friend_added_at 清空,而"是否改判作废"正是看这个字段。 + // 「退回大厅」也必须解绑:后台退回大厅 / 超时重开 / 打手退单通过这三条同义路径都会解绑, + // 只有问题单这条漏了,导致卖家端一直显示「履约中 + 关联订单状态已变化,请联系客服核对」。 + assert.ok( + body.includes("if (targetStatus === 'cancelled' || targetStatus === 'open')"), + '取消与退回大厅都要解绑', + ) + // 退回打手重做必须保持占用:货还在这一单上履约 + assert.ok(body.includes('return_to_worker'), '未找到退回打手重做的分支(该分支不能解绑)') + + // 顺序很重要:那条 UPDATE 在 open/cancelled 时会把 friend_added_at 清空,而"是否改判作废"正是看这个字段。 // 清空之后再解绑,会把已加好友的现货退回在库池 → 二次出货。 const updateIndex = body.indexOf('UPDATE work_orders') assert.ok(updateIndex > 0, '未找到工单状态更新语句')