20-02-2026
This commit is contained in:
parent
a8b395e20d
commit
a00c42e770
252 changed files with 28785 additions and 8907 deletions
|
|
@ -2,31 +2,34 @@
|
|||
|
||||
namespace App\Repositories;
|
||||
|
||||
use PDF;
|
||||
use Storage;
|
||||
use App\Services\Invoice;
|
||||
use App\Models\UserInvoice;
|
||||
use App\Libraries\InvoicePDF;
|
||||
use App\Models\ShoppingOrder;
|
||||
use App\Libraries\MyPDFMerger;
|
||||
use App\Services\UserService;
|
||||
use App\Models\ShoppingOrder;
|
||||
use App\Models\UserInvoice;
|
||||
use App\Models\UserSalesVolume;
|
||||
use App\Services\BusinessPlan\SalesPointsVolume;
|
||||
use App\Services\Invoice;
|
||||
use App\Services\UserService;
|
||||
use Storage;
|
||||
|
||||
class InvoiceRepository extends BaseRepository {
|
||||
|
||||
class InvoiceRepository extends BaseRepository
|
||||
{
|
||||
/** @var \App\Models\ShoppingOrder */
|
||||
protected $model;
|
||||
|
||||
private $invoice_date;
|
||||
|
||||
private $invoice_number;
|
||||
|
||||
private $filename;
|
||||
|
||||
private $dir;
|
||||
|
||||
private $user_sales_volume;
|
||||
|
||||
private $delivery_dir;
|
||||
private $delivery_filename;
|
||||
|
||||
private $delivery_filename;
|
||||
|
||||
public function __construct(ShoppingOrder $model)
|
||||
{
|
||||
|
|
@ -35,54 +38,60 @@ class InvoiceRepository extends BaseRepository {
|
|||
|
||||
public function create($request = [])
|
||||
{
|
||||
//need invoice $data
|
||||
$number = Invoice::getInvoiceNumber();
|
||||
if($payt = $this->model->getLastShoppingPaymentTransaction()){
|
||||
$invoice_date = $payt->created_at->format("d.m.Y");
|
||||
}
|
||||
$this->invoice_date = isset($request['invoice_date']) ? $request['invoice_date'] : $invoice_date;
|
||||
$invoice_send_mail = isset($request['invoice_send_mail']) ? false : true;
|
||||
$this->invoice_number = Invoice::createInvoiceNumber($number, $this->invoice_date);
|
||||
$this->dir = Invoice::getInvoiceStorageDir($this->invoice_date);
|
||||
$this->filename = Invoice::makeInvoiceFilename($this->invoice_number);
|
||||
$this->delivery_dir = Invoice::getDeliveryStorageDir($this->invoice_date);
|
||||
$this->delivery_filename = Invoice::makeDeliveryFilename($this->invoice_number);
|
||||
// Wrap entire invoice creation in transaction to ensure atomicity
|
||||
return \DB::transaction(function () use ($request) {
|
||||
// Get and increment invoice number atomically (includes its own lock)
|
||||
$number = Invoice::makeNextInvoiceNumber();
|
||||
|
||||
$this->makePDF();
|
||||
|
||||
$user_invoice = UserInvoice::create([
|
||||
'shopping_order_id' => $this->model->id,
|
||||
'year' => \Carbon::parse($this->invoice_date)->format('Y'),
|
||||
'month' => \Carbon::parse($this->invoice_date)->format('m'),
|
||||
'date' => $this->invoice_date,
|
||||
'full_number' => $this->invoice_number,
|
||||
'number' => $number,
|
||||
'filename' => $this->filename,
|
||||
'dir' => $this->dir,
|
||||
'delivery_filename' => $this->delivery_filename,
|
||||
'delivery_dir' => $this->delivery_dir,
|
||||
'disk' => 'public',
|
||||
'status' => $this->model->getStatusByOrder()
|
||||
]);
|
||||
Invoice::makeNextInvoiceNumber();
|
||||
if($invoice_send_mail){
|
||||
Invoice::sendInvoiceMail($this->model, $user_invoice);
|
||||
}
|
||||
return $user_invoice;
|
||||
}
|
||||
|
||||
public function update($request = []){
|
||||
if($user_invoice = $this->model->user_invoice){
|
||||
$number = $user_invoice->number;
|
||||
$this->invoice_date = isset($request['invoice_date']) ? $request['invoice_date'] : $user_invoice->date;
|
||||
$invoice_send_mail = isset($request['invoice_send_mail']) ? false: true;
|
||||
if ($payt = $this->model->getLastShoppingPaymentTransaction()) {
|
||||
$invoice_date = $payt->created_at->format('d.m.Y');
|
||||
}
|
||||
$this->invoice_date = isset($request['invoice_date']) ? $request['invoice_date'] : $invoice_date;
|
||||
$invoice_send_mail = isset($request['invoice_send_mail']) && $request['invoice_send_mail'] ? true : false;
|
||||
$this->invoice_number = Invoice::createInvoiceNumber($number, $this->invoice_date);
|
||||
$this->dir = Invoice::getInvoiceStorageDir($this->invoice_date);
|
||||
$this->filename = Invoice::makeInvoiceFilename($this->invoice_number);
|
||||
$this->delivery_dir = Invoice::getDeliveryStorageDir($this->invoice_date);
|
||||
$this->delivery_filename = Invoice::makeDeliveryFilename($this->invoice_number);
|
||||
|
||||
$this->user_sales_volume = UserSalesVolume::where('user_invoice_id', $this->model->user_invoice->id)->first();
|
||||
$this->makePDF();
|
||||
|
||||
$user_invoice = UserInvoice::create([
|
||||
'shopping_order_id' => $this->model->id,
|
||||
'year' => \Carbon::parse($this->invoice_date)->format('Y'),
|
||||
'month' => \Carbon::parse($this->invoice_date)->format('m'),
|
||||
'date' => $this->invoice_date,
|
||||
'full_number' => $this->invoice_number,
|
||||
'number' => $number,
|
||||
'filename' => $this->filename,
|
||||
'dir' => $this->dir,
|
||||
'delivery_filename' => $this->delivery_filename,
|
||||
'delivery_dir' => $this->delivery_dir,
|
||||
'disk' => 'public',
|
||||
'status' => $this->model->getStatusByOrder(),
|
||||
]);
|
||||
|
||||
if ($invoice_send_mail) {
|
||||
Invoice::sendInvoiceMail($this->model, $user_invoice);
|
||||
}
|
||||
|
||||
return $user_invoice;
|
||||
});
|
||||
}
|
||||
|
||||
public function update($request = [])
|
||||
{
|
||||
if ($user_invoice = $this->model->user_invoice) {
|
||||
$number = $user_invoice->number;
|
||||
$this->invoice_date = isset($request['invoice_date']) ? $request['invoice_date'] : $user_invoice->date;
|
||||
$invoice_send_mail = isset($request['invoice_send_mail']) ? false : true;
|
||||
$this->invoice_number = Invoice::createInvoiceNumber($number, $this->invoice_date);
|
||||
$this->dir = Invoice::getInvoiceStorageDir($this->invoice_date);
|
||||
$this->filename = Invoice::makeInvoiceFilename($this->invoice_number);
|
||||
$this->delivery_dir = Invoice::getDeliveryStorageDir($this->invoice_date);
|
||||
$this->delivery_filename = Invoice::makeDeliveryFilename($this->invoice_number);
|
||||
|
||||
$this->user_sales_volume = UserSalesVolume::where('user_invoice_id', $this->model->user_invoice->id)->first();
|
||||
$this->makePDF();
|
||||
|
||||
$user_invoice->fill([
|
||||
|
|
@ -99,16 +108,23 @@ class InvoiceRepository extends BaseRepository {
|
|||
'disk' => 'public',
|
||||
])->save();
|
||||
|
||||
if($invoice_send_mail){
|
||||
if ($invoice_send_mail) {
|
||||
Invoice::sendInvoiceMail($this->model, $user_invoice);
|
||||
}
|
||||
return $user_invoice;
|
||||
}
|
||||
|
||||
return $user_invoice;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function makePDF(){
|
||||
|
||||
/**
|
||||
* Erstellt die PDFs für Rechnung und Lieferschein.
|
||||
* Das deutsche Original wird immer erstellt (Finanzamt-Anforderung).
|
||||
* Bei anderer Kundensprache wird zusätzlich eine Kopie in der Kundensprache erstellt.
|
||||
*/
|
||||
private function makePDF()
|
||||
{
|
||||
$data = [
|
||||
'shopping_order' => $this->model,
|
||||
'invoice_date' => $this->invoice_date,
|
||||
|
|
@ -116,43 +132,89 @@ class InvoiceRepository extends BaseRepository {
|
|||
'user_sales_volume' => $this->user_sales_volume,
|
||||
];
|
||||
|
||||
if($this->model->auth_user_id){
|
||||
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->dir )){
|
||||
Storage::disk('public')->makeDirectory($this->dir); //creates directory
|
||||
}
|
||||
if(!Storage::disk('public')->exists( $this->delivery_dir )){
|
||||
Storage::disk('public')->makeDirectory($this->delivery_dir); //creates directory
|
||||
}
|
||||
|
||||
if (! Storage::disk('public')->exists($this->dir)) {
|
||||
Storage::disk('public')->makeDirectory($this->dir);
|
||||
}
|
||||
if (! Storage::disk('public')->exists($this->delivery_dir)) {
|
||||
Storage::disk('public')->makeDirectory($this->delivery_dir);
|
||||
}
|
||||
|
||||
// Kundensprache ermitteln
|
||||
$customerLocale = $this->model->shopping_user ? $this->model->shopping_user->getLocale() : 'de';
|
||||
$originalLocale = \App::getLocale();
|
||||
|
||||
// 1. IMMER deutsches Original erstellen (Finanzamt-Anforderung)
|
||||
\App::setLocale('de');
|
||||
$this->createPDFFiles($data, 'de');
|
||||
|
||||
// 2. Wenn Kundensprache != DE, Kopie in Kundensprache erstellen
|
||||
if ($customerLocale && $customerLocale !== 'de') {
|
||||
\App::setLocale($customerLocale);
|
||||
$this->createPDFFiles($data, $customerLocale);
|
||||
}
|
||||
|
||||
// Locale zurücksetzen
|
||||
\App::setLocale($originalLocale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt die PDF-Dateien für eine bestimmte Sprache.
|
||||
*/
|
||||
private function createPDFFiles(array $data, string $locale)
|
||||
{
|
||||
$path = Storage::disk('public')->path('');
|
||||
|
||||
//invoice
|
||||
// Dateinamen für diese Sprache
|
||||
$invoiceFilename = Invoice::makeInvoiceFilenameLocale($this->invoice_number, $locale);
|
||||
$deliveryFilename = Invoice::makeDeliveryFilenameLocale($this->invoice_number, $locale);
|
||||
|
||||
// Kopie-Flag: true wenn nicht Deutsch (das Original)
|
||||
$data['is_copy'] = ($locale !== 'de');
|
||||
|
||||
// Template basierend auf Locale
|
||||
$template = $this->getTemplateForLocale($locale);
|
||||
|
||||
// Rechnung erstellen
|
||||
$pdf_file = new InvoicePDF('pdf.invoice');
|
||||
$pdf_file->create($data, $this->filename, 'save', $path.$this->dir);
|
||||
$pdfMerger = new MyPDFMerger();
|
||||
$pdfMerger->addPDF($path.$this->dir.$this->filename);
|
||||
$file = $pdfMerger->myMerge('string', $this->filename, 'template_invoice_de');
|
||||
Storage::disk('public')->put($this->dir.$this->filename, $file);
|
||||
if(!$this->model->shopping_collect_order){
|
||||
$pdf_file->create($data, $invoiceFilename, 'save', $path.$this->dir);
|
||||
$pdfMerger = new MyPDFMerger;
|
||||
$pdfMerger->addPDF($path.$this->dir.$invoiceFilename);
|
||||
$file = $pdfMerger->myMerge('string', $invoiceFilename, $template);
|
||||
Storage::disk('public')->put($this->dir.$invoiceFilename, $file);
|
||||
|
||||
// Lieferschein erstellen (außer bei Sammelbestellung)
|
||||
if (! $this->model->shopping_collect_order) {
|
||||
$pdf_file = new InvoicePDF('pdf.delivery');
|
||||
$pdf_file->create($data, $this->delivery_filename, 'save', $path.$this->delivery_dir);
|
||||
$pdfMerger = new MyPDFMerger();
|
||||
$pdfMerger->addPDF($path.$this->delivery_dir.$this->delivery_filename);
|
||||
$file = $pdfMerger->myMerge('string', $this->delivery_filename, 'template_invoice_de');
|
||||
Storage::disk('public')->put($this->delivery_dir.$this->delivery_filename, $file);
|
||||
$pdf_file->create($data, $deliveryFilename, 'save', $path.$this->delivery_dir);
|
||||
$pdfMerger = new MyPDFMerger;
|
||||
$pdfMerger->addPDF($path.$this->delivery_dir.$deliveryFilename);
|
||||
$file = $pdfMerger->myMerge('string', $deliveryFilename, $template);
|
||||
Storage::disk('public')->put($this->delivery_dir.$deliveryFilename, $file);
|
||||
}
|
||||
}
|
||||
|
||||
public function userSalesVolume()
|
||||
/**
|
||||
* Gibt das PDF-Template für die angegebene Locale zurück.
|
||||
* Verfügbare Templates werden aus config/localization.php geladen.
|
||||
*/
|
||||
private function getTemplateForLocale(string $locale): string
|
||||
{
|
||||
$availableTemplates = config('localization.availableTemplates', ['de']);
|
||||
|
||||
|
||||
if (in_array($locale, $availableTemplates)) {
|
||||
return 'template_invoice_'.$locale;
|
||||
}
|
||||
|
||||
return 'template_invoice_de';
|
||||
}
|
||||
|
||||
public function userSalesVolume() {}
|
||||
|
||||
public function createAndSalesVolume($request = [])
|
||||
{
|
||||
$this->user_sales_volume = SalesPointsVolume::addSalesPointsVolumeUser($this->model);
|
||||
|
|
@ -160,4 +222,225 @@ class InvoiceRepository extends BaseRepository {
|
|||
$this->user_sales_volume->user_invoice_id = $user_invoice->id;
|
||||
$this->user_sales_volume->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine Stornorechnung mit Punktekorrektur
|
||||
*
|
||||
* @param array $request
|
||||
* @return UserInvoice
|
||||
*/
|
||||
public function createCancellation($request = [])
|
||||
{
|
||||
return \DB::transaction(function () use ($request) {
|
||||
$original_invoice = $this->model->user_invoice;
|
||||
|
||||
if (! $original_invoice) {
|
||||
throw new \Exception('Keine Originalrechnung gefunden.');
|
||||
}
|
||||
|
||||
// Nächste Rechnungsnummer für Storno holen
|
||||
$number = Invoice::makeNextInvoiceNumber();
|
||||
|
||||
// Stornodatum
|
||||
$cancellation_date = isset($request['cancellation_date'])
|
||||
? $request['cancellation_date']
|
||||
: now()->format('d.m.Y');
|
||||
|
||||
$cancellation_send_mail = isset($request['cancellation_send_mail']) && $request['cancellation_send_mail'] ? true : false;
|
||||
|
||||
// Rechnungsnummer erstellen
|
||||
$cancellation_number = Invoice::createInvoiceNumber($number, $cancellation_date);
|
||||
$cancellation_dir = Invoice::getInvoiceStorageDir($cancellation_date);
|
||||
$cancellation_filename = Invoice::makeCancellationFilename($cancellation_number);
|
||||
$cancellation_delivery_dir = Invoice::getDeliveryStorageDir($cancellation_date);
|
||||
$cancellation_delivery_filename = Invoice::makeCancellationDeliveryFilename($cancellation_number);
|
||||
|
||||
// Stornorechnung PDF erstellen
|
||||
$this->makeCancellationPDF(
|
||||
$cancellation_date,
|
||||
$cancellation_number,
|
||||
$cancellation_dir,
|
||||
$cancellation_filename,
|
||||
$cancellation_delivery_dir,
|
||||
$cancellation_delivery_filename,
|
||||
$original_invoice
|
||||
);
|
||||
|
||||
// Stornorechnung in DB speichern
|
||||
$cancellation_invoice = UserInvoice::create([
|
||||
'shopping_order_id' => $this->model->id,
|
||||
'year' => \Carbon::parse($cancellation_date)->format('Y'),
|
||||
'month' => \Carbon::parse($cancellation_date)->format('m'),
|
||||
'date' => $cancellation_date,
|
||||
'full_number' => $cancellation_number,
|
||||
'number' => $number,
|
||||
'filename' => $cancellation_filename,
|
||||
'dir' => $cancellation_dir,
|
||||
'delivery_filename' => $cancellation_delivery_filename,
|
||||
'delivery_dir' => $cancellation_delivery_dir,
|
||||
'disk' => 'public',
|
||||
'cancellation' => true,
|
||||
'status' => $original_invoice->status === 1 ? 11 : 12, // 11 = storniert B., 12 = storniert Shop
|
||||
]);
|
||||
|
||||
// Original-Rechnung als storniert markieren
|
||||
$original_invoice->cancellation = true;
|
||||
$original_invoice->cancellation_id = $cancellation_invoice->id;
|
||||
$original_invoice->cancellation_date = $cancellation_date;
|
||||
$original_invoice->save();
|
||||
|
||||
// Bestellstatus auf "storniert" setzen
|
||||
$this->model->txaction = 'cancelled';
|
||||
// Versandstatus auf "storniert" (10) setzen, wenn noch nicht versendet
|
||||
if (in_array($this->model->shipped, [0, 1])) {
|
||||
$this->model->shipped = 10;
|
||||
}
|
||||
$this->model->save();
|
||||
|
||||
\Log::info('Bestellstatus aktualisiert nach Storno', [
|
||||
'order_id' => $this->model->id,
|
||||
'txaction' => $this->model->txaction,
|
||||
'shipped' => $this->model->shipped,
|
||||
]);
|
||||
|
||||
// Punktekorrektur durchführen (nach Erstellung der Stornorechnung)
|
||||
$this->correctPointsForCancellation($original_invoice, $cancellation_invoice);
|
||||
|
||||
// Optional: E-Mail versenden
|
||||
if ($cancellation_send_mail) {
|
||||
Invoice::sendInvoiceMail($this->model, $cancellation_invoice);
|
||||
}
|
||||
|
||||
return $cancellation_invoice;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt die Storno-PDFs (Rechnung und Lieferschein)
|
||||
*/
|
||||
private function makeCancellationPDF(
|
||||
$cancellation_date,
|
||||
$cancellation_number,
|
||||
$cancellation_dir,
|
||||
$cancellation_filename,
|
||||
$cancellation_delivery_dir,
|
||||
$cancellation_delivery_filename,
|
||||
$original_invoice
|
||||
) {
|
||||
$data = [
|
||||
'shopping_order' => $this->model,
|
||||
'invoice_date' => $cancellation_date,
|
||||
'invoice_number' => $cancellation_number,
|
||||
'original_invoice' => $original_invoice,
|
||||
'is_cancellation' => true,
|
||||
];
|
||||
|
||||
if ($this->model->auth_user_id) {
|
||||
UserService::checkUserTaxShippingCountry($this->model->auth_user, $this->model->country_id);
|
||||
$data = array_merge($data, UserService::getYardInfo());
|
||||
}
|
||||
|
||||
// Verzeichnisse erstellen
|
||||
if (! Storage::disk('public')->exists($cancellation_dir)) {
|
||||
Storage::disk('public')->makeDirectory($cancellation_dir);
|
||||
}
|
||||
if (! Storage::disk('public')->exists($cancellation_delivery_dir)) {
|
||||
Storage::disk('public')->makeDirectory($cancellation_delivery_dir);
|
||||
}
|
||||
|
||||
// Kundensprache ermitteln
|
||||
$customerLocale = $this->model->shopping_user ? $this->model->shopping_user->getLocale() : 'de';
|
||||
$originalLocale = \App::getLocale();
|
||||
|
||||
// Deutsches Original (Finanzamt-Anforderung)
|
||||
\App::setLocale('de');
|
||||
$this->createCancellationPDFFiles(
|
||||
$data,
|
||||
'de',
|
||||
$cancellation_number,
|
||||
$cancellation_dir,
|
||||
$cancellation_filename,
|
||||
$cancellation_delivery_dir,
|
||||
$cancellation_delivery_filename
|
||||
);
|
||||
|
||||
// Lokalisierte Version wenn gewünscht
|
||||
if ($customerLocale && $customerLocale !== 'de') {
|
||||
\App::setLocale($customerLocale);
|
||||
$data['is_copy'] = true;
|
||||
$localizedFilename = str_replace('.pdf', '-'.$customerLocale.'.pdf', $cancellation_filename);
|
||||
$localizedDeliveryFilename = str_replace('.pdf', '-'.$customerLocale.'.pdf', $cancellation_delivery_filename);
|
||||
|
||||
$this->createCancellationPDFFiles(
|
||||
$data,
|
||||
$customerLocale,
|
||||
$cancellation_number,
|
||||
$cancellation_dir,
|
||||
$localizedFilename,
|
||||
$cancellation_delivery_dir,
|
||||
$localizedDeliveryFilename
|
||||
);
|
||||
}
|
||||
|
||||
\App::setLocale($originalLocale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt die PDF-Dateien für eine Stornorechnung in einer bestimmten Sprache
|
||||
*/
|
||||
private function createCancellationPDFFiles(
|
||||
array $data,
|
||||
string $locale,
|
||||
string $cancellation_number,
|
||||
string $cancellation_dir,
|
||||
string $cancellation_filename,
|
||||
string $cancellation_delivery_dir,
|
||||
string $cancellation_delivery_filename
|
||||
) {
|
||||
$path = Storage::disk('public')->path('');
|
||||
$template = $this->getTemplateForLocale($locale);
|
||||
|
||||
// Stornorechnung erstellen
|
||||
$pdf_file = new InvoicePDF('pdf.cancellation');
|
||||
$pdf_file->create($data, $cancellation_filename, 'save', $path.$cancellation_dir);
|
||||
$pdfMerger = new MyPDFMerger;
|
||||
$pdfMerger->addPDF($path.$cancellation_dir.$cancellation_filename);
|
||||
$file = $pdfMerger->myMerge('string', $cancellation_filename, $template);
|
||||
Storage::disk('public')->put($cancellation_dir.$cancellation_filename, $file);
|
||||
|
||||
// Storno-Lieferschein erstellen (außer bei Sammelbestellung)
|
||||
if (! $this->model->shopping_collect_order) {
|
||||
$pdf_file = new InvoicePDF('pdf.cancellation_delivery');
|
||||
$pdf_file->create($data, $cancellation_delivery_filename, 'save', $path.$cancellation_delivery_dir);
|
||||
$pdfMerger = new MyPDFMerger;
|
||||
$pdfMerger->addPDF($path.$cancellation_delivery_dir.$cancellation_delivery_filename);
|
||||
$file = $pdfMerger->myMerge('string', $cancellation_delivery_filename, $template);
|
||||
Storage::disk('public')->put($cancellation_delivery_dir.$cancellation_delivery_filename, $file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Korrigiert die Punkte nach Stornierung einer Rechnung
|
||||
* Nutzt den SalesPointsVolume Service für konsistente Berechnung
|
||||
*
|
||||
* @param UserInvoice $original_invoice Die ursprüngliche Rechnung
|
||||
* @param UserInvoice $cancellation_invoice Die Stornorechnung
|
||||
*/
|
||||
private function correctPointsForCancellation($original_invoice, $cancellation_invoice)
|
||||
{
|
||||
// Original UserSalesVolume finden
|
||||
$original_sales_volume = UserSalesVolume::where('user_invoice_id', $original_invoice->id)->first();
|
||||
|
||||
if (! $original_sales_volume) {
|
||||
\Log::warning('Keine UserSalesVolume gefunden für Rechnung', [
|
||||
'invoice_id' => $original_invoice->id,
|
||||
'order_id' => $this->model->id,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Service-Methode verwenden für konsistente Punktekorrektur
|
||||
SalesPointsVolume::cancelSalesPointsVolume($original_sales_volume, $cancellation_invoice->id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue