Gutschriften Phase 3b/1: Gutschrift-PDF (pdfkit)

PDF-Erzeugung fuer Gutschriften mit Firmenstammdaten als Absender,
Empfaenger (Kunde+Adresse), Netto/USt/Brutto (bzw. ohne USt-Ausweis),
Sachwert/'Ware erhalten' bzw. Ueberweisungs-Bankverbindung,
Unterschriftsblock, Firmen-Fusszeile.

Endpoint POST /credit-notes/:id/pdf; 'PDF'-Button in CreditNotesSection
(erzeugen + im Tab oeffnen bzw. vorhandenes ansehen). PDF-Pfad wird bei
inhaltlicher Aenderung geleert -> Neu-Erzeugung. Download ueber
fileDownload (credit-notes subDir, Vertrags-Ownership).

Lokal verifiziert (valides %PDF, korrekte Betraege).

ZUGFeRD-XML-Embedding (PDF/A-3, EN 16931) folgt als Teil 2 mit
Validator-Pruefung.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-06 13:32:34 +02:00
co-authored by Claude Opus 4.8
parent 2c705272ea
commit 642fb05c76
7 changed files with 225 additions and 6 deletions
@@ -4,6 +4,7 @@ import { logChange } from '../services/audit.service.js';
import { ApiError } from '../utils/apiError.js';
import * as creditNoteService from '../services/creditNote.service.js';
import * as numberRangeService from '../services/creditNoteNumberRange.service.js';
import { generateCreditNotePdf } from '../services/creditNotePdf.service.js';
// Gutschriften sind ein reiner Mitarbeiter-/Admin-Bereich (interne
// Subventions-Belege). Portal-Kunden dürfen sie weder sehen noch ändern
@@ -143,6 +144,23 @@ export async function remove(req: AuthRequest, res: Response): Promise<void> {
}
}
// PDF (Gutschrift-Dokument) erzeugen. ZUGFeRD-Embedding folgt (Teil 2).
export async function generatePdf(req: AuthRequest, res: Response): Promise<void> {
try {
if (blockPortal(req, res)) return;
const id = idParam(req, res, 'id');
if (id === null) return;
const { pdfPath } = await generateCreditNotePdf(id);
await logChange({
req, action: 'UPDATE', resourceType: 'CreditNote', resourceId: id.toString(),
label: 'Gutschrift-PDF erzeugt',
});
res.json({ success: true, data: { pdfPath } } as ApiResponse);
} catch (error) {
handleError(res, error, 'Fehler beim Erzeugen des PDF');
}
}
// ---- Nummernkreis (Einstellungen) ----
export async function getNumberRange(req: AuthRequest, res: Response): Promise<void> {