tenant = Tenant::create([ 'slug' => 'tv', 'name' => 'Test', 'email' => 't@example.com', 'email_finance' => 'finance@example.com', 'url' => 'test.local', 'account_name' => 'Test e.V.', 'account_iban' => 'DE00', 'account_bic' => 'XY', 'city' => 'Stadt', 'postcode' => '00000', 'is_active_local_group' => true, 'has_active_instance' => true, ]); app()->instance('tenant', $this->tenant); } private function runAction(bool $taxLiable, int $vatRate, ?string $reason, ?string $note = null): object { return new UpdateTenantTaxAction(new UpdateTenantTaxRequest( tenant: $this->tenant, taxLiable: $taxLiable, vatRate: $vatRate, exemptionReason: $reason, exemptionNote: $note, ))->execute(); } public function test_taxable_sets_rate_and_clears_exemption(): void { $this->tenant->update(['tax_exemption_reason' => 'small_business', 'tax_exemption_note' => 'alt']); $response = $this->runAction(taxLiable: true, vatRate: 7, reason: null); $this->assertTrue($response->success); $fresh = $this->tenant->fresh(); $this->assertTrue($fresh->tax_liable); $this->assertSame(7, $fresh->vat_rate); $this->assertNull($fresh->tax_exemption_reason); $this->assertNull($fresh->tax_exemption_note); } public function test_exemption_reason_persists_and_clears_rate(): void { $response = $this->runAction(taxLiable: false, vatRate: 19, reason: 'youth_welfare'); $this->assertTrue($response->success); $fresh = $this->tenant->fresh(); $this->assertFalse($fresh->tax_liable); $this->assertSame(0, $fresh->vat_rate); $this->assertSame('youth_welfare', $fresh->tax_exemption_reason); $this->assertNull($fresh->tax_exemption_note); } public function test_invalid_exemption_reason_fails(): void { $response = $this->runAction(taxLiable: false, vatRate: 0, reason: 'not_a_reason'); $this->assertFalse($response->success); $this->assertNull($this->tenant->fresh()->tax_exemption_reason); } public function test_custom_reason_requires_note(): void { $missing = $this->runAction(taxLiable: false, vatRate: 0, reason: 'custom', note: ' '); $this->assertFalse($missing->success); $ok = $this->runAction(taxLiable: false, vatRate: 0, reason: 'custom', note: 'Individueller Grund'); $this->assertTrue($ok->success); $this->assertSame('Individueller Grund', $this->tenant->fresh()->tax_exemption_note); } public function test_vat_rate_is_clamped(): void { $this->runAction(taxLiable: true, vatRate: 250, reason: null); $this->assertSame(100, $this->tenant->fresh()->vat_rate); } public function test_enum_invoice_text_per_case(): void { $this->assertSame( 'Gemäß § 19 UStG wird keine Umsatzsteuer berechnet.', TaxExemptionReason::SmallBusiness->invoiceText(), ); $this->assertSame( 'Die Leistung ist gemäß § 4 Nr. 22 Buchst. a UStG von der Umsatzsteuer befreit.', TaxExemptionReason::Education->invoiceText(), ); $this->assertSame( 'Die Leistung ist gemäß § 4 Nr. 25 UStG von der Umsatzsteuer befreit.', TaxExemptionReason::YouthWelfare->invoiceText(), ); $this->assertSame('Mein Text', TaxExemptionReason::Custom->invoiceText('Mein Text')); } }