feat(payment): prefill amount field with remaining balance and cap wallet prefill
This commit is contained in:
@@ -181,7 +181,7 @@ function ContractCard({ contract, item }: { contract: TenantInsurance; item: Ser
|
||||
{!draft.covered && !isLoading && (
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, padding: '12px 14px' }}>
|
||||
<span style={{ fontSize: 12, color: 'var(--text-3)' }}>این خدمت تحت این بیمه پوشش ندارد</span>
|
||||
<button className="btn sm" disabled={saveMut.isPending} onClick={() => saveMut.mutate()}>
|
||||
<button className="btn primary sm" disabled={saveMut.isPending} onClick={() => saveMut.mutate()}>
|
||||
{saveMut.isPending ? '...' : 'ذخیره'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -71,7 +71,8 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
|
||||
const payMut = useMutation({
|
||||
mutationFn: (body: object) => api.post(`/api/v1/session/${sessionUuid}/payments`, body),
|
||||
onSuccess: () => { invalidate(); setAmount(0); toast.success('پرداخت ثبت شد'); },
|
||||
// بعد از ثبت، آکاردئون بسته میشود تا باز شدن بعدی ماندهی بهروزشده را پیشفرض بگذارد.
|
||||
onSuccess: () => { invalidate(); setAmount(0); setExpanded(null); toast.success('پرداخت ثبت شد'); },
|
||||
onError: (e: Error) => toast.error(e.message),
|
||||
});
|
||||
|
||||
@@ -128,6 +129,17 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
: Math.max(0, finalPrice - discountRials);
|
||||
const debt = session.remaining_rials ?? session.patient_debt_rials ?? 0;
|
||||
|
||||
/**
|
||||
* مبلغ پیشفرض هنگام باز شدن هر روش پرداخت = ماندهی فعلی (تومان).
|
||||
* چون `debt` از `remaining_rials` سرور میآید، بعد از هر پرداخت جزئی خودش کم میشود؛
|
||||
* پس در پرداخت چندروشه، روش بعدی باقیماندهی درست را پیشفرض میگیرد.
|
||||
* برای کیف پول سقفِ موجودی هم اعمال میشود.
|
||||
*/
|
||||
const defaultAmountFor = (method: string) => {
|
||||
const cap = method === 'wallet' ? Math.min(debt, walletBalance) : debt;
|
||||
return rialToToman(Math.max(0, cap));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* هزینه سرویس */}
|
||||
@@ -264,7 +276,7 @@ export default function PaymentStep({ recordUuid, session, walletBalance, onCont
|
||||
<button
|
||||
type="button"
|
||||
aria-expanded={open}
|
||||
onClick={() => { setExpanded(open ? null : m.key); setAmount(0); }}
|
||||
onClick={() => { setExpanded(open ? null : m.key); setAmount(open ? 0 : defaultAmountFor(m.key)); }}
|
||||
style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%', padding: '14px 4px', background: 'transparent', border: 'none', cursor: 'pointer' }}
|
||||
>
|
||||
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 600, color: '#111827' }}>{m.label}</span>
|
||||
|
||||
@@ -97,6 +97,24 @@ describe('SessionPaymentPage (تکمیل پرداخت مراجعه)', () => {
|
||||
expect(typeof (body as any).paid_at).toBe('number');
|
||||
});
|
||||
|
||||
it('prefills the amount field with the remaining balance when a method is opened', async () => {
|
||||
// مانده ۲,۳۰۰,۰۰۰ ریال → ۲۳۰,۰۰۰ تومان در فیلد مبلغ
|
||||
mockGets([session({ remaining_rials: 2_300_000 })]);
|
||||
renderPage();
|
||||
|
||||
fireEvent.click(await screen.findByText('پرداخت نقدی'));
|
||||
expect(screen.getByPlaceholderText('مبلغ (تومان)')).toHaveValue('230,000');
|
||||
});
|
||||
|
||||
it('caps the wallet prefill at the wallet balance', async () => {
|
||||
// موجودی کیف پول ۳۰۰,۰۰۰ ریال < مانده ۲,۳۰۰,۰۰۰ ریال → ۳۰,۰۰۰ تومان
|
||||
mockGets([session({ remaining_rials: 2_300_000 })]);
|
||||
renderPage();
|
||||
|
||||
fireEvent.click(await screen.findByText('پرداخت از طریق کیف پول'));
|
||||
expect(screen.getByPlaceholderText('مبلغ (تومان)')).toHaveValue('30,000');
|
||||
});
|
||||
|
||||
it('applies and removes settlement discount (PATCH /session/{uuid})', async () => {
|
||||
mockGets([session()]);
|
||||
patch.mockResolvedValue({ success: true, data: session() });
|
||||
|
||||
Reference in New Issue
Block a user