优化退款

This commit is contained in:
yml2213
2026-07-10 09:53:42 +08:00
parent 3642ad8aec
commit 763f5034fd
4 changed files with 342 additions and 62 deletions
@@ -11,6 +11,11 @@ import { getTaskById } from '../../repositories/task-repo.js'
import { createHttpError } from '../../utils/http.js'
import { maskSecret } from '../../utils/masking.js'
import { checkKuaishouIndustryEticketAvailable } from '../platforms/kuaishou-industry/check-available-service.js'
import {
getKuaishouIndustrySourceConfig,
listKuaishouIndustryShopConfigs,
type KuaishouIndustrySourceConfig,
} from '../platforms/kuaishou-industry/source-config-service.js'
import { resendKuaishouIndustryVoucherSendCallback } from '../platforms/kuaishou-industry/send-code-service.js'
import { consumeKuaishouIndustryVoucher } from '../platforms/kuaishou-industry/voucher-service.js'
import {
@@ -43,14 +48,18 @@ export async function listAdminKuaishouIndustryRefunds(input: JsonObject = {}) {
assertRequired(input.beginTime, '开始时间未填写')
assertRequired(input.endTime, '结束时间未填写')
return mapOpenApiResult(await listKuaishouIndustryRefunds(input))
const payload = await buildRefundOpenApiPayload(input)
return mapOpenApiResult(await listKuaishouIndustryRefunds(payload))
}
export async function approveAdminKuaishouIndustryRefund(input: JsonObject = {}) {
assertRequired(input.refundId, '退款单编号未填写')
assertRequired(input.refundAmount, '退款金额未填写')
return mapOpenApiResult(await approveKuaishouIndustryRefund(input))
const payload = await buildRefundOpenApiPayload(input)
return mapOpenApiResult(await approveKuaishouIndustryRefund(payload))
}
export async function disagreeAdminKuaishouIndustryRefund(input: JsonObject = {}) {
@@ -60,7 +69,9 @@ export async function disagreeAdminKuaishouIndustryRefund(input: JsonObject = {}
assertRequired(input.status, '退款单当前状态未填写')
assertRequired(input.negotiateStatus, '协商状态未填写')
return mapOpenApiResult(await disagreeKuaishouIndustryRefund(input))
const payload = await buildRefundOpenApiPayload(input)
return mapOpenApiResult(await disagreeKuaishouIndustryRefund(payload))
}
export async function checkAdminKuaishouIndustryVoucherAvailable(input: JsonObject = {}) {
@@ -167,21 +178,111 @@ function buildVoucherOpenApiPayload(
orderId: String(input.orderId || input.oid || voucher?.oid || '').trim(),
token: String(input.token || voucher?.token || '').trim(),
serialNum: String(input.serialNum || voucher?.consume_serial_num || '').trim(),
etickets: etickets.length > 0
? etickets
: voucherCode
? [{ id: voucherCode, code: voucherCode, num: 1 }]
: [],
etickets:
etickets.length > 0
? etickets
: voucherCode
? [{ id: voucherCode, code: voucherCode, num: 1 }]
: [],
}
}
async function resolveOptionalVoucher(input: JsonObject): Promise<KuaishouIndustryVoucherRow | null> {
async function buildRefundOpenApiPayload(input: JsonObject): Promise<JsonObject> {
const source = getKuaishouIndustrySourceConfig()
const sellerId =
String(input.sellerId || '').trim() ||
(await resolveRefundSellerIdFromLocalVoucher(input)) ||
resolveSingleEnabledKuaishouIndustrySellerId(source)
if (!sellerId && hasMultipleEnabledKuaishouIndustryShops(source)) {
throw createHttpError('存在多个快手售后退款店铺授权,请先选择 sellerId', {
statusCode: 400,
errorCode: 'admin_kuaishou_industry_refund_seller_id_required',
})
}
return {
...input,
...(sellerId ? { sellerId } : {}),
}
}
async function resolveRefundSellerIdFromLocalVoucher(input: JsonObject): Promise<string> {
const voucherCode = String(input.voucherCode || '').trim()
const oid = String(input.oid || input.orderId || '').trim()
if (voucherCode) {
const voucher = await findKuaishouIndustryVoucherByCode(voucherCode, oid)
return String(voucher?.seller_id || '').trim()
}
const taskId = Number(input.taskId || 0)
if (Number.isFinite(taskId) && taskId > 0) {
return resolveSingleSellerIdFromVouchers(
await listKuaishouIndustryVouchersByTaskId(Math.trunc(taskId)),
'当前任务关联多个卖家,请指定 sellerId',
)
}
if (oid) {
return resolveSingleSellerIdFromVouchers(
await listKuaishouIndustryVouchersByOid(oid),
'当前订单关联多个卖家,请指定 sellerId',
)
}
return ''
}
function resolveSingleSellerIdFromVouchers(
vouchers: KuaishouIndustryVoucherRow[],
multipleMessage: string,
): string {
const sellerIds = Array.from(
new Set(vouchers.map((voucher) => String(voucher.seller_id || '').trim()).filter(Boolean)),
)
if (sellerIds.length > 1) {
throw createHttpError(multipleMessage, {
statusCode: 409,
errorCode: 'admin_kuaishou_industry_refund_seller_id_ambiguous',
})
}
return sellerIds[0] || ''
}
function resolveSingleEnabledKuaishouIndustrySellerId(
source: KuaishouIndustrySourceConfig,
): string {
const enabledShops = listEnabledKuaishouIndustryShops(source)
return enabledShops.length === 1
? String(enabledShops[0]?.sellerId || enabledShops[0]?.shopId || '').trim()
: ''
}
function hasMultipleEnabledKuaishouIndustryShops(source: KuaishouIndustrySourceConfig): boolean {
return listEnabledKuaishouIndustryShops(source).length > 1
}
function listEnabledKuaishouIndustryShops(source: KuaishouIndustrySourceConfig) {
return listKuaishouIndustryShopConfigs(source).filter(
(shop) => shop.enabled !== false && String(shop.sellerId || shop.shopId || '').trim(),
)
}
async function resolveOptionalVoucher(
input: JsonObject,
): Promise<KuaishouIndustryVoucherRow | null> {
const voucherCode = String(input.voucherCode || '').trim()
if (!voucherCode) {
return null
}
const voucher = await findKuaishouIndustryVoucherByCode(voucherCode, String(input.oid || input.orderId || '').trim())
const voucher = await findKuaishouIndustryVoucherByCode(
voucherCode,
String(input.oid || input.orderId || '').trim(),
)
if (!voucher) {
throw createHttpError('电子凭证不存在', {
statusCode: 404,
@@ -201,13 +302,21 @@ async function resolveRequiredVoucher(input: JsonObject): Promise<KuaishouIndust
const taskId = Number(input.taskId || 0)
if (Number.isFinite(taskId) && taskId > 0) {
const vouchers = await listKuaishouIndustryVouchersByTaskId(Math.trunc(taskId))
return resolveSingleVoucher(vouchers, '当前任务没有关联电子凭证', '当前任务关联多个电子凭证,请指定券码')
return resolveSingleVoucher(
vouchers,
'当前任务没有关联电子凭证',
'当前任务关联多个电子凭证,请指定券码',
)
}
const oid = String(input.oid || input.orderId || '').trim()
if (oid) {
const vouchers = await listKuaishouIndustryVouchersByOid(oid)
return resolveSingleVoucher(vouchers, '当前订单没有关联电子凭证', '当前订单关联多个电子凭证,请指定券码')
return resolveSingleVoucher(
vouchers,
'当前订单没有关联电子凭证',
'当前订单关联多个电子凭证,请指定券码',
)
}
throw createHttpError('请填写券码、任务 ID 或订单号', {
@@ -262,6 +262,7 @@ export type AdminKuaishouIndustryRefundListInput = {
export type AdminKuaishouIndustryRefundApproveInput = {
sellerId?: string
orderId?: string
refundId?: number | string
desc?: string
refundAmount?: number | string
@@ -272,6 +273,7 @@ export type AdminKuaishouIndustryRefundApproveInput = {
export type AdminKuaishouIndustryRefundDisagreeInput = {
sellerId?: string
orderId?: string
refundId?: number | string
sellerDisagreeReason?: number | string
sellerDisagreeDesc?: string