Verkauf: Stornorechnung — fehlende createCancellation() im InvoiceRepository ergänzt, eigene Storno-Mail
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>
This commit is contained in:
parent
be29be863f
commit
9c362f14d9
4 changed files with 254 additions and 95 deletions
|
|
@ -25,6 +25,14 @@ class InvoiceRepository extends BaseRepository
|
|||
|
||||
private $delivery_filename;
|
||||
|
||||
private $cancellation_date;
|
||||
|
||||
private $cancellation_number;
|
||||
|
||||
private $cancellation_filename;
|
||||
|
||||
private $cancellation_dir;
|
||||
|
||||
public function __construct(ShoppingOrder $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
|
|
@ -116,6 +124,84 @@ class InvoiceRepository extends BaseRepository
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stornorechnung zu einer bereits erstellten Rechnung erzeugen (Fix 08.09.2026:
|
||||
* die Methode wurde vom SalesController aufgerufen, existierte aber nie —
|
||||
* jeder Storno-Versuch lief in einen 500er).
|
||||
*
|
||||
* Die Stornonummer wird aus demselben Zähler wie die Rechnungsnummer gezogen
|
||||
* (das Modal zeigt "nächste Rechnungsnummer" an) und der Zähler danach erhöht.
|
||||
*
|
||||
* @return bool true = Stornorechnung erstellt
|
||||
*/
|
||||
public function createCancellation($request = [])
|
||||
{
|
||||
// ohne Ursprungsrechnung gibt es nichts zu stornieren
|
||||
if (! Invoice::isInvoice($this->model)) {
|
||||
return false;
|
||||
}
|
||||
// Doppel-Storno verhindern (der Controller prüft das ebenfalls)
|
||||
if (Invoice::isCancellationInvoice($this->model)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$number = Invoice::getInvoiceNumber();
|
||||
$this->cancellation_date = isset($request['cancellation_date']) ? $request['cancellation_date'] : now()->format('d.m.Y');
|
||||
$cancellation_send_mail = isset($request['cancellation_send_mail']) ? true : false;
|
||||
$this->cancellation_number = Invoice::createInvoiceNumber($number, $this->cancellation_date);
|
||||
$this->cancellation_dir = Invoice::getCancellationStorageDir($this->cancellation_date);
|
||||
$this->cancellation_filename = Invoice::makeCancellationFilename($this->cancellation_number);
|
||||
|
||||
$this->makeCancellationPDF();
|
||||
|
||||
$this->model->cancellation_invoice = [
|
||||
'filename' => $this->cancellation_filename,
|
||||
'dir' => $this->cancellation_dir,
|
||||
'disk' => 'public',
|
||||
'cancellation_number' => $this->cancellation_number,
|
||||
'cancellation_date' => $this->cancellation_date,
|
||||
'invoice_number' => Invoice::getNumber($this->model),
|
||||
'invoice_date' => Invoice::getDate($this->model),
|
||||
];
|
||||
$this->model->save();
|
||||
Invoice::makeNextInvoiceNumber();
|
||||
|
||||
if ($cancellation_send_mail) {
|
||||
Invoice::sendCancellationMail($this->model);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function makeCancellationPDF()
|
||||
{
|
||||
$data = [
|
||||
'shopping_order' => $this->model,
|
||||
'cancellation_date' => $this->cancellation_date,
|
||||
'cancellation_number' => $this->cancellation_number,
|
||||
'original_invoice_number' => Invoice::getNumber($this->model),
|
||||
'original_invoice_date' => Invoice::getDate($this->model),
|
||||
];
|
||||
|
||||
if ($this->model->auth_user_id) {
|
||||
UserService::checkUserTaxShippingCountry($this->model->auth_user, $this->model->country_id);
|
||||
$data = array_merge($data, UserService::getYardInfo());
|
||||
}
|
||||
|
||||
if (! Storage::disk('public')->exists($this->cancellation_dir)) {
|
||||
Storage::disk('public')->makeDirectory($this->cancellation_dir);
|
||||
}
|
||||
$path = Storage::disk('public')->path('');
|
||||
|
||||
$pdf_file = new InvoicePDF('pdf.cancellation_invoice');
|
||||
$pdf_file->create($data, $this->cancellation_filename, 'save', $path.$this->cancellation_dir);
|
||||
$pdfMerger = new MyPDFMerger;
|
||||
$pdfMerger->addPDF($path.$this->cancellation_dir.$this->cancellation_filename);
|
||||
// eigenes Storno-Briefpapier gibt es nicht, daher das Rechnungs-Template
|
||||
$file = $pdfMerger->myMerge('string', $this->cancellation_filename, 'template_invoice_de');
|
||||
Storage::disk('public')->put($this->cancellation_dir.$this->cancellation_filename, $file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Altdaten-Reparatur an EINER Stelle (Review 20.07.2026): Rechnung und/oder
|
||||
* Lieferschein fehlen auf der Platte, obwohl die DB-Metadaten existieren
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue