From 7d77314805b6cccb54d3d4f6e997be4d3f95f193 Mon Sep 17 00:00:00 2001 From: Kevin Adametz Date: Thu, 16 Jul 2026 12:11:37 +0000 Subject: [PATCH] =?UTF-8?q?Warenwirtschaft:=20Bugfix=20=E2=80=94=20Logisti?= =?UTF-8?q?k-Mail=20h=C3=A4ngt=20den=20Lieferschein=20IMMER=20an?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kundenmeldung 16.07.2026: Fehlversand an die Rechnungsadresse, weil der Lieferschein (mit der Lieferadresse) in der Versand-Mail fehlte. Ursache: MailLogistic hängte ihn nur bei White-Label-Bestellungen an. Jetzt wird der Lieferschein unabhängig von Logo/White-Label immer mitgesendet; fehlt die PDF-Datei auf der Platte (Altdaten), wird sie mit bestehender Rechnungsnummer regeneriert. Dazu tote Duplikat-Klasse app/Mail/MailLogitic.php entfernt (Tippfehler-Dateiname, definierte dieselbe Klasse in einer Altversion ganz ohne Lieferschein-Anhang — Kollisionsrisiko im Classmap-Autoload). Co-Authored-By: Claude Fable 5 --- app/Mail/MailLogistic.php | 30 +++--- app/Mail/MailLogitic.php | 59 ----------- tests/Feature/LogisticMailTest.php | 163 +++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 74 deletions(-) delete mode 100644 app/Mail/MailLogitic.php create mode 100644 tests/Feature/LogisticMailTest.php diff --git a/app/Mail/MailLogistic.php b/app/Mail/MailLogistic.php index 1ce07d6..690ee25 100644 --- a/app/Mail/MailLogistic.php +++ b/app/Mail/MailLogistic.php @@ -3,6 +3,7 @@ namespace App\Mail; use App\Models\ShoppingOrder; +use App\Repositories\InvoiceRepository; use App\Services\Invoice; use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; @@ -65,21 +66,20 @@ class MailLogistic extends Mailable 'mime' => $mime, ]); - // Wenn mindestens ein White-Label-Produkt enthalten ist, wird der Lieferschein (Etikett-Infos) mit angehängt - $hasWhiteLabel = $this->shopping_order->user_white_label || $this->shopping_order->hasWhitelabelProducts(); - if ($hasWhiteLabel) { - $filenameDelivery = Invoice::getDeliveryFilename($this->shopping_order); - $pathDelivery = Invoice::getDownloadPathDelivery($this->shopping_order); - if (! Storage::disk('public')->exists($pathDelivery)) { - return; - } - $fileDelivery = Storage::disk('public')->path($pathDelivery); - $mimeDelivery = Storage::disk('public')->mimeType($pathDelivery); - - $mail->attach($fileDelivery, [ - 'as' => $filenameDelivery, - 'mime' => $mimeDelivery, - ]); // attach file; + // Kundenanforderung 16.07.2026: Der Lieferschein (mit der Lieferadresse der + // Bestellung) wird IMMER mitgesendet — unabhängig von White-Label/Logo. + // Vorher hing er nur bei White-Label-Bestellungen an; Folge waren + // Fehlversände an die Rechnungsadresse. + $pathDelivery = Invoice::getDownloadPathDelivery($this->shopping_order); + if (! Storage::disk('public')->exists($pathDelivery)) { + // Datei fehlt auf der Platte (Altdaten) — mit bestehender Nummer neu erzeugen + (new InvoiceRepository($this->shopping_order))->update([]); + } + if (Storage::disk('public')->exists($pathDelivery)) { + $mail->attach(Storage::disk('public')->path($pathDelivery), [ + 'as' => Invoice::getDeliveryFilename($this->shopping_order), + 'mime' => Storage::disk('public')->mimeType($pathDelivery), + ]); } return $mail; diff --git a/app/Mail/MailLogitic.php b/app/Mail/MailLogitic.php deleted file mode 100644 index 5105438..0000000 --- a/app/Mail/MailLogitic.php +++ /dev/null @@ -1,59 +0,0 @@ -shopping_order = $shopping_order; - if($shopping_order->user_white_label){ - //Bei allen, die ein eigenes Logo haben - $this->subject = 'Partner (mit Logo) - Firma (Vorname Nachname)'; - }else{ - //Bei allen, die kein Tattoostudio sind - $this->subject = 'Partner - Firma (Vorname Nachname)'; - } - - } - - public function build() - { - - - $title = false; - $copy1line = false; - - $filename = Invoice::getFilename($this->shopping_order); - $path = Invoice::getDownloadPath($this->shopping_order); - if (!Storage::disk('public')->exists($path)) { - return; - } - $file = Storage::disk('public')->path($path); - $mime = Storage::disk('public')->mimeType($path); - - - return $this->view('emails.blank')->with([ - 'title' => $title, - 'copy1line' => $copy1line, - ])->attach($file,[ - 'as' => $filename, - 'mime' => $mime, - ]); // attach file; - } -} \ No newline at end of file diff --git a/tests/Feature/LogisticMailTest.php b/tests/Feature/LogisticMailTest.php new file mode 100644 index 0000000..b83df24 --- /dev/null +++ b/tests/Feature/LogisticMailTest.php @@ -0,0 +1,163 @@ +forceCreate([ + 'code' => 'DE', + 'en' => 'Germany', + 'de' => 'Deutschland', + 'es' => 'Alemania', + 'fr' => 'Allemagne', + 'it' => 'Germania', + 'ru' => 'Germanija', + ]); + $shipping = Shipping::query()->forceCreate(['name' => 'Standard']); + $shippingCountry = ShippingCountry::query()->forceCreate([ + 'shipping_id' => $shipping->id, + 'country_id' => $country->id, + ]); + $shoppingUser = ShoppingUser::query()->forceCreate([ + 'billing_country_id' => $country->id, + 'shipping_country_id' => $country->id, + 'billing_firstname' => 'Lisa', + 'billing_lastname' => 'Logistik', + 'billing_address' => 'Rechnungsweg 1', + 'billing_zipcode' => '11111', + 'billing_city' => 'Rechnungsstadt', + 'same_as_billing' => false, + 'shipping_firstname' => 'Anders', + 'shipping_lastname' => 'Empfänger', + 'shipping_address' => 'Liefergasse 9', + 'shipping_zipcode' => '99999', + 'shipping_city' => 'Lieferdorf', + ]); + $authUser = User::query()->create([ + 'email' => uniqid('lm_', true).'@test.example', + 'password' => bcrypt('password'), + ]); + $account = UserAccount::query()->create([ + 'm_first_name' => 'Lena', + 'm_last_name' => 'Partner', + 'country_id' => $country->id, + ]); + $authUser->forceFill(['account_id' => $account->id])->save(); + + $order = ShoppingOrder::query()->forceCreate([ + 'shopping_user_id' => $shoppingUser->id, + 'auth_user_id' => $authUser->id, + 'country_id' => $shippingCountry->id, + 'shipped' => 0, + 'txaction' => 'paid', + 'total' => 20, + 'user_white_label' => false, + ]); + + $product = Product::query()->create([ + 'name' => 'LM Creme', + 'title' => 'LM Creme', + 'active' => true, + 'is_set' => false, + 'whitelabel' => false, + ]); + ShoppingOrderItem::query()->forceCreate([ + 'shopping_order_id' => $order->id, + 'product_id' => $product->id, + 'qty' => 1, + 'price' => 10, + ]); + + return $order->fresh(); +} + +function lmCreateDocuments(ShoppingOrder $order): void +{ + Setting::setContentBySlug('invoice-number', 4000, 'int'); + $cwd = getcwd(); + chdir(public_path()); + try { + (new InvoiceRepository($order))->create([]); + } finally { + chdir($cwd); + } +} + +test('logistik-mail haengt den lieferschein immer an - auch ohne white-label', function () { + Storage::fake('public'); + $order = lmMakeOrder(); + lmCreateDocuments($order); + $order->refresh(); + + expect($order->user_white_label)->toBeFalse() + ->and($order->hasWhitelabelProducts())->toBeFalse(); + + $mailable = new MailLogistic($order); + $mailable->build(); + + $names = collect($mailable->attachments)->pluck('options.as'); + expect($names)->toHaveCount(2) + ->and($names->first(fn ($n) => str_starts_with((string) $n, 'Rechnung-')))->not->toBeNull() + ->and($names->first(fn ($n) => str_starts_with((string) $n, 'Lieferschein-')))->not->toBeNull(); +}); + +test('fehlende lieferschein-datei wird fuer die mail regeneriert', function () { + Storage::fake('public'); + $order = lmMakeOrder(); + lmCreateDocuments($order); + $order->refresh(); + + $deliveryPath = Invoice::getDownloadPathDelivery($order); + Storage::disk('public')->delete($deliveryPath); + expect(Storage::disk('public')->exists($deliveryPath))->toBeFalse(); + + $cwd = getcwd(); + chdir(public_path()); + try { + $mailable = new MailLogistic($order); + $mailable->build(); + } finally { + chdir($cwd); + } + + expect(Storage::disk('public')->exists($deliveryPath))->toBeTrue(); + $names = collect($mailable->attachments)->pluck('options.as'); + expect($names->first(fn ($n) => str_starts_with((string) $n, 'Lieferschein-')))->not->toBeNull(); +}); + +test('versand-button verschickt die logistik-mail', function () { + Mail::fake(); + Storage::fake('public'); + $order = lmMakeOrder(); + lmCreateDocuments($order); + + $admin = User::query()->create([ + 'email' => uniqid('lmadmin_', true).'@test.example', + 'password' => bcrypt('password'), + ]); + $admin->forceFill(['admin' => 7, 'confirmed' => true, 'active' => true, 'wizard' => 100, 'blocked' => false])->save(); + + $this->actingAs($admin->fresh()) + ->get(route('admin_sales_send_logistic_mail', $order->id)) + ->assertRedirect(route('admin_sales_detail', $order->id)); + + Mail::assertSent(MailLogistic::class); +});