Besseres Handling Rückerstattungen

This commit is contained in:
2026-09-06 20:11:50 +02:00
parent e730d6db63
commit b9795f08f0
26 changed files with 927 additions and 104 deletions
+127
View File
@@ -232,12 +232,26 @@ class ParticipantRefundTest extends TestCase
string $owner = 'Mika Muster',
string $iban = 'DE02120300000000202051',
bool $declarationAccepted = true,
bool $accountDeclarationAccepted = true,
) {
return new AcceptRefundCommand(new AcceptRefundRequest(
refund: $refund,
accountOwner: $owner,
accountIban: $iban,
declarationAccepted: $declarationAccepted,
accountDeclarationAccepted: $accountDeclarationAccepted,
))->execute();
}
/** Der zweite Weg: Der Teili verzichtet auf die Auszahlung und spendet -- ohne Bankverbindung. */
private function acceptAsDonation(?ParticipantRefund $refund, bool $declarationAccepted = true)
{
return new AcceptRefundCommand(new AcceptRefundRequest(
refund: $refund,
accountOwner: '',
accountIban: '',
declarationAccepted: $declarationAccepted,
donation: true,
))->execute();
}
@@ -459,6 +473,105 @@ class ParticipantRefundTest extends TestCase
$this->assertSame(ParticipantRefund::STATUS_PENDING, $refund->fresh()->status);
}
public function test_accept_is_rejected_without_the_account_declaration(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
// Erstattet wird nur auf das Konto, von dem der Beitrag kam. Fehlt die Bestätigung, ließe sich
// über eine Erstattung Geld auf ein fremdes Konto umleiten.
$response = $this->accept($refund, accountDeclarationAccepted: false);
$this->assertFalse($response->success);
$this->assertArrayHasKey('accountDeclaration', $response->errorTypes);
$this->assertSame(ParticipantRefund::STATUS_PENDING, $refund->fresh()->status);
$this->assertNull($refund->fresh()->account_iban);
}
public function test_the_account_declaration_cannot_be_skipped_over_http(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
$this->postJson('/api/v1/participant-refund/' . $refund->token . '/accept', [
'accountOwner' => 'Mika Muster',
'accountIban' => 'DE02 1203 0000 0000 2020 51',
'declarationAccepted' => true,
])
->assertOk()
->assertJsonPath('status', 'error')
->assertJsonStructure(['error_types' => ['accountDeclaration']]);
$this->assertSame(ParticipantRefund::STATUS_PENDING, $refund->fresh()->status);
}
/*
|--------------------------------------------------------------------------
| Spenden statt auszahlen
|--------------------------------------------------------------------------
*/
public function test_a_donation_is_accepted_without_bank_details(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
$response = $this->acceptAsDonation($refund);
$this->assertTrue($response->success);
$this->assertSame(ParticipantRefund::STATUS_ACCEPTED, $refund->fresh()->status);
$this->assertTrue($refund->fresh()->isDonation());
}
public function test_a_donation_still_needs_the_declaration(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
// Der Verzicht ist die Erklärung, die anschließend auf dem Beleg steht -- ohne sie nichts.
$response = $this->acceptAsDonation($refund, declarationAccepted: false);
$this->assertFalse($response->success);
$this->assertArrayHasKey('declaration', $response->errorTypes);
$this->assertSame(ParticipantRefund::STATUS_PENDING, $refund->fresh()->status);
}
public function test_a_donation_ignores_bank_details_sent_along(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
// Wer im Formular erst ein Konto eintippt und dann doch spendet, soll es nicht hinterlassen.
$response = new AcceptRefundCommand(new AcceptRefundRequest(
refund: $refund,
accountOwner: 'Mika Muster',
accountIban: 'DE02120300000000202051',
declarationAccepted: true,
donation: true,
))->execute();
$this->assertTrue($response->success);
$this->assertNull($refund->fresh()->account_owner);
$this->assertNull($refund->fresh()->account_iban);
}
public function test_a_donation_over_http_needs_no_iban(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
$this->postJson('/api/v1/participant-refund/' . $refund->token . '/accept', [
'donation' => true,
'declarationAccepted' => true,
])->assertOk()->assertJsonPath('status', 'success');
$this->assertTrue($refund->fresh()->isDonation());
}
public function test_the_page_shows_a_finished_donation_as_donated(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
$this->acceptAsDonation($refund);
$this->get('/rueckerstattung/' . $refund->token)
->assertOk()
->assertInertia(fn ($page) => $page->where('state', 'accepted')->where('donation', true));
}
public function test_the_public_page_serves_the_declaration_text_name(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
@@ -473,6 +586,19 @@ class ParticipantRefundTest extends TestCase
->assertSee('Ich versichere', false);
}
public function test_the_public_page_serves_the_new_declaration_texts(): void
{
// Beide Erklärungen stehen auf der Seite, die ohne Login erreichbar ist -- käme eine davon
// nicht durch, stünde dort eine leere Checkbox, die sich trotzdem ankreuzen ließe.
$this->get('/api/v1/core/retrieve-text-resource/' . CreateRefundDocumentCommand::ACCOUNT_DECLARATION_TEXT)
->assertOk()
->assertSee('dass das angegebene Konto dasselbe ist', false);
$this->get('/api/v1/core/retrieve-text-resource/' . CreateRefundDocumentCommand::DONATION_DECLARATION_TEXT)
->assertOk()
->assertSee('verzichte auf die Auszahlung', false);
}
public function test_accept_requires_an_account_owner(): void
{
$refund = $this->release($this->makeParticipant($this->makeEvent()))->refund;
@@ -716,6 +842,7 @@ class ParticipantRefundTest extends TestCase
'accountOwner' => 'Mika Muster',
'accountIban' => 'DE02 1203 0000 0000 2020 51',
'declarationAccepted' => true,
'accountDeclarationAccepted' => true,
])->assertOk()->assertJsonPath('status', 'success');
$this->assertSame('DE02120300000000202051', $refund->fresh()->account_iban);