接入多发货平台与电子凭证
This commit is contained in:
@@ -34,6 +34,7 @@ import {
|
||||
rebindKuaishouCloudTaskRole,
|
||||
refreshKuaishouCloudTaskRoleInfo,
|
||||
} from '../fulfillment/kuaishou-cloud/index.js'
|
||||
import { syncKuaishouFeifeiTaskStatus } from '../fulfillment/kuaishou-feifei/index.js'
|
||||
import { buildClaimDetailPayload, getClaimContext } from './kuaishou-cloud-claim-context.js'
|
||||
import { syncKuaishouCloudRoleInfo } from './kuaishou-cloud-sync-service.js'
|
||||
import type { TaskRow } from '../../types/repository/rows.js'
|
||||
@@ -42,6 +43,7 @@ const KUAISHOU_CLOUD_GUIDE_DIR = path.resolve(PROJECT_ROOT, '../../tems/imgs')
|
||||
const ALLOWED_GUIDE_FILES = new Set(['1.png', '2.png', '3.png'])
|
||||
|
||||
type JsonObject = Record<string, any>
|
||||
type ClaimDetailPayload = ReturnType<typeof buildClaimDetailPayload>
|
||||
|
||||
export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: JsonObject = {}) {
|
||||
const context = await getClaimContext(token)
|
||||
@@ -50,7 +52,7 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
||||
const executorKey = String(context.task.executor_key || '').trim()
|
||||
|
||||
if (executorKey === 'kuaishou-industry') {
|
||||
return verifyIndustryeVoucherTicket(context, now)
|
||||
return verifyIndustryVoucherTicket(context, now)
|
||||
}
|
||||
|
||||
if (executorKey !== 'kuaishou_ct_assisted') {
|
||||
@@ -61,6 +63,9 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
||||
}
|
||||
|
||||
const flow = normalizeKuaishouCloudFlow(parseTaskContext(context.task).kuaishouCloudFulfillment)
|
||||
if (hasUsableIndustryVoucher(parseTaskContext(context.task))) {
|
||||
return verifyIndustryVoucherTicket(context, now)
|
||||
}
|
||||
|
||||
const ticketCode = String(payload.ticketCode || payload.eTicketId || '').trim()
|
||||
if (!ticketCode) {
|
||||
@@ -243,10 +248,10 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
||||
return getKuaishouCloudClaimDetail(token)
|
||||
}
|
||||
|
||||
async function verifyIndustryeVoucherTicket(
|
||||
async function verifyIndustryVoucherTicket(
|
||||
context: Awaited<ReturnType<typeof getClaimContext>>,
|
||||
now: string,
|
||||
) {
|
||||
): Promise<ClaimDetailPayload> {
|
||||
const taskContext = parseTaskContext(context.task)
|
||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment)
|
||||
|
||||
@@ -255,33 +260,58 @@ async function verifyIndustryeVoucherTicket(
|
||||
}
|
||||
|
||||
const industryContext = typeof taskContext === 'object' ? taskContext : {}
|
||||
const token = String(industryContext.token || '').trim()
|
||||
const voucherContext = normalizeIndustryVoucherContext(industryContext.kuaishouIndustryVoucher)
|
||||
if (voucherContext.status === 'DESTROYED') {
|
||||
throw createHttpError('当前电子凭证已销毁,无法继续领取', {
|
||||
statusCode: 409,
|
||||
errorCode: 'claim_kuaishou_industry_voucher_destroyed',
|
||||
})
|
||||
}
|
||||
|
||||
const token = String(voucherContext.token || industryContext.token || '').trim()
|
||||
const voucherCode = String(voucherContext.voucherCode || voucherContext.eticketId || '').trim()
|
||||
const certExpireType = Number(industryContext.certExpireType || 0)
|
||||
const certActualStartTime = Number(industryContext.certActualStartTime || 0)
|
||||
const certActualEndTime = Number(industryContext.certActualEndTime || 0)
|
||||
const certActualStartTime = Number(
|
||||
voucherContext.validStartTime || industryContext.certActualStartTime || 0,
|
||||
)
|
||||
const certActualEndTime = Number(
|
||||
voucherContext.validEndTime || industryContext.certActualEndTime || 0,
|
||||
)
|
||||
|
||||
const nextContext = {
|
||||
...taskContext,
|
||||
kuaishouIndustryVoucher: {
|
||||
...voucherContext,
|
||||
oid: voucherContext.oid || context.order.platform_order_id,
|
||||
token,
|
||||
eticketId: voucherCode,
|
||||
voucherCode,
|
||||
status: voucherContext.status || 'UNUSED',
|
||||
verifiedAt: voucherContext.verifiedAt || now,
|
||||
},
|
||||
kuaishouCloudFulfillment: {
|
||||
...flow,
|
||||
ticket: {
|
||||
...flow.ticket,
|
||||
code: '',
|
||||
code: voucherCode,
|
||||
status: 'verified',
|
||||
capturedAt: flow.ticket.capturedAt || now,
|
||||
capturedBy: flow.ticket.capturedBy || { source: 'send_code_callback' },
|
||||
verifiedAt: now,
|
||||
oid: context.order.platform_order_id,
|
||||
oid: voucherContext.oid || context.order.platform_order_id,
|
||||
formToken: token,
|
||||
leftCount: 0,
|
||||
leftCount: voucherContext.status === 'CONSUMED' ? 0 : 1,
|
||||
goodsTitle: context.orderItem.sku_name || context.orderItem.sku_code || '',
|
||||
},
|
||||
consume: {
|
||||
...flow.consume,
|
||||
status: 'pending',
|
||||
status: voucherContext.status === 'CONSUMED' ? 'success' : 'pending',
|
||||
shopId: context.order.shop_id,
|
||||
shopName: context.order.shop_name,
|
||||
autoConsumeEnabled: true,
|
||||
consumedAt: voucherContext.status === 'CONSUMED'
|
||||
? voucherContext.consumedAt || flow.consume.consumedAt || now
|
||||
: flow.consume.consumedAt,
|
||||
},
|
||||
certInfo: {
|
||||
certExpireType,
|
||||
@@ -353,17 +383,41 @@ export async function getKuaishouCloudClaimGuideAssetPath(filename: unknown) {
|
||||
return filePath
|
||||
}
|
||||
|
||||
export async function getKuaishouCloudClaimDetail(token: unknown) {
|
||||
export async function getKuaishouCloudClaimDetail(token: unknown): Promise<ClaimDetailPayload> {
|
||||
const context = await getClaimContext(token)
|
||||
let task = context.task
|
||||
|
||||
const executorKey = String(task.executor_key || '').trim()
|
||||
|
||||
if (executorKey === 'kuaishou_feifei') {
|
||||
task = (await syncKuaishouFeifeiTaskStatus(task)) || task
|
||||
}
|
||||
|
||||
if (executorKey === 'kuaishou-industry') {
|
||||
const flow = normalizeKuaishouCloudFlow(parseTaskContext(task).kuaishouCloudFulfillment)
|
||||
if (flow.consume.status !== 'success') {
|
||||
const now = nowIso()
|
||||
await verifyIndustryeVoucherTicket(context, now).catch(() => null)
|
||||
await verifyIndustryVoucherTicket(context, now).catch(() => null)
|
||||
}
|
||||
}
|
||||
|
||||
if (executorKey === 'kuaishou_ct_assisted') {
|
||||
const taskContext = parseTaskContext(task)
|
||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment)
|
||||
const needsIndustryVoucherPrepare =
|
||||
hasUsableIndustryVoucher(taskContext) &&
|
||||
(
|
||||
flow.ticket.status !== 'verified' ||
|
||||
(flow.binding.prepareStatus !== 'ready' && !flow.binding.bindUrl)
|
||||
)
|
||||
|
||||
if (needsIndustryVoucherPrepare) {
|
||||
const now = nowIso()
|
||||
const prepared: ClaimDetailPayload | null = await verifyIndustryVoucherTicket(context, now)
|
||||
.catch(() => null)
|
||||
if (prepared) {
|
||||
return prepared
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,6 +471,35 @@ function parseTaskContext(task: Partial<TaskRow> | null | undefined): JsonObject
|
||||
}
|
||||
}
|
||||
|
||||
function hasUsableIndustryVoucher(context: JsonObject = {}) {
|
||||
const voucher = normalizeIndustryVoucherContext(context.kuaishouIndustryVoucher)
|
||||
if (!voucher.voucherCode && !voucher.eticketId) {
|
||||
return false
|
||||
}
|
||||
|
||||
return voucher.status !== 'DESTROYED'
|
||||
}
|
||||
|
||||
function normalizeIndustryVoucherContext(value: unknown): JsonObject {
|
||||
const source = value && typeof value === 'object' && !Array.isArray(value)
|
||||
? value as JsonObject
|
||||
: {}
|
||||
const status = String(source.status || 'UNUSED').trim().toUpperCase()
|
||||
|
||||
return {
|
||||
...source,
|
||||
oid: String(source.oid || '').trim(),
|
||||
token: String(source.token || '').trim(),
|
||||
eticketId: String(source.eticketId || source.voucherCode || '').trim(),
|
||||
voucherCode: String(source.voucherCode || source.eticketId || '').trim(),
|
||||
status: status === 'CONSUMED' || status === 'DESTROYED' ? status : 'UNUSED',
|
||||
validStartTime: Number(source.validStartTime || 0) || 0,
|
||||
validEndTime: Number(source.validEndTime || 0) || 0,
|
||||
verifiedAt: source.verifiedAt || null,
|
||||
consumedAt: source.consumedAt || null,
|
||||
}
|
||||
}
|
||||
|
||||
async function queryKuaishouEticketConsumeDetailWithShopFallback({
|
||||
ticketCode,
|
||||
shopId,
|
||||
|
||||
Reference in New Issue
Block a user