添加快手 Cloud 换绑角色功能

This commit is contained in:
yml
2026-05-30 11:23:52 +08:00
parent 681ff44cbc
commit 1c50569ea9
22 changed files with 1537 additions and 953 deletions
@@ -21,20 +21,15 @@ import {
import { createHttpError } from '../../../utils/http.js'
import { nowIso } from '../../../utils/time.js'
import { TASK_STATUS } from '../../../domain/task-status.js'
import {
createAdminViewerContext,
parseTaskContext,
} from '../admin-read-shared-helpers.js'
import {
getRequiredTask,
mapTaskActionPayload,
} from '../admin-task-read-helpers.js'
import { createAdminViewerContext, parseTaskContext } from '../admin-read-shared-helpers.js'
import { getRequiredTask, mapTaskActionPayload } from '../admin-task-read-helpers.js'
import {
ensureTaskClaimLink,
getTaskClaimExpiresAt,
maskCode,
maskPhone,
} from '../write-helpers.js'
import { rebindKuaishouCloudTaskRole } from '../../fulfillment/kuaishou-cloud/index.js'
import {
isKuaishouCloudTask,
normalizeKuaishouCloudFlow,
@@ -210,17 +205,22 @@ export async function prepareAdminTaskKuaishouCloudFulfillment(
updated_at: now,
})
await createTaskEvent(task.id, 'kuaishou_cloud_binding_prepared', {
skuId: flowWithResolvedBinding.binding.skuId,
skuName: flowWithResolvedBinding.binding.skuName,
vnKey: preparedBinding.vnKey,
vnId,
vnPhoneMasked: maskPhone(vnPhone),
bindUrl: preparedBinding.bindUrl,
purchaseTriggered,
usedKnapsack,
resolvedByName: resolvedBinding.resolvedByName,
}, now)
await createTaskEvent(
task.id,
'kuaishou_cloud_binding_prepared',
{
skuId: flowWithResolvedBinding.binding.skuId,
skuName: flowWithResolvedBinding.binding.skuName,
vnKey: preparedBinding.vnKey,
vnId,
vnPhoneMasked: maskPhone(vnPhone),
bindUrl: preparedBinding.bindUrl,
purchaseTriggered,
usedKnapsack,
resolvedByName: resolvedBinding.resolvedByName,
},
now,
)
return {
task: mapTaskActionPayload(updatedTask),
@@ -280,10 +280,10 @@ export async function dispatchAdminTaskKuaishouCloudFulfillment(
now,
actor: session
? {
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
: null,
source: 'admin_task_dispatch',
errorCodePrefix: 'admin_task_kuaishou_cloud',
@@ -309,13 +309,14 @@ export async function dispatchAdminTaskKuaishouCloudFulfillment(
...syncedFlow.ticket,
code: ticketCode || persistedTicketCode,
capturedAt: ticketCode ? now : syncedFlow.ticket.capturedAt,
capturedBy: ticketCode && session
? {
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
: syncedFlow.ticket.capturedBy,
capturedBy:
ticketCode && session
? {
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
: syncedFlow.ticket.capturedBy,
},
dispatch: {
...syncedFlow.dispatch,
@@ -323,10 +324,10 @@ export async function dispatchAdminTaskKuaishouCloudFulfillment(
dispatchAt: now,
dispatchBy: session
? {
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
: null,
sendType: Number(dispatchResult.sendType || 0) || 0,
note: String(dispatchResult.note || dispatchResult.responseMessage || '').trim(),
@@ -338,20 +339,27 @@ export async function dispatchAdminTaskKuaishouCloudFulfillment(
task_status: TASK_STATUS.DISPATCHED_PENDING_RETURN,
delivery_status: 'delivered',
result_code: 'kuaishou_cloud_dispatched',
result_message: String(dispatchResult.responseMessage || dispatchResult.note || 'cloudtentacles 发货成功').trim(),
result_message: String(
dispatchResult.responseMessage || dispatchResult.note || 'cloudtentacles 发货成功',
).trim(),
last_error: '',
context_json: JSON.stringify(nextContext),
updated_at: now,
})
await createTaskEvent(task.id, 'kuaishou_cloud_dispatched', {
ticketCodeMasked: maskCode(ticketCode || persistedTicketCode),
skuId: syncedFlow.binding.skuId,
vnId: syncedFlow.binding.vnId,
vnPhoneMasked: maskPhone(syncedFlow.binding.vnPhone),
sendType: dispatchResult.sendType,
note: dispatchResult.note,
}, now)
await createTaskEvent(
task.id,
'kuaishou_cloud_dispatched',
{
ticketCodeMasked: maskCode(ticketCode || persistedTicketCode),
skuId: syncedFlow.binding.skuId,
vnId: syncedFlow.binding.vnId,
vnPhoneMasked: maskPhone(syncedFlow.binding.vnPhone),
sendType: dispatchResult.sendType,
note: dispatchResult.note,
},
now,
)
return {
task: mapTaskActionPayload(updatedTask),
@@ -414,7 +422,8 @@ export async function refreshAdminTaskKuaishouCloudRoleInfo(
name: bindInfo.name,
rid: bindInfo.rid,
refreshedAt: now,
errorMessage: bindInfo.name || bindInfo.rid ? '' : '当前还没有查询到角色信息,请让客户完成绑定后再刷新',
errorMessage:
bindInfo.name || bindInfo.rid ? '' : '当前还没有查询到角色信息,请让客户完成绑定后再刷新',
rawInfo: bindInfo.rawInfo,
},
},
@@ -427,24 +436,61 @@ export async function refreshAdminTaskKuaishouCloudRoleInfo(
updated_at: now,
})
await createTaskEvent(task.id, 'kuaishou_cloud_role_info_refreshed', {
roleName: bindInfo.name,
roleId: bindInfo.rid,
vnId: flow.binding.vnId,
refreshedBy: session
? {
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
: null,
}, now)
await createTaskEvent(
task.id,
'kuaishou_cloud_role_info_refreshed',
{
roleName: bindInfo.name,
roleId: bindInfo.rid,
vnId: flow.binding.vnId,
refreshedBy: session
? {
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
: null,
},
now,
)
return {
task: mapTaskActionPayload(updatedTask),
}
}
export async function rebindAdminTaskKuaishouCloudRole(
taskId: AdminEntityIdInput,
session: AdminViewerSessionInput | null = null,
): Promise<AdminTaskActionResponse> {
const task = await getRequiredTask(taskId)
const viewerContext = createAdminViewerContext(session)
if (!viewerContext.canManageTaskLifecycle) {
throw createHttpError('当前账号没有权限换绑角色', {
statusCode: 403,
errorCode: 'admin_task_rebind_kuaishou_cloud_forbidden',
})
}
const result = await rebindKuaishouCloudTaskRole(task, {
source: 'admin_task_rebind_role',
actor: session
? {
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
: null,
})
return {
task: mapTaskActionPayload(result.task),
claimUrl: result.claimUrl,
token: result.token,
}
}
export async function returnNumberAdminTaskKuaishouCloudFulfillment(
taskId: AdminEntityIdInput,
session: AdminViewerSessionInput | null = null,
@@ -519,7 +565,11 @@ export async function returnNumberAdminTaskKuaishouCloudFulfillment(
consumeStatus = consumeResult.consumed ? 'success' : 'failed'
consumedAt = consumeResult.consumed ? now : null
consumeErrorMessage = String(consumeResult.errorMessage || '').trim()
} else if (!shopConfig || shopConfig.enabled === false || !String(shopConfig.cookie || '').trim()) {
} else if (
!shopConfig ||
shopConfig.enabled === false ||
!String(shopConfig.cookie || '').trim()
) {
consumeStatus = 'failed'
consumeErrorMessage = '订单对应快手小店缺少可用 Cookie,无法执行快手核销'
} else {
@@ -561,10 +611,10 @@ export async function returnNumberAdminTaskKuaishouCloudFulfillment(
returnedAt: now,
returnedBy: session
? {
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
userId: Number(session.userId || 0) || 0,
username: String(session.username || '').trim(),
role: String(session.role || '').trim(),
}
: null,
},
consume: {
@@ -590,10 +640,15 @@ export async function returnNumberAdminTaskKuaishouCloudFulfillment(
updated_at: now,
})
await createTaskEvent(task.id, 'kuaishou_cloud_number_returned', {
vnId: flow.binding.vnId,
vnPhoneMasked: maskPhone(flow.binding.vnPhone),
}, now)
await createTaskEvent(
task.id,
'kuaishou_cloud_number_returned',
{
vnId: flow.binding.vnId,
vnPhoneMasked: maskPhone(flow.binding.vnPhone),
},
now,
)
await createTaskEvent(
task.id,