Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 17 Min.

Pflichterfüllung

.NET-Entwickler können die ab 2025 im B2B-Markt einsetzende Pflicht zur strukturierten elektronischen Rechnungsstellung und -annahme mit Open-Source-Lösungen erfüllen.
© dotnetpro
Das Thema strukturierter elektronischer Rechnungen (Electronic Billing, E-Invoicing) beschäftigt mich schon seit sehr vielen Jahren. 1998 schrieb ich dazu meine Diplomarbeit im Rahmen meines Wirtschaftsinformatikstudiums an der Universität Essen in Zusammenarbeit mit der damaligen Essener Telefongesellschaft o.tel.o (siehe auch [1]). Meine Diplomarbeit (siehe [2]) habe ich an mehrere Dutzend Firmen verkaufen können, die sich für meine Ideen interessierten. Auch mein erster Fachbeitrag in der Zeitschrift iX in Ausgabe 9/1998 handelte davon. In dem seither vergangenen ­guten Vierteljahrhundert passierte allerdings zunächst lange Zeit fast nichts. Erst in den letzten Jahren hat das Thema etwas Fahrt aufgenommen, aber nur im B2G- und B2B-Markt (siehe Kasten Zu wenig hat sich getan im B2C-Markt).

Zu wenig hat sich getan im B2C-Markt

Zu den Ideen in meiner Diplomarbeit gehörte auch ein effi­zienterer Weg für die Bezahlung von Rechnungen durch Endverbraucher. Rechnungssteller wie Telekommunikationsgesellschaften, Einzelhandelsgeschäfte, Ärzte und Behörden könnten Rechnungen elektronisch an die Bank des Kunden schicken. Die Bank benachrichtigt den Rechnungsempfänger, sie ­präsentiert diesem die Rechnung auf einer Website, und der Zahlungspflichtige kann mit einem Mausklick die Rechnung bestätigen oder zurückweisen. Bei diesem Prozess entfällt nicht nur der Versand der Rechnung, sondern auch das lästige und fehler­anfällige Abtippen von Zahlungsempfänger, Kontodaten, Betrag und Rechnungsnummer. Der Zahlungsempfänger könnte sicher sein, dass er alle notwendigen Angaben für die automa­tisierte Weiterverarbeitung auf der Überweisung erhält. Der Rechnungsempfänger hätte automatisch bei seiner Bank ein elektronisches Rechnungsarchiv; den Buchungsposi­tionen auf dem Konto wäre direkt ein Beleg zugeordnet.

Alternativen zu EDI

Schon seit den 1970er-Jahren gibt es das Konzept Electronic Data Interchange (EDI) [3] mit zahlreichen Standards wie EDIFACT und ODETTE, mit denen Unternehmen auch elektronische Rechnungen austauschen können. Alle diese EDI-Standards waren jedoch komplex in der Umsetzung, entsprechend kostenaufwendig und nur zwischen Großunternehmen verbreitet. Daher entstanden Ende der 1990er-Jahre einige Ideen zur Gestaltung des elektronischen Rechnungsprozesses auf Basis von XML-Daten über das Internet, die nicht nur zwischen Unternehmen, sondern auch zwischen Unternehmen und Endverbrauchern geeignet waren.

Schleppende Akzeptanz von PDF-Rechnungen

Viele Jahre war der elektronische Rechnungsversand in Deutschland an die Verwendung einer qualifizierten elektronischen Signatur gebunden. Erst durch das Steuervereinfachungsgesetz 2011 sind seit dem 1. Juli 2011 elektronische Rechnungen ohne Signatur erlaubt [4] und der Papierrechnung gleichgestellt. Auch danach musste aber das Unternehmen innerbetriebliche Kontrollverfahren etablieren, um die Echtheit der Herkunft, die Unversehrtheit des Inhalts und die Lesbarkeit der Rechnung zu gewährleisten. Das hat viele Unternehmen überfordert, und so verlangten sie von ihren Lieferanten stets eine Rechnung auf Papier. Erst die Corona-Pandemie gab bei den Unternehmen flächendeckend den Impuls, Rechnungen als PDF-Dokument per E-Mail anzunehmen.Eine PDF-Rechnung vereinfacht zwar den Versand, aber nicht die Erfassung in der Buchhaltung. Meist werden PDF-Rechnungen manuell erfasst, manchmal durch Screen-Scraping-Software ausgewertet, die aber meist erst angelernt werden muss. Der Einsatz von künstlicher Intelligenz kann dazu beitragen, die Erfolgsquote beim Screen Scraping deutlich erhöhen (siehe [5] und [6]). Das Thema entwickelt sich aber gerade erst noch.

ZUGFeRD

Dabei gibt es in Deutschland bereits seit dem Jahr 2014 einen Standard für strukturierte elektronische Rechnungen im XML-Format mit dem eigenwilligen Namen ZUGFeRD. Dieses Akronym steht für „Zentraler User Guide des Forums elektronische Rechnung Deutschland“ [7]. Das Forum elek­tronische Rechnung Deutschland wurde unter dem Dach der vom Bundesministerium für Wirtschaft und Energie (BMWi) auf Beschluss des Deutschen Bundestages geförderten Arbeitsgemeinschaft für wirtschaftliche Verwaltung (AWV) gegründet. ZUGFeRD basiert auf dem internationalen Standard Cross Industry Invoice (CII), das durch das United Nations Centre for Trade Facilitation and Electronic Business (UN/CEFACT), also dem Zentrum der Vereinten Nationen für Handelserleichterungen und elektronische Geschäftsprozesse, entwickelt wurde.Die XML-Daten werden bei ZUGFeRD in ein PDF-Dokument (PDF/A-3) als Anhang integriert, sodass der XML-Inhalt mit einem einfachen PDF-Viewer entnommen und betrachtet werden kann (siehe Bild 1). Man spricht daher von einem hybriden Format.
Beispiel für eine ZUGFeRD-Rechnung: Ein PDF mit XML-Anhang – hier in Adobe Acrobat Reader, wobei die enthaltene E-Invoice mit Visual Studio Code geöffnet wurde, weil dies die Standardverknüpfung auf dem System für XML-Dateien war (Bild 1) © Autor
Nach der ersten 2014er-Version von ZUGFeRD erschienen die Versionen 2.0 im März 2019 und 2.1 im März 2020. Hier erfolgte dann eine Angleichung an das parallel entwickelte französische Format Factur-X 1.0. Oft wird auch in Deutschland daher vom Factur-X-Format statt ZUGFeRD gesprochen.ZUGFeRD (aktuelle Version: 2.3 vom 18. September 2024) definiert mittlerweile sechs verschiedene Profile für den XML-Inhalt: Minimum, Basic WL, Basic, EN 16931 (ehemals Comfort genannt), Extended und XRechnung, wobei die ersten beiden XML-Formate in Deutschland umsatzsteuerlich nicht als gültige Rechnungen anerkannt sind.

XRechnung

Parallel zu ZUGFeRD ist das Format XRechnung entstanden. XRechnung ist ein reines XML-Format, welches der EU-Norm 16931 folgt. Diese Norm entstand durch die vom Europäischen Parlament und dem Rat der Europäischen Union am 16. April 2014 verabschiedete EU-Richtlinie 2014/55/EU mit dem Ziel, eine gemeinsame europaweit gültige Norm für das semantische Datenmodell der Kernelemente einer elektronischen Rechnung (also eine europäische Norm für die elektronische Rechnungsstellung) zu etablieren. Die Norm wurde von dem Europäischen Komitee für Normung (CEN) entwickelt und am 17. Oktober 2017 im Amtsblatt der EU als EN 16931 1:2017 veröffentlicht. Sie gibt einen Rahmen vor, lässt Mitgliedsstaaten jedoch eigene Spielräume für die rechtliche, organisatorische und technische Ausgestaltung bei Einführung der elektronischen Rechnung. Unter der Voraussetzung, dass die Ausgestaltung nationaler Standards nicht den Vorgaben der europäischen Richtlinie und Norm widerspricht, ist es jedem Mitgliedstaat gestattet, eigene Erweiterungen (Core Invoice Usage Specifications – CIUS) zu entwickeln. So gibt es in Deutschland zum Beispiel eine Erweiterung für Skonto [8], das in anderen Ländern nicht üblich ist.Die deutsche Version dieser EU-Norm, XRechnung, wurde am 22. Juni 2017 vom IT-Planungsrat für Bund und Länder in der Version 1.0 beschlossen. Seit dem 1. Januar 2019 wird XRechnung von der Koordinierungsstelle für IT-Standards (KoSIT) [9] verantwortet.XRechnungen verwenden als XML-Dialekt entweder den XML-Standard Universal Business Language (UBL) mit Wurzeltag <Invoice> oder Cross Industry Invoice (CII, wie bei ZUGFeRD) mit Wurzeltag <CrossIndustryInvoice>, siehe auch [10]. XRechnungen können Anhänge enthalten, zum Beispiel Lieferscheine, Reisekostenbelege oder auch die Rechnung noch mal als PDF-Dokument.Die Bundesbehörden wurden in Deutschland zum Vorreiter bei den elektronischen Rechnungen: Seit dem 27. November 2018 müssen die obersten Bundesbehörden und die Verfassungsorgane des Bundes XRechnungen empfangen können. Seit dem 27. November 2019 gilt dies für alle anderen Bundesbehörden und seit dem 18. April 2020 auch für die Landesbehörden. Seit dem 27. November 2020 sind Lieferanten des Bundes verpflichtet, die B2G-Rechnungsstellung im Rahmen öffentlicher Aufträge für alle Beträge ab 1000 Euro per XRechnung vorzunehmen. Während in einigen Bundesländern auch entsprechende Verpflichtungen auf Landesebene gelten (zum Beispiel Bremen, Baden-Württemberg, Saarland, Hessen, Rheinland-Pfalz), sind in anderen Bundesländern (zum Beispiel Nordrhein-Westfalen, Berlin, Bayern) Papier- und PDF-Rechnungen weiterhin grundsätzlich erlaubt. Behörden steht es aber frei, eine entsprechende Verpflichtung mit dem Lieferanten vertraglich zu vereinbaren.Erwähnt werden muss aber auch, dass innerhalb der EU andere Staaten Deutschland schon sehr weit voraus waren: E-Invoicing-Pflicht für B2G gilt in Dänemark seit dem Jahr 2005 (auf Basis von UBL 1.0 aus dem Jahr 2004), in Schweden seit 2008, Spanien und Finnland seit 2010 sowie seit 2014 in Italien und Österreich.

E-Rechnungspflicht für B2B-Rechnungen

Das Gesetz zur Stärkung von Wachstumschancen, Investitionen und Innovation sowie Steuervereinfachung und Steuerfairness (Wachstumschancengesetz) 2024 [11] erweitert die elektronische Rechnungspflicht nun in mehreren Schritten auch auf die Rechnungsstellung zwischen Unternehmen (B2B-Markt), was auch andere Länder schon zuvor eingeführt haben, zum Beispiel Italien seit dem 1. Januar 2019 (dort muss die maschinenlesbare Rechnung auch das Finanzamt gesendet werden). Das deutsche Wachstumschancengesetz wurde am 17. November 2023 im Bundestag beschlossen, kam aber dann in den Vermittlungsausschuss und passierte den Bundesrat erst am 23. März 2024.Elektronische Rechnung im Sinne des Wachstumschancengesetzes bedeutet dabei eine strukturierte elektronische Rechnung gemäß der EU-Norm 16931. Diese erlaubt die Formate ZUGFeRD (ab Version 2.0.1) und XRechnung/Factur-X, aber auch andere europäische Formate wie das italienische „FatturaPA. Bei hybriden Formaten gilt im Zweifelsfall die eingebettete XML-Datei als Original. Der Rechnungsempfänger muss diese also immer prüfen und darf sich nicht auf das verlassen, was die PDF-Datei anzeigt. EDI-Verfahren bleiben erlaubt, sofern ein Export der Daten in einer der EU-Norm 16931 gemäßen Form möglich ist.Einen bestimmten Übertragungsweg sieht das Wachstumschancengesetz nicht vor, daher ist die Übertragung der elektronischen Rechnung per E-Mail möglich, auch wenn E-Mail keine Zustellungsgarantie bietet und für Phishing anfällig ist. Für die angedachte zukünftige Umsatzsteuermeldung (siehe EU-Projekt „VAT in the Digital Age – ViDA) [12], bei der jede einzelne Rechnung unverzüglich an das Finanzamt geht (wie heute schon in Italien, Rumänien und der Türkei), wird wohl eine sicherere und strukturiertere Übertragungsmethode verpflichtend sein. Infrage kommt hier Pan-European Public Procurement OnLine (PEPPOL), siehe [13].Die Pflicht gilt für Rechnungen, Stornorechnungen und Gutschriften zwischen inländischen Unternehmen, auch für Kleinunternehmer beziehungsweise Land- und Forstwirte. Die E-Rechnungs-Pflicht gilt nicht:
  • wenn der Betrag kleiner als 250 Euro ist,
  • für Fahrausweise,
  • für Leistungen, die nach § 4 Nummer 8 bis 29 UStG steuerfrei sind (zum Beispiel Bankgeschäfte, Vermietung, Gesundheits- und Pflegedienstleistungen, Schulen),
  • wenn Endverbraucher beteiligt sind.
Unternehmen dürfen aber elektronische Rechnungen an Endverbraucher senden, insofern diese ausdrücklich zustimmen. Nicht durch das Gesetz betroffen sind andere kaufmännische Dokumente wie Bestellungen, Auftragsbestätigungen, Lieferscheine und Mahnungen, auch wenn es dafür schon elektronische Lösungen gibt.Die Pflicht gilt grundsätzlich ab dem 1. Januar 2025. Es gibt aber großzügige Übergangsregelungen bis Ende des Jahres 2027:
  • Bis Ende 2026 dürfen Rechnungen weiterhin auf Papier und elektronische Rechnungen in anderen Formaten (zum Beispiel reines PDF) versendet werden.
  • Bis Ende 2027 ist beides immer noch erlaubt, falls der Rechnungsaussteller einen Vorjahresumsatz (Gesamtumsatz nach § 19 Abs. 3 UStG) von maximal 800 000 Euro hat.
  • Erst ab 2028 sind die strukturierten elektronischen Rechnungen dann wirklich verpflichtend.
Im Netz kursieren auch abweichende Zeitpläne, zum Beispiel auf der Web­site des Buchhaltungssoftware-Anbieters Sage [14]. Die obigen Angaben ­basieren auf einem Beitrag von Haufe [15], der dem rechtlichen Stand vom März 2024 [11] entspricht.Für Rechnungsempfänger sind die Regeln strenger: Alle in Deutschland ansässigen Unternehmen müssen bereits ab dem 1. Januar 2025 strukturierte elektronische Rechnungen empfangen können. Wenn eine E-Mail mit einer XML-Datei eingeht, reicht es, diese in einem beliebigen Texteditor zu öffnen. In der Praxis wird man sich ein Werkzeug zur Visualisierung beschaffen. Ein solches wollte ursprünglich die Bundesregierung bereitstellen, man ist davon aber wieder abgekommen. Es gibt aber ein vom Bundesministerium für Bildung und Forschung (BMBF) via Prototype Fund [16] gefördertes kostenfreies Open-Source-Werkzeug [17] mit Namen „Quba E-Rechnungs-View (kurz: Quba-Viewer) [18], das alle gängigen elektronischen Rechnungsformate darstellen kann (siehe Bild 2). Quba-Viewer ist eine Cross-Platform-Anwendung für Windows, macOS und Linux auf Basis von JavaScript, Vue.js 3 und Electron.
Ausschnitt aus einer XRechnung im Quba-Viewer (Bild 2) © Autor
Bild 2 zeigt auch, dass XRechnung zahlreiche Felder bietet, die optional sind, zum Beispiel für den Abrechnungszeitraum, Projekt- und Vertragsnummern sowie eine Liste früherer Rechnungen.Neben dem Quba-Viewer gibt es für die XRechnung zahlreiche andere Werkzeuge im Netz, zum Beispiel den Validator für XRechnung unter [19].

.NET-Bibliotheken für strukturierte ­elektronische Rechnungen

Gängige kaufmännische Programme bieten längst Unterstützung für ZUGFeRD und XRechnung. Eine Herausforderung gibt es für Unternehmen,
  • die nicht mehr gewartete Programme einsetzen,
  • Rechnungen mit eigener Software generieren oder
  • Rechnungen mit eigener Software automatisiert auswerten.
Die deutsche .NET-Gemeinde hat drei Lösungen hervorgebracht:1. ZUGFeRD.NET [20], als NuGet-Paket unter [21]2. Aloaha ZUGFeRD SDK [22], als NuGet-Paket unter [23]3. ZUGFeRD-csharp [24], als NuGet-Paket unter [25]Lösung 1 ist leider 2015 in der Entwicklung stehen geblieben. Bei den Verbleibenden liegt das kostenlose ZUGFeRD-­csharp mit 367 000 NuGet-Downloads klar vor dem kostenpflichtigen Aloaha ZUGFeRD SDK (60 000 Downloads). ZUGFeRD-csharp kann (ungeachtet des Namens) auch XRechnung, da XRechnung ja, wie weiter oben dargestellt, inzwischen ein Profil innerhalb des ZUGFeRD-Standards ist.Die hier im Folgenden besprochene Bibliothek ZUGFeRD-csharp läuft in allen im Markt relevanten .NET-Versionen, also auf dem klassischen .NET Framework 4.6.1 sowie im modernen .NET ab .NET Core 2.0. Eine Liste von Lösungen für andere Sprachen/Frameworks (zum Beispiel Python, PHP, C++, Java und Delphi) zeigt die ZUGFeRD-Website unter [26].

E-Rechnung erstellen mit ZUGFeRD-csharp

Listing 1 zeigt den Kern der Generierung einer XRechnung ­unter Einsatz von ZUGFeRD-csharp: Man erstellt zunächst ­eine Instanz der zentralen Klasse InvoiceDescriptor mit der statischen Methode InvoiceDescriptor.CreateInvoice() unter Angabe der Rechnungsnummer, des Rechnungsdatums und der Währung.
Listing 1: Erstellung einer strukturierten elektronischen Rechnung mit der Klasse InvoiceDescriptor
/// <summary>
/// Erstellt eine E-Rechnung mit ZUGFeRD-csharp
/// </summary>
private InvoiceDescriptor CreateERechnung(
    RE_Rechnungen re, P_Partner kunde, AG_Angebote ag)
{
  #region --- Ermitteln einiger Werte aus den 
  #Eingangsdaten
  int zahlfristInTagen = re.RE_Zahlfrist ?? 
    STANDARDZAHLFRIST;
  DateTime zahlbarBis = re.RE_DAT.Value.AddDays(
    zahlfristInTagen);
  decimal summeNetto = re.RP_RechnungsPositionen.Sum(
    x => x.RP_Summe.GetValueOrDefault());
  decimal ust = summeNetto * 
    ((re.UST_Satz.GetValueOrDefault() / 100m));
  decimal summeBrutto = summeNetto + ust;
  #endregion
 
  InvoiceDescriptor desc = InvoiceDescriptor.
    CreateInvoice("R-" + re.RE_ID.ToString(), 
    re.RE_DAT.Value, CurrencyCodes.EUR);
  desc.BusinessProcess = "urn:fdc:peppol.eu:2017:
    poacc:billing:01:1.0"; // Neu ab XRechnung 3.0.1
  
  #region --- Kopfdaten der Rechnung
  if (ag != null) // Es gab ein Angebot zu der Rechnung
  {
    desc.ReferenceOrderNo = 
      ag.LeitwegID; // Leitweg-ID für Behörden !!!
    desc.AddNote(re.RE_Grund);
    desc.AddNote("Angebotsnummer: " + ag.AG_GanzeID);
    if (ag?.AG_AuftragsDatum != null)
    {
      desc.AddNote("Ihr Auftrag vom " + 
        ag.AG_AuftragsDatum?.ToShortDateString());
      desc.OrderDate = ag.AG_AuftragsDatum;
    }
    if (ag?.AG_AuftragsNummer != null)
    {
      {
        desc.AddNote("Ihre Auftragsnummer: " 
          + ag.AG_AuftragsNummer);
        desc.OrderNo = ag.AG_AuftragsNummer;
      }
    }
  }
 
  desc.AddNote("Falls Sie mehrere Rechnungen von uns 
    erhalten haben, zahlen Sie diese unbedingt getrennt 
    unter Angabe der jeweiligen Rechnungsnummer, da die 
    Buchhaltung vollautomatisiert ist. Zahlungsavis 
    können nicht verarbeitet werden.");
  desc.AddNote("Bitte beachten Sie, dass der deutsche 
    Gesetzgeber uns verpflichtet, alle Nebenleistungen 
    wie zum Beispiel Reise- und Hotelkosten sowie 
    Fachbücher zum gleichen Umsatzsteuersatz wie die 
    Hauptleistung weiter zu berechnen, selbst wenn 
    dafür ursprünglich ein anderer Steuersatz galt.");
  #endregion
 
  #region --- Informationen über den Rechnungssteller
  desc.SetSeller(
    name: "www.IT-Visions.de Dr. Holger Schwichtenberg",
    postcode: "45257",
    city: "Essen",
    street: "Fahrenberg 40b",
    country: CountryCodes.DE,
    id: "",
    globalID: new GlobalID(
      GlobalIDSchemeIdentifiers.DUNS, "341344246")
  );
 
  desc.SetSellerContact(
    name: "Dr. Holger Schwichtenberg",
    orgunit: "Buchhaltung",
    emailAddress: "Buchhaltung@IT-Visions.de",
    phoneno: "+4920164959044"
  );
  desc.SellerElectronicAddress = new ElectronicAddress() 
      // Neu ab XRechnung 3.0.1
  {
    ElectronicAddressSchemeID = ElectronicAddressScheme
      Identifiers.EM, // EM = E-Mail
    Address = "Buchhaltung@IT-Visions.de"
  };
 
  desc.AddSellerTaxRegistration("112/5392/5120", 
    TaxRegistrationSchemeID.FC);
  desc.AddSellerTaxRegistration("DE 187321081", 
    TaxRegistrationSchemeID.VA);
  #endregion
 
  #region --- Informationen über den Rechnungsempfänger
  desc.SetBuyer(name: kunde.P_Firma,
    postcode: kunde.P_PLZ,
    city: kunde.P_Ort,
    street: kunde.P_Strasse,
    country: CountryCodes.DE,
    id: kunde.P_ID.ToString());
 
  desc.BuyerContact = new Contact()
  {
    Name = kunde.P_Vorname + " " + kunde.P_Name,
    EmailAddress = kunde.P_EMail,
    PhoneNo = kunde.P_Telefon
  };
 
  desc.BuyerElectronicAddress = new ElectronicAddress() 
      // Neu ab XRechnung 3.0.1
  {
    ElectronicAddressSchemeID = 
      ElectronicAddressSchemeIdentifiers.EM, 
      // EM = E-Mail
    Address = kunde.P_EMail
  };
  #endregion
 
  #region --- Zahlungsbedingungen
  desc.SetTradePaymentTerms("Bitte überweisen Sie den 
    Betrag binnen " + zahlfristInTagen + " Tagen ohne 
    Abzüge auf unten genanntes Konto. Bitte beachten 
    Sie, dass Sie nach §286 BGB automatisch in Verzug 
    kommen.", zahlbarBis); 
      // wird sich in kommender Version ändern in 
      // AATradePaymentTerms()
  desc.SetPaymentMeans(PaymentMeansTypeCodes.
    SEPACreditTransfer, "Zahlung per SEPA-Überweisung.");
  desc.AddCreditorFinancialAccount( 
    iban:"DE57360700240109002600", bic: "DEUTDEDBESS", 
    name: "Deutsche Bank Essen");
  desc.AddApplicableTradeTax(
    basisAmount: summeNetto,
    percent: (decimal)re.UST_Satz, // 19.0 oder 7.0
    typeCode: TaxTypes.VAT, // Umsatzsteuer
    categoryCode: re.UST_Satz == 0 ? 
    TaxCategoryCodes.AE : TaxCategoryCodes.S 
      // "Reverse Charge" oder "Standard Tax Rate"
  );
  #endregion
 
  #region --- Rechnungspositionen einfügen
  foreach (var rp in re.RP_RechnungsPositionen)
  {
    desc.AddTradeLineItem(
      name: rp.RP_Text,
      unitCode: QuantityCodes.H87, 
        // H87 = "Stück" siehe https://unece.org/trade/
        // documents/2021/06/uncefact-rec20-0
      billedQuantity: (decimal)rp.RP_Menge.Value,
      netUnitPrice: (decimal)rp.RP_Betrag.Value,
      taxType: TaxTypes.VAT,
      categoryCode: re.UST_Satz == 0 ? 
      TaxCategoryCodes.AE : TaxCategoryCodes.S, 
        // "Reverse Charge" oder "Standard Tax Rate"
      taxPercent: (decimal)re.UST_Satz, 
        // 19.0 oder 7.0 oder 0.0
      lineTotalAmount: (decimal)rp.RP_Summe.Value 
        // optionale Angabe. Wenn vorhanden, muss das 
        // aber stimmen!
                          );
  }
  #endregion
 
  #region --- Gesamtwerte
  desc.SetTotals(
    lineTotalAmount: summeNetto,
    chargeTotalAmount: 0.0m,
    allowanceTotalAmount: 0.0m,
    taxBasisAmount: summeNetto,
    taxTotalAmount: ust,
    grandTotalAmount: summeBrutto,
    totalPrepaidAmount: 0.0m,
    duePayableAmount: summeBrutto
   );
  #endregion
 
  return desc;
} 
Anschließend setzt man mit AddNote() weitere Kopfdaten der Rechnung in reiner Textform. Im Feld ReferenceOrderNo kann man die Auftragsnummer speichern, die der Kunde bei seiner Bestellung genannt hat.Zu beachten ist, dass die Property- und Parameternamen in der .NET-Bibliothek zum Teil von den XML-Tags abweichen. So werden aus der Eigenschaft ReferenceOrderNo in der XRechnung die folgenden XML-Tags:

<ram:BuyerOrderReferencedDocument>
  <ram:IssuerAssignedID>991-80008-08
    ram:IssuerAssignedID>
ram:BuyerOrderReferencedDocument> 
Bei Rechnungen an Behörden muss (zumindest bisher) über die Property ReferenceOrderNo zwingend die jeweilige Leitweg-ID [27] des Rechnungsempfängers übermittelt werden. Dabei handelt es sich um eine 5- bis 46-stellige Zeichenfolge, inklusive einem oder zwei Bindestrichen, zum Beispiel 991-80008-08 für die Deutsche Bundesbank und 059540036036-31001-59 für die Stadt Witten an der Ruhr. Die Leitweg-ID ermöglicht eine elektronische Adressierung und Weiterleitung der XRechnung durch die zentralen Rechnungseingangsplattformen des Bundes [28] beziehungsweise der Länder (zum Beispiel Bremen unter [29] und Nordrhein-Westfalen unter [30]) an die ERP- beziehungsweise Freigabesysteme der angeschlossenen Behörden und Einrichtungen.Ein öffentlicher Rechnungsempfänger hat mindestens eine Leitweg-ID, es können jedoch mehrere Leitweg-IDs pro In­stitution genutzt werden. Rechnungsaussteller an Behörden benötigen hingegen keine eigene Leitweg-ID.Wenn übrigens Behörden neben der Leitweg-ID in der Bestellung noch eine weitere Bestellnummer angeben, muss diese mit AddNote() hinzugefügt werden.Seit XRechnung 3.0.1 gibt es ein Tag <URIUniversalCommunication>, bei dem man neben der E-Mail-Adresse auch andere Kommunikationsadressen wie zum Beispiel eine Leitweg-ID angeben kann. In Listing 1 sieht man E-Mail-Adressen bei den Zuweisungen SellerElectronicAddress und Buyer­ElectronicAddress. Das Bundesministerium des Innern und für Heimat schreibt dazu in [31]: „Nach Absprache mit Ihrem Lieferanten können Sie auch eine Leitweg-ID … angeben beziehungsweise diese einfordern.“ Das Ministerium selbst macht von der Leitweg-ID keinen Gebrauch, ­sondern legt in [32] und [33] fest, dass immer noch das Feld „BT-10“ (das ist das Tag <BuyerOrderReferencedDocument><Issuer­Assig­nedID>) für die Leitweg-ID verwendet werden muss.Die E-Rechnungsportale des Bundes und der Länder bieten außerdem die Option, eine Rechnung manuell in einer Webmaske zu erfassen und daraus die XRechnung zu generieren und zu versenden. Auch auf verschiedenen Internetseiten findet man XRechnungs-Generatoren, zum Beispiel [34]. Das ist eine Alternative für Unternehmen, die nur sehr selten Rechnungen versenden (etwa Kleingewerbetreibende). Man muss sich aber beim Einsatz solcher Tools bewusst sein, dass der Seitenbetreiber die Rechnungsdaten speichern, einsehen und/oder verwenden könnte.Als Nächstes folgen im Listing 1 Daten über den Rechnungssteller via SetSeller(), SetSellerContact() und SellerElectronic­Address sowie AddSellerTaxRegistration() zur Angabe von nationaler und internationaler Steuernummer. Daran schließen sich dann in entsprechender Weise SetBuyer() und die Befüllung von BuyerElec­tronic­Address für die Daten des Rechnungsempfängers an. Bei Rechnungssteller und Rechnungsempfänger kann man optional eine eindeutige Identifikationsnummer angeben, zum Beispiel wie in Listing 1 gezeigt eine Nummer aus dem Data Universal Numbering System (D-U-N-S) [35].Danach kommen
  • die Zahlungsbedingungen mit SetTradePaymentTerms() mit Angabe in Textform und optional auch mit Datum,
  • die Zahlungsart mit SetPaymentMeans(),
  • das Zielbankkonto mit AddCreditorFinancialAccount(),
  • Steuerinformationen mit AddApplicableTradeTax().
Alle Methoden mit Add im Namen können mehrfach aufgerufen werden, zum Beispiel wenn es mehrere Zielkonten oder verschiedene Steuersätze gibt. Vier Tage vor Fertigstellung dieses Beitrags wurde im Master-Branch des Projekts ZUGFeRD-csharp die Methode AddTradePaymentTerms() ergänzt und SetTradePaymentTerms() auf obsolet gesetzt [36].Die Entwicklung ist im Fluss, denn hier kann man in Deutschland statt einer menschenlesbaren Zeichenkette auch formale Skontobedingungen angeben, zum Beispiel für 3 Prozent Skonto innerhalb von 14 Tagen:

desc.SetTradePaymentTerms(
  "#SKONTO#TAGE=14#PROZENT=3.00# ", zahlbarBis); 
Beziehungsweise dann in der kommenden Version:

desc.AddTradePaymentTerms(
  "#SKONTO#TAGE=14#PROZENT=3.00# ", zahlbarBis); 
Daran schließen sich in Listing 1 die einzelnen Rechnungspositionen mit AddTradeLineItem() jeweils unter Angabe von Text, Menge, Nettopreis, Steuersatz und einem TaxCategoryCode an. Standard ist TaxCategoryCodes.S. Andere sind ­TaxCategoryCodes.AE für Reverse Charge und Tax­Cate­gory­Codes.E für Umsatzsteuerausnahmen. Der Programmcode in Listing 1 zeigt nur eine Fallunterscheidung zwischen Standard (S) und Reverse Charge. Anders als bei einer Papier- und PDF-Rechnung muss der Rechnungssteller für jede Rechnungsposition einzeln den Steuertatbestand deklarieren.Merkwürdig erscheint der UnitCode QuantityCodes.H87. Dies ist die Angabe für „Stück und basiert auf der Empfehlung 20 „Codes for Units of Measure Used in International Trade der United Nations Economic Commission for Europe (UNECE), siehe [37].Eine Rechnungsposition kann auch eine globale Identifikation besitzen, zum Beispiel eine European Article Number (EAN). Dies kommt in Listing 1 nicht vor, weil die dort in Rechnung gestellten Schulungsdienstleistungen und Nebenkosten keine EAN besitzen. Der EAN-Fall soll daher hier noch einmal an einem Beispiel gezeigt werden:

desc.AddTradeLineItem(name: "Trennblätter A4",
  unitCode: QuantityCodes.H87,
  sellerAssignedID: "TB100A4",
  id: new GlobalID(GlobalIDSchemeIdentifiers.EAN, 
    "400004672"),
  grossUnitPrice: 9.9m,
  netUnitPrice: 9.9m,
  billedQuantity: 20m,
  taxType: TaxTypes.VAT,
  categoryCode: TaxCategoryCodes.S,
  taxPercent: 19m
); 
Die Routine zur Erstellung der Instanz von InvoiceDescriptor endet mit dem Setzen der Summenwerte für Netto, Brutto und Umsatzsteuer mit der Methode SetTotals().Hier im Beispiel in Listing 1 sieht man einige konstante Daten aus unserem Unternehmen (www.IT-Visions.de) im Programmcode, die eigentlich in Konfigurationsdaten liegen. Das Inlining dieser Daten als Zeichenketten in Listing 1 dient der besseren Veranschaulichung der Nutzung der Bibliothek. Dynamisch aus der Datenbank geladene Daten (Rechnungsnummer, Rechnungsempfänger, Auftragsdaten, Rechnungspositionen und dergleichen) werden aus einem per Entity Framework befüllten Objektmodell genommen. Hieraus stammen die Typen P_Partner, AG_Angebote und RE_Rechnungen; diese gehören also nicht zur Bibliothek ZUGFeRD-csharp. Die XRechnung, die in Listing 1 erstellt wird, entspricht der PDF-Rechnung aus Bild 1 und dem XRechnung-XML-Dokument, das auszugsweise in Listing 2 dargestellt ist.
Listing 2: Auszüge aus den XML-Inhalten der XRechnung, die in Listing 1 erstellt wurde
<?xml version="1.0" encoding="utf-8"?>
<rsm:CrossIndustryInvoice xmlns:a="urn:un:unece:
    uncefact:data:standard:QualifiedDataType:100" 
    xmlns:rsm="urn:un:unece:uncefact:data:standard:
    CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:
    uncefact:data:standard:QualifiedDataType:100" 
    xmlns:ram="urn:un:unece:uncefact:data:standard:
    ReusableAggregateBusinessInformationEntity:100" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:udt="urn:un:unece:uncefact:data:standard:
    UnqualifiedDataType:100">
  <rsm:ExchangedDocumentContext>
    <ram:BusinessProcessSpecifiedDocumentContext
        Parameter>
      <ram:ID>urn:fdc:peppol.eu:2017:poacc:billing:
        01:1.0</ram:ID>
    </ram:BusinessProcessSpecifiedDocumentContext
      Parameter>
    <ram:GuidelineSpecifiedDocumentContextParameter>
      <ram:ID>urn:cen.eu:en16931:2017#compliant#urn:
        xeinkauf.de:kosit:xrechnung_3.0</ram:ID>
    </ram:GuidelineSpecifiedDocumentContextParameter>
  </rsm:ExchangedDocumentContext>
  <rsm:ExchangedDocument>
    <ram:ID>R-2200718</ram:ID>
    <ram:TypeCode>380</ram:TypeCode>
    <ram:IssueDateTime>
      <udt:DateTimeString 
        format="102">20240925</udt:DateTimeString>
    </ram:IssueDateTime>
    <ram:IncludedNote>
      <ram:Content>Schulung (In-House): 
        Umstieg von .NET 8.0 auf .NET 9.0
        Mo, 23.09.2024 bis Di, 24.09.2024 (2 Tage)
        Ort: Musterstraße 71, 12345 Musterstadt
        </ram:Content>
    </ram:IncludedNote>
    <ram:IncludedNote>
      <ram:Content>Angebotsnummer: A-2101869820
        </ram:Content>
    </ram:IncludedNote>
    <ram:IncludedNote>
      <ram:Content>Ihr Auftrag vom 01.08.2024 
        </ram:Content>
    </ram:IncludedNote>
    <ram:IncludedNote>
      <ram:Content>Ihre Auftragsnummer: 123-4567-89
        </ram:Content>
    </ram:IncludedNote>
    <ram:IncludedNote>
      <ram:Content>Falls Sie mehrere Rechnungen von 
        uns erhalten haben, zahlen Sie diese unbedingt 
        getrennt unter Angabe der jeweiligen 
        Rechnungsnummer, da die Buchhaltung 
        vollautomatisiert ist. Zahlungsavis können 
        nicht verarbeitet werden.</ram:Content>
    </ram:IncludedNote>
    <ram:IncludedNote>
      <ram:Content>Bitte beachten Sie, dass der 
        deutsche Gesetzgeber uns verpflichtet, alle 
        Nebenleistungen wie z.B. Reise- und 
        Hotelkosten sowie Fachbücher zum gleichen 
        Umsatzsteuersatz wie die Hauptleistung weiter 
        zu berechnen, selbst wenn dafür ursprünglich 
        ein anderer Steuersatz galt.</ram:Content>
    </ram:IncludedNote>
  
  ...
  <rsm:SupplyChainTradeTransaction>
    <ram:IncludedSupplyChainTradeLineItem>
      <ram:AssociatedDocumentLineDocument>
        <ram:LineID>1</ram:LineID>
      </ram:AssociatedDocumentLineDocument>
      <ram:SpecifiedTradeProduct>
        <ram:Name>Individuelle, maßgeschneiderte 
          Schulung vor Ort in Ihrem Unternehmen</ram:Name>
      </ram:SpecifiedTradeProduct>
      <ram:SpecifiedLineTradeAgreement>
        <ram:NetPriceProductTradePrice>
          <ram:ChargeAmount>1500.00</ram:ChargeAmount>
        </ram:NetPriceProductTradePrice>
      </ram:SpecifiedLineTradeAgreement>
      <ram:SpecifiedLineTradeDelivery>
        <ram:BilledQuantity unitCode="H87">2.0000
          </ram:BilledQuantity>
      </ram:SpecifiedLineTradeDelivery>
      <ram:SpecifiedLineTradeSettlement>
        <ram:ApplicableTradeTax>
          <ram:TypeCode>VAT</ram:TypeCode>
          <ram:CategoryCode>S</ram:CategoryCode>
          <ram:RateApplicablePercent>19.00
            </ram:RateApplicablePercent>
        </ram:ApplicableTradeTax>
        <ram:SpecifiedTradeSettlementLineMonetary
            Summation>
          <ram:LineTotalAmount>3000.00
            </ram:LineTotalAmount>
        </ram:SpecifiedTradeSettlementLineMonetary
          Summation>
      </ram:SpecifiedLineTradeSettlement>
    </ram:IncludedSupplyChainTradeLineItem>
    ...
    <ram:ApplicableHeaderTradeDelivery />
    <ram:ApplicableHeaderTradeSettlement>
      <ram:InvoiceCurrencyCode>EUR
        </ram:InvoiceCurrencyCode>
      <ram:SpecifiedTradeSettlementPaymentMeans>
        <ram:TypeCode>58</ram:TypeCode>
        <ram:Information>Zahlung per 
          SEPA-Überweisung.</ram:Information>
        <ram:PayeePartyCreditorFinancialAccount>
          <ram:IBANID>DE57360700240109002600
            </ram:IBANID>
          <ram:AccountName>Deutsche Bank Essen
            </ram:AccountName>
        </ram:PayeePartyCreditorFinancialAccount>
        <ram:PayeeSpecifiedCreditorFinancial
            Institution>
          <ram:BICID>DEUTDEDBESS</ram:BICID>
        </ram:PayeeSpecifiedCreditorFinancial
          Institution>
      </ram:SpecifiedTradeSettlementPaymentMeans>
      <ram:ApplicableTradeTax>
        <ram:CalculatedAmount>658.73
          </ram:CalculatedAmount>
        <ram:TypeCode>VAT</ram:TypeCode>
        <ram:BasisAmount>3467.00</ram:BasisAmount>
        <ram:CategoryCode>S</ram:CategoryCode>
        <ram:RateApplicablePercent>19.00
          </ram:RateApplicablePercent>
      </ram:ApplicableTradeTax>
      <ram:SpecifiedTradePaymentTerms>
        <ram:Description>Bitte überweisen Sie den 
          Betrag binnen 10 Tagen ohne Abzüge auf unten 
          genanntes Konto. Bitte beachten Sie, dass 
          Sie nach §286 BGB automatisch in Verzug 
          kommen.</ram:Description>
        <ram:DueDateDateTime>
          <udt:DateTimeString format="102">20241005
            </udt:DateTimeString>
        </ram:DueDateDateTime>
      </ram:SpecifiedTradePaymentTerms>
      <ram:SpecifiedTradeSettlementHeaderMonetary
          Summation>
        <ram:LineTotalAmount>3467.00
          </ram:LineTotalAmount>
        <ram:ChargeTotalAmount>0.00
          </ram:ChargeTotalAmount>
        <ram:AllowanceTotalAmount>0.00
          </ram:AllowanceTotalAmount>
        <ram:TaxBasisTotalAmount>3467.00
          </ram:TaxBasisTotalAmount>
        <ram:TaxTotalAmount currencyID="EUR">658.73
          </ram:TaxTotalAmount>
        <ram:GrandTotalAmount>4125.73
          </ram:GrandTotalAmount>
        <ram:TotalPrepaidAmount>0.00
          </ram:TotalPrepaidAmount>
        <ram:DuePayableAmount>4125.73
          </ram:DuePayableAmount>
      </ram:SpecifiedTradeSettlementHeaderMonetary
        Summation>
    </ram:ApplicableHeaderTradeSettlement>
  </rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>  

Speichern der elektronischen Rechnung

Eine elektronische Rechnung speichert man ganz einfach ins Dateisystem, indem man in der Klasse InvoiceDescriptor die Methode Save() aufruft. Dabei kann man die gewünschte ZUGFeRD-Version und das Profil angeben, hier als Beispiel XRechnung:

desc.Save(ZielXMLPath, ZUGFeRDVersion.Version22, 
  s2industries.ZUGFeRD.Profile.XRechnung); 
Das Profil für EN 16931 heißt in der Profile-Enumeration noch Comfort. Alternativ kann mit die XML-Daten bei Save() an ein Objekt des Typs System.IO.Stream übergeben und dann zum Beispiel per Netzwerk versenden.

desc.Save(stream, ZUGFeRDVersion.Version22, s2industries.
  ZUGFeRD.Profile.XRechnung, ZUGFeRDFormats.UBL); 
Bei dieser Überladung von Save() kann man auch für XRechnung das Unterformat UBL mit Wurzeltag <Invoice> wählen. Das Save(), das in eine XML-Datei speichert, erzeugt immer das Unterformat CII mit Wurzeltag <CrossIndustryInvoice>.Für das Anhängen der XML-Datei an ein PDF bietet die Bibliothek ZUGFeRD-csharp leider keine eigene Lösung. Hier greift man zum Beispiel auf die kostenfreie Community-Lösung PdfSharp [38] zurück. Der Name des Anhangs sollte xrechnung.xml sein:

var ZielPDFDateiname = PDFDateiname.Replace(".pdf", 
  ".ZUGFeRD.pdf");
string ZielPDFPfad = $@"I:\Rechnungswesen\" +
  "AusgehendeRechnungen\{jahr}\{ZielPDFDateiname}";
PdfDocument document = PdfReader.Open(PDFPfad);
document.AddEmbeddedFile("xrechnung.xml", 
  ZielXMLPfad);
document.Save(ZielPDFPfad); 
Ausschnitte aus dem resultierenden umfangreichen XRechnung-XML-Dokument zeigt Listing 2, das Sie in vollständiger Fassung in den Downloads zum Artikel finden.

Einlesen einer elektronischen Rechnung

Das Einlesen einer eingehenden E-Invoice in XML-Form erfolgt in einer Zeile via Load() aus einem Stream oder einer Datei:

InvoiceDescriptor desc = 
  InvoiceDescriptor.Load(XMLPath); 
Sofern das ohne Laufzeitfehler klappt, ist die Datei strukturell in Ordnung. Nun kann man auf die zahlreichen Eigenschaften des InvoiceDescriptor-Objekts zugreifen, zum Beispiel
  • desc.Seller.Name
  • desc.TradeLineItems
  • desc.TaxTotalAmount
  • desc.GrandTotalAmount
Allerdings prüft ZUGFeRD-csharp nicht inhaltliche Korrektheit. Die Startseite des Projekts auf GitHub listet drei Punkte auf, die in ZUGFeRD-csharp fehlen:
  • Validierung mithilfe des Standard-XSL (die die KoSIT unter [39] bereitstellt)
  • Vollständige Unterstützung des UBL-Formats (Lesen und Schreiben). Im Test konnte jedoch mit ZUGFeRD-csharp in der bei Abfassung dieses Artikels aktuellen Version 14.1 die von der KoSIT bereitgestellte aktuellste Muster-UBL-Datei 03.06a-INVOICE_ubl.xml ohne Fehler eingelesen werden.
  • Rechnungsvisualisierung
Es gibt aber XRechnungs-Validatoren im Netz ohne Anmeldepflicht, zum Beispiel beim Land Baden-Württemberg [40]. So beschwert sich dieser Validator zum Beispiel über eine XRechnung, die aus diesem Code entsteht:

desc.AddApplicableTradeTax(basisAmount: summeNetto,
  percent: (decimal)re.UST_Satz, // 19.0 oder 7.0
  typeCode: TaxTypes.VAT, // Umsatzsteuer
  categoryCode: TaxCategoryCodes.S, 
    // "Standard Tax Rate"
  exemptionReason: "Bitte beachten Sie, dass der 
    deutsche Gesetzgeber uns verpflichtet, alle 
    Nebenleistungen wie zum Beispiel Reise- und 
    Hotelkosten sowie Fachbücher zum gleichen 
    Umsatzsteuersatz wie die Hauptleistung weiter zu 
    berechnen, selbst wenn dafür ursprünglich ein 
    anderer Steuersatz galt."
); 
Es gibt damit im Validator die Fehlermeldung in Bild 3. Richtig ist: Der Hinweis zum Steuersatz muss mit AddNote() übergeben werden, wie Listing 1 zeigt. Dann ist der Validator zufrieden, siehe Bild 4. Im Prüfbericht erhält man auf Wunsch ein visuelles Ergebnis. Der Validator erkennt mathematische Fehler, also wenn zum Beispiel bei einer Rechnungszeile der ­<LineTotalAmount> nicht dem Produkt aus <ChargeAmount> und <BilledQuantity> entspricht. AddTradeLineItem() in der Bibliothek ZUGFeRD-csharp beschwert sich aber nicht, wenn man bei der Eingabe einen derartigen Fehler macht.
Der XRechnung-Validator mag nicht, dass man einen Text in das Tag geschrieben hat, wenn auf „S“ (Standard) gesetzt wurde (Bild 3) © Autor
Der XRechnung-Validator des Landes Baden-Württemberg ist einverstanden mit der XRechnung (Bild 4) © Autor

XRechnung aus PDF extrahieren

Wenn man keine eigenständige XML-Datei, sondern eine PDF-Datei mit Anhang erhält, muss man wieder auf eine PDF-Bibliothek zurückgreifen. PdfSharp bietet hier leider keine Lösung. Listing 3 zeigt das Extrahieren aller Anhänge aus einer PDF-Datei mit PDFClown [41]. Die Methode Extract­Attachments() liefert ein Byte-Array zurück, das man dann in einen MemoryStream geben kann, den man wiederum mit der Klasse InvoiceDescriptor laden kann:
Listing 3: Extrahieren aller Anhänge aus einer PDF-Datei mit PDFClown
using System;
using System.Collections.Generic;
using org.pdfclown.documents;
using org.pdfclown.documents.files;
using org.pdfclown.documents.interaction.annotations;
using org.pdfclown.objects;
 
namespace ITVisions;
 
internal class PDFUtil
{
  /// <summary>
  /// Extrahieren aller Anhänge aus einer PDF-Datei   
  /// mit PDFClown (https://pdfclown.org/)
  /// </summary>
  /// <param name="pdfPath"></param>
  /// <returns></returns>
  public Dictionary<string, byte[]> 
      ExtractAttachments(string pdfPath)
  {
    Dictionary<string, byte[]> allAttachments = 
      new Dictionary<string, byte[]>();
    Dictionary<string, byte[]> documentAttachments = 
      new Dictionary<string, byte[]>();
    Dictionary<string, byte[]> pageAttachments = 
      new Dictionary<string, byte[]>();
  
    using (org.pdfclown.files.File file = 
        new org.pdfclown.files.File(pdfPath))
    {
      Document document = file.Document;
 
      // 1. Embedded files (document level).
      foreach (KeyValuePair<PdfString, 
          FileSpecification> entry 
          in document.Names.EmbeddedFiles)
      {
        EvaluateDataFile(documentAttachments, 
          entry.Value);
      }
      Console.WriteLine(
        "PDF-Anhänge auf Dokumentebene: " + 
        documentAttachments.Count);
 
      // 2. File attachments (page level).
      foreach (org.pdfclown.documents.Page page in 
          document.Pages)
      {
        foreach (org.pdfclown.documents.interaction.
            annotations.Annotation annotation in 
            page.Annotations)
        {
          if (annotation is FileAttachment)
          { EvaluateDataFile(pageAttachments, 
            ((FileAttachment)annotation).DataFile); }
        }
      }
      Console.WriteLine("PDF-Anhänge auf Seitenebene: " 
        + pageAttachments.Count);
    }
    allAttachments.AddRange(documentAttachments);
    allAttachments.AddRange(pageAttachments);
 
    Console.WriteLine("PDF-Anhänge insgesamt: " + 
      allAttachments.Count);
 
    return allAttachments;
  }
  
  private void EvaluateDataFile(Dictionary<string, 
      byte[]> attachments, FileSpecification dataFile)
  {
    if (dataFile is FullFileSpecification)
    {
      EmbeddedFile embeddedFile = 
        ((FullFileSpecification)dataFile).EmbeddedFile;
      if (embeddedFile != null)
      { attachments[dataFile.Path] = 
        embeddedFile.Data.ToByteArray(); }
    }
  }
} 

var attachments = 
  new PDFUtil().ExtractAttachments(ZielPDFPfad);
var xRechnungAttachment = attachments.FirstOrDefault(
  x => x.Key.ToLower().Contains("xrechnung.xml"));
using (var stream = 
    new MemoryStream(xRechnungAttachment.Value))
{
  var desc = InvoiceDescriptor.Load(stream);
  // Weiterverarbeitung der Daten
} 
Leider ist PDFClown etwas in die Jahre gekommen, und in der Dokumentation lässt sich auch nicht finden, wie man PDF-Anhänge damit erstellen kann. Wenn Sie sich wünschen, für das Einbetten und das Extrahieren von PDF-Anhängen nicht zwei verschiedene Open-Source-Bibliotheken verwenden zu müssen, dann könnten Sie kommerzielle Lösungen wie TextControl [42], iTextSharp [43], iText Core [44] oder Aspose.PDF [45] in Betracht ziehen, die jeweils beide Wege beherrschen.

Fazit

Dank der kostenfreien Lösung ZUGFeRD-csharp ist das Erstellen und Auslesen von strukturierten elektronischen Rechnungen in .NET-Anwendungen sehr einfach. Auch für das Anhängen von XML-Rechnungen an PDF-Dokumenten beziehungsweise die Extraktion gibt es kostenfreie Commu­nity-Lösungen.Da XRechnung bei den Behörden Pflicht ist und ZUGFeRD auch ein Profil für XRechnung bietet, zeichnet sich ab, dass sich das XML-Format von XRechnung durchsetzen wird. Spannend bleibt die Frage, was sich behaupten wird: Reines XML oder PDF mit XML-Anhang (also ZUGFeRD) sowie bei den XRechnung-Formaten UBL oder CII.
Projektdateien herunterladen

Fussnoten

  1. [1] o.tel.o communications bei Wikipedia,
  2. [2] Holger Schwichtenberg, Internet Bill Presentment and Payment als neue Form des Electronic Billing, Diplomarbeit 1998,
  3. [3] Electronic data interchange bei Wikipedia,
  4. [4] nwb Datenbank: Umsatzsteuer; Vereinfachung der elektronischen Rechnungsstellung zum 1. Juli 2011 durch das Steuervereinfachungsgesetz 2011,
  5. [5] avanade, Künstliche Intelligenz für Rechnungen,
  6. [6] InvoiceNet, Deep neural network to extract intelligent information from invoice documents,
  7. [7] Forum elektronische Rechnung Deutschland, https://www.ferd-net.de
  8. [8] Aloaha SDK, Skonto und Verzugszinsen,
  9. [9] KoSIT, https://www.xoev.de
  10. Koordinierungsstelle für IT-Standards, XRechnung Test Suite,
  11. Bundesgesetzblatt, Wachstumschancengesetz 2024,
  12. European Commission, ViDA,
  13. BMI, Der Übertragungskanal Peppol,
  14. Sage-Lexikon, E-Rechnung,
  15. Haufe Online, Verpflichtung zur elektronischen Rechnung,
  16. Prototype Fund, https://www.prototypefund.de/
  17. Quba-Quellcode auf GitHub,
  18. Quba E-Rechnungs-View, https://quba-viewer.org
  19. Validator für XRechnung,
  20. ZUGFeRD.NET, https://konik.io
  21. ZUGFeRD.NET bei NuGet,
  22. Aloaha ZUGFeRD SDK, https://www.zugferdpro.com
  23. Aloaha ZUGFeRD SDK bei NuGet,
  24. ZUGFeRD-csharp,
  25. ZUGFeRD-csharp bei NuGet,
  26. ZUGFeRD, Open-Source Libraries and Tools,
  27. BMI, FAQ zum Thema Leitweg-ID,
  28. ZRE, https://xrechnung.bund.de
  29. Bremer E-Rechnungsportal, https://www.e-rechnung.bremen.de/senden-1459
  30. E-Rechnungsportal in NRW, https://weberfassung.erechnung.nrw/
  31. BMI, Neue Version Standard XRechnung 3.0.1 verfügbar,
  32. BBMI, E-Rechnung für Rechnungssteller der Bundesverwaltung,
  33. BMI, Übersicht über die BT-Felder der OZG-RE,
  34. Manfred Durm, XRechnung nach aktuellem Standard erstellen, https://xrechnung-erstellen.com
  35. Dun & Bradstreet, Data Universal Numbering System, https://www.dnb.com/en-us/smb/duns.html
  36. Klasse InvoiceDescriptor in ZUGFeRD-csharp auf GitHub,
  37. UNECE-Recommendation No. 20,
  38. PdfSharp, https://www.pdfsharp.net
  39. GitHub-Seite der Koordinierungsstelle für IT-Standards, https://github.com/itplr-kosit
  40. Land Baden-Württemberg, E-Rechnungs-Validator,
  41. PDFClown, https://pdfclown.org
  42. TextControl, https://www.textcontrol.com
  43. iTextSharp, https://itextpdf.com/products/itextsharp
  44. iText Core, https://itextpdf.com/products/itext-core
  45. Aspose.PDF, https://products.aspose.com/pdf/
  46. Manfred Durm, Zahlen mit Code, https://zahlen-mit-code.com

Neueste Beiträge

Managed DevOps Pools - Azure DevOps Pipelines Security
Agent Pools als Managed Service mit einfacher Integration in private Netzwerke und Authentisierung mittels Managed Identity tragen deutlich zur Sicherheit der Agent-Infrastruktur bei.
7 Minuten
7. Aug 2025
Müssen Ziele SMART sein?
Wenn es um Ziele im Projektmanagement oder in der Führung einer Organisation geht, stoßen wir schnell und fast ausnahmslos auf das Akronym SMART. Was steckt dahinter, und kann es nicht auch sinnvolle Ziele geben, die nicht SMART sind?
8 Minuten
Browser-Apps mit Avalonia entwickeln - Avalonia
Klassische UI-Frameworks finden ihren Weg in den Browser
7 Minuten
11. Aug 2025
Miscellaneous

Das könnte Dich auch interessieren

Sicher ist sicher - Azure DevOps Pipelines Security
Als integraler Bestandteil der Entwicklungsumgebung ist Azure DevOps Pipelines oft Ziel von Angriffen. Da ist es gut zu wissen, wo die Schwachstellen des Systems liegen.
14 Minuten
16. Jun 2025
CodeProject.AI Server in neuer Version - Lokaler AI-Server
CodeProject.AI Server (jetzt in Version 2.1.10) ist ein lokal installierter, selbstgehosteter, schneller, kostenloser und Open Source Artificial Intelligence Server für jede Plattform und jede Sprache.
2 Minuten
Für Einsteiger: Backend-Webentwicklung mit .NET - Microsoft
Auf YouTube bietet Microsoft eine Videoserie für Einsteiger in die Backend-Webentwicklung mit .NET.
2 Minuten
13. Feb 2024
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige