setDocumentInformation( $inv['rechnungs_nr'], '380', // UN/EDIFACT: Handelsrechnung $rechnungsDatum, 'EUR' ); // Käuferreferenz (BT-10) $doc->setDocumentBuyerReference($inv['kundennummer']); // Verkäufer (BG-4) $doc->setDocumentSeller($settings['firma'] ?? ''); $doc->setDocumentSellerAddress( $settings['strasse'] ?? '', null, null, $settings['plz'] ?? '', $settings['ort'] ?? '', 'DE' ); if (!empty($settings['ust_id'])) { $doc->addDocumentSellerVATRegistrationNumber($settings['ust_id']); } elseif (!empty($settings['steuernummer'])) { $doc->addDocumentSellerTaxNumber($settings['steuernummer']); } // Käufer (BG-7) $buyerName = !empty($inv['firma']) ? $inv['firma'] : trim(($inv['anrede'] ?? '') . ' ' . ($inv['vorname'] ?? '') . ' ' . ($inv['nachname'] ?? '')); $doc->setDocumentBuyer($buyerName, $inv['kundennummer']); $doc->setDocumentBuyerAddress( $inv['strasse'] ?? '', null, null, $inv['plz'] ?? '', $inv['ort'] ?? '', $inv['land'] ?? 'DE' ); if (!empty($inv['ust_id'])) { $doc->addDocumentBuyerVATRegistrationNumber($inv['ust_id']); } // Zahlungsart: Überweisung (BG-16) $iban = preg_replace('/\s+/', '', $settings['iban'] ?? ''); $bic = preg_replace('/\s+/', '', $settings['bic'] ?? ''); if (!empty($iban)) { $doc->addDocumentPaymentMeanToCreditTransfer( $iban, $settings['bank_name'] ?? null, null, $bic ?: null, $inv['rechnungs_nr'] ); } // Zahlungsziel (BT-9) if ($faelligDatum !== null) { $doc->addDocumentPaymentTerm(null, $faelligDatum); } // USt-Zusammenfassung nach Steuersatz gruppieren (BG-23) $taxGroups = []; foreach ($lines as $line) { if (($line['type'] ?? 'position') === 'heading') { continue; } $rate = (float)$line['ust_satz']; $key = number_format($rate, 2); if (!isset($taxGroups[$key])) { $taxGroups[$key] = ['rate' => $rate, 'basis' => 0.0, 'tax' => 0.0]; } $taxGroups[$key]['basis'] += (float)$line['betrag_netto']; $taxGroups[$key]['tax'] += (float)$line['betrag_ust']; } foreach ($taxGroups as $group) { $categoryCode = $group['rate'] > 0 ? 'S' : 'E'; $exemption = $group['rate'] > 0 ? null : 'Kleinunternehmer gemäß § 19 UStG'; $doc->addDocumentTax( $categoryCode, 'VAT', round($group['basis'], 2), round($group['tax'], 2), $group['rate'] > 0 ? $group['rate'] : null, $exemption ); } // Gesamtsummen (BG-22) $doc->setDocumentSummation( round((float)$inv['betrag_brutto'], 2), // Brutto (Zahlbetrag) round((float)$inv['betrag_brutto'], 2), // fällig round((float)$inv['betrag_netto'], 2), // Positionssumme Netto null, null, round((float)$inv['betrag_netto'], 2), // Steuerbemessungsgrundlage round((float)$inv['betrag_ust'], 2) // Steuer gesamt ); // Positionen (BG-25) – Überschriften werden übersprungen $posNr = 0; foreach ($lines as $line) { if (($line['type'] ?? 'position') === 'heading') { continue; } $posNr++; $doc->addNewPosition((string)$posNr); $doc->setDocumentPositionProductDetails($line['bezeichnung']); $doc->setDocumentPositionNetPrice((float)$line['einzelpreis']); $doc->setDocumentPositionQuantity( (float)$line['menge'], $this->mapEinheit($line['einheit'] ?? '') ); $rate = (float)$line['ust_satz']; $categoryCode = $rate > 0 ? 'S' : 'E'; $doc->addDocumentPositionTax($categoryCode, 'VAT', $rate); $doc->setDocumentPositionLineSummation(round((float)$line['betrag_netto'], 2)); } $pdfBuilder = new ZugferdDocumentPdfBuilder($doc, $pdfContent); $pdfBuilder->generateDocument(); return $pdfBuilder->downloadString(); } private function mapEinheit(string $einheit): string { return match (strtolower(trim($einheit))) { 'h', 'std', 'stunden', 'stunde' => 'HUR', 'tag', 'tage', 'd' => 'DAY', 'km' => 'KMT', 'monat', 'monate', 'mon' => 'MON', 'kg' => 'KGM', 'l', 'liter' => 'LTR', default => 'C62', // Stück / Pauschale }; } }