'/'.$name); }); afterEach(function () { Carbon::setTestNow(); }); function calMakeAbo(int $memberId, string $startDate, string $nextDate, int $interval = 5): UserAbo { return UserAbo::create([ 'user_id' => $memberId, 'member_id' => $memberId, 'shopping_user_id' => 0, 'email' => 'cal-'.uniqid('', true).'@example.com', 'is_for' => 'ot', 'payone_userid' => 0, 'clearingtype' => 'cc', 'amount' => 5000, 'active' => true, 'status' => 2, 'abo_interval' => $interval, 'start_date' => $startDate, 'next_date' => $nextDate, ]); } it('rendert die Kundenabo-Liste mit allen gewuenschten Spalten', function (): void { // Kundenwunsch 2026-09-07: Name, Liefertag, Abo-Punkte, naechste Ausfuehrung, // Startdatum, Ausfuehrungen — sortierbar statt als Karten. $user = User::forceCreate([ 'email' => 'cal-owner@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'm_level' => 1, 'payment_account' => now()->addYear(), ]); $abo = calMakeAbo($user->id, '2026-04-20', '2026-09-20', 20); $html = view('user.abo._customer_abo_list', [ 'listAbos' => collect([$abo]), 'customerAboForecast' => ['base' => 0.0, 'days' => [ ['day' => 5, 'date' => '05.09.2026', 'billed' => 0.0, 'upcoming' => 0.0, 'total' => 0.0, 'is_past' => true], ['day' => 10, 'date' => '10.09.2026', 'billed' => 0.0, 'upcoming' => 36.0, 'total' => 36.0, 'is_past' => false], ['day' => 20, 'date' => '20.09.2026', 'billed' => 0.0, 'upcoming' => 81.0, 'total' => 81.0, 'is_past' => false], ['day' => 25, 'date' => '25.09.2026', 'billed' => 0.0, 'upcoming' => 81.0, 'total' => 81.0, 'is_past' => false], ]], ])->render(); expect($html) ->toContain(e(__('tables.abo_delivery_day'))) ->toContain(e(__('tables.next_date'))) ->toContain(e(__('tables.start_date'))) ->toContain(e(__('tables.abo_delivery'))) // Sortier-Partial ist eingebunden und haengt an der richtigen Tabelle ->toContain('customer-abo-table') ->toContain('data-sortable="true"') // Liefertag-Prognose aus den eigenen Kundenabos ->toContain('81') ->toContain(e(__('abo.customer_abo_forecast_title'))); }); it('rendert die Liste auch ohne Liefertag-Prognose', function (): void { // Fuer vergangene Monate uebergibt der Controller null — die Tabelle bleibt. $user = User::forceCreate([ 'email' => 'cal-owner2@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'm_level' => 1, 'payment_account' => now()->addYear(), ]); $html = view('user.abo._customer_abo_list', [ 'listAbos' => collect([calMakeAbo($user->id, '2026-04-20', '2026-09-20')]), 'customerAboForecast' => null, ])->render(); expect($html)->toContain('customer-abo-table') ->not->toContain(e(__('abo.customer_abo_forecast_title'))); }); it('kompiliert die Abo-Seite vollstaendig, ohne Blade-Direktiven zu verschlucken', function (string $view): void { // Regression 2026-09-07: Wird die Ausdrucksform @php(...) mit einem // @php ... @endphp-Block in derselben Datei gemischt, matcht Blades // storePhpBlocks vom ersten @php bis zum ersten @endphp und schluckt // alles dazwischen — dann fehlen Zuweisungen wie $cardAbos zur Laufzeit. $source = file_get_contents(resource_path('views/'.str_replace('.', '/', $view).'.blade.php')); $compiled = app('blade.compiler')->compileString($source); expect($compiled)->not->toMatch('/@(if|unless|foreach|forelse|php|endif|endforeach|endphp)\b/'); })->with([ 'user.abo.index', 'user.abo._customer_abo_list', 'dashboard._statistics', 'user.team.firstlines', 'user.team.points', 'user.team.abos', 'components._sortable_table', ]); it('gibt unformatierte Sortierwerte aus, unabhaengig von der Sprache (A14)', function (string $locale): void { // Der Zellentext ist lokalisiert (en: `Y-m-d` und `1,000.00`), der // Sortierschluessel nicht — sonst sortiert die Tabelle in en falsch. app()->setLocale($locale); $user = User::forceCreate([ 'email' => 'cal-sort-'.$locale.'@example.com', 'password' => bcrypt('secret'), 'lang' => $locale, 'm_level' => 1, 'payment_account' => now()->addYear(), ]); $html = view('user.abo._customer_abo_list', [ 'listAbos' => collect([calMakeAbo($user->id, '2026-04-05', '2026-09-20', 20)]), 'customerAboForecast' => null, ])->render(); expect($html) ->toContain('data-sort-value="2026-09-20"') // naechste Ausfuehrung ->toContain('data-sort-value="2026-04-05"') // Startdatum ->toContain('data-sort-value="20"'); // Liefertag })->with(['de', 'en']); it('zeigt die im Monat abgerechneten Punkte je Abo samt Summenzeile', function (): void { // Die Liste muss sich gegen die Vorschau darueber nachrechnen lassen: Summe // der Monatsspalte = Basis der letzten Kachel. $user = User::forceCreate([ 'email' => 'cal-billed@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'm_level' => 1, 'payment_account' => now()->addYear(), ]); $geliefert = calMakeAbo($user->id, '2026-04-05', '2026-10-05'); $offen = calMakeAbo($user->id, '2026-05-20', '2026-09-20', 20); $html = view('user.abo._customer_abo_list', [ 'listAbos' => collect([$geliefert, $offen]), 'customerAboForecast' => null, // 80 gebucht, aber nur 37 wiederkehrend → 43 einmalig. 'customerAboBilled' => collect([$geliefert->id => 80.0]), 'customerAboBilledTotal' => 80.0, ])->render(); expect($html) ->toContain(e(__('abo.customer_abo_points_billed'))) ->toContain('data-sort-value="80"') ->toContain(e(__('abo.customer_abo_points_extra'))) ->toContain(e(__('abo.customer_abo_list_sum'))) // Kein Rest → weder Rest- noch Monatszeile ->not->toContain(e(__('abo.customer_abo_list_sum_rest'))); }); it('weist einen nicht zuordenbaren Rest in der Summenzeile aus', function (): void { // Ein im Monat geliefertes, inzwischen geloeschtes Abo steht nicht mehr in der // Liste. Ohne die Restzeile ginge die Addition nicht auf. $user = User::forceCreate([ 'email' => 'cal-rest@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'm_level' => 1, 'payment_account' => now()->addYear(), ]); $abo = calMakeAbo($user->id, '2026-04-05', '2026-10-05'); $html = view('user.abo._customer_abo_list', [ 'listAbos' => collect([$abo]), 'customerAboForecast' => null, 'customerAboBilled' => collect([$abo->id => 50.0]), 'customerAboBilledTotal' => 78.0, ])->render(); expect($html) ->toContain(e(__('abo.customer_abo_list_sum_rest'))) ->toContain(e(__('abo.customer_abo_list_sum_month'))) ->toContain('28,00') // Rest ->toContain('78,00'); // Monat gesamt }); it('blendet die Monatsspalte aus, wenn auf einen anderen Monat gefiltert wird', function (): void { $user = User::forceCreate([ 'email' => 'cal-nobilled@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'm_level' => 1, 'payment_account' => now()->addYear(), ]); $html = view('user.abo._customer_abo_list', [ 'listAbos' => collect([calMakeAbo($user->id, '2026-04-05', '2026-10-05')]), 'customerAboForecast' => null, 'customerAboBilled' => null, 'customerAboBilledTotal' => null, ])->render(); expect($html) ->not->toContain(e(__('abo.customer_abo_points_billed'))) ->toContain(e(__('abo.customer_abo_list_sum'))); });