fix(finance): 退款所属期间关账时阻断退款

- 手工退款按实际退款日期校验期间
- 平台退款按当前退款月份校验期间
- 避免退款成功但冲减行被关账跳过的静默丢失
This commit is contained in:
yml2213
2026-11-01 15:21:53 +08:00
parent fd6d2d561b
commit 20287916b1
@@ -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<PoolClient, 'query'>,
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<PoolClient, 'query'>,
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) {