修改领取顺序,先核销
This commit is contained in:
@@ -38,8 +38,8 @@ router.post(
|
|||||||
'/:token/kuaishou-cloud/verify-ticket',
|
'/:token/kuaishou-cloud/verify-ticket',
|
||||||
claimWriteRateLimit,
|
claimWriteRateLimit,
|
||||||
createRouteHandler((req) => verifyKuaishouCloudClaimTicket(req.params.token, req.body), {
|
createRouteHandler((req) => verifyKuaishouCloudClaimTicket(req.params.token, req.body), {
|
||||||
successMessage: '核销码校验成功',
|
successMessage: '核销码提交并核销成功',
|
||||||
errorMessage: '校验核销码失败',
|
errorMessage: '提交核销码失败',
|
||||||
scope: '[claims/:token/kuaishou-cloud/verify-ticket]',
|
scope: '[claims/:token/kuaishou-cloud/verify-ticket]',
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -549,8 +549,12 @@ export async function returnNumberAdminTaskKuaishouCloudFulfillment(
|
|||||||
let nextTaskStatus = 'completed'
|
let nextTaskStatus = 'completed'
|
||||||
let nextResultCode = 'kuaishou_cloud_completed'
|
let nextResultCode = 'kuaishou_cloud_completed'
|
||||||
let nextResultMessage = 'cloudtentacles 发货、退号并完成快手核销'
|
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'
|
consumeStatus = 'failed'
|
||||||
consumeErrorMessage = '任务关联订单不存在,无法执行快手核销'
|
consumeErrorMessage = '任务关联订单不存在,无法执行快手核销'
|
||||||
} else if (!ticketCode) {
|
} else if (!ticketCode) {
|
||||||
@@ -652,7 +656,11 @@ export async function returnNumberAdminTaskKuaishouCloudFulfillment(
|
|||||||
|
|
||||||
await createTaskEvent(
|
await createTaskEvent(
|
||||||
task.id,
|
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),
|
ticketCodeMasked: maskCode(ticketCode),
|
||||||
shopId,
|
shopId,
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ import {
|
|||||||
resolveKuaishouEticketShopConfig,
|
resolveKuaishouEticketShopConfig,
|
||||||
type KuaishouEticketShopConfig,
|
type KuaishouEticketShopConfig,
|
||||||
} from '../platforms/kuaishou-eticket/source-config-service.js'
|
} 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 { isKuaishouEticketMockTicketCode } from '../platforms/kuaishou-eticket/mock-ticket-service.js'
|
||||||
import {
|
import {
|
||||||
dispatchKuaishouCloudFulfillmentTask,
|
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)
|
const mockTicketCode = isKuaishouEticketMockTicketCode(ticketCode)
|
||||||
let shopId = String(
|
let shopId = String(
|
||||||
flow.consume.shopId || context.order.shop_id || (mockTicketCode ? 'mock' : ''),
|
flow.consume.shopId || context.order.shop_id || (mockTicketCode ? 'mock' : ''),
|
||||||
).trim()
|
).trim()
|
||||||
let shopName = String(flow.consume.shopName || context.order.shop_name || '').trim()
|
let shopName = String(flow.consume.shopName || context.order.shop_name || '').trim()
|
||||||
let detailResult
|
let detailResult
|
||||||
|
let shopCookie = ''
|
||||||
|
let consumeBaseUrl = ''
|
||||||
|
|
||||||
if (mockTicketCode) {
|
if (mockTicketCode) {
|
||||||
detailResult = await queryKuaishouEticketConsumeDetail({
|
detailResult = await queryKuaishouEticketConsumeDetail({
|
||||||
@@ -82,6 +99,8 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
|||||||
detailResult = matched.detailResult
|
detailResult = matched.detailResult
|
||||||
shopId = matched.shopConfig.shopId || shopId
|
shopId = matched.shopConfig.shopId || shopId
|
||||||
shopName = matched.shopConfig.kshopName || shopName
|
shopName = matched.shopConfig.kshopName || shopName
|
||||||
|
shopCookie = matched.shopConfig.cookie
|
||||||
|
consumeBaseUrl = getKuaishouEticketSourceConfig().baseUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!detailResult.ok || detailResult.alreadyConsumed || !detailResult.detail) {
|
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 taskContext = parseTaskContext(context.task)
|
||||||
const nextContext = {
|
const nextContext = {
|
||||||
...taskContext,
|
...taskContext,
|
||||||
@@ -114,7 +149,11 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
|||||||
},
|
},
|
||||||
consume: {
|
consume: {
|
||||||
...flow.consume,
|
...flow.consume,
|
||||||
|
status: 'success',
|
||||||
shopId,
|
shopId,
|
||||||
|
shopName,
|
||||||
|
consumedAt: now,
|
||||||
|
errorMessage: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -136,31 +175,29 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const preparedFlow = normalizeKuaishouCloudFlow(nextContext.kuaishouCloudFulfillment)
|
const preparedFlow = normalizeKuaishouCloudFlow(nextContext.kuaishouCloudFulfillment)
|
||||||
if (preparedFlow.binding.prepareStatus !== 'ready' || !preparedFlow.binding.bindUrl) {
|
const taskWithConsumedTicket = (await updateTask(context.task.id, {
|
||||||
await prepareKuaishouCloudFulfillmentTask(
|
claim_token: context.claimToken.token,
|
||||||
{
|
claim_expires_at: context.claimToken.expired_at,
|
||||||
...context.task,
|
context_json: JSON.stringify(nextContext),
|
||||||
context_json: JSON.stringify(nextContext),
|
claimed_at: context.task.claimed_at || now,
|
||||||
},
|
task_status: TASK_STATUS.WAITING_BINDING,
|
||||||
{
|
user_action_status: 'pending_claim',
|
||||||
source: 'claim_page_ticket_verified',
|
last_error: '',
|
||||||
actor: { source: 'claim_page' },
|
updated_at: now,
|
||||||
},
|
})) || {
|
||||||
)
|
...context.task,
|
||||||
} else {
|
context_json: JSON.stringify(nextContext),
|
||||||
await updateTask(context.task.id, {
|
claimed_at: context.task.claimed_at || now,
|
||||||
claim_token: context.claimToken.token,
|
task_status: TASK_STATUS.WAITING_BINDING,
|
||||||
claim_expires_at: context.claimToken.expired_at,
|
user_action_status: 'pending_claim',
|
||||||
context_json: JSON.stringify(nextContext),
|
last_error: '',
|
||||||
last_error: '',
|
updated_at: now,
|
||||||
updated_at: now,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.task.claimed_at) {
|
if (preparedFlow.binding.prepareStatus !== 'ready' || !preparedFlow.binding.bindUrl) {
|
||||||
await updateTask(context.task.id, {
|
await prepareKuaishouCloudFulfillmentTask(taskWithConsumedTicket, {
|
||||||
claimed_at: now,
|
source: 'claim_page_ticket_verified',
|
||||||
updated_at: now,
|
actor: { source: 'claim_page' },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,6 +211,23 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
|||||||
shopName,
|
shopName,
|
||||||
goodsTitle: String(detailResult.goods?.itemTitle || '').trim(),
|
goodsTitle: String(detailResult.goods?.itemTitle || '').trim(),
|
||||||
mock: mockTicketCode,
|
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,
|
now,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -523,8 +523,12 @@ export async function returnKuaishouCloudFulfillmentTask(
|
|||||||
let nextTaskStatus: TaskStatus = TASK_STATUS.COMPLETED;
|
let nextTaskStatus: TaskStatus = TASK_STATUS.COMPLETED;
|
||||||
let nextResultCode = "kuaishou_cloud_completed";
|
let nextResultCode = "kuaishou_cloud_completed";
|
||||||
let nextResultMessage = "cloudtentacles 发货、退号并完成快手核销";
|
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";
|
consumeStatus = "failed";
|
||||||
consumeErrorMessage = "任务关联订单不存在,无法执行快手核销";
|
consumeErrorMessage = "任务关联订单不存在,无法执行快手核销";
|
||||||
} else if (!ticketCode) {
|
} else if (!ticketCode) {
|
||||||
@@ -626,9 +630,11 @@ export async function returnKuaishouCloudFulfillmentTask(
|
|||||||
|
|
||||||
await createTaskEvent(
|
await createTaskEvent(
|
||||||
task.id,
|
task.id,
|
||||||
consumeStatus === "success"
|
consumeAlreadyCompleted
|
||||||
? "kuaishou_cloud_consumed"
|
? "kuaishou_cloud_consume_already_completed"
|
||||||
: "kuaishou_cloud_consume_failed",
|
: consumeStatus === "success"
|
||||||
|
? "kuaishou_cloud_consumed"
|
||||||
|
: "kuaishou_cloud_consume_failed",
|
||||||
{
|
{
|
||||||
source: String(options.source || "system").trim() || "system",
|
source: String(options.source || "system").trim() || "system",
|
||||||
ticketCodeMasked: maskCode(ticketCode),
|
ticketCodeMasked: maskCode(ticketCode),
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const activeGuideNames = ref(['guide'])
|
|||||||
<section class="content-card">
|
<section class="content-card">
|
||||||
<h2>第 1 步:提交核销码</h2>
|
<h2>第 1 步:提交核销码</h2>
|
||||||
<p class="muted">
|
<p class="muted">
|
||||||
请您先从快手小店复制核销码。验证通过后,系统会自动准备绑定资源.
|
请您先从快手小店复制核销码。提交后会立即核销,核销成功后系统会自动准备绑定资源。
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<el-input
|
<el-input
|
||||||
@@ -43,15 +43,13 @@ const activeGuideNames = ref(['guide'])
|
|||||||
:disabled="!canSubmitTicket"
|
:disabled="!canSubmitTicket"
|
||||||
@click="$emit('submitTicket')"
|
@click="$emit('submitTicket')"
|
||||||
>
|
>
|
||||||
验证核销码并继续
|
提交核销码并继续
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<div class="status-banner info">
|
<div class="status-banner info">
|
||||||
<el-icon><Clock /></el-icon>
|
<el-icon><Clock /></el-icon>
|
||||||
<span>{{
|
<span>{{
|
||||||
isBindingPreparing
|
isBindingPreparing ? '核销完成后会自动准备绑定资源。' : '核销完成后会自动进入扫码绑定步骤。'
|
||||||
? '绑定资源会在核销通过后自动准备。'
|
|
||||||
: '核销完成后会自动进入扫码绑定步骤。'
|
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export function useKuaishouCloudClaim(token: () => string) {
|
|||||||
if (isTicketVerified.value) {
|
if (isTicketVerified.value) {
|
||||||
return isBindingPrepared.value ? '请完成扫码绑定' : '绑定链接刷新中,请稍候'
|
return isBindingPrepared.value ? '请完成扫码绑定' : '绑定链接刷新中,请稍候'
|
||||||
}
|
}
|
||||||
return '等待提交核销码'
|
return '等待提交并核销'
|
||||||
})
|
})
|
||||||
|
|
||||||
const resultTitle = computed(() => {
|
const resultTitle = computed(() => {
|
||||||
@@ -198,7 +198,7 @@ export function useKuaishouCloudClaim(token: () => string) {
|
|||||||
ticketCode: normalizedTicketCode,
|
ticketCode: normalizedTicketCode,
|
||||||
})
|
})
|
||||||
await applyDetail(response.data)
|
await applyDetail(response.data)
|
||||||
showSuccess('核销码验证通过,系统已开始准备绑定资源')
|
showSuccess('核销已完成,系统已开始准备绑定资源')
|
||||||
syncPolling()
|
syncPolling()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error instanceof Error ? error.message : '核销码验证失败')
|
showError(error instanceof Error ? error.message : '核销码验证失败')
|
||||||
|
|||||||
Reference in New Issue
Block a user