107 lines
3.6 KiB
PHP
107 lines
3.6 KiB
PHP
<?php
|
|
|
|
use App\Livewire\OpenInvoices;
|
|
use App\Models\Customer;
|
|
use App\Models\User;
|
|
use App\Services\Stripe\FakeStripeClient;
|
|
use App\Services\Stripe\StripeClient;
|
|
use Livewire\Livewire;
|
|
|
|
function portalUserOwing(FakeStripeClient $fake): User
|
|
{
|
|
$fake->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'));
|
|
});
|