====== ZUGFeRD for IT-TransSpedi ====== [[IT-TransSpedi]] project e-Invoice should be integrated in Rolf's telematics system. * Rolf's Plan (Stand 05.06.2026): * August: unsere Version sollte stehen * September - einen Kunden für die Tests anschließen * Oktober - Live gehen mit einem Kunden * er will etwas in weniger als 10 Tagen implementiert haben * ich: lass uns starten, aber in 2 Tagen wird es nicht fertig * Rolf: OK * Am 26.06.2026 Rolf stoppte dieses Projekt (bis auf weiteres) * er will selber was basteln (mit KI etc) * => mal schauen ===== Spec ===== Das ist keine richtige Spezifikation, sondern eine Sammlung von Punkten, die implementiert werden sollen, und Notizen dazu. Vielleicht können wir später auch was besseres daraus machen :) * Die Daten sollen aus der Datenbank im Azure kommen. * Die Anwendung soll in Azure laufen. Im ersten Schritt (für die Entwicklertests) wir die Anwendung über Kommandozeile gestartet. * Mit der Unterstützung von eInvoice ist momentan nur Output gemeint. * als Format soll ZUGFeRD (PDF + XML) genommen werden. Damit ist XRechnung (reines XML) sowieso drin (wenn ich das richtig verstehe) * die vorliegenden PDFs sind leider nicht im Format "PDF/A-3". Also muss auch ein Konverter erstellt/genutzt werden. Dazu gibt es diverse Lösungsalternativen. Ich habe mich für "Free Spire.PDF for Java" entschieden. Es ist kostenlos auch für die kommerzielle Nutzung. (siehe https://www.e-iceblue.com/Download/pdf-for-java-free.html) ==== Datenmapping ==== === Kopfdaten === * dbo.Rechnungerstellt.RIDAuto * interne ID, wird nicht angezeigt * ''ITTInvoiceInfo.invoiceId'' => NOT MAPPED? * dbo.Rechnungerstellt.FIXRechnungsNrComputet * ''ITTInvoiceInfo.invoiceNumber'' * Adressen_1.FIXKundenNrFormat AS FixKundenNrClient * NOT MAPPED * dbo.Rechnungerstellt.RIDAutoComputed * NOT MAPPED * Adressen_1.AdressID AS RECKundenID * ''recipientTradePartyId'' * Adressen_1.FirmenName AS RECFirma * ''recipient.name'' * Adressen_1.Zusatz AS RECZusatz * NOT MAPPED * Adressen_1.StrasseNr AS RECStrasse * ''recipient.street'' * Adressen_1.LandText AS RECLand * ''recipient.country'' * Adressen_1.SteuerNr AS RECSteuerID, * ''recipient.VATID'' * Adressen_1.DebitorDatev AS RECDatevNr, * NOT MAPPED * Adressen_1.AdressAnschrift AS RECAnschrift, * NOT MAPPED * dbo.SYSCompany.FirmenName AS EFirma, * ''sender.name'' * dbo.SYSCompany.Zusatz AS EZusatz, * NOT MAPPED * dbo.SYSCompany.Strasse AS EStrasse, * sender.street * dbo.SYSCompany.Postfach, * NOT MAPPED * dbo.SYSCompany.Plz AS EPlz, * sender.zip * dbo.SYSCompany.Ort AS EOrt, * sender.location * dbo.SYSCompany.TelefonZentrale AS ETelefon, * sender.contact.phone * dbo.SYSCompany.Fax AS EFax, * NOT MAPPED * dbo.SYSCompany.Email AS EEmail, * sender.contact.email * dbo.SYSCompany.Homepage AS EWWW, * NOT MAPPED * dbo.SYSCompany.FirmenInhaber AS EInhaben, * sender.contact.name * dbo.SYSCompany.GerichtsOrt AS EGerichtsOrt, * NOT MAPPED * dbo.SYSCompany.HandelsNr AS EHandelsNr, * NOT MAPPED * dbo.SYSCompany.SteuerNr AS ESteuerID, * sender.vatid * dbo.SYSCompany.ElogoImag AS EImage, * NOT MAPPED * dbo.SYSCompany.AnschriftComputed, * NOT MAPPED * dbo.Rechnungerstellt.RDatum, * info.issueDate * dbo.Rechnungerstellt.Faellig, * info.dueDate * dbo.Rechnungerstellt.Referenz, * NOT MAPPED * => Projektnummer? Vertragsnummer? Bestellnummer? Auftragsnummer? * dbo.Rechnungerstellt.Bemerkung, * NOT MAPPED * dbo.Rechnungerstellt.Reversecharge, * NOT MAPPED * dbo.Rechnungerstellt.Bezahlt, * NOT MAPPED * CASE WHEN txtKonditionComputed = '0 Bankeinzug' THEN 'Bankeinzug' ELSE txtKonditionComputed END AS txtKonditionComputed, * NOT MAPPED * Rolf fragen wann es notwendig sein wird * dbo.SYSCompany.WaehrungText AS Zeichen, * NOT MAPPED * dbo.Waehrung.Waehrungsbezeichnung AS WaehrungText, * NOT MAPPED * dbo.Bank.Name * NOT MAPPED * dbo.Bank.IBAN * sender.bankDetails.IBAN * + N' BIC ' + dbo.Bank.BIC AS Bankverbindung, * dbo.Rechnungerstellt.CompanyID, * NOT MAPPED * '*' + dbo.Rechnungerstellt.FIXRechnungsNrComputet + '*' AS BarCodeRechnungsNr, * NOT MAPPED * dbo.Rechnungerstellt.StornoGrund, * NOT MAPPED * dbo.Bank.BankID * NOT MAPPED ===== Implementation plan ===== * **+** Fetch invoices from the DB * **+** assure DB access (local or on Azure) * ''jdbc:sqlserver:/ /it-transspedi.database.windows.net:1433;databaseName=TransportManagamentSystem_Kopieren'' * **+** write JDBC start code (connection etc) * **-** header data * **+** using dummies * **+** using data from DB * **-** getting ALL data from DB * **-** check validity (MUST-fields etc) * **-** check correctness of ALL fields * **-** fetch seller data * **+** using dummies * **+** using data from DB * **-** getting ALL data from DB * **-** check validity (MUST-fields etc) * **-** check correctness of ALL fields * **-** fetch buyer data * **+** using dummies * **+** using data from DB * **-** getting ALL data from DB * **-** check validity (MUST-fields etc) * **-** check correctness of ALL fields * **-** fetch positions * **+** using dummies * **-** using data from DB * **-** getting ALL data from DB * **-** check validity (MUST-fields etc) * **-** check correctness of ALL fields * **-** validate invoice with our test routines * **-** write a validator which opens Rolf's PDFs and "reports" based on data from my code * "command-line" report * PDF ? * ... * min / max * ... * **-** validate * **-** validate with Mustang * **-** validate with other alternatives(?) * **-** add command-line options * **+** invoice ID * **+** invoice number * **+** input file name * **+** output file name * **-** output format ===== Questions ===== ==== Allgemein ==== ... ==== Kopfdaten ==== * **-** ''Adressen'' * **-** die Tabelle ''Adressen'' enthält kein Feld für Kontaktname. Das führt dazu das: * beim Sender nehme ich den Wert ''Firmeninhaber'' aus der Tabelle ''SYSCompany'' * beim Recipient nehme ich IMMER den leeren Wert * **-** Zahlungsbedingungen * man muss dafür sorgen, dass * auch "Lastschrift"-Rechnungen richtig verarbeitet werden * sonstige Zahlungsbedingungen richtig übernommen werden (als Text?) * im Moment wird Fälligkeitsdatum (DueDate) und Freitext (PaymentTermsDescription = txtKonditionComputed) geschrieben * **-** Leitweg-ID * Info zu Leitweg-ID * so was wie "Zuständige Stelle" beim Amt. Sorgt dafür, dass die Rechnung an den richtigen Bearbeiter geht. * Pflichtfeld, wenn die Rechnung an die öffentlichen Auftraggeber (B2G) ausgestellt wird * => bei B2B nicht relevant (kein Pflichtfeld?) * https://sevdesk.de/lexikon/leitweg-id/ * **-** Momentan schreibe ich IMMER einen leeren Wert. Ist das richtig? ==== Positionsdaten ==== * **-** Sortierung der Positionen * momentan sortiere ich nach ''Laden'' und dann nach ''AuftragsNrComputet'' * **-** ''Loeschen'' * **-** Löschkennzeichen ? * **-** soll ich es beachten? * **-** ''Steuersatz'' und Steuersatz-Kategorie * wie soll ich das richtig verarbeiten? * das Details View enthält momentan nur 19%, 7,7%, 0% und '''' * ich verarbeite es so: * wenn 0, dann Kategorie=Z * alles andere S * es gibt aber noch mehr Kategorien (z.B. "AE" => negativ) * s. auch "Common UNTDID 5305 Tax Category Codes" ===== ZUGFeRD ===== * Aktuelle Version: 2.4 (04.12.2025) * Specs * https://www.ferd-net.de/publikationen-produkte/publikationen/detailseite/zugferd-24-deutsch * Infopaket mit Spec-PDFs, Excels und Beispiel-Rechnungen * [[ZUGFeRD Spec]] * Siehe auch ''/media/diskstation/x/ossconsulting/_projects/zugferdForIttransspedi/specs/zugferd/'' ===== XRechnung ===== * Specs: * https://xeinkauf.de/xrechnung/versionen-und-bundles/ * Pflichtangaben einer XRechnung * Wie auch bei PDF- oder Papierrechnungen gibt es einige Angaben, die auf keinen Fall fehlen dürfen. Dazu gehören: * Vollständiger Name und Anschrift des Rechnungsausstellers sowie des Rechnungsempfängers * Steuernummer oder Umsatzsteuer-ID des Rechnungsstellers * Rechnungsdatum * Fortlaufende Rechnungsnummer * Rechnungsposition (Menge und Art der Lieferung oder Art und Umfang der Leistung) * Leistungszeitraum * Rechnungsbetrag sowie Steuerbetrag und geltender Umsatzsteuersatz * ggf. Hinweis auf Klein­unternehmer­regelung, Gutschrift, Steuerbefreiung oder Reverse Charge * sowie * Leitweg-ID für den Versand an öffentliche Auftraggeber * Bankverbindungsdaten * Zahlungsbedingungen inkl. Zahlungsziel und Fälligkeit * Kontaktdaten (mindestens E-Mail-Adresse) des Rechnungsausstellers * ggf. Lieferantennummer und Bestellnummer * Leitweg-ID: * Info zu Leitweg-ID * so was wie "Zuständige Stelle" beim Amt. Sorgt dafür, dass die Rechnung an den richtigen Bearbeiter geht. * Pflichtfeld, wenn die Rechnung an die öffentlichen Auftraggeber (B2G) ausgestellt wird * => bei B2B nicht relevant (kein Pflichtfeld?) * https://sevdesk.de/lexikon/leitweg-id/ * Mengeneinheit: * BR-CL-23 * Der Fehlercode BR-CL-23 bei einer XRechnung bedeutet, dass die verwendete Mengeneinheit ungültig ist. XRechnungen akzeptieren für Positionsmengen keinen beliebigen Text (wie etwa „Stk.“, „Stück“ oder „Pauschale“). Ursache: Die Einheit entspricht nicht dem verpflichtenden Standard UN/ECE Recommendation 20 (Codes for Units of Measure). * Lösung: * Sie müssen für jede Rechnungsposition einen offiziellen Maßeinheitencode der UN/ECE verwenden. Typische Beispiele sind: * C62 für Stück * HUR für Stunde * KGM für Kilogramm * LTR für Liter * DAY für Tag * MTR für Meter * Alle aktuell erlaubten Codes sind : https://unece.org/trade/documents/revision-17-annexes-i-iii (Stand 2021) * Tools * "Offizielle" Validatoren: * https://e-rechnung-vorlage.de/xrechnung-zugferd-validator/ * https://www.elster.de/eportal/e-rechnung * https://erechnungsvalidator.service-bw.de/ * Diverse: * https://xrechnungzentrale.de/ * https://erechnungs-validator.de/e-rechnung-validieren/ ===== Data saved in IT-TransSpedi ===== -- also 52009 select * from View_Report_RechnungsKopf where RIDAuto=52286 select * from View_Report_RechnungsDetail where RIDAuto=52286 select * from View_Report_Rechnung_Betraege where RIDAuto=52286 select * from SYSCompany where CompanyID=8 select * from Bank select * from Adressen where CompanyId=8 CREATE VIEW dbo.View_Report_RechnungsKopf AS SELECT dbo.Rechnungerstellt.RIDAuto, dbo.Rechnungerstellt.FIXRechnungsNrComputet, Adressen_1.FIXKundenNrFormat AS FixKundenNrClient, dbo.Rechnungerstellt.RIDAutoComputed, Adressen_1.AdressID AS RECKundenID, Adressen_1.FirmenName AS RECFirma, Adressen_1.Zusatz AS RECZusatz, Adressen_1.StrasseNr AS RECStrasse, Adressen_1.LandText AS RECLand, Adressen_1.SteuerNr AS RECSteuerID, Adressen_1.DebitorDatev AS RECDatevNr, Adressen_1.AdressAnschrift AS RECAnschrift, dbo.SYSCompany.FirmenName AS EFirma, dbo.SYSCompany.Zusatz AS EZusatz, dbo.SYSCompany.Strasse AS EStrasse, dbo.SYSCompany.Postfach, dbo.SYSCompany.Plz AS EPlz, dbo.SYSCompany.Ort AS EOrt, dbo.SYSCompany.TelefonZentrale AS ETelefon, dbo.SYSCompany.Fax AS EFax, dbo.SYSCompany.Email AS EEmail, dbo.SYSCompany.Homepage AS EWWW, dbo.SYSCompany.FirmenInhaber AS EInhaben, dbo.SYSCompany.GerichtsOrt AS EGerichtsOrt, dbo.SYSCompany.HandelsNr AS EHandelsNr, dbo.SYSCompany.SteuerNr AS ESteuerID, dbo.SYSCompany.ElogoImag AS EImage, dbo.SYSCompany.AnschriftComputed, dbo.Rechnungerstellt.RDatum, dbo.Rechnungerstellt.Faellig, dbo.Rechnungerstellt.Referenz, dbo.Rechnungerstellt.Bemerkung, dbo.Rechnungerstellt.Reversecharge, dbo.Rechnungerstellt.Bezahlt, CASE WHEN txtKonditionComputed = '0 Bankeinzug' THEN 'Bankeinzug' ELSE txtKonditionComputed END AS txtKonditionComputed, dbo.SYSCompany.WaehrungText AS Zeichen, dbo.Waehrung.Waehrungsbezeichnung AS WaehrungText, dbo.Bank.Name + N' - IBAN ' + dbo.Bank.IBAN + N' BIC ' + dbo.Bank.BIC AS Bankverbindung, dbo.Rechnungerstellt.CompanyID, '*' + dbo.Rechnungerstellt.FIXRechnungsNrComputet + '*' AS BarCodeRechnungsNr, dbo.Rechnungerstellt.StornoGrund, dbo.Bank.BankID FROM dbo.Rechnungerstellt LEFT OUTER JOIN dbo.Waehrung RIGHT OUTER JOIN dbo.SYSCompany ON dbo.Waehrung.WaehrungsID = dbo.SYSCompany.WaehrungID ON dbo.Rechnungerstellt.EigeneFirma = dbo.SYSCompany.CompanyID LEFT OUTER JOIN dbo.Zahlungskonditionen RIGHT OUTER JOIN dbo.Bank RIGHT OUTER JOIN dbo.Adressen AS Adressen_1 ON dbo.Bank.BankID = Adressen_1.BankID ON dbo.Zahlungskonditionen.KonID = Adressen_1.KonditionD ON dbo.Rechnungerstellt.KKID = Adressen_1.AdressID ===== PDF/A-3 conversion ===== * The best way at the moment is to use Free Spire.PDF for Java: * https://dev.to/codesharing/convert-pdf-to-pdf-a-with-a-free-java-api-4nm7 * Apache PDFBox: * https://github.com/ETDA/PdfAConverter/blob/master/src/main/java/pdfbox/ConvertPDFtoA3.java * Validators: * https://www.pdfforge.org/online/de/pdfa-validieren * Some other links: * https://www.baeldung.com/pdf-conversions-java ===== Misc ===== * **-** Bibliotheken für e-Invoicing * https://www.mustangproject.org/ * newest Version 2.23.1 from 21.05.2026 (7 days ago!) * Apache 2 license, free for use in commercial and noncommercial applications * integration possibilities: * command-line * Java library * server with REST-API * https://github.com/codebarista-de/gallop * relatively new * only XRechnung * only two supporters * https://konik.io/ * veraltet, letzte Version 1.3.2 von 2018 * **-** Links * Mustangproject: https://www.mustangproject.org/?lang=de * ZUGFeRD: * https://de.wikipedia.org/wiki/ZUGFeRD * https://e-rechnung-bund.de/faq/was-ist-eine-zugferd-rechnung-wofur-steht-zugferd/ * https://www.zugferd-community.net/ * XRechnung: https://e-rechnung-bund.de/standard-xrechnung-3-0-1/ * https://zugferd.org * libraries list: https://zugferd.org/e-invoicing/1.0.0/index.en.html * Articles and infos * https://taxfix.de/ratgeber/selbststaendige/zugferd/ * Tutotial: https://www.nterra.com/blog/technologie/tutorial-zugferd-xrechnung-mit-java/ * [[https://www.heise.de/news/Jedes-dritte-Unternehmen-hat-noch-nie-eine-E-Rechnung-verschickt-11315569.html|Jedes dritte Unternehmen hat noch nie eine E-Rechnung verschickt]] by heise.de * Zitate: * Nur 24 Prozent der Befragten gaben an, den Prozess abgeschlossen zu haben. * 38 Prozent befinden sich noch mittendrin, * 29 Prozent haben noch gar nicht begonnen oder stehen erst am Anfang der Planung. * **-** Misc * Validator: https://erechnungsvalidator.service-bw.de/ * Open Source Software: * https://www.fakturama.info