refactor(fulfillment): 移除飞飞/乐玩通道,仅保留 affiliate_dash
新单只路由 affiliate_dash(未命中走 manual_dispatch);历史飞飞/乐玩任务保留只读 stub,避免订单重同步失败。同步清理 cloudtentacles 调度、Admin 写路径与相关 env。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,76 +0,0 @@
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
import type { HttpErrorLike } from '../../../utils/http.js'
|
||||
import type { JsonObject } from '../../../types/json.js'
|
||||
import { resolvePersistedCloudtentaclesContextBySourceKeys } from '../../fulfillment/kuaishou-cloud/cloudtentacles-context.js'
|
||||
|
||||
export type { JsonObject }
|
||||
|
||||
export {
|
||||
KUAISHOU_CLOUD_FIXED_VN_KEY,
|
||||
isKuaishouCloudTask,
|
||||
normalizeKuaishouCloudFlow,
|
||||
normalizeKuaishouCloudRoleInfo,
|
||||
resolveKuaishouCloudBindUrlExpiresAt,
|
||||
} from '../../fulfillment/kuaishou-cloud/domain.js'
|
||||
export {
|
||||
prepareKuaishouCloudBindResourceWithFallback,
|
||||
resolveKuaishouCloudBindingResources,
|
||||
resolveKuaishouCloudVnKeyCandidates,
|
||||
} from '../../fulfillment/kuaishou-cloud/binding-resources.js'
|
||||
|
||||
export type CloudtentaclesContext = {
|
||||
baseUrl: string
|
||||
token: string
|
||||
deviceId: string
|
||||
deviceType: number
|
||||
resolvedSourceKey: string
|
||||
}
|
||||
|
||||
export type CloudSkuLikeItem = {
|
||||
id?: number | string
|
||||
name?: string
|
||||
price?: number | string
|
||||
count?: number | string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type { KuaishouCloudFlow } from '../../fulfillment/kuaishou-cloud/domain.js'
|
||||
|
||||
export type KuaishouCloudBindingResources = {
|
||||
skuId: number
|
||||
skuName: string
|
||||
vnKey: string
|
||||
skuItem: CloudSkuLikeItem | null
|
||||
knapsackItem: CloudSkuLikeItem | null
|
||||
resolvedByName: boolean
|
||||
}
|
||||
|
||||
export type PreparedKuaishouCloudBindResource = {
|
||||
vnKey: string
|
||||
vnId: number
|
||||
vnPhone: string
|
||||
bindUrl: string
|
||||
}
|
||||
|
||||
export function resolvePersistedCloudtentaclesContext(
|
||||
sourceKeys: unknown[],
|
||||
): CloudtentaclesContext {
|
||||
try {
|
||||
return resolvePersistedCloudtentaclesContextBySourceKeys(sourceKeys)
|
||||
} catch (error) {
|
||||
if (isMissingCloudtentaclesTokenError(error)) {
|
||||
throw createHttpError('当前 cloudtentacles 没有可用 token,请先到平台配置完成登录校验', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_kuaishou_cloud_missing_cloud_token',
|
||||
cause: error,
|
||||
})
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
function isMissingCloudtentaclesTokenError(error: unknown): boolean {
|
||||
const current = error as HttpErrorLike | null
|
||||
return String(current?.errorCode || '').trim() === 'kuaishou_cloud_missing_cloud_token'
|
||||
}
|
||||
+3
-227
@@ -18,15 +18,6 @@ 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 {
|
||||
dispatchFulfillmentTask,
|
||||
prepareFulfillmentBinding,
|
||||
rebindFulfillmentRole,
|
||||
refreshFulfillmentRole,
|
||||
returnFulfillmentNumber,
|
||||
} from '../../fulfillment/executors/registry.js'
|
||||
import { isKuaishouCloudTask, normalizeKuaishouCloudFlow } from './kuaishou-cloud-helpers.js'
|
||||
|
||||
import type {
|
||||
AdminEntityIdInput,
|
||||
AdminViewerSessionInput,
|
||||
@@ -35,195 +26,6 @@ import type { AdminTaskKuaishouIndustryConsumeInput } from '../../../types/admin
|
||||
import type { AdminTaskActionResponse } from '../../../types/admin/write-models.js'
|
||||
import type { KuaishouIndustryVoucherRow, TaskRow } from '../../../types/repository/rows.js'
|
||||
|
||||
export async function prepareAdminTaskKuaishouCloudFulfillment(
|
||||
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_prepare_kuaishou_cloud_forbidden',
|
||||
})
|
||||
}
|
||||
|
||||
if (!isKuaishouCloudTask(task)) {
|
||||
throw createHttpError('当前任务不是 kuaishou-lewan 履约任务', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_not_kuaishou_cloud',
|
||||
})
|
||||
}
|
||||
|
||||
const result = await prepareFulfillmentBinding(task, {
|
||||
source: 'admin_task_prepare',
|
||||
actor: buildAdminActionActor(session),
|
||||
force: true,
|
||||
})
|
||||
if (!result?.task) {
|
||||
throw createHttpError('当前任务不支持准备绑定资源', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_prepare_not_supported',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
task: mapTaskActionPayload(result.task),
|
||||
claimUrl: String(result.claimUrl || ''),
|
||||
token: String(result.token || ''),
|
||||
}
|
||||
}
|
||||
|
||||
export async function dispatchAdminTaskKuaishouCloudFulfillment(
|
||||
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_dispatch_kuaishou_cloud_forbidden',
|
||||
})
|
||||
}
|
||||
|
||||
if (!isKuaishouCloudTask(task)) {
|
||||
throw createHttpError('当前任务不是 kuaishou-lewan 履约任务', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_not_kuaishou_cloud',
|
||||
})
|
||||
}
|
||||
|
||||
const result = await dispatchFulfillmentTask(task, {
|
||||
source: 'admin_task_dispatch',
|
||||
actor: buildAdminActionActor(session),
|
||||
autoFinalize: false,
|
||||
})
|
||||
if (!result?.task) {
|
||||
throw createHttpError('当前任务不支持 executor 发货', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_dispatch_not_supported',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
task: mapTaskActionPayload(result.task),
|
||||
}
|
||||
}
|
||||
|
||||
export async function refreshAdminTaskKuaishouCloudRoleInfo(
|
||||
taskId: AdminEntityIdInput,
|
||||
session: AdminViewerSessionInput | null = null,
|
||||
): Promise<AdminTaskActionResponse> {
|
||||
const task = await getRequiredTask(taskId)
|
||||
const viewerContext = createAdminViewerContext(session)
|
||||
|
||||
if (!viewerContext.canOperateAssistedTask) {
|
||||
throw createHttpError('当前账号没有权限刷新角色信息', {
|
||||
statusCode: 403,
|
||||
errorCode: 'admin_task_refresh_kuaishou_cloud_role_forbidden',
|
||||
})
|
||||
}
|
||||
|
||||
if (!isKuaishouCloudTask(task)) {
|
||||
throw createHttpError('当前任务不是 kuaishou-lewan 履约任务', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_not_kuaishou_cloud',
|
||||
})
|
||||
}
|
||||
|
||||
const result = await refreshFulfillmentRole(task, {
|
||||
source: 'admin_task_refresh_role',
|
||||
actor: buildAdminActionActor(session),
|
||||
forceProbe: true,
|
||||
recordEvent: true,
|
||||
})
|
||||
if (!result?.task) {
|
||||
throw createHttpError('当前任务不支持刷新角色信息', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_refresh_not_supported',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
task: mapTaskActionPayload(result.task),
|
||||
}
|
||||
}
|
||||
|
||||
export async function rebindAdminTaskKuaishouCloudRole(
|
||||
taskId: AdminEntityIdInput,
|
||||
session: AdminViewerSessionInput | null = null,
|
||||
): Promise<AdminTaskActionResponse> {
|
||||
const task = await getRequiredTask(taskId)
|
||||
const viewerContext = createAdminViewerContext(session)
|
||||
|
||||
// 与刷新角色一致:客服可换绑协助处理 UID 绑错,不开放完整任务生命周期
|
||||
if (!viewerContext.canOperateAssistedTask) {
|
||||
throw createHttpError('当前账号没有权限换绑角色', {
|
||||
statusCode: 403,
|
||||
errorCode: 'admin_task_rebind_kuaishou_cloud_forbidden',
|
||||
})
|
||||
}
|
||||
|
||||
const result = await rebindFulfillmentRole(task, {
|
||||
source: 'admin_task_rebind_role',
|
||||
actor: buildAdminActionActor(session),
|
||||
})
|
||||
if (!result?.task) {
|
||||
throw createHttpError('当前任务不支持换绑角色', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_rebind_not_supported',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
task: mapTaskActionPayload(result.task),
|
||||
claimUrl: String(result.claimUrl || ''),
|
||||
token: String(result.token || ''),
|
||||
}
|
||||
}
|
||||
|
||||
export async function returnNumberAdminTaskKuaishouCloudFulfillment(
|
||||
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_return_kuaishou_cloud_forbidden',
|
||||
})
|
||||
}
|
||||
|
||||
if (!isKuaishouCloudTask(task)) {
|
||||
throw createHttpError('当前任务不是 kuaishou-lewan 履约任务', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_not_kuaishou_cloud',
|
||||
})
|
||||
}
|
||||
|
||||
// admin 退号 = 清理虚拟号占位,不核销电子凭证
|
||||
const result = await returnFulfillmentNumber(task, {
|
||||
source: 'admin_task_return_number',
|
||||
actor: buildAdminActionActor(session),
|
||||
consumeIndustryVoucher: false,
|
||||
})
|
||||
if (!result?.task) {
|
||||
throw createHttpError('当前任务不支持退还号码', {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_return_not_supported',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
task: mapTaskActionPayload(result.task),
|
||||
}
|
||||
}
|
||||
|
||||
export async function resendAdminTaskKuaishouIndustryVoucherCode(
|
||||
taskId: AdminEntityIdInput,
|
||||
session: AdminViewerSessionInput | null = null,
|
||||
@@ -250,7 +52,7 @@ export async function resendAdminTaskKuaishouIndustryVoucherCode(
|
||||
|
||||
if (!result.success) {
|
||||
const message = String(result.error || '电子凭证发码回调重发失败').trim()
|
||||
const failedTask = await updateTask(task.id, {
|
||||
await updateTask(task.id, {
|
||||
task_status: TASK_STATUS.MANUAL_REVIEW,
|
||||
result_code: 'kuaishou_industry_send_callback_resend_failed',
|
||||
result_message: message,
|
||||
@@ -268,7 +70,6 @@ export async function resendAdminTaskKuaishouIndustryVoucherCode(
|
||||
},
|
||||
now,
|
||||
)
|
||||
void failedTask
|
||||
throw createHttpError(message, {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_kuaishou_industry_resend_failed',
|
||||
@@ -405,7 +206,7 @@ export async function consumeAdminTaskKuaishouIndustryVoucher(
|
||||
|
||||
if (!result.ok || !result.voucher) {
|
||||
const message = String(result.errorMessage || '电子凭证核销失败').trim()
|
||||
const failedTask = await updateTask(task.id, {
|
||||
await updateTask(task.id, {
|
||||
task_status: TASK_STATUS.MANUAL_REVIEW,
|
||||
result_code: 'kuaishou_industry_manual_consume_failed',
|
||||
result_message: message,
|
||||
@@ -423,7 +224,6 @@ export async function consumeAdminTaskKuaishouIndustryVoucher(
|
||||
},
|
||||
now,
|
||||
)
|
||||
void failedTask
|
||||
throw createHttpError(message, {
|
||||
statusCode: 409,
|
||||
errorCode: 'admin_task_kuaishou_industry_consume_failed',
|
||||
@@ -436,30 +236,6 @@ export async function consumeAdminTaskKuaishouIndustryVoucher(
|
||||
})
|
||||
const consumeTargetTask = attachedConsumeTask || task
|
||||
const taskContext = parseTaskContext(consumeTargetTask)
|
||||
const hasCloudFulfillmentContext = Boolean(
|
||||
taskContext.kuaishouCloudFulfillment &&
|
||||
typeof taskContext.kuaishouCloudFulfillment === 'object' &&
|
||||
!Array.isArray(taskContext.kuaishouCloudFulfillment),
|
||||
)
|
||||
const flow = hasCloudFulfillmentContext
|
||||
? normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment)
|
||||
: null
|
||||
const nextContext = {
|
||||
...taskContext,
|
||||
...(flow
|
||||
? {
|
||||
kuaishouCloudFulfillment: {
|
||||
...flow,
|
||||
consume: {
|
||||
...flow.consume,
|
||||
status: 'success',
|
||||
consumedAt: result.voucher.consumed_at || now,
|
||||
errorMessage: '',
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
const updatedTask = await updateTask(consumeTargetTask.id, {
|
||||
task_status: TASK_STATUS.COMPLETED,
|
||||
delivery_status: 'delivered',
|
||||
@@ -467,7 +243,7 @@ export async function consumeAdminTaskKuaishouIndustryVoucher(
|
||||
result_message: '电子凭证已手动核销完成',
|
||||
redeemed_at: result.voucher.consumed_at || now,
|
||||
last_error: '',
|
||||
context_json: JSON.stringify(nextContext),
|
||||
context_json: JSON.stringify(taskContext),
|
||||
updated_at: now,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user