From 017e9e98d1bb5a752da7d27e8304fdd478a3245b Mon Sep 17 00:00:00 2001 From: "chihao.ou" Date: Thu, 17 Sep 2026 14:56:33 +0800 Subject: [PATCH] fix(payment): base refund balance warnings on the requested amount --- .../admin/payment/AdminRefundDialog.vue | 2 +- .../AdminRefundDialog.balance.spec.ts | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 frontend/src/components/admin/payment/__tests__/AdminRefundDialog.balance.spec.ts diff --git a/frontend/src/components/admin/payment/AdminRefundDialog.vue b/frontend/src/components/admin/payment/AdminRefundDialog.vue index f58b810388..2774162050 100644 --- a/frontend/src/components/admin/payment/AdminRefundDialog.vue +++ b/frontend/src/components/admin/payment/AdminRefundDialog.vue @@ -214,7 +214,7 @@ const maxRefundable = computed(() => { const balanceInsufficient = computed(() => { if (props.userBalance == null || !props.order) return false - return props.userBalance < props.order.amount + return props.userBalance < form.amount }) watch(() => props.show, (val) => { diff --git a/frontend/src/components/admin/payment/__tests__/AdminRefundDialog.balance.spec.ts b/frontend/src/components/admin/payment/__tests__/AdminRefundDialog.balance.spec.ts new file mode 100644 index 0000000000..8b7322eac3 --- /dev/null +++ b/frontend/src/components/admin/payment/__tests__/AdminRefundDialog.balance.spec.ts @@ -0,0 +1,53 @@ +import { afterEach, describe, expect, it, vi } from 'vitest' +import { enableAutoUnmount, mount } from '@vue/test-utils' +import type { PaymentOrder } from '@/types/payment' +import AdminRefundDialog from '../AdminRefundDialog.vue' + +vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (key: string) => key }) })) +enableAutoUnmount(afterEach) + +async function openRefund(overrides: Partial = {}) { + const order: PaymentOrder = { + id: 1, user_id: 10, amount: 100, pay_amount: 100, fee_rate: 0, + payment_type: 'stripe', out_trade_no: 'order-1', status: 'COMPLETED', + order_type: 'balance', created_at: '2026-09-01', expires_at: '2026-09-02', + refund_amount: 0, ...overrides + } + const wrapper = mount(AdminRefundDialog, { + props: { show: false, order, userBalance: 50 }, + global: { stubs: { BaseDialog: { template: '
' } } } + }) + await wrapper.setProps({ show: true }) + return wrapper +} + +const warning = 'payment.admin.insufficientBalance' + +describe('refund balance warning', () => { + it('compares the available balance with the edited refund amount', async () => { + const wrapper = await openRefund() + expect(wrapper.text()).toContain(warning) + await wrapper.get('input[type="number"]').setValue('20') + expect(wrapper.text()).not.toContain(warning) + await wrapper.get('input[type="number"]').setValue('75') + expect(wrapper.text()).toContain(warning) + }) + + it('does not warn when the balance exactly covers the refund', async () => { + const wrapper = await openRefund() + await wrapper.get('input[type="number"]').setValue('50') + expect(wrapper.text()).not.toContain(warning) + }) + + it('uses the remaining amount for an already partially refunded order', async () => { + const wrapper = await openRefund({ status: 'PARTIALLY_REFUNDED', refund_amount: 80 }) + expect((wrapper.get('input[type="number"]').element as HTMLInputElement).value).toBe('20') + expect(wrapper.text()).not.toContain(warning) + }) + + it('keeps the warning hidden when balance deduction is disabled', async () => { + const wrapper = await openRefund() + await wrapper.get('#deduct-balance').setValue(false) + expect(wrapper.text()).not.toContain(warning) + }) +})