194 lines
6.8 KiB
PHP
194 lines
6.8 KiB
PHP
<?php
|
||
|
||
namespace Tests\Feature;
|
||
|
||
use App\Domains\Invoice\Actions\CreateInvoice\CreateInvoiceCommand;
|
||
use App\Domains\Invoice\Actions\CreateInvoice\CreateInvoiceRequest;
|
||
use App\Domains\Invoice\Actions\CreateInvoice\CreateInvoiceResponse;
|
||
use App\Enumerations\CostUnitType;
|
||
use App\Enumerations\InvoiceStatus;
|
||
use App\Enumerations\InvoiceType;
|
||
use App\Enumerations\TravelReason;
|
||
use App\Models\CostUnit;
|
||
use App\Models\Invoice;
|
||
use App\Models\Tenant;
|
||
use App\Resources\InvoiceResource;
|
||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Mail;
|
||
use Tests\TestCase;
|
||
|
||
/**
|
||
* Der Reisegrund ist eine Auswahl, kein Freitext mehr.
|
||
*
|
||
* Gespeichert wird der Schlüssel des Grundes -- außer bei "Anderer Grund": Der Schlüssel `other` sagt
|
||
* für sich nichts aus, deshalb steht dort der Text. Dieselbe Spalte führt damit weiter den Freitext der
|
||
* Bestandsbelege, ohne dass etwas umgeschrieben werden musste.
|
||
*/
|
||
class TravelReasonTest extends TestCase
|
||
{
|
||
use RefreshDatabase;
|
||
|
||
private Tenant $tenant;
|
||
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
|
||
$this->tenant = Tenant::create([
|
||
'slug' => 'wm',
|
||
'name' => 'Wilde Möhre',
|
||
'address_1' => 'Musterweg 1',
|
||
'email' => 't@example.com',
|
||
'email_finance' => 'finance@example.com',
|
||
'url' => parse_url(config('app.url'), PHP_URL_HOST),
|
||
'account_name' => 'Test e.V.',
|
||
'account_iban' => 'DE00',
|
||
'account_bic' => 'XY',
|
||
'city' => 'Stadt',
|
||
'postcode' => '00000',
|
||
'invoice_prefix' => 'WM',
|
||
'is_active_local_group' => true,
|
||
'has_active_instance' => true,
|
||
]);
|
||
|
||
app()->instance('tenant', $this->tenant);
|
||
|
||
DB::table('cost_unit_types')->insert(['slug' => CostUnitType::COST_UNIT_TYPE_EVENT, 'name' => 'Veranstaltung']);
|
||
DB::table('invoice_status')->insert(['slug' => InvoiceStatus::INVOICE_STATUS_NEW]);
|
||
DB::table('invoice_types')->insert([
|
||
'slug' => InvoiceType::INVOICE_TYPE_TRAVELLING,
|
||
'name' => 'Fahrtkosten',
|
||
'sort_order' => 1,
|
||
'selectable' => true,
|
||
'counts_as_expense' => true,
|
||
]);
|
||
|
||
Mail::fake();
|
||
}
|
||
|
||
private function makeCostUnit(): CostUnit
|
||
{
|
||
return CostUnit::create([
|
||
'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,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Der Weg, den eine eingereichte Fahrtkostenabrechnung nimmt. `contactEmail` bleibt leer, damit kein
|
||
* Bestätigungsmailversand mitläuft.
|
||
*/
|
||
private function submit(?string $reason, ?string $note = null, ?string $travellers = 'Mika und Kim'): CreateInvoiceResponse
|
||
{
|
||
return new CreateInvoiceCommand(new CreateInvoiceRequest(
|
||
costUnit: $this->makeCostUnit(),
|
||
contactName: 'Max Mustermann',
|
||
invoiceType: InvoiceType::INVOICE_TYPE_TRAVELLING,
|
||
totalAmount: 42.0,
|
||
receiptFile: null,
|
||
isDonation: false,
|
||
travelRoute: 'Halle – Leipzig',
|
||
travelReason: $reason,
|
||
travelReasonNote: $note,
|
||
travellers: $travellers,
|
||
))->execute();
|
||
}
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Die Auswahl
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
public function test_the_options_are_ordered_and_only_the_last_one_needs_a_note(): void
|
||
{
|
||
$options = TravelReason::options();
|
||
|
||
$this->assertSame(
|
||
['event_travel', 'material_transport', 'purchase', 'other'],
|
||
array_column($options, 'value')
|
||
);
|
||
$this->assertSame('An-/Abreise zur Veranstaltung', $options[0]['label']);
|
||
$this->assertSame([false, false, false, true], array_column($options, 'requiresNote'));
|
||
}
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Was gespeichert wird
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
public function test_a_fixed_reason_is_stored_as_its_key(): void
|
||
{
|
||
$invoice = $this->submit(TravelReason::MATERIAL_TRANSPORT)->invoice;
|
||
|
||
$this->assertSame(TravelReason::MATERIAL_TRANSPORT, $invoice->travel_reason);
|
||
}
|
||
|
||
public function test_the_purpose_carries_the_name_not_the_key(): void
|
||
{
|
||
// In der Belegliste soll "Materialtransport" stehen, nicht "material_transport".
|
||
$invoice = $this->submit(TravelReason::MATERIAL_TRANSPORT)->invoice;
|
||
|
||
$this->assertSame('Materialtransport — Mika und Kim', $invoice->purpose);
|
||
}
|
||
|
||
public function test_another_reason_stores_the_text_instead_of_the_key(): void
|
||
{
|
||
$invoice = $this->submit(TravelReason::OTHER, 'Abholung der Ausrüstung')->invoice;
|
||
|
||
$this->assertSame('Abholung der Ausrüstung', $invoice->travel_reason);
|
||
$this->assertSame('Abholung der Ausrüstung — Mika und Kim', $invoice->purpose);
|
||
}
|
||
|
||
public function test_another_reason_without_a_text_creates_nothing(): void
|
||
{
|
||
// Sicherheitsnetz hinter der Oberfläche: Dort geht es ohne Erläuterung nicht weiter.
|
||
$response = $this->submit(TravelReason::OTHER, ' ');
|
||
|
||
$this->assertFalse($response->success);
|
||
$this->assertNull($response->invoice);
|
||
$this->assertSame(0, Invoice::count());
|
||
$this->assertNotNull($response->message);
|
||
}
|
||
|
||
public function test_an_unknown_value_passes_through_unchanged(): void
|
||
{
|
||
// Bestandsbelege und ihre Kopien bringen ihren Freitext schon mit.
|
||
$invoice = $this->submit('Fahrt zum Landeslager')->invoice;
|
||
|
||
$this->assertSame('Fahrt zum Landeslager', $invoice->travel_reason);
|
||
$this->assertSame('Fahrt zum Landeslager — Mika und Kim', $invoice->purpose);
|
||
}
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Was angezeigt wird
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
public function test_a_key_is_shown_as_its_name(): void
|
||
{
|
||
$invoice = $this->submit(TravelReason::EVENT_TRAVEL)->invoice;
|
||
|
||
$this->assertSame('An-/Abreise zur Veranstaltung', $invoice->travelReasonText());
|
||
$this->assertSame(
|
||
'An-/Abreise zur Veranstaltung',
|
||
new InvoiceResource($invoice)->toArray()['travelReason']
|
||
);
|
||
}
|
||
|
||
public function test_free_text_is_shown_as_itself(): void
|
||
{
|
||
$invoice = $this->submit('Fahrt zum Landeslager')->invoice;
|
||
|
||
$this->assertSame('Fahrt zum Landeslager', $invoice->travelReasonText());
|
||
}
|
||
}
|