Warenwirtschaft: Bugfix — Logistik-Mail hängt den Lieferschein IMMER an
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 <noreply@anthropic.com>
This commit is contained in:
parent
748f259949
commit
7d77314805
3 changed files with 178 additions and 74 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Mail;
|
namespace App\Mail;
|
||||||
|
|
||||||
use App\Models\ShoppingOrder;
|
use App\Models\ShoppingOrder;
|
||||||
|
use App\Repositories\InvoiceRepository;
|
||||||
use App\Services\Invoice;
|
use App\Services\Invoice;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Mail\Mailable;
|
use Illuminate\Mail\Mailable;
|
||||||
|
|
@ -65,21 +66,20 @@ class MailLogistic extends Mailable
|
||||||
'mime' => $mime,
|
'mime' => $mime,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Wenn mindestens ein White-Label-Produkt enthalten ist, wird der Lieferschein (Etikett-Infos) mit angehängt
|
// Kundenanforderung 16.07.2026: Der Lieferschein (mit der Lieferadresse der
|
||||||
$hasWhiteLabel = $this->shopping_order->user_white_label || $this->shopping_order->hasWhitelabelProducts();
|
// Bestellung) wird IMMER mitgesendet — unabhängig von White-Label/Logo.
|
||||||
if ($hasWhiteLabel) {
|
// Vorher hing er nur bei White-Label-Bestellungen an; Folge waren
|
||||||
$filenameDelivery = Invoice::getDeliveryFilename($this->shopping_order);
|
// Fehlversände an die Rechnungsadresse.
|
||||||
$pathDelivery = Invoice::getDownloadPathDelivery($this->shopping_order);
|
$pathDelivery = Invoice::getDownloadPathDelivery($this->shopping_order);
|
||||||
if (! Storage::disk('public')->exists($pathDelivery)) {
|
if (! Storage::disk('public')->exists($pathDelivery)) {
|
||||||
return;
|
// Datei fehlt auf der Platte (Altdaten) — mit bestehender Nummer neu erzeugen
|
||||||
}
|
(new InvoiceRepository($this->shopping_order))->update([]);
|
||||||
$fileDelivery = Storage::disk('public')->path($pathDelivery);
|
}
|
||||||
$mimeDelivery = Storage::disk('public')->mimeType($pathDelivery);
|
if (Storage::disk('public')->exists($pathDelivery)) {
|
||||||
|
$mail->attach(Storage::disk('public')->path($pathDelivery), [
|
||||||
$mail->attach($fileDelivery, [
|
'as' => Invoice::getDeliveryFilename($this->shopping_order),
|
||||||
'as' => $filenameDelivery,
|
'mime' => Storage::disk('public')->mimeType($pathDelivery),
|
||||||
'mime' => $mimeDelivery,
|
]);
|
||||||
]); // attach file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $mail;
|
return $mail;
|
||||||
|
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace App\Mail;
|
|
||||||
|
|
||||||
use App\User;
|
|
||||||
use App\Services\Invoice;
|
|
||||||
use App\Models\ShoppingOrder;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Mail\Mailable;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
use Storage;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
|
|
||||||
class MailLogistic extends Mailable
|
|
||||||
{
|
|
||||||
use Queueable, SerializesModels;
|
|
||||||
|
|
||||||
protected $shopping_order;
|
|
||||||
|
|
||||||
public $subject;
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct(ShoppingOrder $shopping_order)
|
|
||||||
{
|
|
||||||
$this->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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
163
tests/Feature/LogisticMailTest.php
Normal file
163
tests/Feature/LogisticMailTest.php
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Mail\MailLogistic;
|
||||||
|
use App\Models\Country;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\Setting;
|
||||||
|
use App\Models\Shipping;
|
||||||
|
use App\Models\ShippingCountry;
|
||||||
|
use App\Models\ShoppingOrder;
|
||||||
|
use App\Models\ShoppingOrderItem;
|
||||||
|
use App\Models\ShoppingUser;
|
||||||
|
use App\Models\UserAccount;
|
||||||
|
use App\Repositories\InvoiceRepository;
|
||||||
|
use App\Services\Invoice;
|
||||||
|
use App\User;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
uses(TestCase::class, RefreshDatabase::class);
|
||||||
|
|
||||||
|
function lmMakeOrder(): ShoppingOrder
|
||||||
|
{
|
||||||
|
$country = Country::query()->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);
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue