修改领取顺序,先核销

This commit is contained in:
yml2213
2026-05-31 11:58:12 +08:00
parent 11cf0e93a4
commit 904ecc9303
6 changed files with 105 additions and 39 deletions
+2 -2
View File
@@ -38,8 +38,8 @@ router.post(
'/:token/kuaishou-cloud/verify-ticket',
claimWriteRateLimit,
createRouteHandler((req) => verifyKuaishouCloudClaimTicket(req.params.token, req.body), {
successMessage: '核销码校验成功',
errorMessage: '校验核销码失败',
successMessage: '核销码提交并核销成功',
errorMessage: '提交核销码失败',
scope: '[claims/:token/kuaishou-cloud/verify-ticket]',
}),
)
@@ -549,8 +549,12 @@ export async function returnNumberAdminTaskKuaishouCloudFulfillment(
let nextTaskStatus = 'completed'
let nextResultCode = 'kuaishou_cloud_completed'
let nextResultMessage = 'cloudtentacles 发货、退号并完成快手核销'
const consumeAlreadyCompleted = flow.consume.status === 'success'
if (!order) {
if (consumeAlreadyCompleted) {
consumeStatus = 'success'
consumedAt = flow.consume.consumedAt || now
} else if (!order) {
consumeStatus = 'failed'
consumeErrorMessage = '任务关联订单不存在,无法执行快手核销'
} else if (!ticketCode) {
@@ -652,7 +656,11 @@ export async function returnNumberAdminTaskKuaishouCloudFulfillment(
await createTaskEvent(
task.id,
consumeStatus === 'success' ? 'kuaishou_cloud_consumed' : 'kuaishou_cloud_consume_failed',
consumeAlreadyCompleted
? 'kuaishou_cloud_consume_already_completed'
: consumeStatus === 'success'
? 'kuaishou_cloud_consumed'
: 'kuaishou_cloud_consume_failed',
{
ticketCodeMasked: maskCode(ticketCode),
shopId,
@@ -19,7 +19,10 @@ import {
resolveKuaishouEticketShopConfig,
type KuaishouEticketShopConfig,
} from '../platforms/kuaishou-eticket/source-config-service.js'
import { queryKuaishouEticketConsumeDetail } from '../platforms/kuaishou-eticket/consume-service.js'
import {
consumeKuaishouEticket,
queryKuaishouEticketConsumeDetail,
} from '../platforms/kuaishou-eticket/consume-service.js'
import { isKuaishouEticketMockTicketCode } from '../platforms/kuaishou-eticket/mock-ticket-service.js'
import {
dispatchKuaishouCloudFulfillmentTask,
@@ -59,12 +62,26 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
})
}
const persistedTicketCode = String(flow.ticket.code || '').trim()
if (flow.consume.status === 'success') {
if (!persistedTicketCode || persistedTicketCode === ticketCode) {
return getKuaishouCloudClaimDetail(token)
}
throw createHttpError('当前领取链接已完成核销,不能更换核销码', {
statusCode: 409,
errorCode: 'claim_kuaishou_cloud_ticket_already_consumed',
})
}
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
let shopCookie = ''
let consumeBaseUrl = ''
if (mockTicketCode) {
detailResult = await queryKuaishouEticketConsumeDetail({
@@ -82,6 +99,8 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
detailResult = matched.detailResult
shopId = matched.shopConfig.shopId || shopId
shopName = matched.shopConfig.kshopName || shopName
shopCookie = matched.shopConfig.cookie
consumeBaseUrl = getKuaishouEticketSourceConfig().baseUrl
}
if (!detailResult.ok || detailResult.alreadyConsumed || !detailResult.detail) {
@@ -93,6 +112,22 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
})
}
const consumePayload = {
baseUrl: consumeBaseUrl,
cookie: shopCookie,
eTicketId: detailResult.eTicketId || ticketCode,
oid: String(detailResult.detail.oid || '').trim(),
formToken: String(detailResult.detail.formToken || '').trim(),
num: Number(detailResult.detail.leftCount || 0) || 1,
}
const consumeResult = await consumeKuaishouEticket(consumePayload)
if (!consumeResult.consumed) {
throw createHttpError(consumeResult.errorMessage || '核销失败,请确认核销码状态后重试', {
statusCode: 409,
errorCode: 'claim_kuaishou_cloud_consume_failed',
})
}
const taskContext = parseTaskContext(context.task)
const nextContext = {
...taskContext,
@@ -114,7 +149,11 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
},
consume: {
...flow.consume,
status: 'success',
shopId,
shopName,
consumedAt: now,
errorMessage: '',
},
},
}
@@ -136,31 +175,29 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
})
} else {
const preparedFlow = normalizeKuaishouCloudFlow(nextContext.kuaishouCloudFulfillment)
if (preparedFlow.binding.prepareStatus !== 'ready' || !preparedFlow.binding.bindUrl) {
await prepareKuaishouCloudFulfillmentTask(
{
...context.task,
context_json: JSON.stringify(nextContext),
},
{
source: 'claim_page_ticket_verified',
actor: { source: 'claim_page' },
},
)
} else {
await updateTask(context.task.id, {
claim_token: context.claimToken.token,
claim_expires_at: context.claimToken.expired_at,
context_json: JSON.stringify(nextContext),
last_error: '',
updated_at: now,
})
const taskWithConsumedTicket = (await updateTask(context.task.id, {
claim_token: context.claimToken.token,
claim_expires_at: context.claimToken.expired_at,
context_json: JSON.stringify(nextContext),
claimed_at: context.task.claimed_at || now,
task_status: TASK_STATUS.WAITING_BINDING,
user_action_status: 'pending_claim',
last_error: '',
updated_at: now,
})) || {
...context.task,
context_json: JSON.stringify(nextContext),
claimed_at: context.task.claimed_at || now,
task_status: TASK_STATUS.WAITING_BINDING,
user_action_status: 'pending_claim',
last_error: '',
updated_at: now,
}
if (!context.task.claimed_at) {
await updateTask(context.task.id, {
claimed_at: now,
updated_at: now,
if (preparedFlow.binding.prepareStatus !== 'ready' || !preparedFlow.binding.bindUrl) {
await prepareKuaishouCloudFulfillmentTask(taskWithConsumedTicket, {
source: 'claim_page_ticket_verified',
actor: { source: 'claim_page' },
})
}
}
@@ -174,6 +211,23 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
shopName,
goodsTitle: String(detailResult.goods?.itemTitle || '').trim(),
mock: mockTicketCode,
consumedAt: now,
consumeAlreadyCompleted: consumeResult.alreadyConsumed === true,
},
now,
)
await createTaskEvent(
context.task.id,
'kuaishou_cloud_consumed',
{
source: 'claim_page_ticket_submit',
ticketCodeMasked: maskCode(detailResult.eTicketId || ticketCode),
shopId,
shopName,
consumeStatus: 'success',
consumedAt: now,
mock: mockTicketCode,
},
now,
)
@@ -523,8 +523,12 @@ export async function returnKuaishouCloudFulfillmentTask(
let nextTaskStatus: TaskStatus = TASK_STATUS.COMPLETED;
let nextResultCode = "kuaishou_cloud_completed";
let nextResultMessage = "cloudtentacles 发货、退号并完成快手核销";
const consumeAlreadyCompleted = flow.consume.status === "success";
if (!order) {
if (consumeAlreadyCompleted) {
consumeStatus = "success";
consumedAt = flow.consume.consumedAt || now;
} else if (!order) {
consumeStatus = "failed";
consumeErrorMessage = "任务关联订单不存在,无法执行快手核销";
} else if (!ticketCode) {
@@ -626,9 +630,11 @@ export async function returnKuaishouCloudFulfillmentTask(
await createTaskEvent(
task.id,
consumeStatus === "success"
? "kuaishou_cloud_consumed"
: "kuaishou_cloud_consume_failed",
consumeAlreadyCompleted
? "kuaishou_cloud_consume_already_completed"
: consumeStatus === "success"
? "kuaishou_cloud_consumed"
: "kuaishou_cloud_consume_failed",
{
source: String(options.source || "system").trim() || "system",
ticketCodeMasked: maskCode(ticketCode),