presseportale/tests/Feature/Billing/VatResolverTest.php
Kevin Adametz 894a9436b0 USt-Behandlung: Netto-Preise, VatResolver und Steuer-Ausweis im MAN-Kreis
Einwand/Entscheidung 12.06.2026: Legacy fakturierte brutto (Steuer
inkludiert, z. B. 199 Euro; steuerbefreite Kunden mit Netto-Ausweis
167,23). Alle neuen Preise sind netto; die Steuer wird zur
Rechnungsstellung sauber validiert und ausgewiesen.

- VatResolver + VatTreatment: DE grundsaetzlich immer mit Steuer, EU nur
  mit (formal plausibler) USt-ID befreit (Reverse Charge inkl.
  Pflichthinweis), Drittlaender grundsaetzlich befreit;
  EU-Laenderliste + vat_rate in config/billing.php
- Schema: billing_addresses.vat_id + invoice_billing_addresses.vat_id
  (Snapshot pro Rechnung), invoices.tax_note; Profil-Formular schreibt
  die vorhandene USt-ID jetzt auch an die Rechnungsadresse
- ManualInvoiceService: rechnet auf Netto-Vertragsbasis
  (legacy_conditions.net_cents bzw. Netto-Katalogpreis) und bestimmt
  Steuer/is_netto/tax_note pro Rechnung ueber den VatResolver
- legacy:grandfather-subscriptions: leitet net_cents aus der letzten
  Legacy-Rechnung ab (brutto / 1,19 bzw. is_netto-Betrag direkt);
  fuer DE-Bestandskunden bleibt der Bruttobetrag unveraendert
  (199 brutto -> 167,23 netto + 31,77 USt = 199,00)
- Doku: Decision-Update 2.1 (Netto-Klarstellung), Phase-9-Plan,
  Checkliste, 05-DATABASE-MERGE 5.6; offen: VIES-Validierung der USt-ID

Tests: VatResolverTest (Datasets fuer alle Faelle), Reverse-Charge/
EU-/Drittland-Rechnungen, Netto-Ableitung; Suite 490 passed, 4 skipped.
Pint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 10:58:43 +00:00

33 lines
1.8 KiB
PHP

<?php
use App\Enums\VatTreatment;
use App\Services\Billing\VatResolver;
test('vat treatment follows the 12.06. decision rules', function (?string $country, ?string $vatId, VatTreatment $expected) {
expect(app(VatResolver::class)->resolve($country, $vatId))->toBe($expected);
})->with([
'Deutschland immer mit Steuer' => ['DE', null, VatTreatment::Domestic],
'Deutschland auch mit USt-ID mit Steuer' => ['DE', 'DE123456789', VatTreatment::Domestic],
'EU mit gültiger USt-ID → Reverse Charge' => ['AT', 'ATU12345678', VatTreatment::ReverseCharge],
'EU ohne USt-ID → mit Steuer' => ['AT', null, VatTreatment::EuConsumer],
'EU mit fremdländischer USt-ID → mit Steuer' => ['AT', 'DE123456789', VatTreatment::EuConsumer],
'Griechenland mit EL-Präfix' => ['GR', 'EL123456789', VatTreatment::ReverseCharge],
'Drittland grundsätzlich befreit' => ['CH', null, VatTreatment::ThirdCountry],
'Drittland auch mit ID befreit' => ['US', 'US-TAX-1', VatTreatment::ThirdCountry],
'Fehlendes Land wie Inland behandeln' => [null, null, VatTreatment::Domestic],
]);
test('tax cents are derived from the treatment', function () {
$resolver = app(VatResolver::class);
expect($resolver->taxCentsFor(16723, VatTreatment::Domestic))->toBe(3177);
expect($resolver->taxCentsFor(16723, VatTreatment::EuConsumer))->toBe(3177);
expect($resolver->taxCentsFor(16723, VatTreatment::ReverseCharge))->toBe(0);
expect($resolver->taxCentsFor(16723, VatTreatment::ThirdCountry))->toBe(0);
});
test('exempt treatments carry a legal tax note', function () {
expect(VatTreatment::ReverseCharge->taxNote())->toContain('Reverse Charge');
expect(VatTreatment::ThirdCountry->taxNote())->toContain('Nicht im Inland steuerbar');
expect(VatTreatment::Domestic->taxNote())->toBeNull();
});