Elektronische Rechnungen schreiben und lesen

Lizenz

Mustangproject liegt unter der liberalen Apache Public License 2 vor und darf kostenlos in kommerziellen und nichtkommerziellen Produkten genutzt werden.

Quelltext

Das git repository des Mustangproject-Quelltext liegt auf Github.

Documentation

New project

Die Tastenkürzel dieses Beispiels geht von Eclipse als IDE aus.

Starten Sie Eclipse und erstellen ein neues Maven-Projekt, beispielsweise „MustangSample“ als “simple project”, Gruppen-ID “org.mustangproject”, Artifakt “mustangtest”.

Sie werden

Mit Maven

Öffnen Sie Ihre pom.xml und fügen Sie folgendes Repository


<repositories>
    <repository>
        <id>mustang-mvn-repo</id>
        <url>https://raw.github.com/ZUGFeRD/mustangproject/mvn-repo/</url>
    </repository>
</repositories>

                        

sowie die Abhängigkeiten


<dependencies>
    <dependency>
        <groupId>org.mustangproject.ZUGFeRD</groupId>
        <artifactId>mustang</artifactId>
        <version>1.7.3</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.1</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.2.5</version>
    </dependency>
</dependencies>

                        

hinzu. Um Maven zu veranlassen, Mustangproject herunterzuladen und in Eclipse verfügbar zu machen klicken Sie rechts auf die pom.xml und sagen SieRun as| Maven build. Nennen Sie eclipse:eclipse als goal und klicken Sie auf run.Rechtsklicken Sie auf das Projekt und wählen Sie refresh.

ZUGFeRD-Daten lesen

  1. Erstellen Sie eine neue Klasse im src/main/java-Verzeichnis und nennen Sie es beispielsweise Reader. Wählen Sie dabei die “Public static void main()”-Option.
  2. Erstellen Sie eine “run configuration”: klicken Sie in Run|Run configurations auf Java Application,und dort auf das Icon für eine neue Konfiguration.
  3. Geben Sie innerhalb der Main-Methode ZUGFeRDImporter zu=new ZUGFeRDImporter("MustangGnuaccountingBeispielRE-20190610_507.pdf"); ein und
  4. fügen Sie die imports durch drücken pressing STRG+SHIFT+O (Windows) oder CMD+SHIFT+O (Mac).
  5. prüfen Sie gegebenenfalls mit if (zu.canParse()) ob es sich um eine geeignete ZUGFeRD-Datei handelt
  6. und zu.parse() um in der Folge die getter-Methoden wie getAmount() nutzen zu können
  7. verwenden Sie schließlich beispielsweise zu.getAmount(). Es gibt nur für einige Attribute getter aber weitere können einfach ergänzt werden. Welche Daten verfügbar sind ersehen Sie beispielsweise der ZUGFeRD-invoice.xml die in jede ZUGFeRD-Datei eingebettet ist.
  8. Vollständiges Beispiel
    ZUGFeRDImporter zu=new ZUGFeRDImporter("MustangGnuaccountingBeispielRE-20190610_507.pdf"); System.out.println("Endbetrag: "+zu.getAmount());

Eigenes XML schreiben

Mustangprojects erstellt das nötige XML für Sie, alternativ können Sie auch eigenes XML angeben.

Erstellen Sie dazu eine Klasse XMLWriter mit einer statischen main-Methode. Benutzen Sie


ZUGFeRDExporter ze;
try {
    System.out.println("Converting to PDF/A-3u");

    /*
    * Add .setZUGFeRDVersion and .setZUGFeRDConformanceLevel
    * in the next lines to set the ZUGFeRD version respective profile of the XML
    * you are inserting.
    */
    ze = new ZUGFeRDExporterFromA1Factory().setProducer("My Application")
    .setCreator(System.getProperty("user.name"))
    .load("./MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
    System.out.println("Attaching ZUGFeRD-Data");

    /*
    * Mustangproject checks if the input PDF/A file looks halfway valid and the XML
    * data contains „<rsm:CrossIndustry“ which is the case for both ZF1
    * (CrossIndustryDocument) and ZF2 files (CrossIndustryInvoice).
    * Insert your (validated) XML here.
    */
    String ownZUGFeRDXML = "<rsm:CrossIndustryDocument></rsm:CrossIndustryDocument>";
    ze.setZUGFeRDXMLData(ownZUGFeRDXML.getBytes());
    System.out.println("Writing ZUGFeRD-PDF");
    ze.export("./Target.pdf");
} catch (IOException e) {
    e.printStackTrace();
}
        



                

und importieren Sie die Klassen (STRG+SHIFT+O in Windows oder CMD+SHIFT+O auf dem Mac).Erstellen Sie eine Run-Configuration durch Klick auf Run|Run configurations, dann auf Java Application und dann Klick auf das Icon für “neu”.

Um das eigene EN16931 XML zu schreiben sei erwähnt:

Schema

Die EN16931 Schemadatei für UN/CEFACT is the “SCRDM uncoupled” der 2016 (“16B”) Version
erhältlich von https://www.unece.org/cefact/xml_schemas/ .
Die Schemadatei des ZUGFeRD “info packet” sollte äquivalent sein.

CIUS

Als ZUGFeRD/Factur-X Profil können Sie bspw. einfach EN16931 nutzen. Als CIUS kommt XRechnung soweit als möglich in Frage.

Beispiel

Das XML der Mustangprojects Beispieldatei kann online eingesehen werden.

Der Grund warum diese Datei im XRechnungs-Validierer nicht funktioniert ist interessant:

Validatoren

Sie können sich den offiziellen XRechnung-Validator wie folgt herunterladen, konfigurieren und und verwenden:


mkdir xr
cd xr
wget https://github.com/itplr-kosit/validator/releases/download/v1.0.2/validationtool-1.0.2-full.zip
wget https://github.com/itplr-kosit/validator-configuration-xrechnung/releases/download/release-2018-12-19/validator-configuration-xrechnung_1.2.0_2018-12-19.zip
unzip validationtool-1.0.2-full.zip
unzip validator-configuration-xrechnung_1.2.0_2018-12-19.zip
mkdir test/instances

Ihre Testdateien können Sue dann in test/instances ablegen. Validierungsberichte in HTML in test/reports erhalten Sie dann mit


java -jar validationtool-1.0.2-standalone.jar -s scenarios.xml -o test/reports -h test/instances/*.xml

Das EN16931 ZF Profile erwartet genau urn:cen.eu:en16931:2017 im RAM:ID-Element während die XRechnung urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2 erwartet.

Fügen Sie im Beispiel der RAM:ID #compliant#urn:xoev-de:kosit:standard:xrechnung_1.2 hinzu sollte es den XRechnungs-Validierer erfolgreich durchlaufen.

Die Ausgabe von


wget https://github.com/ZUGFeRD/ZUV/releases/download/v0.8.0/ZUV-0.8.0.jar

java -jar ZUV-0.8.0.jar -x <your file here>

sollte bei Ihren Dateien “valid” sein.

Es ist leider nicht ausreichend, lediglich mit den Schemadateien zu prüfen: Die Schematron-Datei prüft nämlich zusätzlich noch andere Elemente läßt aber auch einiges außer acht was in der Schemadatei steht.

Schematron kann beispielsweise prüfen ob das Lieferdatum vor dem Rechnungsdatum liegt und ob die Gesamtsumme der Summe der Posten entspricht.

Validierer prüfen in der Regel sowohl gegen Schema als auch Schematron und Sie sollten einen benutzen oder diese Doppelprüfung auch vornehmen.

Rechenregeln

Wenn Sie wissen möchten wie viele Stellen hinter dem Komma Sie bei Beträgen angeben müssen oder wie richtig gerechnet wird: Das ist Teil des ersten Teils des Standards.

Codelisten

Wenn Sie Artikel in Fünferpacks verkaufen oder keine deutsche USt-ID angeben möchten, oder Firmen anders identifizieren oder eine Rechnung nach Malaysia schicken möchten brauchen Sie andere Codes.

Das CEF hat eine sehr praktische Liste aller möglichen Codes in EN16931 veröffentlicht.

XML generieren und schreiben

  1. Erstellen Sie eine neue Klasse im src-Ordner, beispielsweise MustangWriter mit einer „Public static void main()“ .
  2. Erstellen Sie eine Run configuration mit Run|Run configurations, Klick auf Java Application und einem Klick auf das Icon für “neu”.
  3. Lassen Sie die Hauptklasse IZUGFeRDExportableTransaction implementieren:
    public class MustangWriter implements IZUGFeRDExportableTransaction {
  4. Fügen Sie folgenden Code vor der Hauptklasse, aber nachpackage mustangtest;, in dieser Datei ein:
    
    class Contact implements IZUGFeRDExportableContact {}
    class Item implements IZUGFeRDExportableItem {
        private BigDecimal price, quantity;
        private Product product;
    }
    class Product implements IZUGFeRDExportableProduct {
        private String description, name, unit;
        private BigDecimal VATPercent;
    }                                
                                
  5. und fügen Sie die Imports durch Klicken von STRG+SHIFT+O (Windows) oder CMD+SHIFT+O (Mac) ein.
  6. Klicken Sie links auf die Hauptklasse MustangWriter und drücken Sie ALT+SHIFT+S
    (Windows)/ALT+CMD+S (Mac),
    wählen Sie “Override/Implement Methods” und drücken Sie Return.
  7. Klicken Sie links auf den Klassenname Contact und drücken Sie ALT+SHIFT+S
    (Windows)/ALT+CMD+S (Mac),
    wählen Sie “Override/Implement Methods” und drücken Sie Return.
  8. Klicken Sie auf Item, drücken Sie ALT+SHIFT+S or ALT+CMD+S, wählen Sie „Generate Getters and Setters“. Wählen Sie “all members” und drücken Sie Return.
  9. Bleiben Sie auf Item, führen Sie ein erneutes Refactoring durch (ALT+SHIFT+S oder ALT+CMD+S) und wählen Sie „Generate Constructor using Fields“. Wählen Sie erneut “all member variables” und drücken Sie Return.
  10. Die Item-Klasse benötigt neben Gettern und Settern auch andere Methoden, refactoren Sie erneut (ALT+SHIFT+S ooder ALT+CMD+S) und wählen Sie Override/Implement Methods
  11. „Generate Getters and Setters“ für die Klasse (nicht die Member Variable) „Product“: Klicken Sie auf Product, (ALT+SHIFT+S oder ALT+CMD+S) und wählen Sie „Generate Getters and Setters“. Wählen Sie “all members” und bestätigen Sie.
  12. Klicken Sie erneut auf Product, drücken Sie ALT+SHIFT+S und wählen Sie „Generate Constructor using Fields“. Wählen Sie erneut all members und bestätigen Sie mit Return.
  13. Ihre Rohfassungs sollte nun wie diese aussehen.
  14. Die folgenden Methoden von Contact sollten jetzt die folgenden Zeichenketten zurückliefern:
    • getCountry(): “DE”
    • getLocation(): “Spielkreis”
    • getName(): “Theodor Est”
    • getStreet(): “Bahnstr. 42”
    • getVATID(): “DE999999999”
    • getZIP(): “88802”;
  15. Die folgenden Methoden der Hauptklasse sollten folgendes zurückliefern:
    • getCurrency(): “EUR”
    • getDeliveryDate(): newGregorianCalendar(2017,Calendar.NOVEMBER,17).getTime();
    • Durch STRG+SHIFT+O (Windows) oder CMD+SHIFT+O (Mac)
      werden die notwendigen GregorianCalendar und Calendar-Klasse importiert
    • getDueDate(): new
      GregorianCalendar(2017,Calendar.DECEMBER,9).getTime();
    • getIssueDate(): new
      GregorianCalendar(2017,Calendar.NOVEMBER,18).getTime();
    • getNumber(): “RE-20171118/506”
    • getOwnBIC(): “COBADEFFXXX”
    • getOwnBankName(): “Commerzbank”
    • getOwnCountry() “DE”
    • getOwnIBAN(): “DE88 2008 0000 0970 3757 00”
    • getOwnLocation() “Stadthausen”
    • getOwnOrganisationFullPlaintextInfo(): “Bei Spiel GmbH\n”+
      “Ecke 12\n”+
      “12345 Stadthausen\n”+
      “Geschäftsführer: Max Mustermann”
    • getOwnOrganisationName(): “Bei Spiel GmbH”
    • getOwnStreet() “Ecke 12”
    • getOwnTaxID(): “22/815/0815/4”
    • getOwnVATID(): “DE136695976”
    • getOwnZIP() “12345”
    • getRecipient(): new Contact();
  16. getZFItems() der Hauptklasse kann jetzt Produkte erstellen und einen Array von Posten zurückliefern:
    
    Item[] allItems=new Item[3];
    Product designProduct=new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung",
    "HUR", new BigDecimal("7.000000"));
    Product balloonProduct=new Product("", "Luftballon: Bunt, ca. 500ml", "C62", new
    BigDecimal("19.000000"));
    Product airProduct=new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
    allItems[0]=new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
    allItems[1]=new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
    allItems[2]=new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct);
    return allItems;                        
                        
  17. Jetzt erstellen wir eine “private void” Methode mit dem Namen apply in der MustangWriter-Klasse
  18. Instanziieren Sie die Hauptklasse von MustangWriter in der main-Funktion und rufen Sie apply()
    auf.
  19. In der apply-Funktionen können Sie nun
    • eine neue ZUGFeRDExporterFromA1Factory instanziieren,
    • setProducer und setCreator darauf laufen lassen (bspw. ZUGFeRDExporter ze=newZUGFeRDExporterFromA1Factory().setProducer("string").setCreator("string")) und den ZUGFeRDExporter von der Factory bekommen load("./MustangGnuaccountingBeispielRE-20171118_506new.pdf").
    • Benutzen Sie gern eine eigene PDF/A-1 Rechnungsdatei.
    • in der Kette (.setProducer().setCreator()…) können Sie auch setZUGFeRDVersion(2) setzen und vor allem
    • die PDFattachZugferdFile-Funktion (mit der IZUGFeRDExportableTransaction, also „this“ als
      Parameter) aus dem ZUGFeRDExporter benutzen sowie
    • export() aufrufen um die PDF/A-3-Datei zu speichern.
    • Die Importe können wieder durch STRG+SHIFT+O (Windows) oder CMD+SHIFT+O (Mac) eingefügt werden.

    Die apply-Funktion sieht dann – mit entsprechenden try/catch-Blöcken- wie folgt aus:

    
    private void apply() {
        try {
            System.out.println("Lese Blanko-PDF");
            ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setProducer("Meine Anwendung")
            .setCreator(System.getProperty("user.name"))
            .load("./MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
            System.out.println("Erzeuge und hänge ZUGFeRD-Daten an");
            ze.PDFattachZugferdFile(this);
            System.out.println("Schreibe ZUGFeRD-PDF");
            ze.export("./MustangGnuaccountingBeispielRE-20190610_507new.pdf");
            System.out.println("Done.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    
    }                    
                    
  20. „Meine Anwendung“ und System.getProperty(“user.name”) werden in den Metadaten als „Producer“ (erzeugende Anwendung) beziehungsweise „Creator“ (Author) gespeichert. Passen Sie dies gegebenenfalls an.
  21. Instanziieren Sie ein MustangWriter in public static void main and rufen seine apply()-Funktion auf.
  22. Start Sie um die ZUGFeRD-Rechnungen in den in Export angegebenen Dateinamen zu schreiben.
  23. Um der APL gerecht zu werden: Passen Sie die NOTICE-Datei an und fügen Sie Ihrer Anwendung hinzu.

Ihre MustangWriter.java sollte nun so aussehen.

Project setup ohne Maven

  1. Download
    1. Mustang
      1. die JAR-Datei http://mustangproject.org/deploy/mustang-1.7.3.jar
      2. die notice-Datei http://mustangproject.org/deploy/NOTICE
  2. In Ihrer Entwicklungsumgebung: Fügen Sie die heruntergeladene JAR-Dateien Ihrem Projekt hinzu (Rechtsklick auf Projektname, Eigenschaften), hinzufügen als „external Jar“ zum „Build Path“ im Reiter „libraries“. Wenn Sie ohnehin bereits PDFBox einbetten (pdfbox, fontbox, preflight, xmpbox sowie deren Abhängigkeiten apache-commons-io und apache-commons-logging) können Sie auch das viel kleinere http://mustangproject.org/deploy/original-mustang-1.7.3.jar herunterladen.

Zusatzfunktionen

new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)
Liefert ein ZUGFeRDExporter im Factur-X-Modus
ZUGFeRDImporter.getXMP()
Liefert die XMP-Metadaten der entsprechenden PDF-Datei
ZUGFeRDExporter.setTest()
setzt ein Attribute in der XML-Struktur um Testrechnungen kennzuzeichnen.
ZUGFeRDExporter.ignoreA1Errors()
überspringt die Prüfung von Eingangs-PDF/A-1-Dateien
ZUGFeRDMigrator().migrateFromV1ToV2(zugferdInvoice)
Ein erster Versuch von ZF1 zu ZF2 zu migrieren kann mit etwas wie String facturx=new
ZUGFeRDMigrator().migrateFromV1ToV2(zugferdInvoice); versucht werden
ZUGFeRDImpoter().getMeta()
Liefert das rohe XML der ZUGFeRD-PDF-Datei.
ZUGFeRDImpoter().getUTF8()
Liefert ebenfalls das XML der ZUGFeRD-PDF-Datei und entfernt gleichzeigt mögliche UTF8 BOMs

Commandline

Mustang können Sie auch auf der Kommandozeile nutzen:

XML extrahieren

➜ target git:(master) ✗ java -jar mustang-1.7.3.jar -e

Source PDF (default: invoice.pdf):
ZUGFeRD XML (default: ZUGFeRD-invoice.xml):
Written to ZUGFeRD-invoice.xml
        

ZUGFeRD 1 auf 2 migrieren

java -jar mustang-1.7.3.jar -u
ZUGFeRD 1.0 XML
        source (default: ZUGFeRD-invoice.xml):
        ZUGFeRD 2.0 XML target (default: factur-x.xml):
    Written to factur-x.xml

Die Migration von ZF1 zu Version 2 benutzt intern eine selbstgeschriebene (lies: unvollständige) XSLT-Transformation. Korrekturen und Ergänzungen sind hochwillkommen.

PDF und XML kombinieren

In diesem Fall muss die PDF-Quelldatei eine PDF/A-1 wie unser “blanko” sein

java -jar mustang-1.7.3.jar -c
Source PDF (default: invoice.pdf):
ZUGFeRD XML (default: ZUGFeRD-invoice.xml):
Ouput PDF (default: invoice.ZUGFeRD.pdf):
ZUGFeRD version (1 or 2) (default: 1):
ZUGFeRD profile b)asic, c)omfort or e)xtended (default: e):
Written to invoice.ZUGFeRD.pdf

PDF/A-1 nach PDF/A-3 konvertieren

java -jar mustang-1.7.3.jar -a

Migriert eine PDF/A-1 in eine PDF/A-3-Datei ohne ZUGFeRD-Daten hinzuzufügen. Derselbe Dateiinhalt wird schlicht als die neue Version ausgewiesen (was funktionieren muss weil das Format rückwärts-kompatibel ist). Zusätzliche Features wie die in PDF/A-2 eingeführte JPG2000-Kompression von Bildern werden nicht genutzt werden.

Metriken

Der Ursprungszweck des Kommandozeilentools war, herauszufinden, wie viele PDF-Dateien in bestimmten Pfaden bereits ZUGFeRD-Rechnungen sind.
Nutzen Sie

java -jar mustang-1.7.3.jar -d <Verzeichnisname>

bspw.

java -jar mustang-1.7.3.jar -d /tmp/XMLExamples
.................................................................................................................................................
===================================================================
Files: 145 Dirs: 15 PDF: 18 ZUGFeRD: 14

Jeder Punkt ist eine überprüfte Datei.
Verzeichnisse werden rekursiv abgehandelt, in diesem Beispiel wurden 18 PDF-Dateien in 15 Verzeichnissen gefunden. 14 der 18 Dateien wurden als ZUGFeRD 1 oder 2 identifiziert. Üblicherweise werden nur Dateien die auf .pdf oder .PDF enden überprüft. Ein zusätzliches -i überprüft alle Dateien.

java -jar mustang-1.7.3.jar -l

Mit -l kann eine Liste der zu überprüfenden Dateien angegeben werden. Eine leere Zeile startet die Überprüfung.
Beispiel:

java -jar mustang-1.7.3.jar -l
./MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf
./MustangGnuaccountingBeispielRE-20171118_506blanko.pdf
./MustangGnuaccountingBeispielRE-20170509_505PDF14.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_COMFORT_Sachversicherung_berechneter_Steuersatz.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_COMFORT_Einfach.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_COMFORT_Rechnungskorrektur.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_EXTENDED_Warenrechnung.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_COMFORT_Kraftfahrversicherung_Bruttopreise.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_COMFORT_SEPA_Prenotification.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_EXTENDED_Kostenrechnung.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_EXTENDED_Rechnungskorrektur.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_BASIC_Rechnungskorrektur.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_BASIC_Einfach.pdf
./ZUGFerdExamples/xslt/factur-x.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_COMFORT_Haftpflichtversicherung_Versicherungssteuer.pdf
./ZUGFerdExamples/ZUGFeRD_1p0_COMFORT_Rabatte.pdf
./MustangGnuaccountingBeispielRE-20170509_505.pdf
./MustangGnuaccountingBeispielRE-20170509_505blanko.pdf
./zf2test.pdf
...................
===================================================================
Files: 19 Dirs: 0 PDF: 19 ZUGFeRD: 15

Detaillierte Parameter

Falls Sie Mustang nicht-interaktiv, beispielsweise in einem Skript verwenden möchten, können Sie je nach Operation auf folgende Parameter zugreifen:

–source <filename>
Eingabe-PDF-Datei
–source-xml <filename>
Eingabe XML-Datei
–out <filename>
Ausgabe-Datei (meist PDF)
–format <fx|zf>
Factur-x oder ZUGFeRD-Ausgabe
–version <1|2>
ZUGFeRD-Version
–profile <…>
ZUGFeRD-Profile

  • Für ZUGFeRD v1: <b>ASIC, <c>OMFORT oder <e>XTENDED
  • Für ZUGFeRD v2: <m>INIMUM, BASIC <w>L, <b>ASIC, <c>IUS, <e>N16931, E<x>TENDED