openInvoiceRows = [[ 'id' => 'in_1', 'number' => 'R-1', 'amount_due_cents' => 21480, 'currency' => 'EUR', 'created_at' => '1750000000', ]]; $user = User::factory()->create(['email' => 'schuldner@portal.test', 'is_admin' => false]); Customer::factory()->create(['email' => 'schuldner@portal.test', 'stripe_customer_id' => 'cus_42']); return $user; } it('shows what is still owed', function () { $fake = new FakeStripeClient; app()->instance(StripeClient::class, $fake); Livewire::actingAs(portalUserOwing($fake)) ->test(OpenInvoices::class) ->assertSee('R-1') ->assertSee('214,80'); }); it('settles an invoice when the customer asks', function () { $fake = new FakeStripeClient; app()->instance(StripeClient::class, $fake); Livewire::actingAs(portalUserOwing($fake)) ->test(OpenInvoices::class) ->call('pay', 'in_1') ->assertHasNoErrors(); expect($fake->paidInvoices)->toBe(['in_1']); }); it('shows a refusal instead of pretending it worked', function () { // Der Fall, der wirklich eintritt. Eine grüne Meldung über einer // abgelehnten Karte ist die teuerste Anzeige, die diese Seite haben kann: // der Kunde geht davon aus, es sei erledigt, und die nächste Nachricht, // die er bekommt, ist eine Mahnung. $fake = new FakeStripeClient; $fake->payDeclines = true; app()->instance(StripeClient::class, $fake); Livewire::actingAs(portalUserOwing($fake)) ->test(OpenInvoices::class) ->call('pay', 'in_1') ->assertSee('declined'); expect($fake->paidInvoices)->toBe([]); }); it('refuses to pay an invoice that is not this customer\'s', function () { // Die ID kommt aus dem Browser. Ohne diese Prüfung könnte jemand eine // fremde Rechnungs-ID einreichen — und Stripe zöge sie beim fremden Kunden // ein, auf dessen Karte. $fake = new FakeStripeClient; app()->instance(StripeClient::class, $fake); Livewire::actingAs(portalUserOwing($fake)) ->test(OpenInvoices::class) ->call('pay', 'in_fremd') ->assertForbidden(); expect($fake->paidInvoices)->toBe([]); }); it('stops paying the rest after the first refusal', function () { // Alle weiteren scheitern an derselben Karte, und drei Ablehnungen // hintereinander lassen Stripes Betrugserkennung anschlagen — danach // lehnt sie auch die Karte ab, die in Ordnung wäre. $fake = new FakeStripeClient; $fake->payDeclines = true; app()->instance(StripeClient::class, $fake); $user = portalUserOwing($fake); $fake->openInvoiceRows[] = [ 'id' => 'in_2', 'number' => 'R-2', 'amount_due_cents' => 1000, 'currency' => 'EUR', 'created_at' => '1750000000', ]; Livewire::actingAs($user)->test(OpenInvoices::class)->call('payAll'); expect($fake->paidInvoices)->toBe([]); }); it('says so plainly when nothing is open', function () { $fake = new FakeStripeClient; app()->instance(StripeClient::class, $fake); $user = User::factory()->create(['email' => 'schuldenfrei@portal.test', 'is_admin' => false]); Customer::factory()->create(['email' => 'schuldenfrei@portal.test', 'stripe_customer_id' => 'cus_9']); Livewire::actingAs($user) ->test(OpenInvoices::class) ->assertSee(__('billing.invoices_none')); });