将 task-finalization 拆为 dispatch/stock/return/redeem/confirm 等用例, claim 与 admin 经 executor registry 调用;admin 退号仅清理虚拟号不核销。
107 lines
3.4 KiB
TypeScript
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 }
|
|
}
|