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>
This commit is contained in:
Michilis
2026-07-26 04:58:40 +00:00
co-authored by Claude Fable 5
parent c9a600b6d6
commit 71c277045b
20 changed files with 570 additions and 290 deletions
+14 -2
View File
@@ -222,7 +222,14 @@ export default function AdminEventsPage() {
</div>
</td>
<td className="px-4 py-3 text-sm text-gray-600">{formatDate(event.startDatetime)}</td>
<td className="px-4 py-3 text-sm">{event.bookedCount || 0} / {event.capacity}</td>
<td className="px-4 py-3 text-sm">
{(event.bookedCount || 0) + (event.claimedCount || 0)} / {event.capacity}
{(event.claimedCount || 0) > 0 && (
<span className="block text-[11px] text-yellow-600">
{event.claimedCount} pending approval
</span>
)}
</td>
<td className="px-4 py-3">
<div className="flex items-center gap-1.5">
{getStatusBadge(event.status)}
@@ -332,7 +339,12 @@ export default function AdminEventsPage() {
</div>
</div>
<div className="flex items-center justify-between mt-2 pt-2 border-t border-gray-100">
<p className="text-xs text-gray-500">{event.bookedCount || 0} / {event.capacity} spots</p>
<p className="text-xs text-gray-500">
{(event.bookedCount || 0) + (event.claimedCount || 0)} / {event.capacity} spots
{(event.claimedCount || 0) > 0 && (
<span className="text-yellow-600"> · {event.claimedCount} pending</span>
)}
</p>
<div className="flex items-center gap-1" onClick={(e) => e.stopPropagation()}>
<Link href={`/admin/events/${event.id}`}
className="p-2 hover:bg-primary-yellow/20 text-primary-dark rounded-btn min-h-[36px] min-w-[36px] flex items-center justify-center">