Projektkonto: Stripe-Rechnungen lesen (Liste, Einzellesen fehlender, Ausfall)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3305371111
commit
10679ae726
2 files changed
+125
No files matched your search
@@ -1,5 +1,8 @@
|
||||
import { STUNDENSATZ_STANDARD_CENTS, VEREINBARTE_STATUS } from './konstanten.js'
|
||||
import { abrechenbar } from './arbeitsblaetter.js'
|
||||
import { getStripe } from '../stripeBilling.js'
|
||||
import { berlinDate } from '../finance/dates.js'
|
||||
import { listInvoices, mapInvoice } from '../finance/stripeFinance.js'
|
||||
|
||||
/**
|
||||
* Projektkonto (Spec 2026-10-06, Abschnitt 4; Uebersicht V4 "L1 - Projektkonto"): reine Rechenregeln und die Ladefunktionen
|
||||
@@ -91,3 +94,42 @@ export function rechneOhneProjekt(rechnungen) {
|
||||
const gezaehlt = rechnungen.filter((invoice) => FINALISIERT.has(invoice.status))
|
||||
return { berechnetCents: summe(gezaehlt, 'totalCents'), bezahltCents: summe(gezaehlt, 'paidCents'), anzahl: gezaehlt.length }
|
||||
}
|
||||
|
||||
// Einzellesen fehlender Rechnungen: wie die Leseanfragen in stripeFinance.js (15 s, eine Wiederholung); stripeFinance.js
|
||||
// haelt seine Optionen privat, daher hier eine eigene Konstante
|
||||
const LESE_OPTIONEN = { timeout: 15_000, maxNetworkRetries: 1 }
|
||||
const EINZELN_PARALLEL = 10
|
||||
// Format der Rechnungs-ID wie im Schema der Projektrechnungen (V1); die IDs des Stripe-Nachbaus (in_test_<n>) passen auch
|
||||
const STRIPE_RECHNUNG = /^in_\w{1,33}$/
|
||||
|
||||
/** Eine Rechnung frisch von Stripe in mapInvoice-Form; null, wenn es sie nicht (mehr) gibt (404); andere Fehler fliegen. */
|
||||
async function leseEinzeln(invoiceId) {
|
||||
try {
|
||||
const raw = await getStripe().invoices.retrieve(invoiceId, { expand: ['customer'] }, LESE_OPTIONEN)
|
||||
return mapInvoice(raw, { today: berlinDate() })
|
||||
} catch (err) {
|
||||
if (err?.statusCode === 404 || err?.code === 'resource_missing') return null
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rechnungsdaten fuer eine Liste von Projektrechnungen: die Rechnungen der letzten 400 Tage aus listInvoices() (60-Sekunden-
|
||||
* Zwischenspeicher); was dort fehlt (aelter, ueber 1000, frisch angelegt), wird einzeln gelesen, hoechstens 10 gleichzeitig.
|
||||
* Scheitert Stripe (Liste oder Einzellesen ausser 404), ist ok false und alles leer; ins Protokoll kommen nur Art und Status.
|
||||
*/
|
||||
export async function ladeStripeRechnungen(projektRechnungen) {
|
||||
try {
|
||||
const alle = await listInvoices()
|
||||
const nachId = new Map(alle.map((invoice) => [invoice.id, invoice]))
|
||||
const fehlend = [...new Set(projektRechnungen.map((eintrag) => eintrag.invoiceId))].filter((id) => STRIPE_RECHNUNG.test(id) && !nachId.has(id))
|
||||
for (let i = 0; i < fehlend.length; i += EINZELN_PARALLEL) {
|
||||
const gelesen = await Promise.all(fehlend.slice(i, i + EINZELN_PARALLEL).map(leseEinzeln))
|
||||
for (const invoice of gelesen) if (invoice) nachId.set(invoice.id, invoice)
|
||||
}
|
||||
return { ok: true, alle, nachId }
|
||||
} catch (err) {
|
||||
console.warn('[projektkonto] Stripe nicht lesbar:', err?.type || err?.name || 'Error', err?.statusCode ?? err?.status ?? '')
|
||||
return { ok: false, alle: [], nachId: new Map() }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user