Der SalesController rief InvoiceRepository::createCancellation() auf, die Methode existierte aber nicht — jeder Storno-Versuch endete im 500er. Die Stornorechnung wird jetzt aus demselben Nummernkreis wie die Rechnung erzeugt (pdf.cancellation_invoice, Rechnungs-Briefpapier), als cancellation_invoice am Auftrag gespeichert und der Zähler erhöht.
Optional geht eine Storno-Mail mit angehängter Stornorechnung (MailCancellation, Texte email.cancellation_title/_copy1line) statt der Rechnungs-Mail an den Kunden.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
document('combined') lief bei fehlender Alt-PDF ungeprüft in eine
PDFMerger-Exception (500); der Sammel-Druck prüfte nur den Lieferschein,
eine fehlende Rechnungs-PDF ließ den ganzen Batch platzen. Neue zentrale
InvoiceRepository::ensureFilesOnDisk() ersetzt den dreifach kopierten
Altdaten-Check (MailLogistic 2x, batchDocuments); Merge-/Response-Code im
OrderFulfillmentController zu mergedPdf()/pdfResponse() dedupliziert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>