修复问题单退回后拼单份额无法验收
This commit is contained in:
@@ -56,7 +56,8 @@ export function resolveWorkOrderShareCancellationStatus(
|
||||
workOrderStatus: string,
|
||||
shareStatus: string,
|
||||
): 'open' | null {
|
||||
if (!['open', 'pending_acceptance'].includes(workOrderStatus)) return null
|
||||
// in_progress 用于解围历史问题单处置产生的"份额已提交、母单回到进行中"的卡死存量单
|
||||
if (!['open', 'pending_acceptance', 'in_progress'].includes(workOrderStatus)) return null
|
||||
if (!['joined', 'submitted'].includes(shareStatus)) return null
|
||||
return 'open'
|
||||
}
|
||||
|
||||
@@ -6,6 +6,16 @@ import { getOutstandingDepositAmountWithClient } from './work-order-deposit-repo
|
||||
import { RESET_GIFT_FLOW_SQL } from './work-order-gift-repo.js'
|
||||
import type { ProblemWorkOrderResolutionAction, WorkOrderRow } from './types.js'
|
||||
|
||||
/** 问题单退回打手时,按标记前状态恢复;异常历史数据回退单人单进行中。 */
|
||||
export function resolveProblemReturnToWorkerStatus(
|
||||
fromStatus: string,
|
||||
): 'open' | 'in_progress' | 'pending_acceptance' {
|
||||
if (['open', 'in_progress', 'pending_acceptance'].includes(fromStatus)) {
|
||||
return fromStatus as 'open' | 'in_progress' | 'pending_acceptance'
|
||||
}
|
||||
return 'in_progress'
|
||||
}
|
||||
|
||||
export async function resolveProblemWorkOrder(input: {
|
||||
workOrderId: number
|
||||
action: ProblemWorkOrderResolutionAction
|
||||
@@ -27,6 +37,26 @@ export async function resolveProblemWorkOrder(input: {
|
||||
const workOrder = currentResult.rows[0] || null
|
||||
if (!workOrder) return null
|
||||
|
||||
// return_to_worker 需恢复到标记问题单前的真实状态:拼单份额已全部提交时
|
||||
// 标记前是 pending_acceptance,若一律回到 in_progress 会陷入"份额已提交、
|
||||
// 母单却不可验收也不可重新提交"的卡死状态,因此按最近一次 marked_problem
|
||||
// 事件的 from_status 恢复。
|
||||
let restoreStatus = ''
|
||||
if (input.action === 'return_to_worker') {
|
||||
const eventResult = await client.query<{ from_status: string }>(
|
||||
`
|
||||
SELECT from_status
|
||||
FROM work_order_events
|
||||
WHERE work_order_id = $1 AND event_type = 'marked_problem'
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
`,
|
||||
[input.workOrderId],
|
||||
)
|
||||
const fromStatus = String(eventResult.rows[0]?.from_status || '').trim()
|
||||
restoreStatus = resolveProblemReturnToWorkerStatus(fromStatus)
|
||||
}
|
||||
|
||||
const shouldReleaseDeposit = ['reopen', 'cancel_release'].includes(input.action)
|
||||
const shouldDeductDeposit = input.action === 'cancel_deduct'
|
||||
const workerId = Number(workOrder.assigned_worker_id || 0)
|
||||
@@ -83,12 +113,16 @@ export async function resolveProblemWorkOrder(input: {
|
||||
|
||||
const targetStatus =
|
||||
input.action === 'return_to_worker'
|
||||
? 'in_progress'
|
||||
? restoreStatus || 'in_progress'
|
||||
: input.action === 'reopen'
|
||||
? 'open'
|
||||
: 'cancelled'
|
||||
const shouldClearAssignment = input.action === 'reopen'
|
||||
const shouldClearSubmission = ['return_to_worker', 'reopen'].includes(input.action)
|
||||
// 仅在真正退回打手重做(回到进行中)时清验收提交;份额已提交待验收的拼单
|
||||
// 需保留母单待验收状态,否则份额验收链路断裂。
|
||||
const shouldClearSubmission =
|
||||
input.action === 'reopen' ||
|
||||
(input.action === 'return_to_worker' && targetStatus === 'in_progress')
|
||||
|
||||
await client.query(
|
||||
`
|
||||
|
||||
@@ -392,8 +392,10 @@ export async function acceptWorkOrderShareAndSettle(input: {
|
||||
failureReason: 'work_order_not_accepting' | 'share_not_submitted' | null
|
||||
}> {
|
||||
return withTransaction(async (client) => {
|
||||
// in_progress 仅用于解围历史问题单处置产生的"份额已提交、母单却回到进行中"
|
||||
// 的卡死存量单;正常拼单流程母单只会是 open / pending_acceptance。
|
||||
const orderResult = await client.query<WorkOrderRow>(
|
||||
`SELECT * FROM work_orders WHERE id = $1 AND status IN ('open', 'pending_acceptance') FOR UPDATE`,
|
||||
`SELECT * FROM work_orders WHERE id = $1 AND status IN ('open', 'pending_acceptance', 'in_progress') FOR UPDATE`,
|
||||
[input.workOrderId],
|
||||
)
|
||||
const workOrder = orderResult.rows[0] || null
|
||||
@@ -592,7 +594,7 @@ export async function cancelWorkOrderShare(input: {
|
||||
[input.workOrderId],
|
||||
)
|
||||
const workOrder = orderResult.rows[0] || null
|
||||
if (!workOrder || !['open', 'pending_acceptance'].includes(workOrder.status)) {
|
||||
if (!workOrder || !['open', 'pending_acceptance', 'in_progress'].includes(workOrder.status)) {
|
||||
return {
|
||||
order: workOrder,
|
||||
share: null,
|
||||
|
||||
@@ -295,7 +295,7 @@ export async function submitWorkOrderShareAcceptance(input: {
|
||||
now: string
|
||||
}): Promise<{
|
||||
share: WorkOrderShareRow | null
|
||||
failureReason: 'share_not_found' | 'share_status_invalid' | null
|
||||
failureReason: 'share_not_found' | 'share_status_invalid' | 'work_order_status_invalid' | null
|
||||
}> {
|
||||
return withTransaction(async (client) => {
|
||||
const orderResult = await client.query<{
|
||||
@@ -309,9 +309,12 @@ export async function submitWorkOrderShareAcceptance(input: {
|
||||
[input.workOrderId],
|
||||
)
|
||||
const workOrder = orderResult.rows[0] || null
|
||||
if (!workOrder || !['open', 'pending_acceptance'].includes(workOrder.status)) {
|
||||
if (!workOrder) {
|
||||
return { share: null, failureReason: 'share_not_found' }
|
||||
}
|
||||
if (!['open', 'pending_acceptance'].includes(workOrder.status)) {
|
||||
return { share: null, failureReason: 'work_order_status_invalid' }
|
||||
}
|
||||
|
||||
const lockResult = await client.query<{ id: number }>(
|
||||
`
|
||||
|
||||
@@ -435,6 +435,12 @@ async function submitWorkerSharingAcceptance(
|
||||
errorCode: 'work_order_sharing_share_submitted',
|
||||
})
|
||||
}
|
||||
if (result.failureReason === 'work_order_status_invalid') {
|
||||
throw createHttpError('当前拼单状态不能提交验收资料,请联系管理员', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_sharing_submit_status_invalid',
|
||||
})
|
||||
}
|
||||
if (!result.share) {
|
||||
throw createHttpError('未找到拼单份额', {
|
||||
statusCode: 404,
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
resolveWorkOrderShareJoinQuantity,
|
||||
resolveOpenSharingSyncReward,
|
||||
} from '../../repositories/worker-platform/index.js'
|
||||
import { resolveProblemReturnToWorkerStatus } from '../../repositories/worker-platform/work-order-issue-repo.js'
|
||||
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
||||
import {
|
||||
assertWithdrawChannelAllowedForAmount,
|
||||
@@ -1045,6 +1046,13 @@ test('拼单份额撤单只允许未验收份额并让母工单回到大厅状
|
||||
assert.equal(resolveWorkOrderShareCancellationStatus('open', 'cancelled'), null)
|
||||
})
|
||||
|
||||
test('问题单退回打手按标记前状态恢复', () => {
|
||||
assert.equal(resolveProblemReturnToWorkerStatus('pending_acceptance'), 'pending_acceptance')
|
||||
assert.equal(resolveProblemReturnToWorkerStatus('open'), 'open')
|
||||
assert.equal(resolveProblemReturnToWorkerStatus('in_progress'), 'in_progress')
|
||||
assert.equal(resolveProblemReturnToWorkerStatus(''), 'in_progress')
|
||||
})
|
||||
|
||||
test('后台更新资料时普通接单可以修改接单价格', () => {
|
||||
assert.equal(
|
||||
resolveAdminMaterialRewardAmount({
|
||||
|
||||
Reference in New Issue
Block a user