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.
|
- **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.
|
- **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.
|
- `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/`
|
## 2026-07-31 – Firmenlogo persistent in `data/logo`, Nutzdaten gebündelt unter `data/`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ class Invoice
|
||||||
{
|
{
|
||||||
return Database::fetchOne(
|
return Database::fetchOne(
|
||||||
'SELECT i.*, i.storno_of_id, c.firma, c.nachname, c.vorname, c.anrede, c.kundennummer,
|
'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
|
FROM invoices i
|
||||||
JOIN customers c ON i.customer_id = c.id
|
JOIN customers c ON i.customer_id = c.id
|
||||||
WHERE i.id = ?',
|
WHERE i.id = ?',
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ class InvoiceXmlExportTest extends TestCase
|
||||||
'ort' => 'Normstadt',
|
'ort' => 'Normstadt',
|
||||||
'land' => 'DE',
|
'land' => 'DE',
|
||||||
'email' => 'buchhaltung@xmltest.example',
|
'email' => 'buchhaltung@xmltest.example',
|
||||||
|
'ust_id' => 'DE987654321',
|
||||||
'payment_days' => 14,
|
'payment_days' => 14,
|
||||||
]);
|
]);
|
||||||
$invoiceId = \Steuerkram\Models\Invoice::create([
|
$invoiceId = \Steuerkram\Models\Invoice::create([
|
||||||
|
|
@ -123,6 +124,16 @@ class InvoiceXmlExportTest extends TestCase
|
||||||
'E-Mail des Ansprechpartners (BT-43) vorhanden – BR-DE-7'
|
'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);
|
$sellerUri = $xp->query('//ram:SellerTradeParty/ram:URIUniversalCommunication/ram:URIID')->item(0);
|
||||||
$buyerUri = $xp->query('//ram:BuyerTradeParty/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)');
|
$this->assertEquals('rechnung@muster.example', $sellerUri?->nodeValue, 'Elektronische Adresse des Verkäufers (BT-34)');
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue