同步飞飞核销券状态
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { createTaskEvent } from '../../../repositories/task-event-repo.js'
|
import { createTaskEvent } from '../../../repositories/task-event-repo.js'
|
||||||
import { updateTask } from '../../../repositories/task-repo.js'
|
import { updateTask } from '../../../repositories/task-repo.js'
|
||||||
import { createHttpError } from '../../../utils/http.js'
|
import { createHttpError } from '../../../utils/http.js'
|
||||||
|
import { logIntegration } from '../../../utils/logger.js'
|
||||||
import { parseTaskContext } from '../../../utils/task-json.js'
|
import { parseTaskContext } from '../../../utils/task-json.js'
|
||||||
import { nowIso } from '../../../utils/time.js'
|
import { nowIso } from '../../../utils/time.js'
|
||||||
import { TASK_STATUS } from '../../../domain/task-status.js'
|
import { TASK_STATUS } from '../../../domain/task-status.js'
|
||||||
@@ -9,6 +10,7 @@ import {
|
|||||||
queryKuaishouFeifeiOrder,
|
queryKuaishouFeifeiOrder,
|
||||||
} from '../../platforms/kuaishou-feifei/order-service.js'
|
} from '../../platforms/kuaishou-feifei/order-service.js'
|
||||||
import { consumeKuaishouIndustryVouchersForTask } from '../../platforms/kuaishou-industry/voucher-service.js'
|
import { consumeKuaishouIndustryVouchersForTask } from '../../platforms/kuaishou-industry/voucher-service.js'
|
||||||
|
import { buildKuaishouIndustryVoucherContext } from '../../platforms/kuaishou-industry/voucher-binding-service.js'
|
||||||
import type { TaskRow } from '../../../types/repository/rows.js'
|
import type { TaskRow } from '../../../types/repository/rows.js'
|
||||||
|
|
||||||
type JsonObject = Record<string, any>
|
type JsonObject = Record<string, any>
|
||||||
@@ -127,6 +129,7 @@ export async function syncKuaishouFeifeiTaskStatus(task: TaskRow) {
|
|||||||
syncedAt: now,
|
syncedAt: now,
|
||||||
claimUrl: resolveKuaishouFeifeiOrderClaimUrl(order) || resolveKuaishouFeifeiClaimUrl(flow),
|
claimUrl: resolveKuaishouFeifeiOrderClaimUrl(order) || resolveKuaishouFeifeiClaimUrl(flow),
|
||||||
})
|
})
|
||||||
|
let nextIndustryVoucher = taskContext.kuaishouIndustryVoucher
|
||||||
|
|
||||||
if (order.rechargeStatus === 30) {
|
if (order.rechargeStatus === 30) {
|
||||||
const consumeResult = await consumeKuaishouIndustryVouchersForTask(task, {
|
const consumeResult = await consumeKuaishouIndustryVouchersForTask(task, {
|
||||||
@@ -134,6 +137,7 @@ export async function syncKuaishouFeifeiTaskStatus(task: TaskRow) {
|
|||||||
consumeType: 'delivery',
|
consumeType: 'delivery',
|
||||||
consumeTime: Date.now(),
|
consumeTime: Date.now(),
|
||||||
})
|
})
|
||||||
|
const consumedVoucher = consumeResult.consumed[0] || null
|
||||||
|
|
||||||
if (consumeResult.ok || consumeResult.vouchers.length === 0) {
|
if (consumeResult.ok || consumeResult.vouchers.length === 0) {
|
||||||
nextTaskStatus = TASK_STATUS.COMPLETED
|
nextTaskStatus = TASK_STATUS.COMPLETED
|
||||||
@@ -143,12 +147,35 @@ export async function syncKuaishouFeifeiTaskStatus(task: TaskRow) {
|
|||||||
resultMessage = order.rechargeStatusLabel || 'kuaishou-feifei 履约成功'
|
resultMessage = order.rechargeStatusLabel || 'kuaishou-feifei 履约成功'
|
||||||
lastError = ''
|
lastError = ''
|
||||||
nextFlow.consumeStatus = consumeResult.vouchers.length > 0 ? 'success' : 'not_required'
|
nextFlow.consumeStatus = consumeResult.vouchers.length > 0 ? 'success' : 'not_required'
|
||||||
|
if (consumedVoucher) {
|
||||||
|
nextIndustryVoucher = buildKuaishouIndustryVoucherContext(
|
||||||
|
consumedVoucher,
|
||||||
|
taskContext.kuaishouIndustryVoucher,
|
||||||
|
now,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
logIntegration('[kuaishou-feifei]', '飞飞履约完成,行业电子凭证核销处理完成', {
|
||||||
|
taskId: task.id,
|
||||||
|
platformOrderNo: nextFlow.platformOrderNo,
|
||||||
|
orderNo: nextFlow.orderNo,
|
||||||
|
voucherCount: consumeResult.vouchers.length,
|
||||||
|
consumedCount: consumeResult.consumed.length,
|
||||||
|
consumeStatus: nextFlow.consumeStatus,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
nextTaskStatus = TASK_STATUS.MANUAL_REVIEW
|
nextTaskStatus = TASK_STATUS.MANUAL_REVIEW
|
||||||
resultCode = 'kuaishou_feifei_industry_consume_failed'
|
resultCode = 'kuaishou_feifei_industry_consume_failed'
|
||||||
resultMessage = consumeResult.failed[0]?.errorMessage || '电子凭证核销失败,请人工处理'
|
resultMessage = consumeResult.failed[0]?.errorMessage || '电子凭证核销失败,请人工处理'
|
||||||
lastError = resultMessage
|
lastError = resultMessage
|
||||||
nextFlow.consumeStatus = 'failed'
|
nextFlow.consumeStatus = 'failed'
|
||||||
|
logIntegration('[kuaishou-feifei]', '飞飞履约完成,但行业电子凭证核销失败', {
|
||||||
|
taskId: task.id,
|
||||||
|
platformOrderNo: nextFlow.platformOrderNo,
|
||||||
|
orderNo: nextFlow.orderNo,
|
||||||
|
voucherCount: consumeResult.vouchers.length,
|
||||||
|
failedCount: consumeResult.failed.length,
|
||||||
|
errorMessage: resultMessage,
|
||||||
|
}, { level: 'warn' })
|
||||||
}
|
}
|
||||||
} else if ([40, 50, 60].includes(order.rechargeStatus)) {
|
} else if ([40, 50, 60].includes(order.rechargeStatus)) {
|
||||||
nextTaskStatus = order.rechargeStatus === 60 ? TASK_STATUS.CLOSED : TASK_STATUS.MANUAL_REVIEW
|
nextTaskStatus = order.rechargeStatus === 60 ? TASK_STATUS.CLOSED : TASK_STATUS.MANUAL_REVIEW
|
||||||
@@ -167,6 +194,7 @@ export async function syncKuaishouFeifeiTaskStatus(task: TaskRow) {
|
|||||||
context_json: JSON.stringify({
|
context_json: JSON.stringify({
|
||||||
...taskContext,
|
...taskContext,
|
||||||
kuaishouFeifei: nextFlow,
|
kuaishouFeifei: nextFlow,
|
||||||
|
kuaishouIndustryVoucher: nextIndustryVoucher,
|
||||||
}),
|
}),
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -62,7 +62,11 @@ export async function attachKuaishouIndustryVoucherToTask(
|
|||||||
) {
|
) {
|
||||||
const now = normalizeTimestampIso(options.now || new Date().toISOString())
|
const now = normalizeTimestampIso(options.now || new Date().toISOString())
|
||||||
const context = parseTaskContext(task)
|
const context = parseTaskContext(task)
|
||||||
const nextVoucherContext = buildVoucherContext(voucher, context.kuaishouIndustryVoucher, now)
|
const nextVoucherContext = buildKuaishouIndustryVoucherContext(
|
||||||
|
voucher,
|
||||||
|
context.kuaishouIndustryVoucher,
|
||||||
|
now,
|
||||||
|
)
|
||||||
const nextContext: JsonObject = {
|
const nextContext: JsonObject = {
|
||||||
...context,
|
...context,
|
||||||
kuaishouIndustryVoucher: nextVoucherContext,
|
kuaishouIndustryVoucher: nextVoucherContext,
|
||||||
@@ -121,7 +125,7 @@ function resolveTaskForVoucher(voucher: KuaishouIndustryVoucherRow, tasks: TaskR
|
|||||||
return tasks[unitIndex - 1] || null
|
return tasks[unitIndex - 1] || null
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildVoucherContext(
|
export function buildKuaishouIndustryVoucherContext(
|
||||||
voucher: KuaishouIndustryVoucherRow,
|
voucher: KuaishouIndustryVoucherRow,
|
||||||
existingValue: unknown,
|
existingValue: unknown,
|
||||||
now: string,
|
now: string,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import test from 'node:test'
|
|||||||
import assert from 'node:assert/strict'
|
import assert from 'node:assert/strict'
|
||||||
|
|
||||||
import { generateKuaishouIndustryVoucherCode } from '../../../repositories/kuaishou-industry-voucher-repo.js'
|
import { generateKuaishouIndustryVoucherCode } from '../../../repositories/kuaishou-industry-voucher-repo.js'
|
||||||
|
import { buildKuaishouIndustryVoucherContext } from './voucher-binding-service.js'
|
||||||
import { resolveKuaishouIndustryVoucherValidity } from './voucher-service.js'
|
import { resolveKuaishouIndustryVoucherValidity } from './voucher-service.js'
|
||||||
|
|
||||||
test('generateKuaishouIndustryVoucherCode creates non-numeric stable voucher code', () => {
|
test('generateKuaishouIndustryVoucherCode creates non-numeric stable voucher code', () => {
|
||||||
@@ -57,3 +58,27 @@ test('resolveKuaishouIndustryVoucherValidity prefers actual certificate time ran
|
|||||||
assert.equal(validity.validStartTime, 1000)
|
assert.equal(validity.validStartTime, 1000)
|
||||||
assert.equal(validity.validEndTime, 5000)
|
assert.equal(validity.validEndTime, 5000)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('buildKuaishouIndustryVoucherContext maps consumed voucher state', () => {
|
||||||
|
const context = buildKuaishouIndustryVoucherContext(
|
||||||
|
{
|
||||||
|
oid: '2618800481389561',
|
||||||
|
voucher_code: 'KSV15K821FDHPMTX1ST',
|
||||||
|
token: 'ticket-token',
|
||||||
|
unit_index: 1,
|
||||||
|
status: 'CONSUMED',
|
||||||
|
valid_start_time: 1783427213868,
|
||||||
|
valid_end_time: 1786019213868,
|
||||||
|
consumed_at: '2026-07-07T12:36:54.626Z',
|
||||||
|
} as any,
|
||||||
|
{
|
||||||
|
verifiedAt: '2026-07-07T12:26:58.421Z',
|
||||||
|
},
|
||||||
|
'2026-07-07T12:36:54.626Z',
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal(context.status, 'CONSUMED')
|
||||||
|
assert.equal(context.consumedAt, '2026-07-07T12:36:54.626Z')
|
||||||
|
assert.equal(context.voucherCode, 'KSV15K821FDHPMTX1ST')
|
||||||
|
assert.equal(context.verifiedAt, '2026-07-07T12:26:58.421Z')
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user