From 487d5864926b1e83075cdee53f72444acd744e61 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Wed, 8 Jul 2026 19:17:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=B5=E5=AD=90=E5=87=AD?= =?UTF-8?q?=E8=AF=81=E9=94=80=E6=AF=81=E4=B8=8E=E9=A3=9E=E9=A3=9E=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E9=87=91=E9=A2=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fulfillment/kuaishou-feifei/index.test.ts | 22 +++++++++ .../fulfillment/kuaishou-feifei/index.ts | 46 ++++++++++++++++++- .../destroy-callback-service.ts | 1 + .../destroy-code-service.test.ts | 37 +++++++++++++++ .../kuaishou-industry/destroy-code-service.ts | 6 +++ .../platforms/kuaishou-industry/payload.ts | 1 + 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 apps/backend/src/services/platforms/kuaishou-industry/destroy-code-service.test.ts diff --git a/apps/backend/src/services/fulfillment/kuaishou-feifei/index.test.ts b/apps/backend/src/services/fulfillment/kuaishou-feifei/index.test.ts index dbc65af2..5d7776bd 100644 --- a/apps/backend/src/services/fulfillment/kuaishou-feifei/index.test.ts +++ b/apps/backend/src/services/fulfillment/kuaishou-feifei/index.test.ts @@ -4,6 +4,7 @@ import assert from 'node:assert/strict' import { buildFeifeiPlatformOrderNo, resolveKuaishouFeifeiClaimUrl, + resolveKuaishouFeifeiPlatformAmount, } from './index.js' import type { TaskRow } from '../../../types/repository/rows.js' @@ -66,6 +67,27 @@ test('buildFeifeiPlatformOrderNo falls back to task number', () => { ) }) +test('resolveKuaishouFeifeiPlatformAmount converts order fen amount to yuan', () => { + assert.equal(resolveKuaishouFeifeiPlatformAmount({ + totalAmountFen: 3800, + quantity: 1, + }), 38) +}) + +test('resolveKuaishouFeifeiPlatformAmount splits amount by item quantity', () => { + assert.equal(resolveKuaishouFeifeiPlatformAmount({ + totalAmountFen: 7600, + quantity: 2, + }), 38) +}) + +test('resolveKuaishouFeifeiPlatformAmount skips empty amount', () => { + assert.equal(resolveKuaishouFeifeiPlatformAmount({ + totalAmountFen: 0, + quantity: 1, + }), 0) +}) + function createTask(patch: Partial = {}): TaskRow { return { id: 123, diff --git a/apps/backend/src/services/fulfillment/kuaishou-feifei/index.ts b/apps/backend/src/services/fulfillment/kuaishou-feifei/index.ts index f23a781b..2180cb3b 100644 --- a/apps/backend/src/services/fulfillment/kuaishou-feifei/index.ts +++ b/apps/backend/src/services/fulfillment/kuaishou-feifei/index.ts @@ -1,3 +1,5 @@ +import { getOrderItemById } from '../../../repositories/order-item-repo.js' +import { getOrderById } from '../../../repositories/order-repo.js' import { createTaskEvent } from '../../../repositories/task-event-repo.js' import { updateTask } from '../../../repositories/task-repo.js' import { createHttpError } from '../../../utils/http.js' @@ -59,11 +61,17 @@ export async function prepareKuaishouFeifeiTask(task: TaskRow) { } const platformOrderNo = flow.platformOrderNo || buildFeifeiPlatformOrderNo(task) - const order = await createKuaishouFeifeiOrder({ + const platformAmount = await resolveKuaishouFeifeiTaskPlatformAmount(task) + const orderInput: Parameters[0] = { platformOrderNo, productCode: flow.productCode, platformBuyNum: 1, - }) + } + if (platformAmount > 0) { + orderInput.platformAmount = platformAmount + } + + const order = await createKuaishouFeifeiOrder(orderInput) const feifeiClaimUrl = resolveKuaishouFeifeiOrderClaimUrl(order) if (!feifeiClaimUrl) { throw createHttpError('kuaishou-feifei 未返回领取链接', { @@ -96,6 +104,7 @@ export async function prepareKuaishouFeifeiTask(task: TaskRow) { platformOrderNo, orderNo: order.orderNo, productCode: flow.productCode, + platformAmount, rechargeStatus: order.rechargeStatus, rechargeStatusLabel: order.rechargeStatusLabel, rechargeUrl: order.h5.rechargeUrl, @@ -356,3 +365,36 @@ export function buildFeifeiPlatformOrderNo(task: TaskRow) { return `OS-FEIFEI-${task.id}` } + +export async function resolveKuaishouFeifeiTaskPlatformAmount(task: TaskRow) { + const [order, orderItem] = await Promise.all([ + getOrderById(task.order_id), + getOrderItemById(task.order_item_id), + ]) + + return resolveKuaishouFeifeiPlatformAmount({ + totalAmountFen: order?.total_amount, + quantity: orderItem?.quantity, + }) +} + +export function resolveKuaishouFeifeiPlatformAmount({ + totalAmountFen, + quantity, +}: { + totalAmountFen?: unknown + quantity?: unknown +} = {}) { + const totalFen = normalizePositiveFen(totalAmountFen) + if (totalFen <= 0) { + return 0 + } + + const normalizedQuantity = Math.max(1, Math.trunc(Number(quantity || 1)) || 1) + return Number((totalFen / normalizedQuantity / 100).toFixed(2)) +} + +function normalizePositiveFen(value: unknown) { + const parsed = Number(value) + return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : 0 +} diff --git a/apps/backend/src/services/platforms/kuaishou-industry/destroy-callback-service.ts b/apps/backend/src/services/platforms/kuaishou-industry/destroy-callback-service.ts index ec40190f..e67690d6 100644 --- a/apps/backend/src/services/platforms/kuaishou-industry/destroy-callback-service.ts +++ b/apps/backend/src/services/platforms/kuaishou-industry/destroy-callback-service.ts @@ -100,6 +100,7 @@ export async function destroyCallback(input: DestroyCallbackInput): Promise<{ su oid: input.oid, sellerId: input.sellerId || '', reason: input.reason, + hasToken: Boolean(input.token), }) try { diff --git a/apps/backend/src/services/platforms/kuaishou-industry/destroy-code-service.test.ts b/apps/backend/src/services/platforms/kuaishou-industry/destroy-code-service.test.ts new file mode 100644 index 00000000..4e948f82 --- /dev/null +++ b/apps/backend/src/services/platforms/kuaishou-industry/destroy-code-service.test.ts @@ -0,0 +1,37 @@ +import test from 'node:test' +import assert from 'node:assert/strict' + +import { normalizeDestroyCodePayload } from './payload.js' +import { resolveDestroyCallbackToken } from './destroy-code-service.js' + +test('normalizeDestroyCodePayload keeps destroy callback token when provided', () => { + const payload = normalizeDestroyCodePayload({ + appkey: 'ks-test', + param: { + oid: '2618901686368642', + reason: 'USER_APPLY_REFUND', + token: 'destroy-token', + etickets: [ + { + id: 'KSVW9JTD4FZM4VDHKBV', + num: 1, + }, + ], + }, + sign: 'test-sign', + signMethod: 'MD5', + timestamp: 1783499780936, + version: '1', + }) + + assert.equal(payload.token, 'destroy-token') +}) + +test('resolveDestroyCallbackToken falls back to stored voucher token', () => { + const token = resolveDestroyCallbackToken([ + { token: '' }, + { token: ' stored-token ' }, + ]) + + assert.equal(token, 'stored-token') +}) diff --git a/apps/backend/src/services/platforms/kuaishou-industry/destroy-code-service.ts b/apps/backend/src/services/platforms/kuaishou-industry/destroy-code-service.ts index 844ac25a..ffe8719e 100644 --- a/apps/backend/src/services/platforms/kuaishou-industry/destroy-code-service.ts +++ b/apps/backend/src/services/platforms/kuaishou-industry/destroy-code-service.ts @@ -39,6 +39,7 @@ export async function handleDestroyCode(rawBody: JsonObject = {}) { : vouchers const callbackSellerId = params.sellerId || String(targetVouchers.find((voucher) => String(voucher.seller_id || '').trim())?.seller_id || '').trim() + const callbackToken = params.token || resolveDestroyCallbackToken(targetVouchers) for (const voucher of targetVouchers) { const status = String(voucher.status || '').trim().toUpperCase() @@ -80,11 +81,16 @@ export async function handleDestroyCode(rawBody: JsonObject = {}) { goodsValue: e.goodsValue, })), reason: params.reason, + token: callbackToken, }) return buildIndustrySuccessResponse({ oid: normalizedOid }) } +export function resolveDestroyCallbackToken(vouchers: Array<{ token?: unknown }> = []) { + return String(vouchers.find((voucher) => String(voucher.token || '').trim())?.token || '').trim() +} + function fireDestroyCallback(input: Parameters[0]) { destroyCallback(input).catch((err) => { logWarn('[kuaishou-industry/destroy-code]', '销毁回调异步执行异常', { diff --git a/apps/backend/src/services/platforms/kuaishou-industry/payload.ts b/apps/backend/src/services/platforms/kuaishou-industry/payload.ts index eb91c87a..05a9cb87 100644 --- a/apps/backend/src/services/platforms/kuaishou-industry/payload.ts +++ b/apps/backend/src/services/platforms/kuaishou-industry/payload.ts @@ -55,6 +55,7 @@ export function normalizeDestroyCodePayload(raw: JsonObject = {}) { oid: normalizeIndustryString(param.oid), sellerId: normalizeIndustryString(param.sellerId), reason: normalizeIndustryString(param.reason), + token: normalizeIndustryString(param.token), etickets: normalizeDestroyEtickets(param.etickets), } }