拆分后台工单验收服务
This commit is contained in:
@@ -0,0 +1,193 @@
|
|||||||
|
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||||
|
import {
|
||||||
|
acceptWorkOrderAndSettle,
|
||||||
|
acceptWorkOrderShareAndSettle,
|
||||||
|
cancelWorkOrderShare,
|
||||||
|
countWorkOrderPendingSharingSubmissions,
|
||||||
|
updateWorkOrder,
|
||||||
|
} from '../../repositories/worker-platform/index.js'
|
||||||
|
import type { JsonObject } from '../../types/json.js'
|
||||||
|
import { createHttpError } from '../../utils/http.js'
|
||||||
|
import { nowIso } from '../../utils/time.js'
|
||||||
|
import { resolveAdminNotificationEntity } from '../admin/admin-notification-service.js'
|
||||||
|
import {
|
||||||
|
publishWorkerWalletRealtimeChange,
|
||||||
|
publishWorkOrderRealtimeChange,
|
||||||
|
} from '../realtime/realtime-event-service.js'
|
||||||
|
import {
|
||||||
|
mapWorkOrderAdmin,
|
||||||
|
mapWorkOrderShare,
|
||||||
|
normalizeOptionalId,
|
||||||
|
resolveWorkOrderOperationalStatus,
|
||||||
|
} from './mappers.js'
|
||||||
|
import { resolveWorkOrderRealtimeWorkerIds } from './admin-work-order-realtime-service.js'
|
||||||
|
import { getWorkerFinanceConfig } from './worker-finance-config-service.js'
|
||||||
|
import { getRequiredWorkOrder } from './worker-session-context-service.js'
|
||||||
|
|
||||||
|
export async function acceptAdminWorkOrder(workOrderId: number | string, actorName = '') {
|
||||||
|
let workOrder = await getRequiredWorkOrder(workOrderId)
|
||||||
|
if (!mapWorkOrderAdmin(workOrder).capabilities.canAccept) {
|
||||||
|
throw createHttpError('只有待验收订单可以通过验收', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_accept_status_invalid',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 历史拼单订单可能仍保留 open,验收前先补齐母工单生命周期状态。
|
||||||
|
if (workOrder.status === WORK_ORDER_STATUS.OPEN) {
|
||||||
|
const promoted = await updateWorkOrder(workOrder.id, {
|
||||||
|
status: WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
|
||||||
|
updated_at: nowIso(),
|
||||||
|
})
|
||||||
|
if (promoted) workOrder = promoted
|
||||||
|
}
|
||||||
|
const now = nowIso()
|
||||||
|
const { order: updated, failureReason } = await acceptWorkOrderAndSettle({
|
||||||
|
workOrderId: workOrder.id,
|
||||||
|
unfreezeDays: getWorkerFinanceConfig().depositUnfreezeDays,
|
||||||
|
now,
|
||||||
|
actorType: 'admin',
|
||||||
|
actorName,
|
||||||
|
})
|
||||||
|
if (failureReason === 'sharing_pending_submissions') {
|
||||||
|
throw createHttpError('还有拼单打手未提交验收资料,暂不能统一验收', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_sharing_pending_submissions',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!updated) {
|
||||||
|
throw createHttpError('验收失败,订单状态可能已变化', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_accept_conflict',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
await resolveAdminNotificationEntity('work_order', Number(workOrder.id), 'accepted')
|
||||||
|
const workerIds = await resolveWorkOrderRealtimeWorkerIds(workOrder)
|
||||||
|
publishWorkOrderRealtimeChange({ workOrderId: Number(workOrder.id), workerIds })
|
||||||
|
for (const workerId of workerIds) publishWorkerWalletRealtimeChange(workerId)
|
||||||
|
return { order: mapWorkOrderAdmin(updated || workOrder) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function acceptAdminWorkOrderShare(
|
||||||
|
workOrderId: number | string,
|
||||||
|
shareId: number | string,
|
||||||
|
actorName = '',
|
||||||
|
) {
|
||||||
|
const result = await acceptWorkOrderShareAndSettle({
|
||||||
|
workOrderId: Number(workOrderId),
|
||||||
|
shareId: Number(shareId),
|
||||||
|
unfreezeDays: getWorkerFinanceConfig().depositUnfreezeDays,
|
||||||
|
now: nowIso(),
|
||||||
|
actorType: 'admin',
|
||||||
|
actorName,
|
||||||
|
})
|
||||||
|
if (result.failureReason === 'work_order_not_accepting') {
|
||||||
|
throw createHttpError('当前母工单不能验收拼单份额', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_sharing_accept_status_invalid',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (result.failureReason === 'share_not_submitted' || !result.share || !result.order) {
|
||||||
|
throw createHttpError('该拼单参与者尚未提交验收资料或已被验收', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_sharing_share_accept_status_invalid',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const workerId = Number(result.share.worker_id || 0)
|
||||||
|
publishWorkOrderRealtimeChange({
|
||||||
|
workOrderId: Number(workOrderId),
|
||||||
|
workerIds: workerId > 0 ? [workerId] : [],
|
||||||
|
})
|
||||||
|
if (workerId > 0) publishWorkerWalletRealtimeChange(workerId)
|
||||||
|
if (result.order.status === WORK_ORDER_STATUS.ACCEPTED) {
|
||||||
|
await resolveAdminNotificationEntity('work_order', Number(workOrderId), 'accepted')
|
||||||
|
}
|
||||||
|
return { order: mapWorkOrderAdmin(result.order), share: mapWorkOrderShare(result.share) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function cancelAdminWorkOrderShare(
|
||||||
|
workOrderId: number | string,
|
||||||
|
shareId: number | string,
|
||||||
|
payload: JsonObject = {},
|
||||||
|
actorName = '',
|
||||||
|
) {
|
||||||
|
const result = await cancelWorkOrderShare({
|
||||||
|
workOrderId: Number(workOrderId),
|
||||||
|
shareId: Number(shareId),
|
||||||
|
now: nowIso(),
|
||||||
|
reason: String(payload.reason || '').trim(),
|
||||||
|
actorName,
|
||||||
|
})
|
||||||
|
if (result.failureReason === 'work_order_not_cancellable') {
|
||||||
|
throw createHttpError('当前拼单状态不能撤销参与者', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_sharing_cancel_status_invalid',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (result.failureReason === 'share_not_found') {
|
||||||
|
throw createHttpError('未找到该拼单参与记录', {
|
||||||
|
statusCode: 404,
|
||||||
|
errorCode: 'work_order_sharing_share_not_found',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (result.failureReason === 'share_status_not_cancellable' || !result.share || !result.order) {
|
||||||
|
throw createHttpError('只有已参与或已提交验收的拼单份额可以撤单', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_sharing_share_cancel_status_invalid',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const workerId = Number(result.share.worker_id || 0)
|
||||||
|
publishWorkOrderRealtimeChange({
|
||||||
|
workOrderId: Number(workOrderId),
|
||||||
|
workerIds: await resolveWorkOrderRealtimeWorkerIds(result.order),
|
||||||
|
hallChanged: true,
|
||||||
|
})
|
||||||
|
if (workerId > 0) publishWorkerWalletRealtimeChange(workerId)
|
||||||
|
return {
|
||||||
|
order: mapWorkOrderAdmin(result.order),
|
||||||
|
share: mapWorkOrderShare(result.share),
|
||||||
|
releasedDepositAmount: result.releasedDepositAmount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function acceptAdminWorkOrders(payload: JsonObject = {}, actorName = '') {
|
||||||
|
const workOrderIds = [
|
||||||
|
...new Set(
|
||||||
|
(Array.isArray(payload.workOrderIds) ? payload.workOrderIds : [])
|
||||||
|
.map((item) => normalizeOptionalId(item))
|
||||||
|
.filter((item): item is number => item !== null),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
if (workOrderIds.length === 0) {
|
||||||
|
throw createHttpError('请至少选择一个待验收订单', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'work_order_batch_accept_required',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const workOrders = await Promise.all(
|
||||||
|
workOrderIds.map((workOrderId) => getRequiredWorkOrder(workOrderId)),
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
workOrders.some(
|
||||||
|
(workOrder) =>
|
||||||
|
resolveWorkOrderOperationalStatus(workOrder) !== WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw createHttpError('选中的订单包含非待验收状态,请刷新后重试', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_batch_accept_status_invalid',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const pendingSharingCounts = await Promise.all(
|
||||||
|
workOrders.map((workOrder) => countWorkOrderPendingSharingSubmissions(workOrder.id)),
|
||||||
|
)
|
||||||
|
if (pendingSharingCounts.some((count) => count > 0)) {
|
||||||
|
throw createHttpError('选中的订单存在拼单打手未提交验收资料,暂不能统一验收', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_batch_accept_sharing_pending_submissions',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const results = []
|
||||||
|
for (const workOrder of workOrders)
|
||||||
|
results.push(await acceptAdminWorkOrder(workOrder.id, actorName))
|
||||||
|
return { orders: results.map((result) => result.order) }
|
||||||
|
}
|
||||||
@@ -33,6 +33,12 @@ export * from './admin-work-order-realtime-service.js'
|
|||||||
export * from './admin-work-order-material-service.js'
|
export * from './admin-work-order-material-service.js'
|
||||||
export * from './admin-mock-work-order-service.js'
|
export * from './admin-mock-work-order-service.js'
|
||||||
export * from './admin-work-order-management-service.js'
|
export * from './admin-work-order-management-service.js'
|
||||||
|
export {
|
||||||
|
acceptAdminWorkOrder,
|
||||||
|
acceptAdminWorkOrderShare,
|
||||||
|
acceptAdminWorkOrders,
|
||||||
|
cancelAdminWorkOrderShare,
|
||||||
|
} from './admin-work-order-acceptance-service.js'
|
||||||
export * from './worker-product-match-config-service.js'
|
export * from './worker-product-match-config-service.js'
|
||||||
export * from './worker-announcement-config-service.js'
|
export * from './worker-announcement-config-service.js'
|
||||||
export * from './worker-hall-config-service.js'
|
export * from './worker-hall-config-service.js'
|
||||||
|
|||||||
Reference in New Issue
Block a user