拆分后台工单资料服务
This commit is contained in:
@@ -61,8 +61,6 @@ import {
|
||||
normalizeProblemResolutionAction,
|
||||
normalizeRequirementFields,
|
||||
normalizeRequirementFieldsFromPayload,
|
||||
normalizeSubmittedFields,
|
||||
normalizeUploadedFiles,
|
||||
resolveFreezeDepositAmount,
|
||||
resolveMatchingProductRuleDecision,
|
||||
resolveKuaishouWorkProductMatchContext,
|
||||
@@ -76,6 +74,7 @@ import {
|
||||
import { ensureWorkerPlatformDefaults } from './worker-platform-defaults.js'
|
||||
import { normalizeWorkOrderTimeoutPolicy } from './work-order-timeout-policy.js'
|
||||
import { getRequiredWorkOrder, getRequiredWorker } from './worker-session-context-service.js'
|
||||
import { resolveWorkOrderRealtimeWorkerIds } from './admin-work-order-realtime-service.js'
|
||||
import {
|
||||
getKuaishouIndustrySourceConfig,
|
||||
listKuaishouIndustryShopConfigs,
|
||||
@@ -288,104 +287,10 @@ export {
|
||||
updateAdminWorkOrderSharing,
|
||||
} from './admin-work-order-sharing-service.js'
|
||||
|
||||
export async function submitAdminWorkOrderMaterial(
|
||||
workOrderId: number | string,
|
||||
payload: JsonObject = {},
|
||||
actorName = '',
|
||||
) {
|
||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||
const materialCapabilities = mapWorkOrderAdmin(workOrder).capabilities
|
||||
if (!materialCapabilities.canUpdateMaterial) {
|
||||
throw createHttpError('当前状态不能更新订单资料', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_material_status_invalid',
|
||||
})
|
||||
}
|
||||
|
||||
const fields = resolveRequirementFields(workOrder)
|
||||
const submittedFields = normalizeSubmittedFields(payload.fields || payload.material || payload)
|
||||
const complete = fields.every(
|
||||
(field) => !field.required || String(submittedFields[field.key] || '').trim(),
|
||||
)
|
||||
const now = nowIso()
|
||||
const screenshots = normalizeUploadedFiles(payload.screenshots || payload.files)
|
||||
const hasActiveShares = Number(workOrder.active_share_quantity || 0) > 0
|
||||
const rewardAmount = resolveAdminMaterialRewardAmount({
|
||||
currentRewardAmount: Number(workOrder.reward_amount || 0),
|
||||
requestedRewardAmount: payload.rewardAmount,
|
||||
sharingEnabled: workOrder.sharing_enabled === true,
|
||||
activeShareQuantity: Number(workOrder.active_share_quantity || 0),
|
||||
})
|
||||
const material = {
|
||||
...safeParseJson(workOrder.material_json),
|
||||
collect: {
|
||||
fields: submittedFields,
|
||||
screenshots,
|
||||
submittedAt: now,
|
||||
complete,
|
||||
source: 'admin',
|
||||
},
|
||||
}
|
||||
const nextStatus =
|
||||
hasActiveShares ||
|
||||
workOrder.status === WORK_ORDER_STATUS.OPEN ||
|
||||
workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS
|
||||
? workOrder.status
|
||||
: complete
|
||||
? WORK_ORDER_STATUS.UNASSIGNED
|
||||
: WORK_ORDER_STATUS.PENDING_MATERIAL
|
||||
const updated = await updateWorkOrder(workOrder.id, {
|
||||
status: nextStatus,
|
||||
material_json: material,
|
||||
reward_amount: rewardAmount,
|
||||
updated_at: now,
|
||||
})
|
||||
await createWorkOrderEvent({
|
||||
workOrderId: workOrder.id,
|
||||
actorType: 'admin',
|
||||
actorId: actorName,
|
||||
eventType:
|
||||
hasActiveShares ||
|
||||
workOrder.status === WORK_ORDER_STATUS.OPEN ||
|
||||
workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS
|
||||
? 'material_updated'
|
||||
: 'material_completed',
|
||||
fromStatus: workOrder.status,
|
||||
toStatus: nextStatus,
|
||||
payloadJson: JSON.stringify({
|
||||
fields: submittedFields,
|
||||
complete,
|
||||
previousRewardAmount: Number(workOrder.reward_amount || 0),
|
||||
rewardAmount,
|
||||
}),
|
||||
now,
|
||||
})
|
||||
if (nextStatus !== WORK_ORDER_STATUS.PENDING_MATERIAL) {
|
||||
await resolveAdminNotificationEntity('work_order', Number(workOrder.id), 'material_completed')
|
||||
}
|
||||
publishWorkOrderRealtimeChange({
|
||||
workOrderId: Number(workOrder.id),
|
||||
workerIds: await resolveWorkOrderRealtimeWorkerIds(workOrder),
|
||||
})
|
||||
return { order: mapWorkOrderAdmin(updated || workOrder), complete }
|
||||
}
|
||||
|
||||
/** 更新资料时仅普通接单可改价;已有参与者的拼单必须保留份额价格快照。 */
|
||||
export function resolveAdminMaterialRewardAmount(input: {
|
||||
currentRewardAmount: number
|
||||
requestedRewardAmount: unknown
|
||||
sharingEnabled: boolean
|
||||
activeShareQuantity: number
|
||||
}): number {
|
||||
if (input.requestedRewardAmount === undefined) return input.currentRewardAmount
|
||||
if (input.sharingEnabled && input.activeShareQuantity > 0) {
|
||||
throw createHttpError('拼单订单的份额奖励已锁定,不能在更新资料时修改价格', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_material_reward_sharing_invalid',
|
||||
})
|
||||
}
|
||||
return normalizeAmountFen(input.requestedRewardAmount, input.currentRewardAmount)
|
||||
}
|
||||
export {
|
||||
resolveAdminMaterialRewardAmount,
|
||||
submitAdminWorkOrderMaterial,
|
||||
} from './admin-work-order-material-service.js'
|
||||
|
||||
export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
||||
const defaults = await ensureWorkerPlatformDefaults()
|
||||
@@ -1208,13 +1113,6 @@ export async function cancelAdminWorkOrder(
|
||||
return { order: mapWorkOrderAdmin(updated), action }
|
||||
}
|
||||
|
||||
async function resolveWorkOrderRealtimeWorkerIds(workOrder: WorkOrderRow) {
|
||||
const shares = await listWorkOrderShares(workOrder.id)
|
||||
return [Number(workOrder.assigned_worker_id), ...shares.map((share) => Number(share.worker_id))]
|
||||
.filter((workerId) => Number.isInteger(workerId) && workerId > 0)
|
||||
.filter((workerId, index, values) => values.indexOf(workerId) === index)
|
||||
}
|
||||
|
||||
export async function getAdminWorkerPlatformSummary() {
|
||||
const hallConfig = getWorkerHallConfig()
|
||||
const [pendingWorkers, pendingMaterial, openOrders, inProgressOrders] = await Promise.all([
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import { createWorkOrderEvent, 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 { safeParseJson } from '../admin/admin-query-utils.js'
|
||||
import { resolveAdminNotificationEntity } from '../admin/admin-notification-service.js'
|
||||
import { publishWorkOrderRealtimeChange } from '../realtime/realtime-event-service.js'
|
||||
import {
|
||||
mapWorkOrderAdmin,
|
||||
normalizeAmountFen,
|
||||
normalizeSubmittedFields,
|
||||
normalizeUploadedFiles,
|
||||
resolveRequirementFields,
|
||||
} from './mappers.js'
|
||||
import { resolveWorkOrderRealtimeWorkerIds } from './admin-work-order-realtime-service.js'
|
||||
import { getRequiredWorkOrder } from './worker-session-context-service.js'
|
||||
|
||||
export async function submitAdminWorkOrderMaterial(
|
||||
workOrderId: number | string,
|
||||
payload: JsonObject = {},
|
||||
actorName = '',
|
||||
) {
|
||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||
const materialCapabilities = mapWorkOrderAdmin(workOrder).capabilities
|
||||
if (!materialCapabilities.canUpdateMaterial) {
|
||||
throw createHttpError('当前状态不能更新订单资料', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_material_status_invalid',
|
||||
})
|
||||
}
|
||||
|
||||
const fields = resolveRequirementFields(workOrder)
|
||||
const submittedFields = normalizeSubmittedFields(payload.fields || payload.material || payload)
|
||||
const complete = fields.every(
|
||||
(field) => !field.required || String(submittedFields[field.key] || '').trim(),
|
||||
)
|
||||
const now = nowIso()
|
||||
const screenshots = normalizeUploadedFiles(payload.screenshots || payload.files)
|
||||
const hasActiveShares = Number(workOrder.active_share_quantity || 0) > 0
|
||||
const rewardAmount = resolveAdminMaterialRewardAmount({
|
||||
currentRewardAmount: Number(workOrder.reward_amount || 0),
|
||||
requestedRewardAmount: payload.rewardAmount,
|
||||
sharingEnabled: workOrder.sharing_enabled === true,
|
||||
activeShareQuantity: Number(workOrder.active_share_quantity || 0),
|
||||
})
|
||||
const material = {
|
||||
...safeParseJson(workOrder.material_json),
|
||||
collect: {
|
||||
fields: submittedFields,
|
||||
screenshots,
|
||||
submittedAt: now,
|
||||
complete,
|
||||
source: 'admin',
|
||||
},
|
||||
}
|
||||
const nextStatus =
|
||||
hasActiveShares ||
|
||||
workOrder.status === WORK_ORDER_STATUS.OPEN ||
|
||||
workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS
|
||||
? workOrder.status
|
||||
: complete
|
||||
? WORK_ORDER_STATUS.UNASSIGNED
|
||||
: WORK_ORDER_STATUS.PENDING_MATERIAL
|
||||
const updated = await updateWorkOrder(workOrder.id, {
|
||||
status: nextStatus,
|
||||
material_json: material,
|
||||
reward_amount: rewardAmount,
|
||||
updated_at: now,
|
||||
})
|
||||
await createWorkOrderEvent({
|
||||
workOrderId: workOrder.id,
|
||||
actorType: 'admin',
|
||||
actorId: actorName,
|
||||
eventType:
|
||||
hasActiveShares ||
|
||||
workOrder.status === WORK_ORDER_STATUS.OPEN ||
|
||||
workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS
|
||||
? 'material_updated'
|
||||
: 'material_completed',
|
||||
fromStatus: workOrder.status,
|
||||
toStatus: nextStatus,
|
||||
payloadJson: JSON.stringify({
|
||||
fields: submittedFields,
|
||||
complete,
|
||||
previousRewardAmount: Number(workOrder.reward_amount || 0),
|
||||
rewardAmount,
|
||||
}),
|
||||
now,
|
||||
})
|
||||
if (nextStatus !== WORK_ORDER_STATUS.PENDING_MATERIAL) {
|
||||
await resolveAdminNotificationEntity('work_order', Number(workOrder.id), 'material_completed')
|
||||
}
|
||||
publishWorkOrderRealtimeChange({
|
||||
workOrderId: Number(workOrder.id),
|
||||
workerIds: await resolveWorkOrderRealtimeWorkerIds(workOrder),
|
||||
})
|
||||
return { order: mapWorkOrderAdmin(updated || workOrder), complete }
|
||||
}
|
||||
|
||||
/** 更新资料时仅普通接单可改价;已有参与者的拼单必须保留份额价格快照。 */
|
||||
export function resolveAdminMaterialRewardAmount(input: {
|
||||
currentRewardAmount: number
|
||||
requestedRewardAmount: unknown
|
||||
sharingEnabled: boolean
|
||||
activeShareQuantity: number
|
||||
}): number {
|
||||
if (input.requestedRewardAmount === undefined) return input.currentRewardAmount
|
||||
if (input.sharingEnabled && input.activeShareQuantity > 0) {
|
||||
throw createHttpError('拼单订单的份额奖励已锁定,不能在更新资料时修改价格', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_material_reward_sharing_invalid',
|
||||
})
|
||||
}
|
||||
return normalizeAmountFen(input.requestedRewardAmount, input.currentRewardAmount)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { listWorkOrderShares, type WorkOrderRow } from '../../repositories/worker-platform/index.js'
|
||||
|
||||
export async function resolveWorkOrderRealtimeWorkerIds(workOrder: WorkOrderRow) {
|
||||
const shares = await listWorkOrderShares(workOrder.id)
|
||||
return [Number(workOrder.assigned_worker_id), ...shares.map((share) => Number(share.worker_id))]
|
||||
.filter((workerId) => Number.isInteger(workerId) && workerId > 0)
|
||||
.filter((workerId, index, values) => values.indexOf(workerId) === index)
|
||||
}
|
||||
@@ -29,6 +29,8 @@ export * from './admin-work-order-query-service.js'
|
||||
export * from './admin-worker-feedback-service.js'
|
||||
export * from './admin-worker-cancel-service.js'
|
||||
export * from './admin-work-order-sharing-service.js'
|
||||
export * from './admin-work-order-realtime-service.js'
|
||||
export * from './admin-work-order-material-service.js'
|
||||
export * from './worker-product-match-config-service.js'
|
||||
export * from './worker-announcement-config-service.js'
|
||||
export * from './worker-hall-config-service.js'
|
||||
|
||||
Reference in New Issue
Block a user