重构 lewan 履约:拆分发货模块并统一 registry 入口
将 task-finalization 拆为 dispatch/stock/return/redeem/confirm 等用例, claim 与 admin 经 executor registry 调用;admin 退号仅清理虚拟号不核销。
This commit is contained in:
@@ -3,9 +3,20 @@ import {
|
||||
shouldEnsureKuaishouCloudClaimLink,
|
||||
TASK_STATUS,
|
||||
} from '../../../domain/task-status.js'
|
||||
import { ensureTaskClaimLink } from '../kuaishou-cloud/index.js'
|
||||
import {
|
||||
confirmKuaishouCloudTaskRole,
|
||||
dispatchKuaishouCloudFulfillmentTask,
|
||||
ensureTaskClaimLink,
|
||||
prepareKuaishouCloudFulfillmentTask,
|
||||
rebindKuaishouCloudTaskRole,
|
||||
redeemKuaishouCloudTask,
|
||||
refreshKuaishouCloudTaskRoleInfo,
|
||||
returnKuaishouCloudFulfillmentTask,
|
||||
} from '../kuaishou-cloud/index.js'
|
||||
import {
|
||||
FULFILLMENT_EXECUTOR_KEYS,
|
||||
type FulfillmentActionOptions,
|
||||
type FulfillmentActionResult,
|
||||
type FulfillmentDeliveryLink,
|
||||
type FulfillmentExecutor,
|
||||
type FulfillmentPrepareDeps,
|
||||
@@ -16,6 +27,13 @@ export const kuaishouCloudExecutor: FulfillmentExecutor = {
|
||||
key: FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_CLOUD,
|
||||
preparePaidTask,
|
||||
resolveDeliveryLink,
|
||||
prepareBinding,
|
||||
rebindRole,
|
||||
refreshRole,
|
||||
confirmRole,
|
||||
redeemTask,
|
||||
dispatchTask,
|
||||
returnNumber,
|
||||
}
|
||||
|
||||
async function preparePaidTask(
|
||||
@@ -71,3 +89,115 @@ async function resolveDeliveryLink(task: TaskRow): Promise<FulfillmentDeliveryLi
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function prepareBinding(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
): Promise<FulfillmentActionResult> {
|
||||
const result = await prepareKuaishouCloudFulfillmentTask(task, {
|
||||
source: options.source || 'executor_prepare_binding',
|
||||
actor: options.actor,
|
||||
force: options.force === true,
|
||||
})
|
||||
return {
|
||||
task: result.task || task,
|
||||
claimUrl: result.claimUrl,
|
||||
token: result.token,
|
||||
flow: result.flow,
|
||||
}
|
||||
}
|
||||
|
||||
async function rebindRole(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
): Promise<FulfillmentActionResult> {
|
||||
const result = await rebindKuaishouCloudTaskRole(task, {
|
||||
source: options.source || 'executor_rebind_role',
|
||||
actor: options.actor,
|
||||
})
|
||||
return {
|
||||
task: result.task || task,
|
||||
claimUrl: result.claimUrl,
|
||||
token: result.token,
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshRole(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
): Promise<FulfillmentActionResult> {
|
||||
const result = await refreshKuaishouCloudTaskRoleInfo(task, {
|
||||
source: options.source || 'executor_refresh_role',
|
||||
actor: options.actor,
|
||||
recordEvent: options.recordEvent !== false,
|
||||
forceProbe: options.forceProbe === true,
|
||||
})
|
||||
return {
|
||||
task: result.task || task,
|
||||
roleInfo: result.roleInfo,
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmRole(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
): Promise<FulfillmentActionResult> {
|
||||
const result = await confirmKuaishouCloudTaskRole(task, {
|
||||
source: options.source || 'executor_confirm_role',
|
||||
actor: options.actor,
|
||||
errorCodePrefix: options.errorCodePrefix,
|
||||
forceProbe: options.forceProbe !== false,
|
||||
})
|
||||
return {
|
||||
task: result.task,
|
||||
alreadySettled: result.alreadySettled,
|
||||
}
|
||||
}
|
||||
|
||||
async function redeemTask(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
): Promise<FulfillmentActionResult> {
|
||||
const result = await redeemKuaishouCloudTask(task, {
|
||||
source: options.source || 'executor_redeem',
|
||||
actor: options.actor,
|
||||
autoFinalize: options.autoFinalize !== false,
|
||||
errorCodePrefix: options.errorCodePrefix,
|
||||
})
|
||||
return {
|
||||
task: result.task,
|
||||
alreadySettled: result.alreadySettled,
|
||||
concurrentSkipped: result.concurrentSkipped,
|
||||
}
|
||||
}
|
||||
|
||||
async function dispatchTask(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
): Promise<FulfillmentActionResult> {
|
||||
const result = await dispatchKuaishouCloudFulfillmentTask(task, {
|
||||
source: options.source || 'executor_dispatch',
|
||||
actor: options.actor,
|
||||
autoFinalize: options.autoFinalize === true,
|
||||
})
|
||||
return {
|
||||
task: result.task || task,
|
||||
flow: result.flow,
|
||||
}
|
||||
}
|
||||
|
||||
async function returnNumber(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
): Promise<FulfillmentActionResult> {
|
||||
const result = await returnKuaishouCloudFulfillmentTask(task, {
|
||||
source: options.source || 'executor_return_number',
|
||||
actor: options.actor,
|
||||
// 未显式传入时保持默认 true(发货收尾);admin 清理会传 false
|
||||
consumeIndustryVoucher: options.consumeIndustryVoucher,
|
||||
})
|
||||
return {
|
||||
task: result.task || task,
|
||||
flow: result.flow,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
|
||||
import {
|
||||
getFulfillmentExecutor,
|
||||
prepareFulfillmentBinding,
|
||||
redeemFulfillmentTask,
|
||||
dispatchFulfillmentTask,
|
||||
confirmFulfillmentRole,
|
||||
rebindFulfillmentRole,
|
||||
refreshFulfillmentRole,
|
||||
returnFulfillmentNumber,
|
||||
} from './registry.js'
|
||||
import { FULFILLMENT_EXECUTOR_KEYS } from './types.js'
|
||||
import type { TaskRow } from '../../../types/repository/rows.js'
|
||||
|
||||
function makeTask(executorKey: string): TaskRow {
|
||||
return {
|
||||
id: 1,
|
||||
executor_key: executorKey,
|
||||
} as TaskRow
|
||||
}
|
||||
|
||||
test('getFulfillmentExecutor 映射 lewan / industry / feifei / manual', () => {
|
||||
assert.equal(
|
||||
getFulfillmentExecutor(FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_CLOUD)?.key,
|
||||
FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_CLOUD,
|
||||
)
|
||||
assert.equal(
|
||||
getFulfillmentExecutor(FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_INDUSTRY)?.key,
|
||||
FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_CLOUD,
|
||||
)
|
||||
assert.equal(
|
||||
getFulfillmentExecutor(FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_FEIFEI)?.key,
|
||||
FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_FEIFEI,
|
||||
)
|
||||
assert.equal(
|
||||
getFulfillmentExecutor(FULFILLMENT_EXECUTOR_KEYS.MANUAL_DISPATCH)?.key,
|
||||
FULFILLMENT_EXECUTOR_KEYS.MANUAL_DISPATCH,
|
||||
)
|
||||
assert.equal(getFulfillmentExecutor('unknown'), null)
|
||||
})
|
||||
|
||||
test('lewan executor 暴露完整履约动作', () => {
|
||||
const executor = getFulfillmentExecutor(FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_CLOUD)
|
||||
assert.ok(executor)
|
||||
assert.equal(typeof executor.prepareBinding, 'function')
|
||||
assert.equal(typeof executor.rebindRole, 'function')
|
||||
assert.equal(typeof executor.refreshRole, 'function')
|
||||
assert.equal(typeof executor.confirmRole, 'function')
|
||||
assert.equal(typeof executor.redeemTask, 'function')
|
||||
assert.equal(typeof executor.dispatchTask, 'function')
|
||||
assert.equal(typeof executor.returnNumber, 'function')
|
||||
})
|
||||
|
||||
test('feifei / manual 不支持 lewan 专属动作时 registry 返回 null', async () => {
|
||||
const feifei = makeTask(FULFILLMENT_EXECUTOR_KEYS.KUAISHOU_FEIFEI)
|
||||
const manual = makeTask(FULFILLMENT_EXECUTOR_KEYS.MANUAL_DISPATCH)
|
||||
|
||||
assert.equal(await prepareFulfillmentBinding(feifei), null)
|
||||
assert.equal(await rebindFulfillmentRole(feifei), null)
|
||||
assert.equal(await refreshFulfillmentRole(feifei), null)
|
||||
assert.equal(await confirmFulfillmentRole(feifei), null)
|
||||
assert.equal(await redeemFulfillmentTask(feifei), null)
|
||||
assert.equal(await dispatchFulfillmentTask(feifei), null)
|
||||
assert.equal(await returnFulfillmentNumber(feifei), null)
|
||||
|
||||
assert.equal(await redeemFulfillmentTask(manual), null)
|
||||
assert.equal(await dispatchFulfillmentTask(manual), null)
|
||||
})
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
FULFILLMENT_EXECUTOR_KEYS,
|
||||
isManualDispatchExecutor,
|
||||
normalizeExecutorKey,
|
||||
type FulfillmentActionOptions,
|
||||
type FulfillmentDeliveryLink,
|
||||
type FulfillmentExecutor,
|
||||
type FulfillmentPrepareDeps,
|
||||
@@ -53,3 +54,73 @@ export async function resolveFulfillmentDeliveryLink(
|
||||
|
||||
return executor.resolveDeliveryLink(task)
|
||||
}
|
||||
|
||||
async function runExecutorAction(
|
||||
task: TaskRow,
|
||||
method:
|
||||
| 'prepareBinding'
|
||||
| 'rebindRole'
|
||||
| 'refreshRole'
|
||||
| 'confirmRole'
|
||||
| 'redeemTask'
|
||||
| 'dispatchTask'
|
||||
| 'returnNumber',
|
||||
options: FulfillmentActionOptions = {},
|
||||
) {
|
||||
const executor = getFulfillmentExecutor(task.executor_key)
|
||||
const handler = executor?.[method]
|
||||
if (!handler) {
|
||||
return null
|
||||
}
|
||||
|
||||
return handler(task, options)
|
||||
}
|
||||
|
||||
export function prepareFulfillmentBinding(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
) {
|
||||
return runExecutorAction(task, 'prepareBinding', options)
|
||||
}
|
||||
|
||||
export function rebindFulfillmentRole(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
) {
|
||||
return runExecutorAction(task, 'rebindRole', options)
|
||||
}
|
||||
|
||||
export function refreshFulfillmentRole(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
) {
|
||||
return runExecutorAction(task, 'refreshRole', options)
|
||||
}
|
||||
|
||||
export function confirmFulfillmentRole(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
) {
|
||||
return runExecutorAction(task, 'confirmRole', options)
|
||||
}
|
||||
|
||||
export function redeemFulfillmentTask(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
) {
|
||||
return runExecutorAction(task, 'redeemTask', options)
|
||||
}
|
||||
|
||||
export function dispatchFulfillmentTask(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
) {
|
||||
return runExecutorAction(task, 'dispatchTask', options)
|
||||
}
|
||||
|
||||
export function returnFulfillmentNumber(
|
||||
task: TaskRow,
|
||||
options: FulfillmentActionOptions = {},
|
||||
) {
|
||||
return runExecutorAction(task, 'returnNumber', options)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,25 @@ export type FulfillmentPrepareDeps = {
|
||||
nowIso: () => string
|
||||
}
|
||||
|
||||
export type FulfillmentActionOptions = {
|
||||
source?: string
|
||||
actor?: unknown
|
||||
autoFinalize?: boolean
|
||||
errorCodePrefix?: string
|
||||
/**
|
||||
* 退号时是否顺带核销行业电子凭证。
|
||||
* - true/默认:发货收尾(claim autoFinalize)
|
||||
* - false:仅清理虚拟号(admin 退号),与核销无关
|
||||
*/
|
||||
consumeIndustryVoucher?: boolean
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type FulfillmentActionResult = {
|
||||
task: TaskRow
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type FulfillmentExecutor = {
|
||||
key: FulfillmentExecutorKey
|
||||
preparePaidTask?: (
|
||||
@@ -38,6 +57,44 @@ export type FulfillmentExecutor = {
|
||||
deps: FulfillmentPrepareDeps,
|
||||
) => Promise<TaskRow | null>
|
||||
resolveDeliveryLink?: (task: TaskRow) => Promise<FulfillmentDeliveryLink | null>
|
||||
/** lewan:准备绑定资源(虚拟号 / bindUrl) */
|
||||
prepareBinding?: (
|
||||
task: TaskRow,
|
||||
options?: FulfillmentActionOptions,
|
||||
) => Promise<FulfillmentActionResult>
|
||||
/** lewan:换绑角色 */
|
||||
rebindRole?: (
|
||||
task: TaskRow,
|
||||
options?: FulfillmentActionOptions,
|
||||
) => Promise<FulfillmentActionResult>
|
||||
/** lewan:刷新角色信息 */
|
||||
refreshRole?: (
|
||||
task: TaskRow,
|
||||
options?: FulfillmentActionOptions,
|
||||
) => Promise<FulfillmentActionResult>
|
||||
/** lewan:确认角色(UID 匹配后落 ROLE_CONFIRMED) */
|
||||
confirmRole?: (
|
||||
task: TaskRow,
|
||||
options?: FulfillmentActionOptions,
|
||||
) => Promise<FulfillmentActionResult>
|
||||
/** lewan:一键兑换(状态机 + dispatch) */
|
||||
redeemTask?: (
|
||||
task: TaskRow,
|
||||
options?: FulfillmentActionOptions,
|
||||
) => Promise<FulfillmentActionResult>
|
||||
/** lewan:后台/系统发货(不经 claim 一键兑换) */
|
||||
dispatchTask?: (
|
||||
task: TaskRow,
|
||||
options?: FulfillmentActionOptions,
|
||||
) => Promise<FulfillmentActionResult>
|
||||
/**
|
||||
* lewan:退还虚拟号。
|
||||
* 默认可顺带核销;admin 清理请传 consumeIndustryVoucher: false。
|
||||
*/
|
||||
returnNumber?: (
|
||||
task: TaskRow,
|
||||
options?: FulfillmentActionOptions,
|
||||
) => Promise<FulfillmentActionResult>
|
||||
}
|
||||
|
||||
export function normalizeExecutorKey(value: unknown): FulfillmentExecutorKey {
|
||||
|
||||
Reference in New Issue
Block a user