fix(worker): 拼单单人撤单后空出份额回大厅并重算母单状态
This commit is contained in:
@@ -196,7 +196,8 @@ export async function cancelAdminWorkOrderShare(
|
||||
* 后台按份数撤销某个打手的部分份额。
|
||||
*
|
||||
* 减少的份数会随「大厅余量 = 总份数 − Σ有效份额数量」自动回到大厅;押金保持原冻结额,
|
||||
* 母单状态与验收资料都不动(之后仍可对该份额「单独验收」)。
|
||||
* 母单状态按剩余份额重算(可能从待验收回到代练中,保留原大厅队列位置),
|
||||
* 该份额的验收资料不动(之后仍可对该份额「单独验收」)。
|
||||
*/
|
||||
export async function reduceAdminWorkOrderShareQuantity(
|
||||
workOrderId: number | string,
|
||||
|
||||
@@ -3510,13 +3510,21 @@ type ShareAggregate = {
|
||||
async function runRecompute(
|
||||
workOrder: Partial<WorkOrderRow>,
|
||||
aggregate: ShareAggregate,
|
||||
): Promise<{ status: string | null; updates: unknown[][]; shareQueries: number }> {
|
||||
options: { preserveHallQueue?: boolean } = {},
|
||||
): Promise<{
|
||||
status: string | null
|
||||
updates: unknown[][]
|
||||
shareQueries: number
|
||||
updateSqls: string[]
|
||||
}> {
|
||||
const updates: unknown[][] = []
|
||||
const updateSqls: string[] = []
|
||||
let shareQueries = 0
|
||||
const client = {
|
||||
query: async (sql: string, params: unknown[] = []) => {
|
||||
if (sql.includes('UPDATE work_orders')) {
|
||||
updates.push(params)
|
||||
updateSqls.push(sql)
|
||||
return { rows: [{ ...buildWorkOrderRow(workOrder), status: params[0] }] }
|
||||
}
|
||||
if (sql.includes('FROM work_orders')) {
|
||||
@@ -3534,8 +3542,9 @@ async function runRecompute(
|
||||
client,
|
||||
1,
|
||||
'2026-10-23T12:00:00.000Z',
|
||||
options,
|
||||
)
|
||||
return { status: updated ? String(updated.status) : null, updates, shareQueries }
|
||||
return { status: updated ? String(updated.status) : null, updates, shareQueries, updateSqls }
|
||||
}
|
||||
|
||||
test('拼单母单状态由份额集合唯一推导:满额且无待履约份额才转待验收', async () => {
|
||||
@@ -3574,7 +3583,7 @@ test('拼单母单已验收或已取消时 recompute 不回头改状态', async
|
||||
}
|
||||
})
|
||||
|
||||
test('后台单人撤单不改母单状态;份额超时仍交给 recompute 收敛', async () => {
|
||||
test('后台单人撤单重算母单状态,空出份额回大厅并保留原队列位置', async () => {
|
||||
const src = fs.readFileSync(
|
||||
new URL('../../repositories/worker-platform/work-order-settlement-repo.ts', import.meta.url),
|
||||
'utf8',
|
||||
@@ -3585,14 +3594,18 @@ test('后台单人撤单不改母单状态;份额超时仍交给 recompute 收
|
||||
)
|
||||
assert.ok(cancelBlock.length > 0, 'cancelWorkOrderShare 片段必须存在')
|
||||
assert.ok(
|
||||
!cancelBlock.includes('recomputeWorkOrderSharingStatusWithClient('),
|
||||
'后台单人撤单不得重算母单状态(撤一份会把待验收的母单踢回大厅)',
|
||||
cancelBlock.includes('recomputeWorkOrderSharingStatusWithClient('),
|
||||
'后台单人撤单必须重算母单状态,空出的份数才能回到大厅',
|
||||
)
|
||||
assert.ok(cancelBlock.includes('preserveHallQueue: true'), '后台单人撤单回大厅必须保留原队列位置')
|
||||
assert.ok(
|
||||
!/UPDATE\s+work_orders\s+SET[\s\S]{0,80}?status\s*=/i.test(cancelBlock),
|
||||
'后台单人撤单不得自己写母单 status',
|
||||
)
|
||||
assert.ok(cancelBlock.includes('toStatus: workOrder.status'), '撤单事件不得记录母单状态迁移')
|
||||
assert.ok(
|
||||
cancelBlock.includes('toStatus: updatedOrder?.status || workOrder.status'),
|
||||
'撤单事件必须记录母单重算后的状态',
|
||||
)
|
||||
|
||||
const timeoutBlock = src.slice(
|
||||
src.indexOf('export async function settleOverdueWorkOrderShare('),
|
||||
@@ -3603,6 +3616,7 @@ test('后台单人撤单不改母单状态;份额超时仍交给 recompute 收
|
||||
timeoutBlock.includes('recomputeWorkOrderSharingStatusWithClient('),
|
||||
'份额超时必须用 recompute 收敛母单状态',
|
||||
)
|
||||
assert.ok(timeoutBlock.includes('preserveHallQueue: true'), '份额超时回大厅必须保留原队列位置')
|
||||
assert.ok(
|
||||
!/UPDATE\s+work_orders\s+SET[\s\S]{0,80}?status\s*=/i.test(timeoutBlock),
|
||||
'份额超时不得自己写母单 status(只能由 recompute 推导)',
|
||||
@@ -3642,6 +3656,11 @@ test('撤份额与单人撤单都把原因和份数写进份额行,列表才
|
||||
shareSrc.indexOf('export async function submitWorkOrderShareAcceptance('),
|
||||
)
|
||||
assert.ok(reduceBlock.length > 0, 'reduceWorkOrderShareQuantity 片段必须存在')
|
||||
assert.ok(
|
||||
reduceBlock.includes('recomputeWorkOrderSharingStatusWithClient('),
|
||||
'撤份额必须重算母单状态,减少的份数才能回大厅',
|
||||
)
|
||||
assert.ok(reduceBlock.includes('preserveHallQueue: true'), '撤份额回大厅必须保留原队列位置')
|
||||
assert.ok(reduceBlock.includes('cancel_note = $'), '撤份额必须把原因写进 cancel_note')
|
||||
assert.ok(
|
||||
reduceBlock.includes('String(share.cancel_note'),
|
||||
|
||||
Reference in New Issue
Block a user