Files
Spanglish/frontend/src/lib/api/payments.ts
T
MichilisandClaude Fable 5 71c277045b Centralize seat capacity accounting and the payment provider registry.
Replace manualProviders.ts with a paymentProviders.ts registry
(automatic vs manual settlement) and move all seat counting into
capacity.ts as the single source of truth: only paid/checked-in tickets
and pending_approval payments hold a seat, so abandoned checkouts never
block sales. Admins can now knowingly approve a payment over capacity
(allowOverCapacity), with the booking and admin UIs updated to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 04:58:40 +00:00

69 lines
2.8 KiB
TypeScript

import { fetchApi } from './client';
import type { Payment, PaymentWithDetails } from './types';
// Mirrors backend/src/lib/paymentProviders.ts: manual gateways need an admin to
// verify the money arrived; automatic ones (lightning) confirm themselves.
export const MANUAL_PAYMENT_PROVIDERS = ['tpago', 'bank_transfer', 'card', 'cash'];
export function isManualProvider(provider: string): boolean {
return MANUAL_PAYMENT_PROVIDERS.includes(provider);
}
export const paymentsApi = {
getAll: (params?: { status?: string; provider?: string; pendingApproval?: boolean; eventId?: string; eventIds?: string[] }) => {
const query = new URLSearchParams();
if (params?.status) query.set('status', params.status);
if (params?.provider) query.set('provider', params.provider);
if (params?.pendingApproval) query.set('pendingApproval', 'true');
if (params?.eventId) query.set('eventId', params.eventId);
if (params?.eventIds && params.eventIds.length > 0) query.set('eventIds', params.eventIds.join(','));
return fetchApi<{ payments: PaymentWithDetails[] }>(`/api/payments?${query}`);
},
getPendingApproval: () =>
fetchApi<{ payments: PaymentWithDetails[] }>('/api/payments/pending-approval'),
update: (id: string, data: { status: string; reference?: string; adminNote?: string }) =>
fetchApi<{ payment: Payment }>(`/api/payments/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
}),
approve: (id: string, adminNote?: string, sendEmail: boolean = true, allowOverCapacity: boolean = false) =>
fetchApi<{ payment: Payment; message: string }>(`/api/payments/${id}/approve`, {
method: 'POST',
body: JSON.stringify({ adminNote, sendEmail, allowOverCapacity }),
}),
reject: (id: string, adminNote?: string, sendEmail: boolean = true) =>
fetchApi<{ payment: Payment; message: string }>(`/api/payments/${id}/reject`, {
method: 'POST',
body: JSON.stringify({ adminNote, sendEmail }),
}),
sendReminder: (id: string) =>
fetchApi<{ message: string; reminderSentAt?: string }>(`/api/payments/${id}/send-reminder`, {
method: 'POST',
}),
updateNote: (id: string, adminNote: string) =>
fetchApi<{ payment: Payment; message: string }>(`/api/payments/${id}/note`, {
method: 'POST',
body: JSON.stringify({ adminNote }),
}),
refund: (id: string) =>
fetchApi<{ message: string }>(`/api/payments/${id}/refund`, { method: 'POST' }),
reactivate: (id: string) =>
fetchApi<{ payment: Payment; message: string }>(`/api/payments/${id}/reactivate`, {
method: 'POST',
}),
reopen: (id: string, adminNote?: string) =>
fetchApi<{ payment: Payment; message: string }>(`/api/payments/${id}/reopen`, {
method: 'POST',
body: JSON.stringify({ adminNote }),
}),
};