Fix: EN16931-Lieferdatum (BT-72) und leere XML-Elemente in ZUGFeRD-Rechnungen

This commit is contained in:
fds2610-bot 2026-06-01 19:11:19 +02:00
parent 6bff984ca0
commit 0488edba7c
3 changed files with 31 additions and 8 deletions

View file

@ -2,6 +2,11 @@
---
## 2026-06-01 – Fix: EN16931-Validierungsfehler in ZUGFeRD-Rechnungen
- **[BR-FX-EN-04]** behoben: `ZugferdService` setzt jetzt BT-72 (Liefer-/Leistungsdatum) via `setDocumentSupplyChainEvent()`; das Datum wird aus dem Feld `leistungszeitraum` geparst (Format `DD.MM.YYYY` → direkt; Format `MM.YYYY` → letzter Tag des Monats; sonst Fallback auf Rechnungsdatum)
- **[PEPPOL-EN16931-R008]** behoben: Leere Strings in optionalen Adressfeldern (Straße, PLZ, Ort) werden als `null` übergeben, sodass keine leeren XML-Elemente entstehen
## 2026-05-28 – Feature: Buchungsvorlagen im Buchungsdialog
- **Datenbank:** 3 neue Tabellen `buchungsvorlagen`, `buchungsvorlage_felder`, `buchungsvorlage_regeln` (Migrationen 078–080); initiale Vorlage "Essensbeleg n. abzugsfähig (nur USt.)" per Migration 080 eingespielt

View file

@ -30,17 +30,21 @@ class ZugferdService
'EUR'
);
// BT-72: Liefer-/Leistungsdatum aus leistungszeitraum ableiten (EN16931-Pflichtfeld)
$deliveryDate = $this->parseLeistungszeitraumDate($inv['leistungszeitraum'] ?? '', $rechnungsDatum);
$doc->setDocumentSupplyChainEvent($deliveryDate);
// Käuferreferenz (BT-10)
$doc->setDocumentBuyerReference($inv['kundennummer']);
// Verkäufer (BG-4)
$doc->setDocumentSeller($settings['firma'] ?? '');
$doc->setDocumentSellerAddress(
$settings['strasse'] ?? '',
$settings['strasse'] ?: null,
null,
null,
$settings['plz'] ?? '',
$settings['ort'] ?? '',
$settings['plz'] ?: null,
$settings['ort'] ?: null,
'DE'
);
if (!empty($settings['ust_id'])) {
@ -55,12 +59,12 @@ class ZugferdService
: trim(($inv['anrede'] ?? '') . ' ' . ($inv['vorname'] ?? '') . ' ' . ($inv['nachname'] ?? ''));
$doc->setDocumentBuyer($buyerName, $inv['kundennummer']);
$doc->setDocumentBuyerAddress(
$inv['strasse'] ?? '',
$inv['strasse'] ?: null,
null,
null,
$inv['plz'] ?? '',
$inv['ort'] ?? '',
$inv['land'] ?? 'DE'
$inv['plz'] ?: null,
$inv['ort'] ?: null,
$inv['land'] ?: 'DE'
);
if (!empty($inv['ust_id'])) {
$doc->addDocumentBuyerVATRegistrationNumber($inv['ust_id']);
@ -148,6 +152,20 @@ class ZugferdService
return $pdfBuilder->downloadString();
}
private function parseLeistungszeitraumDate(string $lz, DateTime $fallback): DateTime
{
// DD.MM.YYYY
$dt = DateTime::createFromFormat('d.m.Y', trim($lz));
if ($dt !== false) {
return $dt;
}
// MM.YYYY → letzter Tag des Monats
if (preg_match('/^(\d{1,2})\.(\d{4})$/', trim($lz), $m)) {
return new DateTime(sprintf('last day of %04d-%02d', (int)$m[2], (int)$m[1]));
}
return $fallback;
}
private function mapEinheit(string $einheit): string
{
return match (strtolower(trim($einheit))) {

View file

@ -1 +1 @@
1-260530
1-260601