Fix #xml-rechnung: USt-IdNr. des Kunden (BT-48) landet wieder im XML
Invoice::find() selektierte c.ust_id nicht, invoices hat keine eigene Spalte dafür - der Zweig addDocumentBuyerVATRegistrationNumber() lief deshalb nie. Bei Kategorie S optional, bei Reverse Charge und innergemeinschaftlichen Lieferungen aber Pflicht.
This commit is contained in:
parent
117c9a5c88
commit
d83d63cc14
3 changed files with 13 additions and 1 deletions
|
|
@ -21,6 +21,7 @@ Der E-Rechnungsvalidator (KoSIT-Prüfkonfiguration) meldete für die heruntergel
|
|||
- **PEPPOL-EN16931-R001/R010/R020 (Hinweise):** Geschäftsprozess (BT-23) sowie die elektronischen Adressen von Verkäufer (BT-34) und Käufer (BT-49, aus der Kunden-E-Mail) werden jetzt mit ausgegeben.
|
||||
- **Die PDF-Einbettung bleibt unverändert** beim Profil EN16931 (Factur-X, `factur-x.xml`) – dem üblichen Format für hybride B2B-Rechnungen. Die neuen Kontakt- und Adressangaben stehen aber auch dort, das PDF-XML wird dadurch nur vollständiger.
|
||||
- `collectMissingData()` prüft zusätzlich Ansprechpartner (BT-41), Telefon (BT-42), E-Mail (BT-43/BT-34) und die Kunden-E-Mail (BT-49); Test 72 deckt die neuen Elemente sowie eine XSD-Prüfung des erzeugten XML ab.
|
||||
- **Fix: USt-IdNr. des Kunden (BT-48) fehlte immer im XML.** `Invoice::find()` selektierte vom Kunden zwar Adresse, E-Mail und Zahlungsziel, aber nicht `c.ust_id` – und `invoices` hat keine eigene Spalte dafür. Der Zweig `addDocumentBuyerVATRegistrationNumber()` in `ZugferdService` lief deshalb nie, auch wenn beim Kunden eine USt-IdNr. gepflegt war (Bestandsfehler, betraf auch das in die PDF eingebettete XML). Bei inländischen Leistungen mit Steuerkategorie „S" ist BT-48 optional, weshalb es nicht auffiel; bei Reverse Charge (§ 13b UStG) und innergemeinschaftlichen Lieferungen ist die Angabe dagegen Pflicht. `Invoice::find()` liefert `c.ust_id` jetzt mit, Test 72 prüft BT-31 und BT-48 samt Schemakennung „VA".
|
||||
|
||||
## 2026-07-31 – Firmenlogo persistent in `data/logo`, Nutzdaten gebündelt unter `data/`
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class Invoice
|
|||
{
|
||||
return Database::fetchOne(
|
||||
'SELECT i.*, i.storno_of_id, c.firma, c.nachname, c.vorname, c.anrede, c.kundennummer,
|
||||
c.strasse, c.plz, c.ort, c.land, c.email, c.payment_days
|
||||
c.strasse, c.plz, c.ort, c.land, c.email, c.payment_days, c.ust_id
|
||||
FROM invoices i
|
||||
JOIN customers c ON i.customer_id = c.id
|
||||
WHERE i.id = ?',
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ class InvoiceXmlExportTest extends TestCase
|
|||
'ort' => 'Normstadt',
|
||||
'land' => 'DE',
|
||||
'email' => 'buchhaltung@xmltest.example',
|
||||
'ust_id' => 'DE987654321',
|
||||
'payment_days' => 14,
|
||||
]);
|
||||
$invoiceId = \Steuerkram\Models\Invoice::create([
|
||||
|
|
@ -123,6 +124,16 @@ class InvoiceXmlExportTest extends TestCase
|
|||
'E-Mail des Ansprechpartners (BT-43) vorhanden – BR-DE-7'
|
||||
);
|
||||
|
||||
// USt-IdNr. beider Parteien (BT-31 / BT-48) – BT-48 nur, wenn beim Kunden gepflegt
|
||||
$sellerVat = $xp->query('//ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="VA"]')->item(0);
|
||||
$buyerVat = $xp->query('//ram:BuyerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="VA"]')->item(0);
|
||||
$this->assertEquals('DE123456789', $sellerVat?->nodeValue, 'USt-IdNr. des Verkäufers als BT-31 mit Schema "VA"');
|
||||
$this->assertEquals('DE987654321', $buyerVat?->nodeValue, 'USt-IdNr. des Kunden als BT-48 mit Schema "VA"');
|
||||
$this->assertNotEmpty(
|
||||
$invoice['ust_id'] ?? '',
|
||||
'Invoice::find() liefert die USt-IdNr. des Kunden mit (Voraussetzung für BT-48)'
|
||||
);
|
||||
|
||||
$sellerUri = $xp->query('//ram:SellerTradeParty/ram:URIUniversalCommunication/ram:URIID')->item(0);
|
||||
$buyerUri = $xp->query('//ram:BuyerTradeParty/ram:URIUniversalCommunication/ram:URIID')->item(0);
|
||||
$this->assertEquals('rechnung@muster.example', $sellerUri?->nodeValue, 'Elektronische Adresse des Verkäufers (BT-34)');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue