Files
order_site/apps/backend/src/services/fulfillment/kuaishou-cloud/confirm-role.ts
T
yml2213 792680bd19 重构 lewan 履约:拆分发货模块并统一 registry 入口
将 task-finalization 拆为 dispatch/stock/return/redeem/confirm 等用例,
claim 与 admin 经 executor registry 调用;admin 退号仅清理虚拟号不核销。
2026-07-10 22:23:26 +08:00

107 lines
3.4 KiB
TypeScript

import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { updateTask } from '../../../repositories/task-repo.js'
import {
TASK_STATUS,
isKuaishouCloudRoleConfirmSettledStatus,
} from '../../../domain/task-status.js'
import { createHttpError } from '../../../utils/http.js'
import { nowIso } from '../../../utils/time.js'
import type { TaskRow } from '../../../types/repository/rows.js'
import {
assertBoundUidMatchesExpected,
assertClaimExpectedUidReady,
} from '../../claim/claim-identity.js'
import { isKuaishouCloudTask, normalizeKuaishouCloudFlow, type JsonObject } from './domain.js'
import { isKuaishouCloudMockContext, isKuaishouCloudMockTask } from './mock-helpers.js'
import { refreshKuaishouCloudTaskRoleInfo } from './refresh-role-info.js'
import { normalizeActor, parseTaskContext } from './task-context.js'
export type ConfirmKuaishouCloudRoleResult = {
task: TaskRow
alreadySettled: boolean
}
/**
* lewan 确认角色用例:刷新角色 → UID 闸门 → ROLE_CONFIRMED。
* 一键兑换路径里 WAITING_BINDING 的自动晋升在 redeem 内完成,不必先调本函数。
*/
export async function confirmKuaishouCloudTaskRole(
task: TaskRow,
options: JsonObject = {},
): Promise<ConfirmKuaishouCloudRoleResult> {
if (!isKuaishouCloudTask(task)) {
throw createHttpError('当前任务不是 kuaishou-lewan 履约任务', {
statusCode: 409,
errorCode: 'kuaishou_cloud_task_invalid',
})
}
const now = String(options.now || '').trim() || nowIso()
const source = String(options.source || 'system_confirm_role').trim() || 'system_confirm_role'
const actor = normalizeActor(options.actor)
const errorCodePrefix =
String(options.errorCodePrefix || 'kuaishou_cloud_confirm').trim() || 'kuaishou_cloud_confirm'
if (isKuaishouCloudRoleConfirmSettledStatus(task.task_status)) {
return { task, alreadySettled: true }
}
const expectedUid = assertClaimExpectedUidReady(task)
const mockMode = isKuaishouCloudMockTask(task) || isKuaishouCloudMockContext(parseTaskContext(task))
const refreshed = mockMode
? { task }
: await refreshKuaishouCloudTaskRoleInfo(task, {
source,
actor,
recordEvent: options.recordEvent === true,
forceProbe: options.forceProbe !== false,
})
const flow = normalizeKuaishouCloudFlow(
parseTaskContext(refreshed.task).kuaishouCloudFulfillment,
)
if (!flow.binding.vnPhone || !flow.binding.roleName || !flow.binding.roleId) {
throw createHttpError('角色信息还未刷新到系统,请完成绑定后稍等片刻再试', {
statusCode: 409,
errorCode: `${errorCodePrefix}_role_not_ready`,
})
}
if (!mockMode) {
assertBoundUidMatchesExpected(refreshed.task, flow, {
errorCodePrefix,
})
}
const updatedTask =
(await updateTask(task.id, {
task_status: TASK_STATUS.ROLE_CONFIRMED,
role_id: flow.binding.roleId,
role_name: flow.binding.roleName,
user_action_status: TASK_STATUS.ROLE_CONFIRMED,
role_confirmed_at: now,
last_error: '',
updated_at: now,
})) ||
refreshed.task ||
task
await createTaskEvent(
task.id,
'kuaishou_cloud_role_confirmed',
{
expectedUid,
vnPhone: flow.binding.vnPhone,
roleName: flow.binding.roleName,
roleId: flow.binding.roleId,
source,
actor,
},
now,
)
return { task: updatedTask, alreadySettled: false }
}