Abo Einmalprodukte: Phasen 5-7, konfigurierbare Sperrfristen, Lokalisierung & Dashboard
Rechnung/Lieferschein: - PDF-Gruppierung Abo- vs. Einmal-Artikel (is_abo_addon), rueckwaertskompatibel - Vorschau-Command sales:preview-invoice (umgeht Test-System-Gate, ohne Rechnungsnummer) Reminder-Mail (vorbereitet, Cron inaktiv): - MailAboExecutionReminder + Template, abo:send-execution-reminder, Spalte onetime_reminder_sent_for - Berater -> Sales Center, Kunde -> Portal; Vorschau abo:preview-reminder - Datum-Fix: formatDateDB() statt formatDate() (ICU-Format) Sperrfristen konfigurierbar (Admin-Settings): - abo-lock-days-change (Liefertag + Abo-Produkte), abo-lock-days-pause-cancel - Meldungen mit :lock-Platzhalter; Pausieren/Kuendigen vom Change-Lock entkoppelt - Abo-Produkt-Aenderungen im Lock-Fenster server- + clientseitig eingefroren - Selbstbedienung: Add-only/Lock nach $view (kein Admin-Bypass), Stale-Cache-Fix beim Mengen-Update Dashboard: - Einmalprodukte-Card + Team-Abo-KPI-Card, News-Card responsiv (col-xl-6) Lokalisierung: - Sprachdateien en/es/fr vollstaendig mit de synchronisiert (inkl. marketingplan/portal) - LocalizationSyncTest sichert Key-Gleichheit ab Tests: AboOneTimeInvoiceGrouping, AboExecutionReminder, AboLockDaysSetting, AboOnetimeDashboardAndMail, PreviewInvoiceCommand, TeamAboOverview + erweiterte View-Tests Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
9f996a7f1b
commit
65b867f8ee
96 changed files with 4154 additions and 1189 deletions
110
tests/Feature/AboOneTimeInvoiceGroupingTest.php
Normal file
110
tests/Feature/AboOneTimeInvoiceGroupingTest.php
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
use App\Models\ShoppingOrder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(Tests\TestCase::class, RefreshDatabase::class);
|
||||
|
||||
/**
|
||||
* Phase 5 – Rechnung & Lieferschein: Positionen werden nach `is_abo_addon`
|
||||
* gruppiert (Abo-Produkte oben, abgegrenzter Block „Einmalig hinzugefügte
|
||||
* Artikel" darunter). Bestellungen ohne Einmal-Artikel bleiben unverändert.
|
||||
*/
|
||||
beforeEach(fn () => makeShopEnv());
|
||||
|
||||
function makeMixedOrder(bool $withAddon = true): ShoppingOrder
|
||||
{
|
||||
$order = ShoppingOrder::create([
|
||||
'shopping_user_id' => 1,
|
||||
'auth_user_id' => 1,
|
||||
'country_id' => 1,
|
||||
'user_shop_id' => 0,
|
||||
'payment_for' => 6,
|
||||
'shipping' => 0,
|
||||
'shipping_net' => 0,
|
||||
'subtotal_ws' => 100,
|
||||
'tax' => 0,
|
||||
'total_shipping' => 100,
|
||||
'is_abo' => true,
|
||||
]);
|
||||
|
||||
$aboProduct = makeProduct(['12'], 50, 0);
|
||||
$order->shopping_order_items()->create([
|
||||
'product_id' => $aboProduct->id,
|
||||
'is_abo_addon' => false,
|
||||
'qty' => 1,
|
||||
'price' => 50,
|
||||
'price_net' => 50,
|
||||
'tax_rate' => 0,
|
||||
'tax' => 0,
|
||||
'price_vk_net' => 50,
|
||||
'discount' => 0,
|
||||
'points' => 0,
|
||||
]);
|
||||
|
||||
if ($withAddon) {
|
||||
$addonProduct = makeProduct(['2'], 30, 0);
|
||||
$order->shopping_order_items()->create([
|
||||
'product_id' => $addonProduct->id,
|
||||
'is_abo_addon' => true,
|
||||
'qty' => 1,
|
||||
'price' => 30,
|
||||
'price_net' => 30,
|
||||
'tax_rate' => 0,
|
||||
'tax' => 0,
|
||||
'price_vk_net' => 30,
|
||||
'discount' => 0,
|
||||
'points' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
return $order->fresh('shopping_order_items.product');
|
||||
}
|
||||
|
||||
describe('Rechnung-PDF Gruppierung', function () {
|
||||
it('zeigt bei gemischter Bestellung beide Block-Überschriften, Abo vor Einmal', function () {
|
||||
$order = makeMixedOrder();
|
||||
|
||||
$html = view('pdf.invoice-detail', ['shopping_order' => $order])->render();
|
||||
|
||||
expect($html)->toContain(__('pdf.abo_items_heading'))
|
||||
->and($html)->toContain(__('pdf.abo_addon_items_heading'));
|
||||
|
||||
$aboPos = strpos($html, __('pdf.abo_items_heading'));
|
||||
$addonPos = strpos($html, __('pdf.abo_addon_items_heading'));
|
||||
expect($aboPos)->toBeLessThan($addonPos);
|
||||
});
|
||||
|
||||
it('zeigt KEINE Block-Überschriften bei reiner Bestellung ohne Einmal-Artikel', function () {
|
||||
$order = makeMixedOrder(withAddon: false);
|
||||
|
||||
$html = view('pdf.invoice-detail', ['shopping_order' => $order])->render();
|
||||
|
||||
expect($html)->not->toContain(__('pdf.abo_addon_items_heading'))
|
||||
->and($html)->not->toContain(__('pdf.abo_items_heading'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Lieferschein-PDF Gruppierung', function () {
|
||||
it('zeigt bei gemischter Bestellung beide Block-Überschriften, Abo vor Einmal', function () {
|
||||
$order = makeMixedOrder();
|
||||
|
||||
$html = view('pdf.delivery-detail', ['shopping_order' => $order])->render();
|
||||
|
||||
expect($html)->toContain(__('pdf.abo_items_heading'))
|
||||
->and($html)->toContain(__('pdf.abo_addon_items_heading'));
|
||||
|
||||
$aboPos = strpos($html, __('pdf.abo_items_heading'));
|
||||
$addonPos = strpos($html, __('pdf.abo_addon_items_heading'));
|
||||
expect($aboPos)->toBeLessThan($addonPos);
|
||||
});
|
||||
|
||||
it('zeigt KEINE Block-Überschriften bei reiner Bestellung ohne Einmal-Artikel', function () {
|
||||
$order = makeMixedOrder(withAddon: false);
|
||||
|
||||
$html = view('pdf.delivery-detail', ['shopping_order' => $order])->render();
|
||||
|
||||
expect($html)->not->toContain(__('pdf.abo_addon_items_heading'))
|
||||
->and($html)->not->toContain(__('pdf.abo_items_heading'));
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue