ZUGFeRD-Rechnungsmodul (Factur-X, EN 16931) #16
Labels
No labels
component/backend
component/docs
component/e2e
component/frontend
component/infra
component/keycloak
prio/high
prio/low
prio/medium
type/bug
type/chore
type/feature
type/refactor
type/test
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
WompSchmiede/FamilienFeierPlaner#16
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Generierung strukturierter XML-Rechnungen nach EN 16931 mit lückenlosen Rechnungsnummern per DB-Sequenz. Siehe docs/design/02-datenmodell.md (Rechnungsgenerierung).
Gesamtplan ZUGFeRD-Rechnungsmodul
Abhaengigkeit: Voraussetzung
Vor diesem Issue muss ein Refaktor laufen:
contributionEuro(Decimal) →contributionCents(Int)Decimal @default(0.00) @db.Decimal(10, 2)→Int @default(0)* 100, Spalten-UmbenennungcalculateContribution()gibt Cents zurueck, allecontributionEuro→contributionCents(cents / 100).toLocaleString(...)statt Direktformatierungnumber/floataufinteger(Der Refaktor wird als separater Commit vor Phase 2 durchgefuehrt.)
Phase 1: Backend — Datenmodell
1.1 Prisma:
Invoice-Model anpassenAenderungen gegenuber heute:
eventIdnullable +onDelete: SetNull— Force-Delete des Events blockiert nichtgroupIdneu (optional) — HaushaltsrechnungengrossAmountvonDecimalaufInt(Cents) — konsistent zuFormFieldOption.pricexmlPayloadwird perencrypt()/decrypt()auscrypto.tsverschluesselt1.2 Neues Model:
InvoiceJob1.3 DB-Sequenz fuer Rechnungsnummern
Format:
RE-{YYYY}-{5-stellig}Phase 2: Backend — Invoice-Endpunkte
POST /api/v1/events/{eventId}/invoice-runrequireOrganizerOrEventAdmin202 { jobId }POST /api/v1/events/{eventId}/guests/{personId}/invoicerequireOrganizerOrEventAdminPOST /api/v1/events/{eventId}/groups/{groupId}/invoicerequireOrganizerOrEventAdminGET /api/v1/jobs/{jobId}requireOrganizerOrEventAdminGET /api/v1/events/{eventId}/invoicesrequireOrganizerOrEventAdminGET /api/v1/invoicesrequireAuthpersonId=$meoder Mitglied ingroupIdGET /api/v1/invoices/{invoiceId}/downloadrequireAuth+ Self/GroupMember/Organizer2.1 Invoice-Run als async-Job
Flow analog zum bestehenden Muster in
deletion-requests.ts(setImmediate+202 Accepted):POST /api/v1/events/{eventId}/invoice-runInvoiceJob(status:pending)202 { jobId }setImmediate()startetprocessInvoiceJob(jobId)processInvoiceJob(jobId)im Hintergrund:runningtotalGuests= Anzahl der zu verarbeitenden Gaeste setzeneventGuestsmitstatus=confirmed,paymentStatus=open,contributionCents>0groupId:contributionCentsaller Mitglieder → eine Rechnung;personId= invoiceRecipient (siehe separates Issue) odergroup.createdBypersonIdnextvalholen, ZUGFeRD-XML generieren,encrypt(), INSERTInvoice,processed++completedfailed,errorMessagesetzenFrontend pollt
GET /api/v1/jobs/{jobId}, zeigt nachcompleteddie Ergebnisse2.2 ZUGFeRD/PDF-Generierung
backend/src/lib/invoice-generator.tsevents.createdBy→persons+contactData)personIdaus Invoice →persons+contactData0.00(privat, keine MwSt-Pflicht)encrypt(xmlPayload)→ DBPDF-Generierung via
pdf-lib:factur-x.xmlals Embedded File (ZUGFeRD-Konformitaet)Content-Type: application/pdfPhase 3: Frontend
3.1 Payment-Tab (
/app/events/[eventId])3.2 Self-Service (
/app/events/[eventId], Gast-Ansicht)GET /api/v1/invoices?eventId=XPhase 4: Autorisierung
POST invoice-runPOST /guests/{id}/invoicePOST /groups/{id}/invoiceGET /jobs/{id}GET /events/{id}/invoicesGET /invoices(Self)GET /invoices/{id}/downloadPhase 5: OpenAPI & Tests
Invoice-Schema umgroupIdergaenzenInvoiceJob,InvoiceRunResponse,CreateInvoice,InvoiceDownloadopenapi.yamldeklarieren__tests__/)Phase 6: Schwaache Abhaengigkeit (E-Mail)
Sobald ein Backend-E-Mail-Versand existiert (separater Issue, noch nicht angelegt), sollen Rechnungen automatisch als PDF-Anhang an den Rechnungsempfaenger gesendet werden. Bis dahin: Download-only.
Rechnungsempfaenger im Haushalt
Wurde in #253 umgesetzt. Rechnungsempfaenger kann abgefragt werden.
Dateien (neu / geaendert)
backend/prisma/schema.prismabackend/prisma/migrations/...backend/src/lib/invoice-generator.tsbackend/src/routes/invoices.tsbackend/src/__tests__/invoices.test.tsbackend/openapi.yamlbackend/package.jsonpdf-libfrontend/src/lib/api/generated.tsfrontend/src/routes/app/events/[eventId]/+page.sveltefrontend/src/routes/app/events/[eventId]/+page.server.tsdocs/design/02-datenmodell.mdNachtrag: Separater Issue #216 fuer Rechnungsempfaenger im Haushalt wurde angelegt.
niboer referenced this issue2026-07-09 23:47:29 +02:00