import { api, type ApiError } from '@/api'; import { toast } from 'sonner'; import { errMessage } from '@/lib/utils'; /** * Create a manual payment, treating the server's "duplicate suspected" (409) as a * question rather than an error. The deliberate manual-add path must never * *silently* drop a legitimately-identical second payment (same bill, date, * amount) — losing a real payment is itself a money-integrity bug. So the server * returns `409 DUPLICATE_SUSPECTED` instead of silently deduping, and here we * surface an "add anyway?" toast; confirming resends with `allow_duplicate`. * * `onSuccess` runs after any *real* creation — immediate OR confirmed-retry — so * callers put their toast/refresh/close there. Any non-duplicate error re-throws * for the caller's existing `catch`. */ export async function createPaymentOrConfirm( payload: Record, onSuccess: () => void | Promise, ): Promise { const create = async (allowDuplicate: boolean) => { await api.createPayment(allowDuplicate ? { ...payload, allow_duplicate: true } : payload); await onSuccess(); }; try { await create(false); } catch (err) { const e = err as ApiError; if (e?.status === 409 && e?.code === 'DUPLICATE_SUSPECTED') { toast.warning('A matching payment already exists for this bill, date, and amount.', { description: 'Add it anyway?', action: { label: 'Add anyway', onClick: () => { create(true).catch(retryErr => toast.error(errMessage(retryErr, 'Failed to add payment'))); }, }, }); return; // handled — not an error the caller should re-toast } throw err; } }