'wm', 'name' => 'Wilde Möhre', 'email' => 'wm@example.com', 'email_finance' => 'wm-f@example.com', 'url' => parse_url(config('app.url'), PHP_URL_HOST), 'account_name' => 'Wilde Möhre e.V.', 'account_iban' => 'DE00', 'account_bic' => 'XY', 'city' => 'Stadt', 'postcode' => '00000', 'is_active_local_group' => true, 'has_active_instance' => true, ]); app()->instance('tenant', $tenant); // Zwei wählbare Typen neben der Beitragserstattung, die aus der Migration kommt. DB::table('invoice_types')->insert([ ['slug' => InvoiceType::INVOICE_TYPE_PROGRAM, 'name' => 'Programmkosten', 'sort_order' => 1, 'selectable' => true], ['slug' => InvoiceType::INVOICE_TYPE_OTHER, 'name' => 'Sonstige Kosten', 'sort_order' => 3, 'selectable' => true], ]); } public function test_the_refund_type_exists_but_is_not_selectable(): void { // `where` und nicht `find`: InvoiceType deklariert keinen Primärschlüssel, `find` suchte nach `id`. $type = InvoiceType::where('slug', InvoiceType::INVOICE_TYPE_PARTICIPATION_REFUND)->first(); $this->assertNotNull($type, 'Der Typ muss existieren -- invoices.type ist ein Fremdschlüssel darauf.'); $this->assertFalse($type->selectable); } public function test_it_is_missing_from_the_new_invoice_form(): void { $response = $this->getJson('/api/v1/core/retrieve-invoice-types'); $response->assertOk(); $slugs = array_column($response->json('invoiceTypes'), 'slug'); $this->assertNotContains(InvoiceType::INVOICE_TYPE_PARTICIPATION_REFUND, $slugs); $this->assertContains(InvoiceType::INVOICE_TYPE_PROGRAM, $slugs); $this->assertContains(InvoiceType::INVOICE_TYPE_OTHER, $slugs); } public function test_it_is_missing_when_a_treasurer_rebooks(): void { // Ohne diese Sperre ließe sich jede beliebige Abrechnung nachträglich zu einer // Beitragserstattung machen, ohne dass ein Erstattungsvorgang dahinterstünde. $response = $this->getJson('/api/v1/core/retrieve-invoice-types-all'); $response->assertOk(); $slugs = array_column($response->json('invoiceTypes'), 'slug'); $this->assertNotContains(InvoiceType::INVOICE_TYPE_PARTICIPATION_REFUND, $slugs); $this->assertContains(InvoiceType::INVOICE_TYPE_PROGRAM, $slugs); // "Sonstige Kosten" steht dort bewusst am Ende. $this->assertSame(InvoiceType::INVOICE_TYPE_OTHER, end($slugs)); } public function test_selectable_returns_only_choosable_types_in_order(): void { $this->assertSame( [InvoiceType::INVOICE_TYPE_PROGRAM, InvoiceType::INVOICE_TYPE_OTHER], InvoiceType::selectable()->pluck('slug')->all() ); } public function test_the_refund_type_does_not_count_as_an_expense(): void { // Sie mindert die Einnahmenseite bereits -- als Ausgabe gezählt, stünde sie zweimal in der Bilanz. $this->assertSame( [InvoiceType::INVOICE_TYPE_PROGRAM, InvoiceType::INVOICE_TYPE_OTHER], InvoiceType::countingAsExpense()->pluck('slug')->all() ); $type = InvoiceType::where('slug', InvoiceType::INVOICE_TYPE_PARTICIPATION_REFUND)->first(); $this->assertFalse($type->counts_as_expense); } }