Approven von Beitragserstattungen
This commit is contained in:
@@ -10,10 +10,14 @@ use App\Domains\ParticipantRefund\Actions\CreateRefundDocument\CreateRefundDocum
|
||||
use App\Domains\ParticipantRefund\Actions\ReleaseRefund\ReleaseRefundCommand;
|
||||
use App\Domains\ParticipantRefund\Actions\ReleaseRefund\ReleaseRefundRequest;
|
||||
use App\Enumerations\EfzStatus;
|
||||
use App\Enumerations\CostUnitType;
|
||||
use App\Enumerations\InvoiceStatus;
|
||||
use App\Enumerations\InvoiceType;
|
||||
use App\Enumerations\RefundReason;
|
||||
use App\Enumerations\UserRole;
|
||||
use App\Mail\ParticipantRefundMails\RefundAcceptedMail;
|
||||
use App\Mail\ParticipantRefundMails\RefundReleasedMail;
|
||||
use App\Models\CostUnit;
|
||||
use App\Models\DocumentTemplate;
|
||||
use App\Models\Event;
|
||||
use App\Models\EventParticipant;
|
||||
@@ -67,6 +71,10 @@ class ParticipantRefundTest extends TestCase
|
||||
|
||||
DB::table('participation_types')->insert(['slug' => 'participant', 'name' => 'Teilnehmer']);
|
||||
DB::table('participation_fee_types')->insert(['slug' => 'fixed', 'name' => 'Fix']);
|
||||
// Lookup-Tabellen mit Fremdschlüsselzwang -- ohne sie scheitert schon das Anlegen.
|
||||
// `invoice_types.participation_refund` bringt die Migration bereits mit.
|
||||
DB::table('cost_unit_types')->insert(['slug' => CostUnitType::COST_UNIT_TYPE_EVENT, 'name' => 'Veranstaltung']);
|
||||
DB::table('invoice_status')->insert(['slug' => InvoiceStatus::INVOICE_STATUS_NEW]);
|
||||
PaymentMethod::create(['slug' => PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION]);
|
||||
PaymentMethod::create(['slug' => PaymentMethod::PAYMENT_NOT_DEFINED]);
|
||||
EfzStatus::create(['slug' => EfzStatus::EFZ_STATUS_NOT_REQUIRED, 'name' => 'Nicht erforderlich']);
|
||||
@@ -112,6 +120,20 @@ class ParticipantRefundTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
/** Die Kostenstelle, auf die die Erstattung gebucht wird -- beim Anlegen einer Veranstaltung entsteht sie mit. */
|
||||
private function makeCostUnit(array $attributes = []): CostUnit
|
||||
{
|
||||
return CostUnit::create(array_merge([
|
||||
'tenant' => $this->tenant->slug,
|
||||
'name' => 'Sommerlager',
|
||||
'type' => CostUnitType::COST_UNIT_TYPE_EVENT,
|
||||
'distance_allowance' => 0.25,
|
||||
'mail_on_new' => false,
|
||||
'allow_new' => true,
|
||||
'archived' => false,
|
||||
], $attributes));
|
||||
}
|
||||
|
||||
private function makeEvent(array $attributes = []): Event
|
||||
{
|
||||
$fee = EventParticipationFee::create([
|
||||
@@ -125,6 +147,7 @@ class ParticipantRefundTest extends TestCase
|
||||
]);
|
||||
|
||||
return Event::create(array_merge([
|
||||
'cost_unit_id' => $this->makeCostUnit()->id,
|
||||
'tenant' => $this->tenant->slug,
|
||||
'name' => 'Sommerlager',
|
||||
'identifier' => 'evt-' . uniqid(),
|
||||
@@ -532,18 +555,32 @@ class ParticipantRefundTest extends TestCase
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public function test_amount_paid_is_untouched_through_the_whole_process(): void
|
||||
public function test_amount_paid_survives_the_release_and_falls_with_the_confirmation(): void
|
||||
{
|
||||
$participant = $this->makeParticipant($this->makeEvent());
|
||||
|
||||
// Die Freigabe allein ändert nichts -- solange der Teili nicht bestätigt hat, ist der Beitrag
|
||||
// unverändert beim Verband.
|
||||
$refund = $this->release($participant)->refund;
|
||||
$this->assertEqualsWithDelta(300.0, $participant->fresh()->amount_paid->getAmount(), 0.001);
|
||||
|
||||
$this->accept($refund);
|
||||
$this->assertEqualsWithDelta(300.0, $participant->fresh()->amount_paid->getAmount(), 0.001);
|
||||
$this->assertEqualsWithDelta(0.0, $participant->fresh()->amount_paid->getAmount(), 0.001);
|
||||
|
||||
// Der Sollbetrag bleibt: was der Teili hätte zahlen müssen, ändert die Erstattung nicht.
|
||||
$this->assertEqualsWithDelta(300.0, $participant->fresh()->amount->getAmount(), 0.001);
|
||||
}
|
||||
|
||||
public function test_a_cancelled_release_leaves_amount_paid_alone(): void
|
||||
{
|
||||
$participant = $this->makeParticipant($this->makeEvent());
|
||||
$refund = $this->release($participant)->refund;
|
||||
|
||||
new CancelRefundCommand(new CancelRefundRequest($refund))->execute();
|
||||
|
||||
$this->assertEqualsWithDelta(300.0, $participant->fresh()->amount_paid->getAmount(), 0.001);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Über HTTP: Routen, Zugriffsschutz und die öffentliche Seite
|
||||
@@ -565,6 +602,22 @@ class ParticipantRefundTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
/** Das Konto, an dem eine Anmeldung hängen kann -- entscheidet über den Login-Hinweis in der Mail. */
|
||||
private function makeParticipantUser(): User
|
||||
{
|
||||
return User::create([
|
||||
'username' => 'teili-' . uniqid() . '@example.com',
|
||||
'email' => 'teili-' . uniqid() . '@example.com',
|
||||
'firstname' => 'Mika',
|
||||
'lastname' => 'Muster',
|
||||
'password' => bcrypt('secret'),
|
||||
'local_group' => $this->tenant->slug,
|
||||
'user_role_main' => UserRole::USER_ROLE_USER,
|
||||
'user_role_local_group' => UserRole::USER_ROLE_USER,
|
||||
'active' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_release_over_http_creates_the_refund(): void
|
||||
{
|
||||
$this->actingAs($this->makeAdmin());
|
||||
@@ -753,6 +806,40 @@ class ParticipantRefundTest extends TestCase
|
||||
$this->assertStringContainsString('Anhang', $html);
|
||||
}
|
||||
|
||||
public function test_the_acceptance_mail_points_at_the_invoice(): void
|
||||
{
|
||||
$participant = $this->makeParticipant($this->makeEvent(), ['user_id' => $this->makeParticipantUser()->id]);
|
||||
$refund = $this->release($participant)->refund;
|
||||
$this->accept($refund);
|
||||
|
||||
$html = new RefundAcceptedMail($participant, $refund->fresh())->render();
|
||||
|
||||
// Die Mail ist nur noch informativ -- eingereicht ist die Erstattung bereits.
|
||||
$this->assertStringContainsString('musst nichts weiter tun', $html);
|
||||
$this->assertStringContainsString($refund->fresh()->invoice()->first()->invoice_number, $html);
|
||||
$this->assertStringContainsString('/invoice/my-invoices/new', $html);
|
||||
}
|
||||
|
||||
public function test_the_acceptance_mail_omits_the_login_hint_without_an_account(): void
|
||||
{
|
||||
// Ohne Nutzerkonto bliebe "Meine Abrechnungen" leer -- die Seite filtert über die Verknüpfung.
|
||||
$participant = $this->makeParticipant($this->makeEvent(), ['user_id' => null]);
|
||||
$refund = $this->release($participant)->refund;
|
||||
$this->accept($refund);
|
||||
|
||||
$html = new RefundAcceptedMail($participant, $refund->fresh())->render();
|
||||
|
||||
$this->assertStringNotContainsString('/invoice/my-invoices/new', $html);
|
||||
}
|
||||
|
||||
public function test_an_empty_second_address_gets_no_mail(): void
|
||||
{
|
||||
// Der Anmeldewizard legt das Feld bei Volljährigen als Leerstring an, nicht als NULL.
|
||||
$this->release($this->makeParticipant($this->makeEvent(), ['email_2' => '']));
|
||||
|
||||
Mail::assertSent(RefundReleasedMail::class, 1);
|
||||
}
|
||||
|
||||
public function test_the_acceptance_mail_renders_without_a_document(): void
|
||||
{
|
||||
$participant = $this->makeParticipant($this->makeEvent());
|
||||
|
||||
Reference in New Issue
Block a user