/** * Prepaid mutations. Account-balance is the writer when NATS or HTTP books exist. * Tests (no NATS_URL, no ACCOUNT_BALANCE_URL) keep a local cache only. */ import { natsAdjust, natsPublish, natsStatement } from './billing-nats'; import type { AccessPlane } from './billing-nats'; export type PrepaidRow = { customerId: string; veraeUserId?: string; cents: number; reason: string; agent: string; kind?: string; prepaidCents?: number; }; function booksUrl(): string { return (process.env.ACCOUNT_BALANCE_URL || '').replace(/\/$/, ''); } export function booksConfigured(): boolean { return Boolean(process.env.NATS_URL || booksUrl()); } export async function ledgerAdjust(row: PrepaidRow, plane: AccessPlane): Promise { const viaNats = await natsAdjust(row, plane); if (viaNats && typeof viaNats === 'object' && viaNats !== null && 'prepaidCents' in viaNats) { return viaNats as PrepaidRow; } const base = booksUrl(); if (!base) return null; const r = await fetch(`${base}/adjust`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(row), }); if (!r.ok) return null; return (await r.json()) as PrepaidRow; } export async function ledgerPutCustomer(row: { customerId: string; name?: string; veraeUserId?: string; }): Promise { natsPublish('verae.billing.customer.put', row, 'staff'); const base = booksUrl(); if (!base) return; await fetch(`${base}/customer`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(row), }).catch(() => {}); } export async function ledgerStatement(customerId: string, plane: AccessPlane, veraeUserId?: string) { const nats = await natsStatement(customerId, plane, veraeUserId); if (nats) return nats; const base = booksUrl(); if (!base) return null; const r = await fetch(`${base}/statement/${encodeURIComponent(customerId)}`); if (!r.ok) return null; return r.json(); }