Billing System

R1’s invoicing module — the largest single domain cluster in the schema: 26 billing_* tables, 3 enums, a unified read view, 60 frontend components, 6 query modules, and 4 scheduled BullMQ jobs. It covers invoice creation through dunning, bank-statement matching, write-off, and the sevDesk Integration accounting handoff. This page is a catalog with pointers, not a deep dive.

Foundation: PR#1397, consolidated via the V3 rebase PR#1674 and refinements PR#1751. Backend services: backend/src/services/billing/; workers: backend/src/lib/billing/.

Table Catalog (backend/src/db/schema.ts)

ClusterTables
Core documentsbilling_invoices, billing_invoice_line_items, billing_invoice_pdf_versions, billing_credit_notes, billing_change_orders (Nachträge), billing_service_catalog
Audit & snapshotsbilling_invoice_event_log, billing_invoice_role_snapshots, billing_config_change_log, billing_failed_jobs (retry queue)
Payments & bankingbilling_payments, billing_payment_reconciliations, billing_bank_statement_imports, billing_bank_statement_entries, billing_building_accounts (per-building aggregates)
Dunning & termsbilling_dunning_schedule_rules, billing_dunning_stop_requests (Mahnstopp), billing_customer_payment_terms
Configurationbilling_entities (§14 UStG legal-entity data), billing_document_templates, billing_email_templates, billing_number_sequences, billing_clarifications
Accounting exportbilling_accounting_exports, billing_contact_accounts (DATEV Debitorenkonten), billing_accounting_field_mappings

Enums: billing_document_status (draft → pending_approval → approved → sent / rejected / cancelled), billing_claim_status (open, overdue, paid, partially_paid, clarification states, disputed, in_collection, written_off, unable_to_pay, insolvency states), billing_deal_type (EB / KOP).

Unified Read Model (dealType EB/KOP)

billing_invoices.deal_type distinguishes EB (EnergieBeratung) from KOP (contractor package) business. The read-only SQL view in backend/src/db/views/billing-items-view.ts merges invoices and credit notes into one BillingItemRow interface (itemType, documentNumber, both statuses, dealType, amounts, dunning level) consumed by all Billing-tab queries via BillingItemsService. Wire types in shared/billing-types.ts. The dashboard revenue tab built on it: PR#1860.

GoBD Snapshot (RNW-391)

billing_invoices.entity_snapshot (JSONB) freezes the issuing legal entity’s data when an invoice transitions to sent; a DB trigger then blocks UPDATE so the issued invoice stays reproducible byte-for-byte for the audit retention window. Written by billing-invoice-service-impl.ts; landed in PR#1631.

Email Templates via Migration (RNW-394)

Seven bilingual templates (invoice_sent, payment_reminder, dunning_1/2/3, payment_confirmation, credit_note) are config data seeded by atlas migration (20260523064608_billing_pr_consolidated.sql), not mocks — they ship to every environment. Subject/body are LocalizedText with placeholders; editable in the billing settings email tab.

Money Rule (MANDATORY)

All billing arithmetic goes through shared/money.ts (Big.js): fromString/fromCents at the boundary, add/sub/mul/div, round(m, 2) HALF_UP. Money is decimal strings on the wire, never JS numbers. Spec: docs/superpowers/specs/2026-04-24-money-arithmetic-bigjs-design.md; type PR#1628, guardrails PR#1669.

CAMT Import, Dunning, Write-Off

  • Bank import: camt-import-service-impl.ts + the dependency-free regex parser lib/billing/accounting/camt053-parser.ts (ISO 20022 CAMT.053; MT940 also a stored format). Entries land in billing_bank_statement_entries with match status unmatched → fuzzy → exact → manual; matched payments reference the import via billing_payments.bankStatementImportId.
  • Dunning: levels 0–3 (Erinnerung, 1.–3. Mahnung) configured in billing_dunning_schedule_rules; per-invoice state in the dunning JSONB; Mahnstopp via billing_dunning_stop_requests; escalation by billing-dunning-worker.ts.
  • Write-off: claim statuses written_off (§252 HGB), unable_to_pay, insolvent_no_claim, insolvent_claimed; UI BillingWriteOffDialog.tsx, backend via the billing operations service (RNW-426).

sevDesk Handoff

Publish/send/cancel/PDF and the 10-minute payment-status sync run through sevdesk-service-impl.ts and the invoice bridge; state columns externalId, externalInvoiceNumber, accountingSyncStatus on billing_invoices. DATEV export batches in billing_accounting_exports. Full detail: sevDesk Integration.

Scheduled Jobs (BullMQ)

JobScheduleWorker
billing-retryevery 5 minlib/billing/billing-retry-worker.ts — drains billing_failed_jobs
billing-overduehourlylib/billing/billing-overdue-worker.ts — flags past-due invoices
billing-dunningdaily 04:00lib/billing/billing-dunning-worker.ts — escalates dunning levels
sevdesk-payment-syncevery 10 minservices/sevdesk/invoice-bridge.ts

Processors in backend/src/lib/jobs/processors/billing-scheduled.ts, registered in schedulers.ts.

Frontend

frontend/src/components/billing/ — 60 production components (93 .tsx incl. tests/stories) across 7 subfolders (detail-panel, table-view, settings, standalone, customer-tab, filters, analytics). Main tabs: BillingDashboardTab, BillingInvoicesTab, BillingCustomersTab, BillingSettingsTab (dunning/email/numbering/payment/tax/templates/API mapping), BillingExportImportTab, BillingFieldMappingTab. Query modules (6): billingQueries, billingItemsQueries, billingMailQueries, billingDocumentTemplates, billingStandaloneInvoiceQueries, billingServiceCatalogQueries.

See Also