From 20287916b11b83e75fc6356d142c9b0af012a8b2 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 1 Nov 2026 15:21:53 +0800 Subject: [PATCH] =?UTF-8?q?fix(finance):=20=E9=80=80=E6=AC=BE=E6=89=80?= =?UTF-8?q?=E5=B1=9E=E6=9C=9F=E9=97=B4=E5=85=B3=E8=B4=A6=E6=97=B6=E9=98=BB?= =?UTF-8?q?=E6=96=AD=E9=80=80=E6=AC=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 手工退款按实际退款日期校验期间 - 平台退款按当前退款月份校验期间 - 避免退款成功但冲减行被关账跳过的静默丢失 --- .../services/finance/order-refund-service.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/apps/backend/src/services/finance/order-refund-service.ts b/apps/backend/src/services/finance/order-refund-service.ts index 27dca865..25faeb92 100644 --- a/apps/backend/src/services/finance/order-refund-service.ts +++ b/apps/backend/src/services/finance/order-refund-service.ts @@ -144,6 +144,7 @@ export async function createManualRefund( }) } await assertBasisPeriodOpen(client, order.basis_at, '退款') + await assertRefundMonthOpen(client, '退款', toChinaDate(refundedAt || now)) const itemsResult = await client.query<{ id: number @@ -396,6 +397,7 @@ export async function voidOrderRefund( }) } await assertBasisPeriodOpen(client, row.basis_at, '撤销退款') + await assertRefundMonthOpen(client, '撤销退款') await client.query( ` UPDATE order_refunds @@ -490,6 +492,25 @@ export function mapOrderRefund(row: OrderRefundRow): OrderRefund { } } +async function assertRefundMonthOpen( + client: Pick, + action: string, + date?: string, +) { + const day = date || CHINA_DATE_FORMATTER.format(new Date()) + const periodKey = day.slice(0, 7) + const period = await client.query<{ status: string }>( + `SELECT status FROM finance_periods WHERE period_key = $1 LIMIT 1`, + [periodKey], + ) + if (period.rows[0]?.status === 'closed') { + throw createHttpError(`退款所属期间 ${periodKey} 已关账,请先反关账后再${action}`, { + statusCode: 409, + errorCode: 'order_refund_period_closed', + }) + } +} + async function assertBasisPeriodOpen( client: Pick, basisAt: string, @@ -664,6 +685,19 @@ export async function approveAndRecordKuaishouRefund( } } + // 退款当天所属期间也必须开着,否则退款冲减会静默丢失。 + const refundPeriodKey = CHINA_DATE_FORMATTER.format(new Date()).slice(0, 7) + const refundPeriod = await query<{ status: string }>( + `SELECT status FROM finance_periods WHERE period_key = $1 LIMIT 1`, + [refundPeriodKey], + ) + if (refundPeriod.rows[0]?.status === 'closed') { + throw createHttpError(`退款所属期间 ${refundPeriodKey} 已关账,请先反关账后再退款`, { + statusCode: 409, + errorCode: 'order_refund_period_closed', + }) + } + // 已经登记过的平台退款必须幂等返回,不能因为剩余可退为 0 被误判为超额。 const recorded = await findRecordedPlatformRefund(orderId, platformRefundId) if (recorded) {