简化履约匹配并支持mock订单测试
This commit is contained in:
@@ -8,9 +8,12 @@ import { createHttpError } from '../../utils/http.js'
|
||||
import { nowIso } from '../../utils/time.js'
|
||||
import {
|
||||
getKuaishouEticketSourceConfig,
|
||||
listKuaishouEticketShopConfigs,
|
||||
resolveKuaishouEticketShopConfig,
|
||||
type KuaishouEticketShopConfig,
|
||||
} from '../platforms/kuaishou-eticket/source-config-service.js'
|
||||
import { queryKuaishouEticketConsumeDetail } from '../platforms/kuaishou-eticket/consume-service.js'
|
||||
import { isKuaishouEticketMockTicketCode } from '../platforms/kuaishou-eticket/mock-ticket-service.js'
|
||||
import {
|
||||
dispatchKuaishouCloudFulfillmentTask,
|
||||
maskCode,
|
||||
@@ -48,24 +51,28 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
||||
})
|
||||
}
|
||||
|
||||
const shopId = String(flow.consume.shopId || context.order.shop_id || '').trim()
|
||||
const shopConfig = resolveKuaishouEticketShopConfig({
|
||||
shopId,
|
||||
shopName: String(context.order.shop_name || '').trim(),
|
||||
})
|
||||
if (!shopConfig || shopConfig.enabled === false || !String(shopConfig.cookie || '').trim()) {
|
||||
throw createHttpError('这笔订单对应的快手小店还没有配置可用 Cookie,请联系客服处理', {
|
||||
statusCode: 409,
|
||||
errorCode: 'claim_kuaishou_cloud_shop_cookie_missing',
|
||||
})
|
||||
}
|
||||
const mockTicketCode = isKuaishouEticketMockTicketCode(ticketCode)
|
||||
let shopId = String(flow.consume.shopId || context.order.shop_id || (mockTicketCode ? 'mock' : '')).trim()
|
||||
let shopName = String(flow.consume.shopName || context.order.shop_name || '').trim()
|
||||
let detailResult
|
||||
|
||||
const eticketSource = getKuaishouEticketSourceConfig()
|
||||
const detailResult = await queryKuaishouEticketConsumeDetail({
|
||||
baseUrl: eticketSource.baseUrl,
|
||||
cookie: shopConfig.cookie,
|
||||
eTicketId: ticketCode,
|
||||
})
|
||||
if (mockTicketCode) {
|
||||
detailResult = await queryKuaishouEticketConsumeDetail({
|
||||
eTicketId: ticketCode,
|
||||
goodsTitle: context.orderItem.sku_name || context.orderItem.sku_code,
|
||||
})
|
||||
} else {
|
||||
const matched = await queryKuaishouEticketConsumeDetailWithShopFallback({
|
||||
ticketCode,
|
||||
shopId,
|
||||
shopName,
|
||||
fallbackShopName: String(context.order.shop_name || '').trim(),
|
||||
})
|
||||
|
||||
detailResult = matched.detailResult
|
||||
shopId = matched.shopConfig.shopId || shopId
|
||||
shopName = matched.shopConfig.kshopName || shopName
|
||||
}
|
||||
|
||||
if (!detailResult.ok || detailResult.alreadyConsumed || !detailResult.detail) {
|
||||
throw createHttpError(detailResult.errorMessage || '核销码校验失败,请确认是否复制完整', {
|
||||
@@ -130,8 +137,9 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
||||
await createTaskEvent(context.task.id, 'kuaishou_cloud_ticket_verified', {
|
||||
ticketCodeMasked: maskCode(detailResult.eTicketId || ticketCode),
|
||||
shopId,
|
||||
shopName: String(context.order.shop_name || '').trim(),
|
||||
shopName,
|
||||
goodsTitle: String(detailResult.goods?.itemTitle || '').trim(),
|
||||
mock: mockTicketCode,
|
||||
}, now)
|
||||
|
||||
return getKuaishouCloudClaimDetail(token)
|
||||
@@ -190,6 +198,133 @@ function parseTaskContext(task: Partial<TaskRow> | null | undefined): JsonObject
|
||||
}
|
||||
}
|
||||
|
||||
async function queryKuaishouEticketConsumeDetailWithShopFallback({
|
||||
ticketCode,
|
||||
shopId,
|
||||
shopName,
|
||||
fallbackShopName = '',
|
||||
}: {
|
||||
ticketCode: string
|
||||
shopId: string
|
||||
shopName: string
|
||||
fallbackShopName?: string
|
||||
}) {
|
||||
const eticketSource = getKuaishouEticketSourceConfig()
|
||||
const shopConfigs = resolveKuaishouEticketDetailCandidateShops({
|
||||
shopId,
|
||||
shopName,
|
||||
fallbackShopName,
|
||||
})
|
||||
|
||||
if (shopConfigs.length === 0) {
|
||||
throw createHttpError('还没有配置可用的快手小店 Cookie,请联系客服处理', {
|
||||
statusCode: 409,
|
||||
errorCode: 'claim_kuaishou_cloud_shop_cookie_missing',
|
||||
})
|
||||
}
|
||||
|
||||
let lastResult: JsonObject | null = null
|
||||
let lastError: unknown = null
|
||||
|
||||
for (const shopConfig of shopConfigs) {
|
||||
try {
|
||||
const detailResult = await queryKuaishouEticketConsumeDetail({
|
||||
baseUrl: eticketSource.baseUrl,
|
||||
cookie: shopConfig.cookie,
|
||||
eTicketId: ticketCode,
|
||||
})
|
||||
|
||||
lastResult = detailResult
|
||||
if (detailResult.ok || detailResult.alreadyConsumed) {
|
||||
return {
|
||||
shopConfig,
|
||||
detailResult,
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
lastError = error
|
||||
}
|
||||
}
|
||||
|
||||
if (lastResult) {
|
||||
const fallbackShopConfig = shopConfigs[0]
|
||||
if (!fallbackShopConfig) {
|
||||
throw createHttpError('还没有配置可用的快手小店 Cookie,请联系客服处理', {
|
||||
statusCode: 409,
|
||||
errorCode: 'claim_kuaishou_cloud_shop_cookie_missing',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
shopConfig: fallbackShopConfig,
|
||||
detailResult: lastResult,
|
||||
}
|
||||
}
|
||||
|
||||
throw createHttpError(lastError instanceof Error ? lastError.message : '核销码校验失败,请确认是否复制完整', {
|
||||
statusCode: 409,
|
||||
errorCode: 'claim_kuaishou_cloud_ticket_invalid',
|
||||
})
|
||||
}
|
||||
|
||||
function resolveKuaishouEticketDetailCandidateShops({
|
||||
shopId,
|
||||
shopName,
|
||||
fallbackShopName = '',
|
||||
}: {
|
||||
shopId: string
|
||||
shopName: string
|
||||
fallbackShopName?: string
|
||||
}) {
|
||||
const candidates: KuaishouEticketShopConfig[] = []
|
||||
const configuredShop = resolveKuaishouEticketShopConfig({
|
||||
shopId,
|
||||
shopName: shopName || fallbackShopName,
|
||||
})
|
||||
|
||||
if (isUsableKuaishouEticketShopConfig(configuredShop)) {
|
||||
candidates.push(configuredShop)
|
||||
}
|
||||
|
||||
for (const shopConfig of listKuaishouEticketShopConfigs()) {
|
||||
if (!isUsableKuaishouEticketShopConfig(shopConfig)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (candidates.some((item) => isSameKuaishouEticketShopConfig(item, shopConfig))) {
|
||||
continue
|
||||
}
|
||||
|
||||
candidates.push(shopConfig)
|
||||
}
|
||||
|
||||
return candidates
|
||||
}
|
||||
|
||||
function isUsableKuaishouEticketShopConfig(
|
||||
shopConfig: KuaishouEticketShopConfig | null | undefined,
|
||||
): shopConfig is KuaishouEticketShopConfig {
|
||||
return Boolean(
|
||||
shopConfig &&
|
||||
shopConfig.enabled !== false &&
|
||||
String(shopConfig.cookie || '').trim(),
|
||||
)
|
||||
}
|
||||
|
||||
function isSameKuaishouEticketShopConfig(
|
||||
left: KuaishouEticketShopConfig,
|
||||
right: KuaishouEticketShopConfig,
|
||||
) {
|
||||
const leftShopId = String(left.shopId || '').trim()
|
||||
const rightShopId = String(right.shopId || '').trim()
|
||||
|
||||
if (leftShopId && rightShopId) {
|
||||
return leftShopId === rightShopId
|
||||
}
|
||||
|
||||
return String(left.kshopName || '').trim() === String(right.kshopName || '').trim()
|
||||
}
|
||||
|
||||
export async function confirmKuaishouCloudClaimRole(token: unknown) {
|
||||
const context = await getClaimContext(token)
|
||||
const now = nowIso()
|
||||
|
||||
Reference in New Issue
Block a user