setLaravelSession(app('session.store')); URL::resolveMissingNamedRoutesUsing(fn ($name, $parameters = []) => '/'.$name.'/'.implode('/', (array) $parameters)); }); afterEach(fn () => Carbon::setTestNow()); function pcsUser(): User { return User::forceCreate([ 'email' => 'pcs-'.uniqid('', true).'@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'm_level' => 1, 'payment_account' => now()->addYear(), ]); } function pcsAbo(User $user, int $paidDeliveries = 6, string $nextDate = '2026-10-05', array $attributes = []): UserAbo { $abo = UserAbo::create(array_merge([ 'user_id' => $user->id, 'member_id' => $user->id, 'shopping_user_id' => 0, 'email' => 'pcs-abo-'.uniqid('', true).'@example.com', 'is_for' => 'me', 'payone_userid' => 0, 'clearingtype' => 'cc', 'amount' => 5000, 'active' => true, 'status' => 2, 'abo_interval' => 5, 'start_date' => '2026-01-05', 'last_date' => '2026-09-05', 'next_date' => $nextDate, ], $attributes)); for ($i = 0; $i < $paidDeliveries; $i++) { UserAboOrder::create([ 'user_abo_id' => $abo->id, 'shopping_order_id' => 0, 'status' => 2, 'paid' => true, ]); } return $abo->fresh(); } function pcsRender(UserAbo $abo, string $view = 'me'): string { return view('admin.abo._pause_cancel', ['user_abo' => $abo, 'view' => $view])->render(); } it('zeigt nach der Mindestlaufzeit Pause und Kuendigung mit Modal, Folgen-Hinweis und Bestaetigungs-Checkbox', function () { $abo = pcsAbo(pcsUser()); $html = pcsRender($abo); expect($html) ->toContain('id="abo-pause-cancel"') ->toContain(__('abo.pause_cancel_title')) ->toContain(__('abo.pause_cancel_progress', ['count' => 6, 'min' => 6])) ->toContain('id="abo-pause-form"') ->toContain('name="abo_pause" value="true"') ->toContain('id="modal-abo-cancel"') ->toContain('name="abo_cancel" value="true"') ->toContain(__('abo.cancel_consequence_restart', ['min' => 6])) ->toContain(__('abo.cancel_prefer_pause_button')) ->toContain(__('abo.cancel_anyway_button')) ->toContain('id="abo-cancel-confirm"') ->toContain('id="abo-cancel-submit" disabled') ->toContain('/user_abos_update/me/'.$abo->id) ->not->toContain(__('abo.info_min_duration_orders_left', ['count' => 0])); }); it('zeigt vor der Mindestlaufzeit nur den Fortschritt und den Hinweis auf die verbleibenden Lieferungen', function () { $abo = pcsAbo(pcsUser(), paidDeliveries: 4); $html = pcsRender($abo, 'portal'); expect($html) ->toContain(__('abo.pause_cancel_progress', ['count' => 4, 'min' => 6])) ->toContain(__('abo.info_min_duration_orders_left', ['count' => 2])) ->not->toContain('id="modal-abo-cancel"') ->not->toContain('name="abo_cancel"') ->not->toContain('name="abo_pause"'); }); it('zeigt innerhalb der Sperrfrist vor der Ausfuehrung den Hinweis statt der Buttons', function () { // Ausfuehrung in 2 Tagen, Sperre pausieren/kuendigen = 3 Tage Setting::setContentBySlug('abo-lock-days-pause-cancel', 3, 'int'); $abo = pcsAbo(pcsUser(), nextDate: '2026-09-18'); expect(AboHelper::isPauseCancelLocked($abo, 'me'))->toBeTrue() ->and(AboHelper::isPauseCancelLocked($abo, 'admin'))->toBeFalse(); $html = pcsRender($abo); expect($html) ->toContain(__('abo.pause_cancel_locked_hint', ['date' => '18.09.2026', 'lock' => 3, 'days' => 2])) ->not->toContain('id="modal-abo-cancel"') ->not->toContain('name="abo_pause"'); }); it('zeigt ohne Vorlaufsperre am Ausfuehrungstag den Vortag-Hinweis (A2)', function () { $abo = pcsAbo(pcsUser(), nextDate: '2026-09-16'); $html = pcsRender($abo); expect($html) ->toContain(__('abo.pause_cancel_locked_hint_zero', ['date' => '16.09.2026', 'lock' => 0, 'days' => 0])) ->not->toContain('id="modal-abo-cancel"'); expect(pcsRender(pcsAbo(pcsUser(), nextDate: '2026-09-17')))->toContain('id="modal-abo-cancel"'); }); it('bietet im Kuendigungs-Modal keine Pause an, wenn die Pause gerade nicht moeglich ist', function () { $abo = pcsAbo(pcsUser(), attributes: ['last_pause_date' => '2026-08-01']); $html = pcsRender($abo); expect($html) ->toContain('id="modal-abo-cancel"') ->toContain(__('abo.info_pause_available_from', ['date' => '01.02.2027', 'months' => 6])) ->not->toContain('id="abo-pause-form"') ->not->toContain(__('abo.cancel_prefer_pause_button')) ->not->toContain(__('abo.cancel_alternative_pause')); }); it('blendet den Abschnitt fuer beendete Abos aus', function () { $cancelled = pcsAbo(pcsUser(), attributes: ['status' => 4, 'active' => false]); $finished = pcsAbo(pcsUser(), attributes: ['status' => 5, 'active' => false]); expect(pcsRender($cancelled))->not->toContain('abo-pause-cancel') ->and(pcsRender($finished))->not->toContain('abo-pause-cancel'); }); it('verweist im Einstellungs-Modal nur noch auf den Abschnitt statt direkt zu kuendigen', function () { $abo = pcsAbo(pcsUser()); $html = view('admin.abo.modal_abo_update', [ 'user_abo' => $abo, 'data' => ['action' => 'abo_update_settings', 'id' => $abo->id, 'view' => 'portal'], 'route' => '/portal/abo/update', ])->render(); expect($html) ->toContain(__('abo.cancel_abo')) ->toContain(__('abo.cancel_in_section_hint')) ->toContain('abo-pause-cancel') ->toContain('name="abo_pause"') ->not->toContain('name="abo_cancel"'); }); it('kuendigt als eigenstaendige Aktion: Erfolgsmeldung, kein Liefertermin-Hinweis, next_date unveraendert', function () { $user = pcsUser(); $abo = pcsAbo($user); $this->actingAs($user); $repository = new AboRepository; $repository->setModel($abo); $result = $repository->update([ 'action' => 'abo_update_settings', 'id' => $abo->id, 'view' => 'me', 'abo_interval' => 5, 'abo_is_active' => 1, 'abo_cancel' => 'true', 'abo_cancel_confirm' => '1', ]); $abo = $abo->fresh(); expect($result)->toBeTrue() ->and((int) $abo->status)->toBe(4) ->and($abo->active)->toBeFalse() ->and(Carbon::parse($abo->getRawOriginal('next_date'))->format('Y-m-d'))->toBe('2026-10-05') ->and(session('alert-success'))->toBe(__('abo.cancel_success')) ->and(session('alert-warning'))->toBeNull() ->and(session('alert-error'))->toBeNull(); }); it('lehnt die Kuendigung vor der Mindestlaufzeit ab, ohne den Liefertag anzufassen', function () { $user = pcsUser(); $abo = pcsAbo($user, paidDeliveries: 2); $this->actingAs($user); $repository = new AboRepository; $repository->setModel($abo); $result = $repository->update([ 'action' => 'abo_update_settings', 'id' => $abo->id, 'view' => 'me', 'abo_interval' => 5, 'abo_cancel' => 'true', ]); $abo = $abo->fresh(); expect($result)->toBeFalse() ->and((int) $abo->status)->toBe(2) ->and($abo->active)->toBeTrue() ->and(session('alert-error'))->toBe(__('abo.info_min_duration_orders_left', ['count' => 4])) ->and(session('alert-success'))->toBeNull() ->and(session('alert-warning'))->toBeNull(); }); it('rendert den Abschnitt mit einer abweichenden Mindestlaufzeit aus dem Setting', function () { Setting::setContentBySlug('abo-min-duration', 3, 'int'); $abo = pcsAbo(pcsUser(), paidDeliveries: 3); $html = pcsRender($abo); expect($html) ->toContain(__('abo.pause_cancel_progress', ['count' => 3, 'min' => 3])) ->toContain(__('abo.cancel_consequence_restart', ['min' => 3])) ->toContain('id="modal-abo-cancel"'); });