/** * Gemeinsame Anfragehilfen der Finanzbuchhaltungs-Module (Kantinenabrechnung, * Handelsware; quick-261002-fm5). `credentials: 'include'` fuer Cookie-Auth, * `NEXT_PUBLIC_API_URL` als Basis — Muster `custom-modules-api.ts`. */ export const ACCOUNTING_API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'; /** Dateiantwort der API (Base64) — wie beim Zertifikat-Manager. */ export interface FileResponse { filename: string; content: string; mimeType: string; } /** * Fehler mit HTTP-Status, maschinenlesbarer Kennung (`code`, falls die API * eine liefert) und deutscher Servermeldung. */ export class AccountingRequestError extends Error { constructor( readonly status: number, readonly code: string | null, message: string, readonly details: unknown = null, ) { super(message); this.name = 'AccountingRequestError'; } } async function failure(res: Response): Promise { let message = `Request failed (${res.status})`; let code: string | null = null; let details: unknown = null; try { const body = await res.json(); const raw = body?.message; if (Array.isArray(raw)) message = raw.join(' '); else if (typeof raw === 'string') message = raw; if (typeof body?.code === 'string') code = body.code; details = body?.errors ?? null; } catch { // Antwort ohne JSON-Koerper — Standardmeldung bleibt. } return new AccountingRequestError(res.status, code, message, details); } export async function accountingRequest( path: string, init: { method?: string; json?: unknown; form?: FormData } = {}, ): Promise { const headers: Record = {}; let body: BodyInit | undefined; if (init.form) { body = init.form; } else if (init.json !== undefined) { headers['Content-Type'] = 'application/json'; body = JSON.stringify(init.json); } const res = await fetch(`${ACCOUNTING_API_URL}${path}`, { method: init.method ?? 'GET', credentials: 'include', headers, body, }); if (!res.ok) throw await failure(res); if (res.status === 204) return undefined as T; return (await res.json()) as T; }