添加快手 Cloud 换绑角色功能
This commit is contained in:
@@ -7,12 +7,18 @@ import { listTaskEventsByTaskId } from '../../repositories/task-event-repo.js'
|
||||
import { listCloudtentaclesSources } from '../platforms/cloudtentacles/source-config-service.js'
|
||||
import { createHttpError } from '../../utils/http.js'
|
||||
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
||||
import { normalizeDateQuery, normalizePage, normalizePageSize, safeParseJson } from './admin-query-utils.js'
|
||||
import {
|
||||
normalizeDateQuery,
|
||||
normalizePage,
|
||||
normalizePageSize,
|
||||
safeParseJson,
|
||||
} from './admin-query-utils.js'
|
||||
import {
|
||||
canCompleteManualDispatchTaskStatus,
|
||||
canDispatchKuaishouCloudFulfillmentStatus,
|
||||
canMarkManualReviewTaskStatus,
|
||||
canPrepareKuaishouCloudFulfillmentStatus,
|
||||
canRebindKuaishouCloudRoleStatus,
|
||||
canReturnKuaishouCloudFulfillmentStatus,
|
||||
canRetryTaskStatus,
|
||||
} from '../../domain/task-status.js'
|
||||
@@ -55,7 +61,9 @@ import type {
|
||||
|
||||
type JsonRecord = Record<string, any>
|
||||
|
||||
export async function getAdminOrders(query: AdminOrderListQueryInput = {}): Promise<AdminOrderListResponse> {
|
||||
export async function getAdminOrders(
|
||||
query: AdminOrderListQueryInput = {},
|
||||
): Promise<AdminOrderListResponse> {
|
||||
const page = normalizePage(query.page)
|
||||
const pageSize = normalizePageSize(query.pageSize)
|
||||
const { items, total } = await listOrders({
|
||||
@@ -110,9 +118,10 @@ export async function getAdminOrderDetail(orderId: AdminEntityIdInput): Promise<
|
||||
createdAt: order.created_at,
|
||||
updatedAt: order.updated_at,
|
||||
itemSummary,
|
||||
rawPayload: order.raw_payload_json && typeof order.raw_payload_json === 'object'
|
||||
? order.raw_payload_json
|
||||
: JSON.parse(String(order.raw_payload_json || '{}')),
|
||||
rawPayload:
|
||||
order.raw_payload_json && typeof order.raw_payload_json === 'object'
|
||||
? order.raw_payload_json
|
||||
: JSON.parse(String(order.raw_payload_json || '{}')),
|
||||
fulfillmentProgress: buildOrderFulfillmentProgress(tasks),
|
||||
},
|
||||
items: items.map((item) => ({
|
||||
@@ -122,9 +131,10 @@ export async function getAdminOrderDetail(orderId: AdminEntityIdInput): Promise<
|
||||
itemTitle: resolveOrderItemTitle(item),
|
||||
quantity: item.quantity,
|
||||
deliveryMode: resolveOrderItemDeliveryMode(tasks, item.id),
|
||||
spec: item.spec_json && typeof item.spec_json === 'object'
|
||||
? item.spec_json
|
||||
: JSON.parse(String(item.spec_json || '{}')),
|
||||
spec:
|
||||
item.spec_json && typeof item.spec_json === 'object'
|
||||
? item.spec_json
|
||||
: JSON.parse(String(item.spec_json || '{}')),
|
||||
})),
|
||||
tasks: tasks.map((task) => mapAdminTaskSummary(task)),
|
||||
}
|
||||
@@ -182,46 +192,49 @@ export async function getAdminTaskDetail(
|
||||
const claimUrl = claimToken ? buildClaimUrl(claimToken.token) : ''
|
||||
const screenshotUrl = await resolveAdminTaskScreenshotUrl(task, viewerContext)
|
||||
const cloudSourceLabelMap = buildCloudSourceLabelMap()
|
||||
const kuaishouCloudFulfillment = mapKuaishouCloudFulfillmentContext(
|
||||
taskContext.kuaishouCloudFulfillment,
|
||||
{ cloudSourceLabelMap },
|
||||
) || mapKuaishouCloudTaskStateProjection(task, { cloudSourceLabelMap })
|
||||
const kuaishouCloudFulfillment =
|
||||
mapKuaishouCloudFulfillmentContext(taskContext.kuaishouCloudFulfillment, {
|
||||
cloudSourceLabelMap,
|
||||
}) || mapKuaishouCloudTaskStateProjection(task, { cloudSourceLabelMap })
|
||||
|
||||
return {
|
||||
task: mapAdminTaskListItem({
|
||||
...task,
|
||||
sku_code: orderItem?.sku_code || '',
|
||||
sku_name: orderItem?.sku_name || '',
|
||||
claim_token: claimToken?.token || '',
|
||||
}, viewerContext),
|
||||
task: mapAdminTaskListItem(
|
||||
{
|
||||
...task,
|
||||
sku_code: orderItem?.sku_code || '',
|
||||
sku_name: orderItem?.sku_name || '',
|
||||
claim_token: claimToken?.token || '',
|
||||
},
|
||||
viewerContext,
|
||||
),
|
||||
order: order
|
||||
? {
|
||||
orderId: order.id,
|
||||
provider: order.provider || '',
|
||||
platform: order.platform,
|
||||
shopId: order.shop_id || '',
|
||||
shopName: order.shop_name || '',
|
||||
platformOrderId: order.platform_order_id,
|
||||
payStatus: order.pay_status,
|
||||
orderStatus: order.order_status,
|
||||
}
|
||||
orderId: order.id,
|
||||
provider: order.provider || '',
|
||||
platform: order.platform,
|
||||
shopId: order.shop_id || '',
|
||||
shopName: order.shop_name || '',
|
||||
platformOrderId: order.platform_order_id,
|
||||
payStatus: order.pay_status,
|
||||
orderStatus: order.order_status,
|
||||
}
|
||||
: null,
|
||||
orderItem: orderItem
|
||||
? {
|
||||
orderItemId: orderItem.id,
|
||||
skuCode: orderItem.sku_code,
|
||||
skuName: orderItem.sku_name,
|
||||
quantity: orderItem.quantity,
|
||||
}
|
||||
orderItemId: orderItem.id,
|
||||
skuCode: orderItem.sku_code,
|
||||
skuName: orderItem.sku_name,
|
||||
quantity: orderItem.quantity,
|
||||
}
|
||||
: null,
|
||||
claimToken: claimToken
|
||||
? {
|
||||
primaryClaimTokenId: claimToken.id,
|
||||
token: viewerContext.canViewSensitiveTaskData ? claimToken.token : '',
|
||||
status: claimToken.status,
|
||||
expiredAt: claimToken.expired_at,
|
||||
claimUrl,
|
||||
}
|
||||
primaryClaimTokenId: claimToken.id,
|
||||
token: viewerContext.canViewSensitiveTaskData ? claimToken.token : '',
|
||||
status: claimToken.status,
|
||||
expiredAt: claimToken.expired_at,
|
||||
claimUrl,
|
||||
}
|
||||
: null,
|
||||
artifacts: viewerContext.canViewSensitiveTaskData ? safeParseJson(task.artifacts_json) : {},
|
||||
screenshotUrl,
|
||||
@@ -236,27 +249,42 @@ export async function getAdminTaskDetail(
|
||||
manualDispatch: mapManualDispatchContext(taskContext.manualDispatch, viewerContext),
|
||||
events: taskEvents.map(mapAdminTaskEvent),
|
||||
operations: {
|
||||
canRetry: viewerContext.canManageTaskLifecycle
|
||||
&& !isManualDispatchTask(task)
|
||||
&& canRetryTaskStatus(task.task_status),
|
||||
canRetry:
|
||||
viewerContext.canManageTaskLifecycle &&
|
||||
!isManualDispatchTask(task) &&
|
||||
canRetryTaskStatus(task.task_status),
|
||||
canRegenerateClaimLink: canRegenerateClaimLinkForViewer(task, viewerContext),
|
||||
canClose: canViewerCloseTask(task, viewerContext),
|
||||
canMarkManualReview: viewerContext.canManageTaskLifecycle && canMarkManualReviewTaskStatus(task.task_status),
|
||||
canCompleteManualDispatch: viewerContext.canManageTaskLifecycle && isManualDispatchTask(task) && canCompleteManualDispatchTaskStatus(task.task_status),
|
||||
canPrepareKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
||||
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
||||
&& String(kuaishouCloudFulfillment?.dispatch.status || 'pending').trim() === 'pending'
|
||||
&& String(kuaishouCloudFulfillment?.returnNumber.status || 'pending').trim() === 'pending'
|
||||
&& canPrepareKuaishouCloudFulfillmentStatus(task.task_status),
|
||||
canRefreshKuaishouCloudRoleInfo: viewerContext.canOperateAssistedTask
|
||||
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
||||
&& Number(kuaishouCloudFulfillment?.binding.vnId || 0) > 0,
|
||||
canDispatchKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
||||
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
||||
&& canDispatchKuaishouCloudFulfillmentStatus(task.task_status),
|
||||
canReturnKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
||||
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
||||
&& canReturnKuaishouCloudFulfillmentStatus(task.task_status),
|
||||
canMarkManualReview:
|
||||
viewerContext.canManageTaskLifecycle && canMarkManualReviewTaskStatus(task.task_status),
|
||||
canCompleteManualDispatch:
|
||||
viewerContext.canManageTaskLifecycle &&
|
||||
isManualDispatchTask(task) &&
|
||||
canCompleteManualDispatchTaskStatus(task.task_status),
|
||||
canPrepareKuaishouCloudFulfillment:
|
||||
viewerContext.canManageTaskLifecycle &&
|
||||
String(task.executor_key || '').trim() === 'kuaishou_ct_assisted' &&
|
||||
String(kuaishouCloudFulfillment?.dispatch.status || 'pending').trim() === 'pending' &&
|
||||
String(kuaishouCloudFulfillment?.returnNumber.status || 'pending').trim() === 'pending' &&
|
||||
canPrepareKuaishouCloudFulfillmentStatus(task.task_status),
|
||||
canRefreshKuaishouCloudRoleInfo:
|
||||
viewerContext.canOperateAssistedTask &&
|
||||
String(task.executor_key || '').trim() === 'kuaishou_ct_assisted' &&
|
||||
Number(kuaishouCloudFulfillment?.binding.vnId || 0) > 0,
|
||||
canRebindKuaishouCloudRole:
|
||||
viewerContext.canManageTaskLifecycle &&
|
||||
String(task.executor_key || '').trim() === 'kuaishou_ct_assisted' &&
|
||||
canRebindKuaishouCloudRoleStatus(task.task_status) &&
|
||||
String(kuaishouCloudFulfillment?.dispatch.status || 'pending').trim() !== 'success' &&
|
||||
Number(kuaishouCloudFulfillment?.binding.vnId || 0) > 0,
|
||||
canDispatchKuaishouCloudFulfillment:
|
||||
viewerContext.canManageTaskLifecycle &&
|
||||
String(task.executor_key || '').trim() === 'kuaishou_ct_assisted' &&
|
||||
canDispatchKuaishouCloudFulfillmentStatus(task.task_status),
|
||||
canReturnKuaishouCloudFulfillment:
|
||||
viewerContext.canManageTaskLifecycle &&
|
||||
String(task.executor_key || '').trim() === 'kuaishou_ct_assisted' &&
|
||||
canReturnKuaishouCloudFulfillmentStatus(task.task_status),
|
||||
canViewSensitiveTaskData: viewerContext.canViewSensitiveTaskData,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@ import {
|
||||
parseTaskContext as parseTaskContextValue,
|
||||
parseTaskState as parseTaskStateValue,
|
||||
} from '../../utils/task-json.js'
|
||||
import {
|
||||
canRegenerateClaimLinkStatus,
|
||||
isTaskFinalStatus,
|
||||
} from '../../domain/task-status.js'
|
||||
import { canRegenerateClaimLinkStatus, isTaskFinalStatus } from '../../domain/task-status.js'
|
||||
|
||||
import type { AdminViewerSessionInput } from '../../types/admin/read-inputs.js'
|
||||
import type { OrderItemRow, TaskRow } from '../../types/repository/rows.js'
|
||||
@@ -51,16 +48,19 @@ export function mapManualDispatchContext(
|
||||
return {
|
||||
outcome: String(record.outcome || '').trim(),
|
||||
deliveryReference: String(record.deliveryReference || '').trim(),
|
||||
deliveredCredential: viewerContext.canViewSensitiveTaskData ? String(record.deliveredCredential || '').trim() : '',
|
||||
deliveredCredential: viewerContext.canViewSensitiveTaskData
|
||||
? String(record.deliveredCredential || '').trim()
|
||||
: '',
|
||||
resultMessage: String(record.resultMessage || '').trim(),
|
||||
completedAt: record.completedAt || null,
|
||||
completedBy: record.completedBy && typeof record.completedBy === 'object'
|
||||
? {
|
||||
userId: Number(record.completedBy.userId || 0) || 0,
|
||||
username: String(record.completedBy.username || '').trim(),
|
||||
role: String(record.completedBy.role || '').trim(),
|
||||
}
|
||||
: null,
|
||||
completedBy:
|
||||
record.completedBy && typeof record.completedBy === 'object'
|
||||
? {
|
||||
userId: Number(record.completedBy.userId || 0) || 0,
|
||||
username: String(record.completedBy.username || '').trim(),
|
||||
role: String(record.completedBy.role || '').trim(),
|
||||
}
|
||||
: null,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ export function mapKuaishouCloudFulfillmentContext(
|
||||
const role = record.role && typeof record.role === 'object' ? record.role : {}
|
||||
const purchase = record.purchase && typeof record.purchase === 'object' ? record.purchase : {}
|
||||
const dispatch = record.dispatch && typeof record.dispatch === 'object' ? record.dispatch : {}
|
||||
const returnNumber = record.returnNumber && typeof record.returnNumber === 'object' ? record.returnNumber : {}
|
||||
const returnNumber =
|
||||
record.returnNumber && typeof record.returnNumber === 'object' ? record.returnNumber : {}
|
||||
const consume = record.consume && typeof record.consume === 'object' ? record.consume : {}
|
||||
const cloudSourceKeys = Array.isArray(binding.cloudSourceKeys)
|
||||
? binding.cloudSourceKeys.map((value: unknown) => String(value || '').trim()).filter(Boolean)
|
||||
@@ -156,6 +157,7 @@ export function mapKuaishouCloudFulfillmentContext(
|
||||
consumedAt: consume.consumedAt || null,
|
||||
errorMessage: String(consume.errorMessage || '').trim(),
|
||||
},
|
||||
rebind: mapKuaishouCloudRebindContext(record.rebind),
|
||||
notes: String(record.notes || '').trim(),
|
||||
}
|
||||
}
|
||||
@@ -204,9 +206,13 @@ export function mapKuaishouCloudTaskStateProjection(
|
||||
binding: {
|
||||
prepareStatus: task.kuaishou_bind_url ? 'ready' : 'pending',
|
||||
cloudSourceKeys: sourceKey ? [sourceKey] : [],
|
||||
cloudSourceLabels: sourceKey ? [resolveCloudSourceLabel(sourceKey, options.cloudSourceLabelMap)] : [],
|
||||
cloudSourceLabels: sourceKey
|
||||
? [resolveCloudSourceLabel(sourceKey, options.cloudSourceLabelMap)]
|
||||
: [],
|
||||
resolvedSourceKey: sourceKey,
|
||||
resolvedSourceLabel: sourceKey ? resolveCloudSourceLabel(sourceKey, options.cloudSourceLabelMap) : '',
|
||||
resolvedSourceLabel: sourceKey
|
||||
? resolveCloudSourceLabel(sourceKey, options.cloudSourceLabelMap)
|
||||
: '',
|
||||
skuId: 0,
|
||||
skuName: '',
|
||||
vnKey: '',
|
||||
@@ -255,6 +261,10 @@ export function mapKuaishouCloudTaskStateProjection(
|
||||
consumedAt: null,
|
||||
errorMessage: '',
|
||||
},
|
||||
rebind: {
|
||||
currentAttempt: 0,
|
||||
history: [],
|
||||
},
|
||||
notes: '',
|
||||
}
|
||||
}
|
||||
@@ -263,13 +273,67 @@ function resolveCloudSourceLabel(sourceKey: string, labelMap: CloudSourceLabelMa
|
||||
const key = String(sourceKey || '').trim()
|
||||
if (!key) return ''
|
||||
|
||||
const label = labelMap instanceof Map
|
||||
? labelMap.get(key)
|
||||
: labelMap?.[key]
|
||||
const label = labelMap instanceof Map ? labelMap.get(key) : labelMap?.[key]
|
||||
|
||||
return String(label || key).trim() || key
|
||||
}
|
||||
|
||||
function mapKuaishouCloudRebindContext(value: unknown): JsonRecord {
|
||||
const record = value && typeof value === 'object' ? (value as JsonRecord) : {}
|
||||
const history = Array.isArray(record.history) ? record.history : []
|
||||
|
||||
return {
|
||||
currentAttempt: Math.max(0, Number(record.currentAttempt || 0) || 0),
|
||||
history: history.map((item) => mapKuaishouCloudRebindHistoryItem(item)).filter(Boolean),
|
||||
}
|
||||
}
|
||||
|
||||
function mapKuaishouCloudRebindHistoryItem(value: unknown): JsonRecord | null {
|
||||
if (!value || typeof value !== 'object') {
|
||||
return null
|
||||
}
|
||||
|
||||
const record = value as JsonRecord
|
||||
const oldBinding =
|
||||
record.oldBinding && typeof record.oldBinding === 'object'
|
||||
? (record.oldBinding as JsonRecord)
|
||||
: {}
|
||||
const newBinding =
|
||||
record.newBinding && typeof record.newBinding === 'object'
|
||||
? (record.newBinding as JsonRecord)
|
||||
: null
|
||||
|
||||
return {
|
||||
attempt: Math.max(1, Number(record.attempt || 1) || 1),
|
||||
source: String(record.source || '').trim(),
|
||||
requestedAt: record.requestedAt || null,
|
||||
requestedBy:
|
||||
record.requestedBy && typeof record.requestedBy === 'object' ? record.requestedBy : null,
|
||||
status: String(record.status || '').trim(),
|
||||
errorMessage: String(record.errorMessage || '').trim(),
|
||||
oldBinding: {
|
||||
vnKey: String(oldBinding.vnKey || '').trim(),
|
||||
vnId: Number(oldBinding.vnId || 0) || 0,
|
||||
vnPhone: String(oldBinding.vnPhone || '').trim(),
|
||||
bindUrl: String(oldBinding.bindUrl || '').trim(),
|
||||
bindPreparedAt: oldBinding.bindPreparedAt || null,
|
||||
bindExpiresAt: oldBinding.bindExpiresAt || null,
|
||||
roleName: String(oldBinding.roleName || '').trim(),
|
||||
roleId: String(oldBinding.roleId || '').trim(),
|
||||
},
|
||||
newBinding: newBinding
|
||||
? {
|
||||
vnKey: String(newBinding.vnKey || '').trim(),
|
||||
vnId: Number(newBinding.vnId || 0) || 0,
|
||||
vnPhone: String(newBinding.vnPhone || '').trim(),
|
||||
bindUrl: String(newBinding.bindUrl || '').trim(),
|
||||
bindPreparedAt: newBinding.bindPreparedAt || null,
|
||||
bindExpiresAt: newBinding.bindExpiresAt || null,
|
||||
}
|
||||
: null,
|
||||
}
|
||||
}
|
||||
|
||||
export function mapRedeemResolutionContext(value: unknown): JsonRecord | null {
|
||||
if (!value || typeof value !== 'object') {
|
||||
return null
|
||||
@@ -278,8 +342,8 @@ export function mapRedeemResolutionContext(value: unknown): JsonRecord | null {
|
||||
const record = value as JsonRecord
|
||||
const attempts = Array.isArray(record.attempts)
|
||||
? record.attempts
|
||||
.map((attempt) => mapRedeemResolutionAttempt(attempt))
|
||||
.filter((attempt): attempt is RedeemResolutionAttempt => Boolean(attempt))
|
||||
.map((attempt) => mapRedeemResolutionAttempt(attempt))
|
||||
.filter((attempt): attempt is RedeemResolutionAttempt => Boolean(attempt))
|
||||
: []
|
||||
|
||||
return {
|
||||
@@ -296,7 +360,9 @@ export function getTaskPrimaryClaimTokenId(task: TaskLike | null | undefined): n
|
||||
return Number.isFinite(value) && value > 0 ? value : null
|
||||
}
|
||||
|
||||
export function createAdminViewerContext(session: AdminViewerSessionInput | null = null): AdminViewerContext {
|
||||
export function createAdminViewerContext(
|
||||
session: AdminViewerSessionInput | null = null,
|
||||
): AdminViewerContext {
|
||||
const role = normalizeAdminRole(session?.role)
|
||||
|
||||
return {
|
||||
@@ -326,7 +392,11 @@ export function canViewerCloseTask(task: TaskLike, viewerContext: AdminViewerCon
|
||||
return !isTaskFinalStatus(task?.task_status)
|
||||
}
|
||||
|
||||
export function resolveDisplayShopName(provider: unknown, shopId: unknown, shopName: unknown): string {
|
||||
export function resolveDisplayShopName(
|
||||
provider: unknown,
|
||||
shopId: unknown,
|
||||
shopName: unknown,
|
||||
): string {
|
||||
const normalizedShopName = String(shopName || '').trim()
|
||||
if (normalizedShopName) {
|
||||
return normalizedShopName
|
||||
@@ -367,8 +437,13 @@ export function resolveOrderItemTitle(item: Partial<OrderItemRow> | null | undef
|
||||
])
|
||||
}
|
||||
|
||||
export function resolveOrderItemDeliveryMode(tasks: TaskLike[] | null | undefined, orderItemId: number | string): string {
|
||||
const task = (Array.isArray(tasks) ? tasks : []).find((item) => item.order_item_id === orderItemId)
|
||||
export function resolveOrderItemDeliveryMode(
|
||||
tasks: TaskLike[] | null | undefined,
|
||||
orderItemId: number | string,
|
||||
): string {
|
||||
const task = (Array.isArray(tasks) ? tasks : []).find(
|
||||
(item) => item.order_item_id === orderItemId,
|
||||
)
|
||||
|
||||
if (!task) {
|
||||
return ''
|
||||
@@ -382,7 +457,12 @@ export function resolveOrderItemDeliveryMode(tasks: TaskLike[] | null | undefine
|
||||
return 'kuaishou_cloud'
|
||||
}
|
||||
|
||||
if (task.requires_claim || getTaskPrimaryClaimTokenId(task) || task.primary_claim_token || task.claim_token) {
|
||||
if (
|
||||
task.requires_claim ||
|
||||
getTaskPrimaryClaimTokenId(task) ||
|
||||
task.primary_claim_token ||
|
||||
task.claim_token
|
||||
) {
|
||||
return 'claim_link'
|
||||
}
|
||||
|
||||
@@ -393,7 +473,10 @@ export function isManualDispatchTask(task: TaskLike | null | undefined): boolean
|
||||
return String(task?.executor_key || '').trim() === 'manual_dispatch'
|
||||
}
|
||||
|
||||
export function canRegenerateClaimLinkForViewer(task: TaskLike, viewerContext: AdminViewerContext): boolean {
|
||||
export function canRegenerateClaimLinkForViewer(
|
||||
task: TaskLike,
|
||||
viewerContext: AdminViewerContext,
|
||||
): boolean {
|
||||
if (isManualDispatchTask(task)) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user