fix(fulfillment): 封堵重复载体并完善统一SKU映射
This commit is contained in:
@@ -8,13 +8,21 @@ import {
|
||||
type FulfillmentBindingLike,
|
||||
} from '../fulfillment/planner.js'
|
||||
import { preparePaidFulfillmentTask } from '../fulfillment/executors/registry.js'
|
||||
import type { FulfillmentPrepareDeps } from '../fulfillment/executors/types.js'
|
||||
import {
|
||||
FULFILLMENT_EXECUTOR_KEYS,
|
||||
type FulfillmentPrepareDeps,
|
||||
} from '../fulfillment/executors/types.js'
|
||||
import { nowIso } from '../../utils/time.js'
|
||||
import { randomId } from '../../utils/random.js'
|
||||
import { logInfo, logWarn } from '../../utils/logger.js'
|
||||
import { TASK_STATUS, resolveInitialPaidTaskStatus } from '../../domain/task-status.js'
|
||||
import type { JsonObject } from '../../types/json.js'
|
||||
import type { OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'
|
||||
import {
|
||||
findConflictingCarrier,
|
||||
loadActiveCarrierEvidence,
|
||||
} from '../fulfillment/carrier-evidence-service.js'
|
||||
import type { FulfillmentChannel } from '../fulfillment/channel-types.js'
|
||||
|
||||
type ClaimTokenLike = {
|
||||
token: string
|
||||
@@ -30,6 +38,7 @@ type DeliveryTaskRow = TaskRow & {
|
||||
type DeliveryTaskDeps = {
|
||||
createTask?: typeof createTask
|
||||
listTasksByOrderId?: typeof listTasksByOrderId
|
||||
loadActiveCarrierEvidence?: typeof loadActiveCarrierEvidence
|
||||
updateTask?: typeof updateTask
|
||||
getFulfillmentProfileByKey?: (profileKey: string) => Promise<FulfillmentBindingLike | null>
|
||||
createTaskClaimToken?: (taskId: number | string) => Promise<ClaimTokenLike>
|
||||
@@ -60,6 +69,7 @@ export async function syncDeliveryTasksForOrderWithDeps(
|
||||
const {
|
||||
createTask: createDeliveryTask = createTask,
|
||||
listTasksByOrderId: listTasks = listTasksByOrderId,
|
||||
loadActiveCarrierEvidence: loadCarrierEvidence = loadActiveCarrierEvidence,
|
||||
updateTask: updateDeliveryTask = updateTask,
|
||||
getFulfillmentProfileByKey: getProfileByKey = getFulfillmentProfileByKey,
|
||||
createTaskClaimToken: createClaimToken = createTaskClaimToken,
|
||||
@@ -81,6 +91,7 @@ export async function syncDeliveryTasksForOrderWithDeps(
|
||||
const existingTasks = await listTasks(order.id)
|
||||
const tasks: DeliveryTaskRow[] = [...existingTasks]
|
||||
const existingTaskKeys = new Set(existingTasks.map(buildTaskUnitKey))
|
||||
const carrierEvidence = await loadCarrierEvidence(orderItems.map((item) => Number(item.id)))
|
||||
|
||||
writeInfoLog('[delivery-task-service]', '开始核对订单履约任务完整性', {
|
||||
...buildOrderLogContext(order),
|
||||
@@ -126,6 +137,32 @@ export async function syncDeliveryTasksForOrderWithDeps(
|
||||
continue
|
||||
}
|
||||
|
||||
const plannedChannel = executorKeyToFulfillmentChannel(plan.executorKey)
|
||||
if (plannedChannel) {
|
||||
const assignedChannel = String(item.fulfillment_channel || '').trim()
|
||||
if (item.fulfillment_status === 'assigned' && assignedChannel !== plannedChannel) {
|
||||
writeInfoLog('[delivery-task-service]', '订单项已分配其它渠道,跳过载体补建', {
|
||||
...buildOrderItemLogContext(item),
|
||||
assignedChannel,
|
||||
plannedChannel,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
const conflictingCarrier = findConflictingCarrier(
|
||||
carrierEvidence.get(Number(item.id)),
|
||||
plannedChannel,
|
||||
)
|
||||
if (conflictingCarrier) {
|
||||
writeWarnLog('[delivery-task-service]', '订单项已有其它真实载体,跳过载体补建', {
|
||||
...buildOrderItemLogContext(item),
|
||||
existingCarrier: conflictingCarrier,
|
||||
plannedChannel,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for (const unitIndex of missingUnitIndexes) {
|
||||
const createdAt = getNowIso()
|
||||
const initialStatus =
|
||||
@@ -256,6 +293,12 @@ export async function syncDeliveryTasksForOrderWithDeps(
|
||||
return preparedTasks.filter(isTaskRow)
|
||||
}
|
||||
|
||||
function executorKeyToFulfillmentChannel(executorKey: string): FulfillmentChannel | null {
|
||||
if (executorKey === FULFILLMENT_EXECUTOR_KEYS.AFFILIATE_DASH) return 'affiliate_dash'
|
||||
if (executorKey === FULFILLMENT_EXECUTOR_KEYS.MANUAL_DISPATCH) return 'manual'
|
||||
return null
|
||||
}
|
||||
|
||||
async function preparePaidTaskWithDiagnostics(
|
||||
order: OrderRow,
|
||||
task: TaskRow,
|
||||
|
||||
Reference in New Issue
Block a user