Abo Einmalprodukte: Review-Gate (VIP), Verbindlichkeit & Summen-Layout

- Live-Review-Gate: Einmalprodukte nur fuer VIP im Sales Center sichtbar,
  Portal ausgeblendet (AboHelper::isOneTimeFeatureVisible + Gates in Controllern)
- Nur verbindlich bestaetigte Einmal-Artikel fliessen in die Lieferung;
  Service-Helfer confirmedItems/pendingItems/pendingGross
- Footer-Layout der Einmalprodukt-Liste: bestaetigte Summe + Gesamtbetrag,
  Trennstrich, offener Betrag und neue Gesamtsumme (dunkelgruen)
- Uebersetzungen DE/EN/ES/FR (onetime_new_total u.a.), Tests angepasst/ergaenzt

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin 2026-06-08 14:59:22 +00:00
parent 5c11d48e6d
commit 8f616ff4de
16 changed files with 356 additions and 46 deletions

View file

@ -9,7 +9,7 @@ uses(Tests\TestCase::class, RefreshDatabase::class);
describe('Abo Einmal-Produkte Views', function () {
beforeEach(fn () => makeShopEnv());
it('rendert die Einmal-Produktliste mit Position und Zwischensumme', function () {
it('rendert die Einmal-Produktliste mit Position und offener Zwischensumme', function () {
$abo = makeMeAbo();
$product = makeProduct(['2'], 119, 19);
@ -21,7 +21,7 @@ describe('Abo Einmal-Produkte Views', function () {
'price_net' => 100.0,
'tax_rate' => 19.0,
'tax' => 19.0,
'status' => 1,
'status' => 0,
]);
$summary = ['one_time' => ['gross' => 238.0, 'net' => 200.0, 'tax' => 38.0]];
@ -32,10 +32,50 @@ describe('Abo Einmal-Produkte Views', function () {
])->render();
expect($html)->toContain($product->getLang('name'))
->and($html)->toContain(__('abo.onetime_subtotal'))
->and($html)->toContain(__('abo.onetime_pending_subtotal'))
->and($html)->toContain(__('abo.onetime_status_pending'))
->and($html)->toContain('238,00');
});
it('zeigt bestätigte und offene Artikel mit getrennten Zwischensummen', function () {
$abo = makeMeAbo();
$confirmed = makeProduct(['2'], 119, 19);
$pending = makeProduct(['2'], 50, 19);
UserAboOneTimeItem::create([
'user_abo_id' => $abo->id,
'product_id' => $confirmed->id,
'qty' => 1,
'confirmed_qty' => 1,
'confirmed_at' => now(),
'price' => 119.0,
'tax_rate' => 19.0,
'status' => 1,
]);
UserAboOneTimeItem::create([
'user_abo_id' => $abo->id,
'product_id' => $pending->id,
'qty' => 1,
'price' => 50.0,
'tax_rate' => 19.0,
'status' => 0,
]);
$html = view('admin.abo._order_onetime_show', [
'user_abo' => $abo->fresh(),
'summary' => ['one_time' => ['gross' => 119.0], 'total_with_shipping' => 219.0],
])->render();
expect($html)->toContain(__('abo.onetime_confirmed_subtotal'))
->and($html)->toContain(__('abo.onetime_pending_subtotal'))
->and($html)->toContain(__('abo.onetime_new_total'))
->and($html)->toContain(__('abo.onetime_status_confirmed'))
->and($html)->toContain(__('abo.onetime_status_pending'))
->and($html)->toContain(__('abo.onetime_pending_hint'))
->and($html)->toContain('50,00')
->and($html)->toContain('169,00');
});
it('zeigt bei unbestätigten Einmal-Artikeln die Bestätigungsbuttons', function () {
$abo = makeMeAbo();
$product = makeProduct(['2'], 119, 19);
@ -56,7 +96,7 @@ describe('Abo Einmal-Produkte Views', function () {
'summary' => ['one_time' => ['gross' => 119.0], 'total_with_shipping' => 219.0],
])->render();
expect($html)->toContain(__('abo.onetime_next_delivery_total'))
expect($html)->toContain(__('abo.onetime_pending_subtotal'))
->and($html)->toContain(__('abo.onetime_legal_notice', [
'nextBillingDate' => $abo->next_date,
'agb' => '<a href="'.url('/agb').'" target="_blank">'.__('abo.confirm_terms_link').'</a>',