T1neu: Unternehmer-Pflicht-Checkbox im Checkout, protokolliert mit AGB-Version

B2B-Gate (AGB v0.6 par. 1 Abs. 4): Das Buchungs-Modal verlangt vor jedem
Stripe-Checkout die Bestaetigung 'Ich bestelle in Ausuebung meiner
gewerblichen oder selbstaendigen beruflichen Taetigkeit (par. 14 BGB)'.

- booking_confirmations: user, Buchungstyp/-ref, AGB-Version, IP,
  confirmed_at (Nachweis laut Datenschutz Abschnitt 7)
- Checkout-Link erscheint erst nach der Checkbox; CheckoutController
  verlangt zusaetzlich serverseitig eine zeitnahe Bestaetigung (30 Min.)
  fuer Abo/Einzel-PM/Credit-Topup — Direktaufrufe laufen ins Leere
- config/legal.php als zentrale AGB-Versionsquelle (Seite + Protokoll,
  Uebergangsloesung bis zum legal_documents-System E3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-03 16:17:59 +00:00
parent 99ab47ba1f
commit 8916bcce7c
9 changed files with 311 additions and 7 deletions

View file

@ -2,6 +2,7 @@
use App\Enums\UserPaymentOptionStatus;
use App\Models\BillingAddress;
use App\Models\BookingConfirmation;
use App\Models\Plan;
use App\Models\SinglePurchase;
use App\Models\User;
@ -49,8 +50,11 @@ test('the bookings page renders the active plans with checkout links', function
->assertSee('max. 2 Veröffentlichungen pro Tag')
->assertSee('2 Monate gratis')
->assertDontSee('Versteckt')
// Buchung läuft über das Bestätigungs-Modal (selectBooking → Checkout-URL).
// Buchung läuft über das Bestätigungs-Modal; der Checkout-Link
// erscheint erst nach der Unternehmer-Bestätigung (T1neu).
->call('selectBooking', 'subscription', 'business', 'monthly')
->assertDontSee(route('me.checkout.subscription', ['planSlug' => 'business', 'interval' => 'monthly']), false)
->set('entrepreneurConfirmed', true)
->assertSee(route('me.checkout.subscription', ['planSlug' => 'business', 'interval' => 'monthly']), false);
});
@ -86,6 +90,7 @@ test('the single pm block links to its checkout', function () {
->call('selectBooking', 'single_pm')
->assertSee('Buchung bestätigen')
->assertSee('zzgl. 19 % USt.')
->set('entrepreneurConfirmed', true)
->assertSee(route('me.checkout.single-pm'), false);
});
@ -207,8 +212,9 @@ test('the wallet block shows the balance and the credit pack topup links', funct
->assertSee('Preisliste')
->assertSee('Was kostet wie viel')
->assertDontSee('Prüfkontingent') // Phase 2 — vorerst ausgeblendet
// Paket-Kauf läuft über das Bestätigungs-Modal.
// Paket-Kauf läuft über das Bestätigungs-Modal (inkl. T1neu-Checkbox).
->call('selectBooking', 'credit_pack', 'p25')
->set('entrepreneurConfirmed', true)
->assertSee(route('me.checkout.credit-topup', ['pack' => 'p25']), false);
});
@ -252,6 +258,8 @@ test('with a billing address the banner is gone and the booking modal offers the
->assertDontSee('Rechnungsadresse fehlt')
->call('selectBooking', 'single_pm')
->assertSee('Kostenpflichtig buchen')
->assertSee('gewerblichen oder selbständigen beruflichen Tätigkeit')
->set('entrepreneurConfirmed', true)
->assertSee(route('me.checkout.single-pm'), false);
});
@ -283,3 +291,40 @@ test('buying an extra pm without enough credits shows the mini checkout hint', f
expect($user->singlePurchases()->count())->toBe(0);
});
test('checking the entrepreneur box records a booking confirmation with the agb version', function () {
/** @var TestCase $this */
// T1neu (AGB v0.6 § 1 Abs. 4): Die Pflicht-Checkbox protokolliert
// Zeitpunkt + AGB-Version — das B2B-Gate stützt sich auf diesen Nachweis.
$user = bookingsTestCustomer();
BillingAddress::factory()->create(['user_id' => $user->id]);
config()->set('billing.single_pm_stripe_price_id', 'price_test_single_pm');
$this->actingAs($user);
LivewireVolt::test('customer.bookings')
->call('selectBooking', 'single_pm')
->set('entrepreneurConfirmed', true);
$confirmation = BookingConfirmation::query()->sole();
expect($confirmation->user_id)->toBe($user->id);
expect($confirmation->booking_type)->toBe('single_pm');
expect($confirmation->agb_version)->toBe((string) config('legal.agb_version'));
expect($confirmation->confirmed_at)->not->toBeNull();
});
test('selecting a new booking resets the entrepreneur confirmation checkbox', function () {
/** @var TestCase $this */
$user = bookingsTestCustomer();
BillingAddress::factory()->create(['user_id' => $user->id]);
config()->set('billing.single_pm_stripe_price_id', 'price_test_single_pm');
$this->actingAs($user);
LivewireVolt::test('customer.bookings')
->call('selectBooking', 'single_pm')
->set('entrepreneurConfirmed', true)
->call('selectBooking', 'single_pm')
->assertSet('entrepreneurConfirmed', false);
});