Fix: EN16931-Lieferdatum (BT-72) und leere XML-Elemente in ZUGFeRD-Rechnungen
This commit is contained in:
parent
6bff984ca0
commit
0488edba7c
3 changed files with 31 additions and 8 deletions
|
|
@ -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
|
## 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
|
- **Datenbank:** 3 neue Tabellen `buchungsvorlagen`, `buchungsvorlage_felder`, `buchungsvorlage_regeln` (Migrationen 078–080); initiale Vorlage "Essensbeleg n. abzugsfähig (nur USt.)" per Migration 080 eingespielt
|
||||||
|
|
|
||||||
|
|
@ -30,17 +30,21 @@ class ZugferdService
|
||||||
'EUR'
|
'EUR'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// BT-72: Liefer-/Leistungsdatum aus leistungszeitraum ableiten (EN16931-Pflichtfeld)
|
||||||
|
$deliveryDate = $this->parseLeistungszeitraumDate($inv['leistungszeitraum'] ?? '', $rechnungsDatum);
|
||||||
|
$doc->setDocumentSupplyChainEvent($deliveryDate);
|
||||||
|
|
||||||
// Käuferreferenz (BT-10)
|
// Käuferreferenz (BT-10)
|
||||||
$doc->setDocumentBuyerReference($inv['kundennummer']);
|
$doc->setDocumentBuyerReference($inv['kundennummer']);
|
||||||
|
|
||||||
// Verkäufer (BG-4)
|
// Verkäufer (BG-4)
|
||||||
$doc->setDocumentSeller($settings['firma'] ?? '');
|
$doc->setDocumentSeller($settings['firma'] ?? '');
|
||||||
$doc->setDocumentSellerAddress(
|
$doc->setDocumentSellerAddress(
|
||||||
$settings['strasse'] ?? '',
|
$settings['strasse'] ?: null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
$settings['plz'] ?? '',
|
$settings['plz'] ?: null,
|
||||||
$settings['ort'] ?? '',
|
$settings['ort'] ?: null,
|
||||||
'DE'
|
'DE'
|
||||||
);
|
);
|
||||||
if (!empty($settings['ust_id'])) {
|
if (!empty($settings['ust_id'])) {
|
||||||
|
|
@ -55,12 +59,12 @@ class ZugferdService
|
||||||
: trim(($inv['anrede'] ?? '') . ' ' . ($inv['vorname'] ?? '') . ' ' . ($inv['nachname'] ?? ''));
|
: trim(($inv['anrede'] ?? '') . ' ' . ($inv['vorname'] ?? '') . ' ' . ($inv['nachname'] ?? ''));
|
||||||
$doc->setDocumentBuyer($buyerName, $inv['kundennummer']);
|
$doc->setDocumentBuyer($buyerName, $inv['kundennummer']);
|
||||||
$doc->setDocumentBuyerAddress(
|
$doc->setDocumentBuyerAddress(
|
||||||
$inv['strasse'] ?? '',
|
$inv['strasse'] ?: null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
$inv['plz'] ?? '',
|
$inv['plz'] ?: null,
|
||||||
$inv['ort'] ?? '',
|
$inv['ort'] ?: null,
|
||||||
$inv['land'] ?? 'DE'
|
$inv['land'] ?: 'DE'
|
||||||
);
|
);
|
||||||
if (!empty($inv['ust_id'])) {
|
if (!empty($inv['ust_id'])) {
|
||||||
$doc->addDocumentBuyerVATRegistrationNumber($inv['ust_id']);
|
$doc->addDocumentBuyerVATRegistrationNumber($inv['ust_id']);
|
||||||
|
|
@ -148,6 +152,20 @@ class ZugferdService
|
||||||
return $pdfBuilder->downloadString();
|
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
|
private function mapEinheit(string $einheit): string
|
||||||
{
|
{
|
||||||
return match (strtolower(trim($einheit))) {
|
return match (strtolower(trim($einheit))) {
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
1-260530
|
1-260601
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue