diff --git a/History.md b/History.md index 44209a82..023b8606 100644 --- a/History.md +++ b/History.md @@ -1,8 +1,20 @@ -#820/801/815 -#822 -#843 -add getCalculation on calculatedInvoice -Transactioncalculator getTaxDetails to include correct percentage, calculated amounts +- support parsing of BT-90 CreditorReferenceID +- #870 +- #871 sec +- #868 + +2.17.0 +======= +2025-06-11 +- Breaking change: #764 Item allowances not to be multiplied by quantity +(there are now product level quantities for that) +- #820/801/815 Fix invoiceImporter: empty NodeList, empty Strings +- #822 Wrapping Message Text in Validation Result PDF +- #843 Re-Initialize the HTML-template on language change +- #854 allow multiple item charges/allowances when visualizing to html +- #786 Fix Invoices with Category Code "O" #786 +- add getCalculation on calculatedInvoice +- Transactioncalculator getTaxDetails to include correct percentage, calculated amounts 2.16.5 ======= diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml index 77b79394..2922415d 100644 --- a/Mustang-CLI/pom.xml +++ b/Mustang-CLI/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.17.0-SNAPSHOT + 2.17.1-SNAPSHOT 4.0.0 org.mustangproject @@ -12,7 +12,7 @@ should also work for XRechnung/CII. jar - 2.17.0-SNAPSHOT + 2.17.1-SNAPSHOT UTF-8 11 @@ -23,7 +23,7 @@ org.mustangproject validator - 2.17.0-SNAPSHOT + 2.17.1-SNAPSHOT diff --git a/README.md b/README.md index 43ea3671..6c4ecb6c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ If you set up a Maven project, you can reference the mustang artifact like this: org.mustangproject validator - 2.15.0 + 2.17.0 shaded ``` diff --git a/doc/MustangWriter.java b/doc/MustangWriter.java deleted file mode 100644 index 6cf8670b..00000000 --- a/doc/MustangWriter.java +++ /dev/null @@ -1,277 +0,0 @@ -package mustangtest; - -import java.io.IOException; -import java.math.BigDecimal; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; - -import org.mustangproject.ZUGFeRD.IExportableTransaction; -import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge; -import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem; -import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct; -import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty; -import org.mustangproject.ZUGFeRD.IZUGFeRDExporter; -import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1; - -class Contact implements IZUGFeRDExportableTradeParty { - - public String getCountry() { - return "DE"; - } - - public String getLocation() { - return "Spielkreis"; - } - - public String getName() { - return "Theodor Est"; - } - - public String getStreet() { - return "Bahnstr. 42"; - } - - public String getVATID() { - return "DE999999999"; - } - - public String getZIP() { - return "88802"; - } -} - -class Item implements IZUGFeRDExportableItem { - public Item(BigDecimal price, BigDecimal quantity, Product product) { - super(); - this.price = price; - this.quantity = quantity; - this.product = product; - } - - private BigDecimal price, quantity; - private Product product; - - public BigDecimal getPrice() { - return price; - } - - public void setPrice(BigDecimal price) { - this.price = price; - } - - public BigDecimal getQuantity() { - return quantity; - } - - public void setQuantity(BigDecimal quantity) { - this.quantity = quantity; - } - - public Product getProduct() { - return product; - } - - public void setProduct(Product product) { - this.product = product; - } - - public IZUGFeRDAllowanceCharge[] getItemAllowances() { - // TODO Auto-generated method stub - return null; - } - - public IZUGFeRDAllowanceCharge[] getItemCharges() { - // TODO Auto-generated method stub - return null; - } -} - -class Product implements IZUGFeRDExportableProduct { - public Product(String description, String name, String unit, BigDecimal vATPercent) { - super(); - this.description = description; - this.name = name; - this.unit = unit; - VATPercent = vATPercent; - } - - private String description, name, unit; - private BigDecimal VATPercent; - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - public BigDecimal getVATPercent() { - return VATPercent; - } - - public void setVATPercent(BigDecimal vATPercent) { - VATPercent = vATPercent; - } -} - -public class MustangWriter implements IExportableTransaction { - - private void apply() { - try { - System.out.println("Reading Blanko-PDF"); - IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setProducer("My Application") - .setCreator(System.getProperty("user.name")) - .load("./MustangGnuaccountingBeispielRE-20170509_505blanko.pdf"); - System.out.println("Generating and attaching ZUGFeRD-Data"); - ze.setTransaction(this); - System.out.println("Writing ZUGFeRD-PDF"); - ze.export("./MustangGnuaccountingBeispielRE-20170509_505new.pdf"); - System.out.println("Done."); - } catch (IOException e) { - e.printStackTrace(); - } - - } - - public static void main(String[] args) { - MustangWriter mw=new MustangWriter(); - mw.apply(); - } - - public String getCurrency() { - return "EUR"; - } - - public Date getDeliveryDate() { - return new GregorianCalendar(2017, Calendar.NOVEMBER, 17).getTime(); - } - - public Date getDueDate() { - return new GregorianCalendar(2017, Calendar.DECEMBER, 9).getTime(); - } - - public Date getIssueDate() { - return new GregorianCalendar(2017, Calendar.NOVEMBER, 18).getTime(); - } - - public String getNumber() { - // TODO Auto-generated method stub - return "RE-20171118/506"; - } - - public String getOwnBIC() { - // TODO Auto-generated method stub - return "COBADEFFXXX"; - } - - public String getOwnBankName() { - // TODO Auto-generated method stub - return "Commerzbank"; - } - - public String getOwnCountry() { - // TODO Auto-generated method stub - return "DE"; - } - - public String getOwnIBAN() { - // TODO Auto-generated method stub - return "DE88 2008 0000 0970 3757 00"; - } - - public String getOwnLocation() { - // TODO Auto-generated method stub - return "Stadthausen"; - } - - public String getOwnOrganisationFullPlaintextInfo() { - // TODO Auto-generated method stub - return "Bei Spiel GmbH\n" + "Ecke 12\n" + "12345 Stadthausen\n" + "Geschäftsführer: Max Mustermann"; - } - - public String getOwnOrganisationName() { - // TODO Auto-generated method stub - return "Bei Spiel GmbH"; - } - - public String getOwnPaymentInfoText() { - // TODO Auto-generated method stub - return null; - } - - public String getOwnStreet() { - return "Ecke 12"; - } - - public String getOwnTaxID() { - return "22/815/0815/4"; - } - - public String getOwnVATID() { - return "DE136695976"; - } - - public String getOwnZIP() { - return "12345"; - } - - public String getPaymentTermDescription() { - // TODO Auto-generated method stub - return null; - } - - public IZUGFeRDExportableTradeParty getRecipient() { - return new Contact(); - } - - public String getReferenceNumber() { - // TODO Auto-generated method stub - return null; - } - - public IZUGFeRDAllowanceCharge[] getZFAllowances() { - // TODO Auto-generated method stub - return null; - } - - public IZUGFeRDAllowanceCharge[] getZFCharges() { - // TODO Auto-generated method stub - return null; - } - - public IZUGFeRDExportableItem[] getZFItems() { - 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; - } - - public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/doc/ZugferdDev.de.adoc b/doc/ZugferdDev.de.adoc new file mode 100644 index 00000000..accca91c --- /dev/null +++ b/doc/ZugferdDev.de.adoc @@ -0,0 +1,446 @@ +== [#anchor]####Mustang Project Nutzerdokumentation + +Jochen Stärk + +zu Mustangproject 1.5.1, 13.01.2018 + +http://www.mustangproject.org/[http://www.mustangproject.org] + +== [#anchor-1]####Über Mustangproject + +Mustangproject ist eine Java-Bibliothek zur Unterstützung von +erweiterten („ZUGFeRD“-)Metadaten in PDF-Rechnungsdateien. Sie verwendet +als Eingabe PDF/A-Dateien, benötigt die Apache PDFBox-Bibliothek und +unterliegt wie diese der APL-Lizenz. Sie ist daher, entsprechend den +Richtlinien der Apache Public License, unter Einbettung einer +entsprechenden „Notice“-Datei kostenlos einsetzbar in kommerziellen und +nichtkommerziellen Projekten. + +== [#anchor-2]####Übersicht von ZUGFeRD-Lösungen + +[cols=",,,,,,,,,,,",] +|=== +| |Plattform |Lizenz |ZF Versionen |Funktionsumfang |Geeignet für |Preis +| | | | | + +|Lesen |XML erzeugen |PDF Schreiben |PDF/A-Umwandlung |Kommerz. Software +|Freeware |Open Source | | | | | + +|intarsys |Java |proprietär |1 |Ja |Ja |Ja |Ja |Ja |Ja |Nein |a.A. + +|Konik |Java |AGPL |1 |Ja |Ja |Ja |Nein |Nein |Nein |Ja |0 € + +|Mustang |Java |APL |1 |Ja |Ja |Ja |Nein |Ja |Ja |Ja |0 € + +|https://github.com/akretion/factur-x |Python |BSD |1,2 |Nein |Nein |Ja +|Nein |Ja |Ja |Ja |0€ + +|https://github.com/stephanstapel/ZUGFeRD-csharp |C# |APL |1 |Ja |Ja +|Nein |Nein |Ja |Ja |Ja |0 € +|=== + +== [#anchor-3]####Download/Projekteinrichtung + +=== [#anchor-4]####Source code + +Heimat der Mustangprojekt-Quelltexte ist +https://github.com/ZUGFeRD/mustangproject/ + +=== [#anchor-5]####Projekteinrichtung ohne Maven + +Mit installiertem OpenOffice.org oder LibreOffice und Eclipse for Java. + +[arabic] +. Starten Sie Eclipse, Neues Java-Eclipse-Projekt erstellen, +beispielsweise „MustangSample“. +. Wechseln Sie in der Shell in den erstellten Ordner. +. Download von +[arabic] +.. Mustang +[arabic] +... Downloaden Sie +http://mustangproject.org/deploy/mustang-1.5.1.jarfootnote:[Falls Sie +ohnehin PDFBox verwenden (pdfbox, fontbox, preflight, xmpbox sowie deren +Abhängigkeiten apache-commons-io und apache-commons-logging) können Sie +auch die wesentlich kleinere +http://mustangproject.org/deploy/original-mustang-1.5.1.jar verwenden] +... Downloaden Sie http://mustangproject.org/deploy/NOTICE +.. Laden Sie +[arabic] +... Direkt eine PDF-A/1-Musterrechnung noch ohne +ZUGFeRD-Mhttp://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf[http://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-2017]etadaten +von +http://www.mustangproject.org/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf[1118]http://www.mustangproject.org/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf[_50]http://www.mustangproject.org/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf[6]http://www.mustangproject.org/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf[blanko.pdf] +herunter. +... oder erzeugen sich alternativ +[arabic] +.... ein eigenes Beispiel-PDF durch Download der Quelldatei im +OpenOffice.org-Format +http://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20171118_506.odt[http://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-]http://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20171118_506.odt[20171118_506.odt] +und +[arabic] +..... Öffnen Sie die Datei in OpenOffice.org +..... Datei|Exportieren als PDF: Wichtig ist hier, dass Sie die Checkbox +PDF/A-1a setzen +..... Speichern Sie die PDF-Datei beispielsweise als +„http://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf[MustangGnuaccountingBeispiel]http://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf[RE-20171118_506blanko.pdf]“ +im MustangSample-Ordner +. Wechseln Sie zurück zu Eclipse. Fügen Sie durch Rechtsklick auf das +Projekt („Eigenschaften“) die heruntergeladene JAR-Dateien +Projekteigenschaften als „externe Jars“ zum „Java Build Path“ Reiter +„Bibliotheken“ hinzu. + +=== [#anchor-6]####Mit Maven + +Mit folgendem Repository + + + + + +mustang-mvn-repo + +https://raw.github.com/ZUGFeRD/mustangproject/mvn-repo/ + + + + + +und folgender Dependency + + + +org.mustangproject.ZUGFeRD + +mustang + +1.5.1 + + + +Bei der Gelegenheit kann man auch gleich Apache Commons Logging und JAXB +importieren: + + + +commons-logging + +commons-logging + +1.1.1 + + + + + +com.sun.xml.bind + +jaxb-impl + +2.2.5 + + + +== [#anchor-7]####Lesen von ZUGFeRD-Daten + +[arabic] +. Laden Sie sich eine PDF-Datei mit ZUGFeRD-Daten herunter, +beispielsweise +http://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20171118_506.pdf +. Erstellen Sie eine neue Java-Klasse unterhalb von src, beispielsweise +MustangReader. inklusive „Public static void main()“ +. Geben Sie innerhalb von Main „ZUGFeRDImporter zi=**new** +ZUGFeRDImporter();“ ein und lassen Sie den Import durch STRG+SHIFT+O +ergänzen +. verwenden Sie zi.extract(PDF-Dateiname) und ggf. canParse() um +festzustellen ob es sich um ZUGFeRD-Daten handelt. +. Nach zi.parse() haben Sie Zugriff auf die getter wie getAmount() +. Welche Daten enthalten sind, können Sie der XML-Datei entnehmen die im +ZUGFeRD-Beispiel-PDF eingebettet ist + +=== [#anchor-8]####Komplettes Lesebeispiel + +[arabic, start=7] +. + +*package* sample; + +*import* org.mustangproject.ZUGFeRD.ZUGFeRDImporter; + +*public* *class* Read \{ + +*public* *static* *void* main(String[] args) \{ + +ZUGFeRDImporter zi=**new** ZUGFeRDImporter(); + +zi.extract("./MustangGnuaccountingBeispielRE-20171118_506.pdf"); + +System._out_.println("Lese ZUGFeRD"); + +*if* (zi.canParse()) \{ + +zi.parse(); + +System._out_.println("Fälliger Betrag:"+zi.getAmount()); + +System._out_.println("BIC:"+zi.getBIC()); + +System._out_.println("IBAN:"+zi.getIBAN()); + +System._out_.println("Kontoinhaber:"+zi.getHolder()); + +System._out_.println("Rechnungsnr:"+zi.getForeignReference()); + +} + +} + +} + +== [#anchor-9]####Schreiben einer ZUGFeRD-PDF-Datei + +Ein Beispielprogramm zum Schreiben ist deshalb umfangreicher, weil +erstens mehr Daten in einer differenzierteren Struktur geschrieben +werden als derzeit beim Lesen benötigt und zweitens dem Exporter die +Daten per Interface zur Verfügung gestellt werden müssen. + +[arabic] +. Erstellen Sie eine neue Klasse unterhalb von src, beispielsweise +MustangWriter inklusive des obligatorischen „Public static void main()“ +. +. Ändern Sie __*public* *class* MustangWriter __in__ *public* *class* +MustangWriter *implements* IZUGFeRDExportableTransaction__ +. Fügen Sie innerhalb der Klasse MustangWriter folgende Klassen hinzu +[arabic] +.. *class* _Contact_ *implements* IZUGFeRDExportableContact \{} +.. *class* _Item_ *implements* IZUGFeRDExportableItem \{ +[arabic] +... _*private* BigDecimal price, quantity;_ + +*private* Product product; + +[arabic, start=4] +. {blank} +[arabic] +.. } +.. *class* Product *implements* IZUGFeRDExportableProduct \{ +[arabic] +... *private* String description, name, unit; + +*private* BigDecimal VATPercent; + +} + +[arabic, start=5] +. Generieren Sie die Imports durch Drücken von STRG+SHIFT+O +. Markieren Sie den Klassennamen MustangWriter und drücken Sie +ALT+SHIFT+S, wählen Sie Override/Implement Methods und drücken Return. +. Klicken Sie auf Contact und Wiederholen Sie den letzten Schritt. +. Klicken Sie auf Item, markieren Sie die Variablen und wählen Sie +zuerst „_Generate Getters and Setters_“ nach drücken von ALT+SHIFT+S. +Wählen Sie alle Member aus und drücken Sie Return. +. Klicken Sie erneut auf Item, drücken von ALT+SHIFT+S und wählen +„Generate Constructor using Fields“. Wählen Sie erneut alle Member aus +und drücken Sie Return. +. Auf Item muss der Quick Fix „add unimplemented methods“ ausgeführt +werden, die zwei generierten Funktionen (getItemAllowances und +getItemCharges) dürfen null zurück geben. +. Wenden Sie die beiden letzten Schritte auch auf Product an: Klicken +Sie auf Product, markieren Sie die Variablen und wählen Sie „Generate +Getters and Setters“ nach drücken von ALT+SHIFT+S. Wählen Sie alle +Member aus und drücken Sie Return. +. Item benötigt neben den getter/setter auch noch andere Methode, wählen +Sie Item aus, drücken Sie ALT+SHIFT+S, wählen Sie Override/Implement +Methods +. Klicken Sie erneut auf Product, drücken von ALT+SHIFT+S und wählen +„Generate Constructor using Fields“. Wählen Sie erneut alle Member aus +und drücken Sie Return. +. Folgende Methoden von Contact sollten Folgendes zurückgeben: +[arabic] +.. getCountry(): "DE" +.. getLocation(): "Spielkreis" +.. getName(): "Theodor Est" +.. getStreet(): "Bahnstr. 42" +.. getVATID(): "DE999999999" +.. getZIP(): "88802"; +. Folgende Methoden der Hauptklasse -MustangWriter- sollten folgendes +zurückgeben: +[arabic] +.. getDeliveryDate(): *new* +GregorianCalendar(2017,Calendar._NOVEMBER_,17).getTime() +.. Zweimaliges CTRL+SHIFT+O importiert die dazu nötige GregorianCalendar +und Calendar Klasse +.. getDueDate(): *new* +GregorianCalendar(2017,Calendar._DECEMBER_,9).getTime() +.. getIssueDate(): *new* +GregorianCalendar(2017,Calendar._NOVEMBER_,18).getTime() +.. __getNumber(): "RE-2017__1118__/50__6__"__ +.. _getOwnBIC(): "COBADEFFXXX"_ +.. getOwnBankName(): "Commerzbank" +.. getOwnCountry() "DE" +.. getOwnIBAN(): "DE88 2008 0000 0970 3757 00" +.. getOwnLocation() "Stadthausen" +.. _getOwnOrganisationName(): "Bei Spiel GmbH"_ +.. getOwnStreet() "Ecke 12" +.. getOwnTaxID(): "22/815/0815/4" +.. getOwnVATID(): "DE136695976" +.. getOwnZIP(): "12345" +.. getOwnOrganisationFullPlaintextInfo(): "Bei Spiel GmbH\n"+ ++ +"Ecke 12\n"+ ++ +"12345 Stadthausen\n"+ ++ +"Geschäftsführer: Max Mustermann" +.. _getRecipient(): *new* Contact()_ ++ +.. getZFItems() der Hauptklasse kann jetzt Produkte anlegen und diese +als Array von Posten (Items) 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; + +[arabic] +. + +[arabic] +. {blank} +[arabic] +.. Legen Sie eine neue Funktion, beispielsweise „apply“ an (private +reicht). +.. In der Main-Methode der Hauptklasse instantiiert man jetzt die Klasse +und rufen Sie dort apply() auf. +.. In der apply-Methode kann man jetzt +[arabic] +... eine ZUGFeRDExporterFactory instantiieren, +... darauf Producer und Creator setzen (bspw. ZUGFeRDExporter ze=new +ZUGFeRDExporterFromA1Factory().setProducer(_"string"_).setCreator(_"string"_)) +und über load die PDF-A/1-Datei angeben und über den Rückgabewert den +ZUGFeRDExporter holen. Die ZUGFeRD-Version kann man in der +setProducer.setCreator-Kette mit setZUGFeRDVersion(2) angeben. +... Auf dem Exporter ruft man diePDFattachZugferdFile-Methode (mit this +als IZUGFeRDExportableTransaction) auf und +... benutzt schlussendlich die export-Funktion. Die apply-Methode sieht +dann – mit entsprechenden try/catch-Blöcken- beispielsweise so aus: + +* try* \{ + +System._out_.println("Lese Blanko-PDF"); + +ZUGFeRDExporter ze = *new* +ZUGFeRDExporterFromA1Factory().setProducer("My +Application").setCreator(System._getProperty_("user.name")).load("./MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); + +System._out_.println("Generiere ZUGFeRD-Daten"); + +ze.PDFattachZugferdFile(*this*); + +System._out_.println("Schreibe ZUGFeRD-PDF"); + +ze.export("./MustangGnuaccountingBeispielRE-20171118_506new.pdf"); + +System._out_.println("Fertig."); + +} *catch* (IOException e) \{ + +e.printStackTrace(); + +} + +[arabic, start=2] +. {blank} +[arabic] +.. Ein CTRL+SHIFT+O hilft wieder beim Hinzufügen der nötigen Imports +.. „My Application“ und __System.getProperty("user.name") __werden in +den Metadaten als „Producer“ (in etwa: erstellende Anwendung) +beziehungsweise „Creator“ (in etwa: Autor) gespeichert. Bitte passen Sie +die Werte entsprechend Ihrer Anwendung an. +.. Starten Sie, es sollte eine valide ZUFeRD-Rechnung in +_./MustangGnuaccountingBeispielRE-20171118_506new.pdf_ ++ +erstellt werden. +.. Passen Sie ggf. die NOTICE-Datei an und fügen Sie Ihrer Anwendung +hinzu. +.. Stellen Sie sicher, dass die XML-Daten in der dem PDF eingebetteten +ZUGFeRD-invoice.xml immer den menschenlesbaren Daten im PDF entsprechen. + +Die erzeugte Datei beinhaltet ZUGFeRD-invoice.xml statt factur-x.xml im +offiziellen Beispiel so lange die ZUGFeRD-Version in der Factory nicht +auf 2 gesetzt wurde. + +[arabic] +. + +=== [#anchor-10]####Komplettes Schreibbeispiel + +Siehe MustangWriter.java in diesem Verzeichnis. + +=== [#anchor-11]####Schreiben eigener XML-Daten + +Sollten Sie eine eigene Implementierung verwenden um ZUGFeRD-XML-Daten +zu erzeugen können Sie diese mit setZUGFeRDXMLData schreiben: + +ZUGFeRDExporter ze; + +*try* \{ + +System.*_out_*.println("Konvertiere zu PDF/A-3u"); + +ze = new + +ZUGFeRDExporterFromA1Factory().setProducer("My + +Application").setCreator(System._getProperty_("user.name")).load("./MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); + +System.*_out_*.println("Hänge ZUGFeRD-Datei an"); + +String ownZUGFeRDXML = +""; + +ze.setZUGFeRDXMLData(ownZUGFeRDXML.getBytes()); + +System.*_out_*.println("Schreibe ZUGFeRD-PDF"); + +ze.export("./Target.pdf"); + +System.*_out_*.println("Fertig."); + +} *catch* (IOException e) \{ + +e.printStackTrace(); + +} + +Mustangproject prüft, die Eingabedatei auf einigermaßen korrektes PDF/A +ist und dass die XML-Daten mindestens + + org.mustangproject + validator + shaded + 2.17.0 + + +---- + +Open the Maven Window and click Sync all Maven projects. + +== Reading Factur-X/ZUGFeRD data + +[arabic] +. Download a factur-x sample with metadata like +https://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20201121_508.pdf[https://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20201121_508.pdf] +. Create a new Maven project. Add the jar in the pom.xml as described above. In +---- +public class Main { +public static void main(String[] args) { +System.out.println("Hello, World!"); +} +} +---- + +use + +---- + ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter("MustangGnuaccountingBeispielRE-20201121_508.pdf"); + CalculatedInvoice ci=new CalculatedInvoice(); + try { + zii.extractInto(ci); + System.out.println("Pay: "+ci.getDuePayable()); + } catch (XPathExpressionException e) { + throw new RuntimeException(e); + } catch (ParseException e) { + throw new RuntimeException(e); + } +---- + +To find out how much you have to pay. + +=== Complete sample source code for reading ZUGFeRD data + + +---- +package de.usegroup; + +import org.mustangproject.CalculatedInvoice; +import org.mustangproject.ZUGFeRD.ZUGFeRDInvoiceImporter; + +import javax.xml.xpath.XPathExpressionException; +import java.text.ParseException; + +public class Main { + public static void main(String[] args) { + ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter("MustangGnuaccountingBeispielRE-20201121_508.pdf"); + CalculatedInvoice ci=new CalculatedInvoice(); + try { + zii.extractInto(ci); + System.out.println("Pay: "+ci.getDuePayable()); + } catch (XPathExpressionException e) { + throw new RuntimeException(e); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +} +---- + +NOTE: You can additionally validate the file with two additional lines +---- + ZUGFeRDValidator zv=new ZUGFeRDValidator(); + System.out.println(zv.validate("MustangGnuaccountingBeispielRE-20201121_508.pdf")); +---- + + +== Writing a ZUGFeRD-PDF file + +A sample for writing Factur-X/ZUGFeRD PDFs requires a PDF/A file to attach the XML to, +saved +e.g. as link:https://www.mustangproject.org/files/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf[blanko.pdf] + +The core is creating an exporter, an invoice and send the invoice through the exporter: +---- + IZUGFeRDExporter ze = new ZUGFeRDExporterFromPDFA().load(sourcePDF).setProducer("My Application"). + setCreator(System.getProperty("user.name")); + + Invoice i=new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()) + .setSender(new TradeParty("ACME co", "teststr", "55232", "teststadt", "DE") + .addBankDetails(new BankDetails("777666555", "DE4321"))).setOwnTaxID("4711").setOwnVATID("DE19990815") + .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE") + .setContact(new Contact("nameRep", "phoneRep", "emailRep@test.com"))).setNumber("X12") + .addItem(new Item(new Product("Testproduct", "", "H87", new BigDecimal(19)), + new BigDecimal(2.5), new BigDecimal(1.0))); + ze.setTransaction(i); + ze.export("factur-x.pdf"); +---- +Additionally, you should confirm that Mustangs calculated total matches that of your PDF/A file, for which you can use +the TransactionCalculator (which is also used internally in the exporter): + +---- + TransactionCalculator tc=new TransactionCalculator(i); + System.out.println("Confirm "+tc.getDuePayable()+ " is also the final amount in your PDF"); +---- + +NOTE: We're using BigDecimals to avoid rounding errors. + +So the complete write example looks like this: +---- +package de.usegroup; + +import org.mustangproject.*; +import org.mustangproject.ZUGFeRD.IZUGFeRDExporter; +import org.mustangproject.ZUGFeRD.TransactionCalculator; +import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromPDFA; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Date; + +public class Main { + public static void main(String[] args) { + + String sourcePDF="MustangGnuaccountingBeispielRE-20201121_508.pdf"; + try { + IZUGFeRDExporter ze = new ZUGFeRDExporterFromPDFA().load(sourcePDF).setProducer("My Application"). + setCreator(System.getProperty("user.name")); + + Invoice i=new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()) + .setSender(new TradeParty("ACME co", "teststr", "55232", "teststadt", "DE") + .addBankDetails(new BankDetails("777666555", "DE4321"))).setOwnTaxID("4711").setOwnVATID("DE19990815") + .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE") + .setContact(new Contact("nameRep", "phoneRep", "emailRep@test.com"))).setNumber("X12") + .addItem(new Item(new Product("Testproduct", "", "H87", new BigDecimal(19)), + new BigDecimal(2.5), new BigDecimal(1.0))); + ze.setTransaction(i); + ze.export("factur-x.pdf"); + TransactionCalculator tc=new TransactionCalculator(i); + System.out.println("Confirm "+tc.getDuePayable()+ " is also the final amount in your PDF"); + } catch (IOException e) { + e.printStackTrace(); + } + } +} +---- diff --git a/doc/ZugferdDev.en.pdf b/doc/ZugferdDev.en.pdf index a16e3e9c..c8c206a5 100644 Binary files a/doc/ZugferdDev.en.pdf and b/doc/ZugferdDev.en.pdf differ diff --git a/library/pom.xml b/library/pom.xml index f9745ed8..ed2754e2 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.17.0-SNAPSHOT + 2.17.1-SNAPSHOT 4.0.0 org.mustangproject library - 2.17.0-SNAPSHOT + 2.17.1-SNAPSHOT jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -133,7 +133,7 @@ com.helger en16931-cii2ubl - 2.2.4 + 2.3.0 diff --git a/library/src/main/java/org/mustangproject/Allowance.java b/library/src/main/java/org/mustangproject/Allowance.java index e378f767..d8b5f3fe 100644 --- a/library/src/main/java/org/mustangproject/Allowance.java +++ b/library/src/main/java/org/mustangproject/Allowance.java @@ -3,8 +3,10 @@ package org.mustangproject; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; +import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider; import java.math.BigDecimal; +import java.math.RoundingMode; /*** * (absolute) allowances on item and document level @@ -29,6 +31,22 @@ public class Allowance extends Charge { } + + + @Override + public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) { + if(totalAmount != null) { + return totalAmount; + } else if (percent!=null) { + BigDecimal singlePrice=currentItem.getValue().divide(BigDecimal.ONE.add(getPercent().divide(new BigDecimal(100))), 18, RoundingMode.HALF_UP); +// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100)))); + BigDecimal singlePriceDiff=currentItem.getValue().subtract(singlePrice); + return singlePriceDiff; + } else { + throw new RuntimeException("percent must be set"); + } + } + /*** * Always to return false for IZUGFeRDAllowanceCharge * @return false since its not supposed to be calculated negatively diff --git a/library/src/main/java/org/mustangproject/BankDetails.java b/library/src/main/java/org/mustangproject/BankDetails.java index a16976f3..773c12b3 100644 --- a/library/src/main/java/org/mustangproject/BankDetails.java +++ b/library/src/main/java/org/mustangproject/BankDetails.java @@ -23,6 +23,14 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment { * the "name" of the bank account (holder) */ protected String accountName = null; + /** + * payment means code + */ + protected String paymentMeansCode = "58"; + /** + * payment means information + */ + protected String paymentMeansInformation = "SEPA credit transfer"; /*** * bean constructor @@ -123,5 +131,31 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment { return accountName; } + /** + * set payment means code + * + * @param paymentMeansCode the payment means code + * @return fluent setter + */ + public BankDetails setPaymentMeansCode(String paymentMeansCode) { + this.paymentMeansCode = paymentMeansCode; + return this; + } + @Override + public String getPaymentMeansCode() { return paymentMeansCode; } + + /** + * set payment means information + * + * @param paymentMeansInformation the payment mean information + * @return fluent setter + */ + public BankDetails setPaymentMeansInformation(String paymentMeansInformation) { + this.paymentMeansInformation = paymentMeansInformation; + return this; + } + + @Override + public String getPaymentMeansInformation() { return paymentMeansInformation; } } diff --git a/library/src/main/java/org/mustangproject/CalculatedInvoice.java b/library/src/main/java/org/mustangproject/CalculatedInvoice.java index f993db83..d496744f 100644 --- a/library/src/main/java/org/mustangproject/CalculatedInvoice.java +++ b/library/src/main/java/org/mustangproject/CalculatedInvoice.java @@ -103,7 +103,6 @@ public class CalculatedInvoice extends Invoice implements Serializable { * @return a updated transactioncalulator */ public TransactionCalculator getCalculation() { - calculate(); return tc; } diff --git a/library/src/main/java/org/mustangproject/Charge.java b/library/src/main/java/org/mustangproject/Charge.java index 1b3320bf..c906a704 100644 --- a/library/src/main/java/org/mustangproject/Charge.java +++ b/library/src/main/java/org/mustangproject/Charge.java @@ -7,6 +7,7 @@ import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider; import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge; import java.math.BigDecimal; +import java.math.RoundingMode; /*** * Absolute and relative charges for document and item level @@ -23,6 +24,10 @@ public class Charge implements IZUGFeRDAllowanceCharge { * the absolute value if not percentage */ protected BigDecimal totalAmount; + /** + * the value the percentage is applied upon + */ + protected BigDecimal basisAmount; /** * the tax rate the charge belongs to */ @@ -103,6 +108,22 @@ public class Charge implements IZUGFeRDAllowanceCharge { } + @Override + public BigDecimal getBasisAmount() { + return basisAmount; + } + + /*** + * sets a potential basis for the potential percentage + * @param basis the basis amount + * @return fluid setter + */ + public Charge setBasisAmount(BigDecimal basis) { + this.basisAmount = basis; + return this; + } + + @Override public String getReasonCode() { return reasonCode; @@ -121,10 +142,13 @@ public class Charge implements IZUGFeRDAllowanceCharge { @Override public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) { - if (percent!=null) { - return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100))); - } else if(totalAmount != null) { + if(totalAmount != null) { return totalAmount; + } else if (percent!=null) { + BigDecimal singlePrice=currentItem.getValue().divide(BigDecimal.ONE.add(getPercent().divide(new BigDecimal(100))), 18, RoundingMode.HALF_UP); +// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100)))); + BigDecimal singlePriceDiff=currentItem.getValue().add(singlePrice); + return singlePriceDiff; } else { throw new RuntimeException("percent must be set"); } diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index 54f20084..6d57722d 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -72,8 +72,6 @@ public class Item implements IZUGFeRDExportableItem { //we need: name description unitcode //and we additionally have vat% - // Bharti's homework 20241126:Streams https://www.youtube.com/watch?v=Lf01cBzmuXw - // and Lambdas https://www.youtube.com/watch?v=HCyx31NW8xg setProduct(new Product(itemMap.getNode("Item").get())); icnm.getAsString("Name").ifPresent(product::setName); icnm.getAsString("Description").ifPresent(product::setDescription); @@ -86,17 +84,6 @@ public class Item implements IZUGFeRDExportableItem { BuyersItemIdentification.getAsString("ID").ifPresent(product::setBuyerAssignedID); }); -// String name = icnm.getAsStringOrNull("Name"); -// String val = icnm.getAsStringOrNull("Value"); -// if (name != null && val != null) { -// if (attributes == null) { -// attributes = new HashMap<>(); -// } -// product.attributes.put(name, val); -// } - //icnm.getNode("AdditionalItemProperty").flatMap(n ->n.getAttributes()).ifPresent(product::setAttributes); - - icnm.getAsNodeMap("ClassifiedTaxCategory").flatMap(m -> m.getAsBigDecimal("Percent")) .ifPresent(product::setVATPercent); }); @@ -175,11 +162,12 @@ public class Item implements IZUGFeRDExportableItem { .ifPresent(product::setTaxExemptionReason); icnm.getAllNodes("SpecifiedTradeAllowanceCharge").map(NodeMap::new).forEach(stac -> { - stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> { //CII + stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> { String isChargeString = ci.getAsString("Indicator").get(); - String percentString = stac.getAsStringOrNull("CalculationPercent");//MultiplierFactorNumeric - String amountString = stac.getAsStringOrNull("ActualAmount");//Amount - String reason = stac.getAsStringOrNull("Reason");//AllowanceChargeReason + String percentString = stac.getAsStringOrNull("CalculationPercent"); + String amountString = stac.getAsStringOrNull("ActualAmount"); + String basisAmountString = stac.getAsStringOrNull("BasisAmount"); + String reason = stac.getAsStringOrNull("Reason"); Charge izac = new Charge(); if (isChargeString.equalsIgnoreCase("false")) { izac = new Allowance(); @@ -188,6 +176,12 @@ public class Item implements IZUGFeRDExportableItem { } if (amountString != null) { izac.setTotalAmount(new BigDecimal(amountString)); + if (percentString!=null&&(percentString!="0")) { + izac.setTotalAmount(new BigDecimal(amountString).divide(getQuantity())); + } + } + if (basisAmountString != null) { + izac.setBasisAmount(new BigDecimal(basisAmountString)); } if (percentString != null) { izac.setPercent(new BigDecimal(percentString)); @@ -288,6 +282,16 @@ public class Item implements IZUGFeRDExportableItem { return this; } + @Override public IZUGFeRDAllowanceCharge[] getAllowances() { + IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Allowances.size()]; + return Allowances.toArray(izac); + } + + @Override public IZUGFeRDAllowanceCharge[] getCharges() { + IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Charges.size()]; + return Charges.toArray(izac); + } + /*** * BT 132 (issue https://github.com/ZUGFeRD/mustangproject/issues/247) * @return the line ID of the order (BT132) @@ -461,6 +465,7 @@ public class Item implements IZUGFeRDExportableItem { * @return fluent setter */ public Item addAllowance(IZUGFeRDAllowanceCharge izac) { + Allowances.add(izac); return this; } diff --git a/library/src/main/java/org/mustangproject/Product.java b/library/src/main/java/org/mustangproject/Product.java index 4f0397ee..93e48a79 100644 --- a/library/src/main/java/org/mustangproject/Product.java +++ b/library/src/main/java/org/mustangproject/Product.java @@ -32,6 +32,8 @@ public class Product implements IZUGFeRDExportableProduct { protected boolean isIntraCommunitySupply = false; protected SchemedID globalId = null; protected String countryOfOrigin = null; + protected ArrayList charges=new ArrayList<>(); + protected ArrayList allowances=new ArrayList<>(); protected HashMap attributes = new HashMap<>(); protected List classifications = new ArrayList<>(); @@ -393,4 +395,42 @@ public class Product implements IZUGFeRDExportableProduct { this.classifications.add(classification); return this; } + + public Product addCharge(Charge e) { + charges.add(e); + return this; + } + + public Product addAllowance(Allowance a) { + allowances.add(a); + return this; + } + + /*** + * returns the AppliedTradeAllowanceCharges of this product which are actually Charges + * @return array of or null, if none + */ + @Override + public Charge[] getCharges() { + if (charges.size()==0) { + return null; + } + Charge[] chargeArr = new Charge[charges.size()]; + return charges.toArray(chargeArr); + } + + @Override + /*** + * returns the AppliedTradeAllowanceCharges of this product which are actually Allowances + * @return array of or null, if none + */ + public Allowance[] getAllowances() { + if (allowances.size()==0) { + return null; + } + Allowance[] allowanceArr = new Allowance[allowances.size()]; + return allowances.toArray(allowanceArr); + } + + } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceCharge.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceCharge.java index 0c61ba5b..bcdab413 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceCharge.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceCharge.java @@ -38,6 +38,12 @@ public interface IZUGFeRDAllowanceCharge { */ default BigDecimal getPercent() {return null;} + /*** + * returns a basis the precentage is calculated from + * @return null or the basis + */ + default BigDecimal getBasisAmount() {return null;} + /*** * get a description for the allowance/charge * @return the description diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java index 6d68cdff..1dee20c2 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java @@ -43,7 +43,11 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{ * item level discounts * @return array of the discounts on a single item */ + @Deprecated default IZUGFeRDAllowanceCharge[] getItemAllowances() { + if (getProduct()!=null) { + return getProduct().getAllowances(); + } return null; } @@ -51,10 +55,27 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{ * item level price additions * @return array of the additional charges on the item */ + @Deprecated default IZUGFeRDAllowanceCharge[] getItemCharges() { + if (getProduct()!=null) { + return getProduct().getCharges(); + } return null; } + @Deprecated + default IZUGFeRDAllowanceCharge[] getAllowances() { + return null; + } + + /** + * item level price additions + * @return array of the additional charges on the item + */ + @Deprecated + default IZUGFeRDAllowanceCharge[] getCharges() { + return null; + } /*** * BT 132 (issue https://github.com/ZUGFeRD/mustangproject/issues/247) @@ -147,9 +168,9 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{ } /*** - * specify allowances amount for the line item total + * get all (allowances and charges) SpecifiedTradeAllowanceCharges * - * @return the sum of allowances for this item + * @return the real item lecel SpecifiedTradeAllowanceCharges */ default IZUGFeRDAllowanceCharge[] getItemTotalAllowances() { return null; diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java index ae9eb5b8..6ee5f22e 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java @@ -166,6 +166,25 @@ public interface IZUGFeRDExportableProduct { return null; } + + /** + * product level discounts (AppliedTradeAllowanceCharge, will change net price) + * @return array of the discounts on a single product + */ + default IZUGFeRDAllowanceCharge[] getAllowances() { + return null; + } + + /** + * product level charges (AppliedTradeAllowanceCharge, will change net price) + * @return array of the additional charges on the product + */ + default IZUGFeRDAllowanceCharge[] getCharges() { + return null; + } + + + /** * Detailed information about the product * diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java index 9731a9a5..4edb6cb0 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java @@ -59,6 +59,16 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement */ default String getAccountName() { return null; } + /*** + * @return payment means code (BT-81 / UNTDID 4461) + */ + default String getPaymentMeansCode() { return null; }; + + /*** + * @return payment means description (BT-82) (optional) + */ + default String getPaymentMeansInformation() { return null; }; + @Override @JsonIgnore @@ -70,12 +80,14 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement } String xml = "" - + "58" - + "SEPA credit transfer" - + "" - + "" + XMLTools.encodeXML(getOwnIBAN()) + ""; - xml+= accountNameStr; - xml+= ""; + + "" + XMLTools.encodeXML(getPaymentMeansCode()) + "" + + "" + XMLTools.encodeXML(getPaymentMeansInformation()) + ""; + if (getOwnIBAN() != null) { + xml += "" + + "" + XMLTools.encodeXML(getOwnIBAN()) + "" + + accountNameStr + + ""; + } if (getOwnBIC()!=null) { xml+= "" + "" + XMLTools.encodeXML(getOwnBIC()) + "" diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java index d17ccfec..a0566f3e 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java @@ -2,30 +2,49 @@ package org.mustangproject.ZUGFeRD; import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.Arrays; +import java.util.List; /*** * the linecalculator does the math within an item line, and e.g. calculates quantity*price. * @see TransactionCalculator */ public class LineCalculator { - private final BigDecimal price; - private final BigDecimal priceGross; - private final BigDecimal itemTotalNetAmount; - private final BigDecimal itemTotalVATAmount; - private BigDecimal allowance = BigDecimal.ZERO; - private BigDecimal charge = BigDecimal.ZERO; - private BigDecimal allowanceItemTotal = BigDecimal.ZERO; + protected BigDecimal price; + protected BigDecimal priceGross; + protected BigDecimal itemTotalNetAmount; + protected BigDecimal itemTotalVATAmount; + protected BigDecimal lineAllowance = BigDecimal.ZERO; + protected BigDecimal lineCharge = BigDecimal.ZERO; + protected BigDecimal itemAllowance = BigDecimal.ZERO; + protected BigDecimal itemCharge = BigDecimal.ZERO; + protected BigDecimal allowanceItemTotal = BigDecimal.ZERO; public LineCalculator(IZUGFeRDExportableItem currentItem) { if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) { for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) { - addAllowance(allowance.getTotalAmount(currentItem)); + BigDecimal factor=BigDecimal.ONE; + BigDecimal singleAllowance=allowance.getTotalAmount(currentItem); + addItemAllowance(singleAllowance); + + if ((allowance.getPercent()!=null)&&(allowance.getPercent().compareTo(BigDecimal.ZERO)!=0)) { + factor=currentItem.getQuantity(); + } + addAllowanceItemTotal(singleAllowance.multiply(factor)); + } } if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) { for (IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) { - addCharge(charge.getTotalAmount(currentItem)); + BigDecimal factor=BigDecimal.ONE; + BigDecimal singleCharge=charge.getTotalAmount(currentItem); + addItemCharge(singleCharge); + if ((charge.getPercent()!=null)&&(charge.getPercent().compareTo(BigDecimal.ZERO)!=0)) { + factor=currentItem.getQuantity(); + } + subtractAllowanceItemTotal(singleCharge.multiply(factor)); + } } if (currentItem.getItemTotalAllowances() != null && currentItem.getItemTotalAllowances().length > 0) { @@ -42,22 +61,41 @@ public class LineCalculator { vatPercent = BigDecimal.ZERO; } BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100)); - priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159 - price = priceGross.subtract(allowance).add(charge); BigDecimal quantity=BigDecimal.ZERO; if ((currentItem!=null)&&(currentItem.getQuantity()!=null)) { quantity=currentItem.getQuantity(); } + price=currentItem.getPrice(); + priceGross=price; +// price=price.subtract(itemAllowance).add(itemCharge); +// BigDecimal delta=charge.subtract(allowanceItemTotal).subtract(allowance); +// delta=delta.divide(currentItem.getQuantity(), 18, RoundingMode.HALF_UP); + + BigDecimal delta=BigDecimal.ZERO; + if(currentItem.getProduct()!=null){ + if (currentItem.getProduct().getAllowances()!=null) { + for (IZUGFeRDAllowanceCharge ccaf:currentItem.getProduct().getAllowances()) { + delta=delta.subtract(ccaf.getTotalAmount(currentItem)); + } + } + if (currentItem.getProduct().getCharges()!=null) { + for (IZUGFeRDAllowanceCharge ccaf : currentItem.getProduct().getCharges()) { + delta = delta.subtract(ccaf.getTotalAmount(currentItem)); + } + } + } + + price=price.add(delta); // Division/Zero occurred here. // Used the setScale only because that's also done in getBasisQuantity BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ONE.setScale(4) : currentItem.getBasisQuantity(); itemTotalNetAmount = quantity.multiply(price).divide(basisQuantity, 18, RoundingMode.HALF_UP) - .subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP); - itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator); + .add(lineCharge).subtract(lineAllowance).subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP); + itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);//.setScale(2, RoundingMode.HALF_UP); } public BigDecimal getPrice() { @@ -80,16 +118,27 @@ public class LineCalculator { return priceGross; } - public void addAllowance(BigDecimal b) { - allowance = allowance.add(b); + public void addLineAllowance(BigDecimal b) { + lineAllowance = lineAllowance.add(b); } - public void addCharge(BigDecimal b) { - charge = charge.add(b); + public void addLineCharge(BigDecimal b) { + lineCharge = lineCharge.add(b); + } + + public void addItemAllowance(BigDecimal b) { + itemAllowance = itemAllowance.add(b); + } + + public void addItemCharge(BigDecimal b) { + itemCharge = itemCharge.add(b); } public void addAllowanceItemTotal(BigDecimal b) { allowanceItemTotal = allowanceItemTotal.add(b); } + public void subtractAllowanceItemTotal(BigDecimal b) { + allowanceItemTotal = allowanceItemTotal.subtract(b); + } } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java b/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java index 813db1a2..9b426390 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java @@ -145,7 +145,7 @@ public class VATAmount { } public VATAmount add(VATAmount v) { - return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode).setVatExemptionReasonText(v.getVatExemptionReasonText()); + return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode).setVatExemptionReasonText(v.getVatExemptionReasonText() != null ? v.getVatExemptionReasonText(): this.vatExemptionReasonText); } public VATAmount subtract(VATAmount v) { diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 8c7c4041..ae6216be 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -48,6 +48,7 @@ import org.mustangproject.IncludedNote; import org.mustangproject.ReferencedDocument; import org.mustangproject.XMLTools; import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants; +import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -152,12 +153,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { if (profile == Profiles.getByName("Minimum")) { xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + ""; } else { - String schemeAttribute=""; - if ((party.getLegalOrganisation().getSchemedID().getScheme()!=null)&&(party.getLegalOrganisation().getSchemedID().getScheme().length()>0)) { - schemeAttribute="schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme())+"\""; + String schemeAttribute = ""; + if ((party.getLegalOrganisation().getSchemedID().getScheme() != null) && (party.getLegalOrganisation().getSchemedID().getScheme().length() > 0)) { + schemeAttribute = "schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme()) + "\""; } - xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + ""; + xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + ""; } } if (party.getLegalOrganisation().getTradingBusinessName() != null) { @@ -320,11 +321,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } String reason = ""; - if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) { + boolean isEN16931=(profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931")); + if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || isEN16931)) { reason = "" + XMLTools.encodeXML(allowance.getReason()) + ""; } String reasonCode = ""; - if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("XRechnung"))) { + if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("Extended") || isEN16931)) { // only in XRechnung profile reasonCode = "" + allowance.getReasonCode() + ""; } @@ -395,20 +397,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + "" + "" + "" + XMLTools.encodeXML(trans.getNumber()) + ""; - if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) { - xml += "" + XMLTools.encodeXML(trans.getDocumentName()) + ""; - } - xml += "" + typecode + "" - + "" + DATE.udtFormat(trans.getIssueDate()) + "" // date - + buildNotes(trans) - + "" - + ""; + if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) { + xml += "" + XMLTools.encodeXML(trans.getDocumentName()) + ""; + } + xml += "" + typecode + "" + + "" + DATE.udtFormat(trans.getIssueDate()) + "" // date + + buildNotes(trans) + + "" + + ""; int lineID = 0; for (final IZUGFeRDExportableItem currentItem : trans.getZFItems()) { lineID++; String lineIDStr = Integer.toString(lineID); - if (currentItem.getId()!=null) { - lineIDStr=currentItem.getId(); + if (currentItem.getId() != null) { + lineIDStr = currentItem.getId(); } final LineCalculator lc = new LineCalculator(currentItem); if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BasicWL"))) { @@ -432,24 +434,29 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + ""; } String allowanceChargeStr = ""; - if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) { - for (final IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) { + if (currentItem.getProduct().getAllowances() != null && currentItem.getProduct().getAllowances().length > 0) { + for (final IZUGFeRDAllowanceCharge allowance : currentItem.getProduct().getAllowances()) { allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem); } } - if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) { - for (final IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) { + if (currentItem.getProduct().getCharges() != null && currentItem.getProduct().getCharges().length > 0) { + for (final IZUGFeRDAllowanceCharge charge : currentItem.getProduct().getCharges()) { allowanceChargeStr += getAllowanceChargeStr(charge, currentItem); } } String itemTotalAllowanceChargeStr = ""; - if (currentItem.getItemTotalAllowances() != null && currentItem.getItemTotalAllowances().length > 0) { - for (final IZUGFeRDAllowanceCharge itemTotalAllowance : currentItem.getItemTotalAllowances()) { + if (currentItem.getAllowances() != null && currentItem.getAllowances().length > 0) { + for (final IZUGFeRDAllowanceCharge itemTotalAllowance : currentItem.getAllowances()) { itemTotalAllowanceChargeStr += getItemTotalAllowanceChargeStr(itemTotalAllowance, currentItem); } } + if (currentItem.getCharges() != null && currentItem.getCharges().length > 0) { + for (final IZUGFeRDAllowanceCharge itemTotalCharges : currentItem.getCharges()) { + itemTotalAllowanceChargeStr += getItemTotalAllowanceChargeStr(itemTotalCharges, currentItem); + } + } xml += "" + XMLTools.encodeXML(currentItem.getProduct().getName()) + ""; if (currentItem.getProduct().getDescription() != null && currentItem.getProduct().getDescription().length() > 0) { @@ -531,15 +538,16 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + "" + "" + "VAT"; - if (currentItem.getProduct().getTaxExemptionReason() != null) { xml += "" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + ""; } - - xml += "" + currentItem.getProduct().getTaxCategoryCode() + "" - + "" - + vatFormat(currentItem.getProduct().getVATPercent()) + "" - + ""; + xml += "" + currentItem.getProduct().getTaxCategoryCode() + ""; + if (!currentItem.getProduct().getTaxCategoryCode().equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) { + xml += "" + + vatFormat(currentItem.getProduct().getVATPercent()) + ""; + } + xml += ""; + if ((currentItem.getDetailedDeliveryPeriodFrom() != null) || (currentItem.getDetailedDeliveryPeriodTo() != null)) { xml += ""; if (currentItem.getDetailedDeliveryPeriodFrom() != null) { @@ -551,7 +559,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { xml += ""; } - xml += itemTotalAllowanceChargeStr; + // item charges/allowances + if (!itemTotalAllowanceChargeStr.isEmpty()) { + xml += itemTotalAllowanceChargeStr ; + } xml += "" + "" + currencyFormat(lc.getItemTotalNetAmount()) @@ -725,9 +736,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + exemptionReasonTextXML + "" + currencyFormat(amount.getBasis()) + "" // currencyID=\"EUR\" + "" + amountCategoryCode + "" - + (amountDueDateTypeCode != null ? "" + amountDueDateTypeCode + "" : "") - + "" - + vatFormat(amount.getApplicablePercent()) + ""; + + (amountDueDateTypeCode != null ? "" + amountDueDateTypeCode + "" : ""); + if (!amountCategoryCode.equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) { + xml += "" + + vatFormat(amount.getApplicablePercent()) + ""; + } + xml += ""; } } } @@ -743,7 +757,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) { - if ((profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931")) || (profile == Profiles.getByName("EXTENDED"))) { + if ((profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931")) || (profile == Profiles.getByName("EXTENDED"))) { for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) { xml += "" + "" + @@ -759,7 +773,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { xml += "" + "VAT" + "" + charge.getCategoryCode() + ""; - if (charge.getTaxPercent() != null) { + if (charge.getTaxPercent() != null && !charge.getCategoryCode().equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) { xml += "" + vatFormat(charge.getTaxPercent()) + ""; } xml += "" + @@ -842,7 +856,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { if (paymentTermsDescription != null) { xml += "" + paymentTermsDescription + ""; } - + if (trans.getDueDate() != null) { xml += "" // $NON-NLS-2$ + DATE.udtFormat(trans.getDueDate()) @@ -874,7 +888,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { final String chargesTotalLine = "" + currencyFormat(calc.getChargesForPercent(null)) + ""; xml += ""; - if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BASICWL"))) { + if ((getProfile() != Profiles.getByName("Minimum"))) { xml += "" + currencyFormat(calc.getTotal()) + ""; xml += chargesTotalLine + allowanceTotalLine; @@ -910,12 +924,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { if (trans.getInvoiceReferencedDocuments() != null) { for (ReferencedDocument doc : trans.getInvoiceReferencedDocuments()) { xml += "" - + "" - + XMLTools.encodeXML(doc.getIssuerAssignedID()) + ""; + + "" + + XMLTools.encodeXML(doc.getIssuerAssignedID()) + ""; if (doc.getFormattedIssueDateTime() != null) { xml += "" - + DATE.qdtFormat(doc.getFormattedIssueDateTime()) - + ""; + + DATE.qdtFormat(doc.getFormattedIssueDateTime()) + + ""; } xml += ""; } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 53f4562b..daa26916 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -383,29 +383,7 @@ public class ZUGFeRDInvoiceImporter { }); }); String street, name, additionalStreet, city, postal, countrySubentity, line, country = null; -/* - String idx = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"ID\"]"); - street = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name()=\"Address\"]/*[local-name()=\"StreetName\"]"); - additionalStreet = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]/*[local-name() = \"AdditionalStreetName\"]"); - city = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]/*[local-name() = \"CityName\"]"); - postal = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]/*[local-name() = \"PostalZone\"]"); - countrySubentity = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]/*[local-name() = \"CountrySubentity\"]"); - line = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]//*[local-name() = \"AddressLine\"]/*[local-name() = \"Line\"]"); - country = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]//*[local-name() = \"Country\"]/*[local-name() = \"IdentificationCode\"]"); - name = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"DeliveryParty\"]//*[local-name() = \"PartyName\"]/*[local-name() = \"Name\"]"); -*/ zpp.setDeliveryAddress(delivery); - /* - zpp.setDeliveryAddress(new TradeParty() - .setStreet(street) - .setAdditionalAddress(additionalStreet) - .setLocation(city) - .setZIP(postal) - .setAdditionalAddressExtension(line) - .setCountry(country) - .setName(name) - ); -*/ } @@ -420,14 +398,6 @@ public class ZUGFeRDInvoiceImporter { XPathExpression shipPayee = xpath.compile("//*[local-name()=\"PayeeParty\"]/*"); NodeList ublPayeeNodes = (NodeList) shipPayee.evaluate(getDocument(), XPathConstants.NODESET); -// if(ublPayeeNodes != null) { -// TradeParty payee = new TradeParty(); -// NodeMap nodeMap = new NodeMap(ublPayeeNodes).getAsNodeMap("PayeeParty").get(); -// nodeMap.getNode("ID").ifPresent(s -> { -// SchemedID sID = new SchemedID().setScheme(s.getAttributes().getNamedItem("schemeID").getTextContent()).setId(s.getTextContent()); -// payee.addGlobalID(sID); -// }); -// } //NodeList UBLpayeeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); if (ublPayeeNodes.getLength() > 0) { zpp.setPayee(new TradeParty(ublPayeeNodes)); @@ -598,6 +568,15 @@ public class ZUGFeRDInvoiceImporter { } } + String creditorReferenceID = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"CreditorReferenceID\"]").trim();//BT-90 + if ((creditorReferenceID == null)||(creditorReferenceID.length()==0)) { + //maybe it's there in UBL? + creditorReferenceID = extractString("//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyIdentification\"]/*[local-name()=\"ID\"]").trim(); + } + if ((creditorReferenceID != null)&&(creditorReferenceID.length()>0)) { + zpp.setCreditorReferenceID(creditorReferenceID); + } + xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeDelivery\"]|//*[local-name()=\"Delivery\"]"); NodeList headerTradeDeliveryNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); @@ -836,9 +815,6 @@ public class ZUGFeRDInvoiceImporter { } } } -// if ((paymentMeansChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("DirectDebitMandateID"))) { -// directDebitMandateID = paymentTermChilds.item(paymentTermChildIndex).getTextContent(); -// } if ((paymentMeansChilds.item(meansChildIndex).getLocalName() != null) && (paymentMeansChilds.item(meansChildIndex).getLocalName().equals("PaymentMandate"))) { NodeList paymentMandateChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes(); @@ -974,6 +950,7 @@ public class ZUGFeRDInvoiceImporter { NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes(); boolean isCharge = true; String chargeAmount = null; + String basisAmount = null; String reason = null; String reasonCode = null; String taxPercent = null; @@ -1001,6 +978,8 @@ public class ZUGFeRDInvoiceImporter { } else if (chargeChildName.equals("ActualAmount") || chargeChildName.equals("Amount")) { chargeAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex)); + } else if (chargeChildName.equals("BasisAmount")) { + basisAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex)); } else if (chargeChildName.equals("Reason") || chargeChildName.equals("AllowanceChargeReason")) { reason = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex)); } else if (chargeChildName.equals("ReasonCode") || chargeChildName.equals("AllowanceChargeReasonCode")) { @@ -1028,6 +1007,9 @@ public class ZUGFeRDInvoiceImporter { if (taxPercent != null) { c.setTaxPercent(new BigDecimal(taxPercent)); } + if (basisAmount != null) { + c.setBasisAmount(new BigDecimal(basisAmount)); + } zpp.addCharge(c); } else { Allowance a = new Allowance(new BigDecimal(chargeAmount)); @@ -1040,6 +1022,9 @@ public class ZUGFeRDInvoiceImporter { if (taxPercent != null) { a.setTaxPercent(new BigDecimal(taxPercent)); } + if (basisAmount != null) { + a.setBasisAmount(new BigDecimal(basisAmount)); + } zpp.addAllowance(a); } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java b/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java index c9ecc2a0..afd5ee28 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java @@ -1,21 +1,23 @@ -/** ********************************************************************** - * +/** + * ********************************************************************* + *

* Copyright 2018 Jochen Staerk - * + *

* Use is subject to license terms. - * + *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0. - * + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * + *

* See the License for the specific language governing permissions and * limitations under the License. - * - *********************************************************************** */ + *

+ * ********************************************************************** + */ package org.mustangproject.ZUGFeRD.model; import java.util.Set; @@ -31,5 +33,5 @@ public class TaxCategoryCodeTypeConstants { public static final String INTRACOMMUNITY = "K"; public static final String FREEEXPORT = "G"; - public static Set CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT).collect(Collectors.toSet()); + public static Set CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT, UNTAXEDSERVICE).collect(Collectors.toSet()); } diff --git a/library/src/main/resources/stylesheets/l10n/de.xml b/library/src/main/resources/stylesheets/l10n/de.xml index fa975bb6..1f893468 100644 --- a/library/src/main/resources/stylesheets/l10n/de.xml +++ b/library/src/main/resources/stylesheets/l10n/de.xml @@ -136,7 +136,7 @@ Vergabenummer Kennung der Empfangsbestätigung Kennung der Versandanzeige - Prozesskennung + Prozesskennung Spezifikationskennung Objektkennung Schema der Objektkennung diff --git a/library/src/main/resources/stylesheets/ubl-creditnote-xr.xsl b/library/src/main/resources/stylesheets/ubl-creditnote-xr.xsl index da2b18c8..e7498922 100644 --- a/library/src/main/resources/stylesheets/ubl-creditnote-xr.xsl +++ b/library/src/main/resources/stylesheets/ubl-creditnote-xr.xsl @@ -99,11 +99,11 @@ - + - + diff --git a/library/src/main/resources/stylesheets/ubl-invoice-xr.xsl b/library/src/main/resources/stylesheets/ubl-invoice-xr.xsl index 7bdec35d..0ba37f26 100644 --- a/library/src/main/resources/stylesheets/ubl-invoice-xr.xsl +++ b/library/src/main/resources/stylesheets/ubl-invoice-xr.xsl @@ -98,11 +98,11 @@ - + - + diff --git a/library/src/main/resources/stylesheets/xr-content.xsl b/library/src/main/resources/stylesheets/xr-content.xsl index cbc50ec2..69f91322 100644 --- a/library/src/main/resources/stylesheets/xr-content.xsl +++ b/library/src/main/resources/stylesheets/xr-content.xsl @@ -818,7 +818,6 @@ - diff --git a/library/src/main/resources/stylesheets/xrechnung-html.univ.xsl b/library/src/main/resources/stylesheets/xrechnung-html.univ.xsl index 92689837..618feb87 100644 --- a/library/src/main/resources/stylesheets/xrechnung-html.univ.xsl +++ b/library/src/main/resources/stylesheets/xrechnung-html.univ.xsl @@ -1797,7 +1797,7 @@ function downloadData (element_id) {

:
-
+
:
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java index 9f3f3ea2..7fc94f5f 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java @@ -54,9 +54,9 @@ public class CalculationTest extends ResourceCase { final LineCalculator calculator = new LineCalculator(currentItem); - assertEquals(valueOf(133.857).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros()); - assertEquals(valueOf(1606.28).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros()); - assertEquals(valueOf(257.0048).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros()); + assertEquals(valueOf(148.73).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros()); + assertEquals(valueOf(1769.89).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros()); + assertEquals(valueOf(283.1824).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros()); } @Test @@ -74,17 +74,20 @@ public class CalculationTest extends ResourceCase { final LineCalculator calculator = new LineCalculator(currentItem); - assertEquals(valueOf(163.603).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros()); - assertEquals(valueOf(1963.24).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros()); - assertEquals(valueOf(314.1184).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros()); + assertEquals(valueOf(148.73).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros()); + assertEquals(valueOf(1799.63).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros()); + assertEquals(valueOf(287.9408).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros()); } @Test public void testLineCalculatorForeignCurrencyExample() { - -/* +/*** xml of official fx sample with allowances and charges + * 10x100 with 10% and 50€ item discount =850€ + * +8,75 charges on document level=858,75, +19%VAT=1021,91 + * prepaid 500->due payable=521,91 + */ File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml"); -inputCII=new File("C:\\Users\\jstaerk\\workspace\\XMLExamples\\zfdiverses\\20250407\\fremdwaehrung.xml"); + ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter(); Invoice invoice=null; zii.doIgnoreCalculationErrors(); @@ -104,9 +107,9 @@ inputCII=new File("C:\\Users\\jstaerk\\workspace\\XMLExamples\\zfdiverses\\20250 final TransactionCalculator calculator = new TransactionCalculator(invoice); - assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros()); + assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getDuePayable().stripTrailingZeros()); + - */ } @@ -221,9 +224,94 @@ inputCII=new File("C:\\Users\\jstaerk\\workspace\\XMLExamples\\zfdiverses\\20250 invoice.addAllowance(new Allowance().setPercent(total_discount_percent).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatte")); } TransactionCalculator calculator = new TransactionCalculator(invoice); - assertEquals(valueOf(101.86).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros()); + assertEquals(valueOf(307.18).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros()); } + public void testSimpleItemPercentAllowance() { + /*** + * a product with net 1.10 and qty 5 and relative item allowance of 10% should return 5 as line and grand total + */ + SimpleDateFormat sqlDate = new SimpleDateFormat("yyyy-MM-dd"); + + Invoice invoice = new Invoice(); + invoice.setDocumentName("Rechnung"); + invoice.setNumber("777777"); + try { + invoice.setIssueDate(sqlDate.parse("2020-12-31")); + invoice.setDetailedDeliveryPeriod(sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[0]), sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[1])); + invoice.setDeliveryDate(sqlDate.parse("2020-12-31")); + invoice.setDueDate(sqlDate.parse("2021-01-15")); + } catch (Exception e) { + LOGGER.error("Failed to set dates", e); + + } + TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE"); + sender.addVATID("DE2222222222"); + invoice.setSender(sender); + + /* trade party (recipient) */ + TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE"); + recipient.setID("111111"); + recipient.addVATID("DE111111111"); + invoice.setRecipient(recipient); + + /* item */ + Product product; + Item item; + + product = new Product("AAA", "", "H84", BigDecimal.ZERO); + item = new Item(product, new BigDecimal("1.10"), new BigDecimal(5.00)); + + item.addAllowance(new Allowance().setPercent(new BigDecimal(10)).setTaxPercent(BigDecimal.ZERO)); + invoice.addItem(item); + + TransactionCalculator calculator = new TransactionCalculator(invoice); + assertEquals(new BigDecimal(5), calculator.getGrandTotal().stripTrailingZeros()); + } + + public void testSimpleItemTotalAllowance() { + /*** + * a product with net 1 and qty 5 and absolute _item_ allowance of 1 should return 4 as line total, and grand total + */ + SimpleDateFormat sqlDate = new SimpleDateFormat("yyyy-MM-dd"); + + Invoice invoice = new Invoice(); + invoice.setDocumentName("Rechnung"); + invoice.setNumber("777777"); + try { + invoice.setIssueDate(sqlDate.parse("2020-12-31")); + invoice.setDetailedDeliveryPeriod(sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[0]), sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[1])); + invoice.setDeliveryDate(sqlDate.parse("2020-12-31")); + invoice.setDueDate(sqlDate.parse("2021-01-15")); + } catch (Exception e) { + LOGGER.error("Failed to set dates", e); + + } + TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE"); + sender.addVATID("DE2222222222"); + invoice.setSender(sender); + + /* trade party (recipient) */ + TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE"); + recipient.setID("111111"); + recipient.addVATID("DE111111111"); + invoice.setRecipient(recipient); + + /* item */ + Product product; + Item item; + + product = new Product("AAA", "", "H84", BigDecimal.ZERO); + item = new Item(product, new BigDecimal("1.00"), new BigDecimal(5.00)); + + item.addAllowance(new Allowance(new BigDecimal(1)).setTaxPercent(BigDecimal.ZERO)); + invoice.addItem(item); + + TransactionCalculator calculator = new TransactionCalculator(invoice); + assertEquals(new BigDecimal(4), calculator.getGrandTotal().stripTrailingZeros()); + } + + /** * LineCalculator should not throw an exception when calculating a non-terminating decimal expansion * */ diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java index bb41fb5a..fd0e7b97 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java @@ -395,7 +395,7 @@ public class DeSerializationTest extends ResourceCase { try { Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class); TransactionCalculator tc=new TransactionCalculator(newInvoiceFromJSON); - assertEquals(new BigDecimal("19.52"),tc.getGrandTotal()); + assertEquals(new BigDecimal("18.92"),tc.getGrandTotal()); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java index 2b63a5da..db772ff1 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java @@ -32,6 +32,8 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.Date; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class VisualizationTest extends ResourceCase { @@ -80,7 +82,7 @@ public class VisualizationTest extends ResourceCase { } catch (ParserConfigurationException e) { fail("ParserConfigurationException should not happen: " + e.getMessage()); } - + assertNotNull(result); /* remove file endings so that tests can also pass after checking out from git with arbitrary options (which may include CSRF changes) @@ -94,6 +96,7 @@ public class VisualizationTest extends ResourceCase { .replace(" ", "")); } + public void testPDFVisualizationCII() { File CIIinputFile = getResourceAsFile("cii/01.01a-INVOICE.cii.xml"); diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java index df97bd6a..e7a2a951 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java @@ -34,6 +34,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; +import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.io.BufferedWriter; @@ -61,8 +62,8 @@ public class XRTest extends TestCase { TradeParty recipient = new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"); recipient.setEmail("quack@ducktown.org"); Invoice i = createInvoice(recipient); - String legalOrgID="aCustomSellerLegalOrgId"; - String sellerID="aSellerTradePartyID"; + String legalOrgID = "aCustomSellerLegalOrgId"; + String sellerID = "aSellerTradePartyID"; i.getSender().setLegalOrganisation(new LegalOrganisation(legalOrgID)); i.getSender().setID(sellerID); ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider(); @@ -70,8 +71,8 @@ public class XRTest extends TestCase { zf2p.generateXML(i); String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8); assertTrue(theXML.contains(""+sellerID+""));// must be possible without scheme # - assertTrue(theXML.contains(""+legalOrgID+""));// must be possible without scheme # + assertTrue(theXML.contains("" + sellerID + ""));// must be possible without scheme # + assertTrue(theXML.contains("" + legalOrgID + ""));// must be possible without scheme # assertThat(theXML).valueByXPath("count(//*[local-name()='IncludedSupplyChainTradeLineItem'])") .asInt() .isEqualTo(1); //2 errors are OK because there is a known bug @@ -90,6 +91,7 @@ public class XRTest extends TestCase { } + public void testXREdgeExport() { // the writing part @@ -109,7 +111,7 @@ public class XRTest extends TestCase { .setReferenceNumber("991-01484-64")//leitweg-id // not using any VAT, this is also a test of zero-rated goods: .setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO).setTaxExemptionReason("Kleinunternehmer"), amount, new BigDecimal(1.0))) - .setPayee( new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199"))) + .setPayee(new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199"))) .embedFileInXML(fe1); @@ -149,9 +151,9 @@ public class XRTest extends TestCase { fail("ParseException not expected"); } catch (IOException e) { fail("IOException not expected"); - } - FileAttachment[] attachedFiles=readInvoice.getAdditionalReferencedDocuments(); - assertNotNull(attachedFiles); + } + FileAttachment[] attachedFiles = readInvoice.getAdditionalReferencedDocuments(); + assertNotNull(attachedFiles); assertEquals(attachedFiles.length, 1); assertTrue(Arrays.equals(attachedFiles[0].getData(), b)); @@ -289,6 +291,36 @@ public class XRTest extends TestCase { } + public void testApplicablePercentInUntaxedService() { + + // the writing part + TradeParty recipient = new TradeParty("Franz Müller", null, "55232", "Entenhausen", "DE"); + String orgname = "Test company"; + String number = "123"; + String amountStr = "1.00"; + BigDecimal amount = new BigDecimal(amountStr); + var i = new Invoice().setDueDate(new java.util.Date()).setIssueDate(new java.util.Date()).setDeliveryDate(new java.util.Date()) + .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("DE4711").addVATID("DE0815").setEmail("info@example.org").setContact(new org.mustangproject.Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new org.mustangproject.BankDetails("DE12500105170648489890", "COBADEFXXX"))) + .setRecipient(recipient) + .setReferenceNumber("991-01484-64")//leitweg-id + // not using any VAT, this is also a test of zero-rated goods: + .setNumber(number).addItem(new org.mustangproject.Item(new org.mustangproject.Product("Testprodukt", "", "C62", java.math.BigDecimal.ZERO).setTaxCategoryCode(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE).setTaxExemptionReason("Expemtion reason"), amount, new java.math.BigDecimal(1.0))); + + ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider(); + zf2p.setProfile(Profiles.getByName("XRechnung")); + zf2p.generateXML(i); + String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8); + // Untaxed services don't have the field RateApplicablePercent, since it would be always 0. An error is thrown on validation, if 0 is set. + assertThat(theXML).valueByXPath("count(//*[local-name()='RateApplicablePercent'])") + .asInt() + .isEqualTo(0); + + //Exemption reason needs to be set if TaxCategoryCode == "O", reason should be at the product and in the ApplicableTradeTax + assertThat(theXML).valueByXPath("count(//*[local-name()='ExemptionReason'])") + .asInt() + .isEqualTo(2); + } + private org.mustangproject.Invoice createInvoice(TradeParty recipient) { String orgname = "Test company"; String number = "123"; diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java index 10f28a3a..9c60b75b 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java @@ -141,7 +141,7 @@ public class ZF2PushTest extends TestCase { String senderDescription = "Kleinunternehmer"; String taxID = "9990815"; - String theNote="oh lala"; + String theNote = "oh lala"; BigDecimal price = new BigDecimal(priceStr); try { InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf"); @@ -177,7 +177,7 @@ public class ZF2PushTest extends TestCase { throw new RuntimeException(e); } - assertEquals(i.getZFItems()[0].getNotesWithSubjectCode().get(0).getContent(),theNote); + assertEquals(i.getZFItems()[0].getNotesWithSubjectCode().get(0).getContent(), theNote); assertEquals(senderDescription, i.getSender().getDescription()); // now check the contents (like MustangReaderTest) @@ -255,16 +255,16 @@ public class ZF2PushTest extends TestCase { // ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr", "55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number) // .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50))))); - Invoice i=new Invoice().setDueDate(new Date()).setIssueDate(new Date()) + Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()) .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815")) .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE") .setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562"))) .setNumber(number) .addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AReason").setTaxPercent(new BigDecimal(19))) - .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1")))) - .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))) + .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1")).setReasonCode("95"))) + .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)).setReason("In love with salesperson"))) .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AnotherReason"))) - .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1))).addAllowance(new Allowance(new BigDecimal("1")))); + .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("Yet another reason")).addAllowance(new Allowance(new BigDecimal("1")).setReason("Something completely strange"))); ze.setTransaction(i); @@ -275,21 +275,20 @@ public class ZF2PushTest extends TestCase { fail("IOException should not be raised"); } - // now check the contents (like MustangReaderTest) - ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_ITEMCHARGESALLOWANCESPDF); - - assertEquals("EUR", zi.getInvoiceCurrencyCode()); - assertTrue(zi.getUTF8().contains("0911623562")); // fax number - assertTrue(zi.getUTF8().contains("ABK")); - - // Reading ZUGFeRD - assertEquals("19.52", zi.getAmount()); - assertEquals(orgname, zi.getHolder()); - assertEquals(number, zi.getForeignReference()); try { + // now check the contents (like MustangReaderTest) + ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_ITEMCHARGESALLOWANCESPDF); + assertEquals("EUR", zi.getInvoiceCurrencyCode()); + assertTrue(zi.getUTF8().contains("0911623562")); // fax number + assertTrue(zi.getUTF8().contains("ABK")); + + // Reading ZUGFeRD + assertEquals("18.92", zi.getAmount()); + assertEquals(orgname, zi.getHolder()); + assertEquals(number, zi.getForeignReference()); assertEquals(zi.getVersion(), 2); } catch (Exception e) { - e.printStackTrace(); + fail("Exception should not be raised"); } } @@ -595,7 +594,7 @@ public class ZF2PushTest extends TestCase { assertEquals(1, i.getInvoiceReferencedDocuments().size()); assertEquals("abcd1234", i.getInvoiceReferencedDocuments().get(0).getIssuerAssignedID()); assertEquals("4304171000002", i.getRecipient().getGlobalID()); - SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd"); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); assertEquals(occurrenceFrom, sdf.format(i.getDetailedDeliveryPeriodFrom())); assertEquals(occurrenceTo, sdf.format(i.getDetailedDeliveryPeriodTo())); assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID()); @@ -629,7 +628,7 @@ public class ZF2PushTest extends TestCase { .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815")) .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")) .setNumber(number) - .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19)))) + .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).addAllowance(new Allowance(BigDecimal.ONE)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19)))) .addAllowance(new Allowance(new BigDecimal(600)).setTaxPercent(new BigDecimal(19))) ); String theXML = new String(ze.getProvider().getXML()); @@ -645,7 +644,7 @@ public class ZF2PushTest extends TestCase { assertEquals("EUR", zi.getInvoiceCurrencyCode()); // Reading ZUGFeRD - assertEquals("4046.00", zi.getAmount()); + assertEquals("10805.20", zi.getAmount()); assertEquals(orgname, zi.getHolder()); assertEquals(number, zi.getForeignReference()); try { @@ -675,8 +674,8 @@ public class ZF2PushTest extends TestCase { .setNumber(number) .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0))) .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0))) - .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)).addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)))) - .addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19))) + .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)).addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"))) + .addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt")) ); String theXML = new String(ze.getProvider().getXML()); assertTrue(theXML.contains(" + + + + urn:cen.eu:en16931:2017 + + + + 123456 + 380 + + 20250426 + + + Jahresbeitrag + + + + + + 1 + + + Product: Plus + + + + 239.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + 239.00 + + + + + + 1 + + + Getting Started-Rabatt + + + + 120.00 + + + + -1.00 + + + + VAT + S + 19.00 + + + -120.00 + + + + + 7777777 + + --- + + --- + Geschäftsführer + + --- + + + q@q.com + + + + 12345 + Str. 11 + --- + DE + + + a@a.com + + + DE111111111 + + + + a & b GmbH + + 123456 + -- + Str. 17 + -- + DE + + + + + + DE11111111111111111111 + EUR + + 59 + + DE22222222222222222222 + + + + 22.61 + VAT + 119.00 + S + 19.00 + + + + 20250426 + + + 20250525 + + + + Zahlbar sofort + + 20250426 + + + + 119.00 + 0.00 + 0.00 + 119.00 + 22.61 + 141.61 + 0.00 + 141.61 + + + + diff --git a/library/src/test/resources/factur-x-vis-extended.de.html b/library/src/test/resources/factur-x-vis-extended.de.html index 4ef990b5..4b049257 100644 --- a/library/src/test/resources/factur-x-vis-extended.de.html +++ b/library/src/test/resources/factur-x-vis-extended.de.html @@ -1,10 +1,9 @@ - - - - XRechnung - + + + + XRechnung + - - -
- -
-
-
-
-
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
-
-
-
+ box-sizing: border-box; + -moz-box-sizing: border-box; + } + + .clear:after + { + content: "."; + clear: both; + display: block; + visibility: hidden; + height: 0; + } + + html, + body + { + height: 100%; + min-width: 320px; + margin: 0; + padding: 0; + color: #000; + font-size: 14px; + } + + body + { + overflow-y: scroll; + background-color: rgba(4, 101, 161, 0.08); + } + + h4 + { + color: inherit; + font-size: inherit; + margin-bottom: 0.5rem; + } + + + /* Grundaufbau *************************************************/ + + .menue + { + position: relative; + z-index: 2000; + background-color: #000; + margin-bottom: 30px; + } + + .innen + { + max-width: 1080px; + margin: 0 auto; + padding: 0 2%; + } + + + + /* Formatierungen *************************************************/ + + .color2 + { + color: rgba(0, 0, 0, 0.6); + } + + .schwarz + { + color: #555 !important; + } + + .normal + { + font-weight: normal; + } + + .bold + { + font-weight: bold; + } + + .abstandUnten + { + margin-bottom: 5px; + } + + .abstandUntenKlein + { + margin-bottom: 10px; + } + + .noPaddingTop + { + padding-top: 0 !important; + } + + .ausrichtungRechts + { + text-align: right; + } + + + + + /* Menü ********************************************************/ + + button + { + position: relative; + font-family: serif; + padding-top: 15px; + padding-left: 0; + padding-right: 0; + margin-right: 2%; + } + + .btnAktiv + { + font-size: 22px; + color: #ffb619; + height: 50px; + outline: none; + border: none; + background: none; + } + + .btnAktiv:after + { + content: ""; + display: block; + position: absolute; + top: 50px; + left: 50%; + z-index: 10; + font-size: 0; + line-height: 0; + height: 0; + padding: 0; + margin: 0; + transform: translateX(-50%); + border: 15px solid #000; + border-right-color: transparent; + border-bottom-color: transparent; + border-left-color: transparent; + } + + .btnInaktiv, + .tab + { + font-size: 22px; + color: #fff; + height: 50px; + z-index: 0; + outline: none; + border: none; + background: none; + transition: color 0.3s ease; + } + + .btnInaktiv:hover, + .tab:hover + { + color: #ffb619; + cursor: pointer; + } + + .divHide + { + display: none; + } + + /* Content *********************************************************************/ + + .inhalt + { + font-family: sans-serif; + margin-bottom: 30px; + } + + .haftungausschluss + { + color: #000; + text-align: center; + padding: 7px; + margin-bottom: 30px; + width: 100%; + border: 1px solid #ffb619; + background-color: #fff; + } + + .box + { + position: relative; + display: table-cell; + padding: 0; + border: 1px solid rgba(4, 101, 161, 0.2); + background-color: #fff; + } + + .subBox + { + border-top: none; + width: 50%; + } + + .subBox:last-child + { + border-left: none; + } + + .first > .boxzeile > .subBox + { + border-top: 1px solid rgba(4, 101, 161, 0.2) !important; + } + + .boxtitel + { + display: inline-block; + background-color: #0465A1; + padding: 7px 10px; + color: #fff; + font-weight: bold; + } + + .boxBorderTop + { + border-top: none; + } + + .boxBorderLeft + { + border-left: none; + } + + .boxtitelSub + { + color: #000; + background-color: rgba(4, 101, 161, 0.1); + border-right: 1px solid rgba(4, 101, 161, 0.2); + border-bottom: 1px solid rgba(4, 101, 161, 0.2); + } + + .boxinhalt + { + padding: 15px 20px; + } + + .boxtabelle + { + display: table; + width: 100%; + } + + .borderSpacing + { + border-spacing: 0 5px; + } + + .boxabstandtop + { + margin-top: 30px; + } + + .boxzeile + { + display: table-row; + } + + .boxzeile .box:last-child + { + margin-bottom: 0; + } + + .boxdaten + { + display: table-cell; + padding: 5px 0; + vertical-align: middle; + height: 38px; + /* + -ms-word-break: break-all; + word-break: break-all; + word-break: break-word; + -webkit-hyphens: auto; + -moz-hyphens: auto; + hyphens: auto; + */ + } + + .boxdaten.wert + { + padding: 5px 10px; + } + + .boxcell + { + display: table-cell; + } + + .boxdatenBlock + { + display: block; + padding: 3px 0; + /* + -ms-word-break: break-all; + word-break: break-all; + word-break: break-word; + -webkit-hyphens: auto; + -moz-hyphens: auto; + hyphens: auto; + */ + } + + .noBreak + { + -ms-word-break: keep-all; + word-break: keep-all; + word-break: keep-all; + -webkit-hyphens: none; + -moz-hyphens: none; + hyphens: none; + } + + .boxabstand + { + display: table-cell; + width: 30px; + } + + .legende + { + color: rgba(0, 0, 0, 0.6); + width: 170px; + font-size: 13px; + line-height: 16px; + padding-right: 5px; + } + + .wert + { + background-color: rgba(4, 101, 161, 0.03); + } + + .boxtabelleEinspaltig + { + width: 49%; + } + + .boxtabelleZweispaltig, + .boxtabelleDreispaltig + { + width: 100%; + } + + .box5050 + { + width: 50%; + } + + .boxEinspaltig + { + width: 100%; + } + + .boxZweispaltig + { + width: 48.5%; + } + + .boxSpalte1 { + width: 50%; + } + + .boxSpalte2 { + width: 50%; + padding-left: 20px; + } + + .paddingLeft { + padding-left: 0.1em; + } + + .noPadding { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + + .rechnungsZeile + { + display: table-row; + } + + .rechnungsZeile .boxdaten + { + height: auto; + } + + .rechnungSp1 + { + width: 65%; + font-size: 16px; + } + + .rechnungSp2 + { + width: 10%; + } + + .rechnungSp3 + { + width: 25%; + font-size: 16px; + text-align: right; + } + + .detailSp1, + .detailSp2 + { + width: 50%; + } + + .detailSp2 + { + text-align: right; + } + + .line1Bottom + { + border-bottom: 1px solid #000; + } + + .line1BottomLight + { + padding-bottom: 5px; + border-bottom: 1px solid #f0f0f0; + margin-bottom: 5px; + } + + .line2Bottom + { + border-bottom: 2px solid #000; + } + + .paddingTop + { + padding-top: 10px; + } + + .paddingBottom + { + padding-bottom: 10px; + } + + .grund + { + font-size: 16px; + display: block; + width: 100%; + padding: 0 20px 15px 20px; + } + + .grundDetail + { + display: block; + width: 100%; + padding: 0 20px 15px 20px; + } + + /* Übersichtformatierungen */ + #uebersichtLastschrift.box, + #uebersichtUeberweisung.box + { + border-top: none; + } + + #uebersichtUeberweisung.box + { + border-left: none; + } + + + /* Formatierungen Detailseite */ + + .detailsSpalte1, + .detailsSpalte2 + { + width: 30%; + float: left; + font-size: 90%; + line-height: 115%; + margin-right: 5%; + } + + .detailsSpalte3 + { + width: 30%; + float: left; + font-size: 90%; + line-height: 115%; + } + + .detailsSpalte1 .legende, + .detailsSpalte2 .legende, + .detailsSpalte3 .legende + { + width: 145px; + } + + .titelPosition + { + font-size: 17px; + font-weight: bold; + } + + + /* Laufzettelformatierungen */ + #laufzettelHistorie .boxtabelle:not(:nth-child(2)) + { + border-top: 1px solid rgba(4, 101, 161, 0.2); + padding-top: 10px; + margin-top: 10px; + } + + + + + + /* 1023px und kleiner ************************************************/ + + @media screen and (max-width : 1023px) { + + .box + { + display: block; + width: 100%; + margin-bottom: 20px; + } + + .boxabstandtop + { + margin-top: 15px; + } + + .subBox:first-child + { + margin-bottom: 0 !important; + } + + .subBox:last-child + { + border-left: 1px solid rgba(4, 101, 161, 0.2); + } + + .first > .boxzeile > .subBox + { + border-top: none !important; + } + + .first > .boxzeile > .subBox:first-child + { + border-top: 1px solid rgba(4, 101, 161, 0.2) !important; + } + + .first > .boxzeile + { + margin-bottom: 0; + } + + #uebersichtUeberweisung.box + { + border-left: 1px solid rgba(4, 101, 161, 0.2); + } + + #uebersichtLastschrift.box + { + margin-bottom: 0; + } + + .boxzeile + { + display: block; + margin-bottom: 5px; + } + + .boxzeile:after + { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; + } + + #details > .boxtabelle > .boxzeile + { + margin-bottom: 0px; + } + + .boxcell + { + display: block; + } + + .boxcell:last-child + { + margin-top: 20px; + } + + .boxZweispaltig + { + width: 100%; + } + + .legende + { + display: block; + float: left; + width: 170px; + padding: 5px 0; + height: auto; + } + + .wert + { + display: block; + float: left; + width: calc(100% - 170px); + padding: 11px 10px !important; + line-height: 1.3; + min-height: 38px; + height: auto; + } + + .boxdaten .legende + { + height: auto; + } + + .rechnungsZeile .boxdaten + { + padding: 5px 0; + } + + .boxabstand + { + display: none; + } + + .boxtabelleEinspaltig { + width: 100%; + } + + .boxSpalte1 { + display: block; + width: auto; + } + + .boxSpalte2 { + display: block; + width: auto; + padding-left: 0px; + margin-top: 1.2rem; + } + + .detailsSpalte1, + .detailsSpalte2, + .detailsSpalte3 + { + width: 100%; + float: none; + padding-right: 0px; + } + + .detailsSpalte2, + .detailsSpalte3 + { + margin-top: 15px; + } + + .detailsSpalte2, + .detailsSpalte3 + { + margin-top: 10px; + } + + .tableNumberAlignRight + { + display: block; + width: 130px; + text-align: right; + } + } + + + + /* 800px und kleiner ************************************************/ + + @media screen and (max-width : 800px) { + + button + { + padding-top: 10px; + } + + .btnAktiv, + .btnInaktiv, + .tab + { + font-size: 20px; + height: 40px; + } + + .btnAktiv:after + { + top: 40px; + } + + .rechnungSp1 + { + width: 55%; + font-size: 15px; + } + + .rechnungSp2 + { + width: 10%; + } + + .rechnungSp3 + { + width: 35%; + text-align: right; + font-size: 15px; + } + + .grund + { + font-size: 15px; + } + } + + /* 450px und kleiner ************************************************/ + + @media screen and (max-width : 450px) + { + + html, + body + { + font-size: 12px; + } + + .menue + { + margin-bottom: 20px; + } + + button + { + padding-top: 5px; + } + + .btnAktiv, + .btnInaktiv, + .tab + { + font-size: 17px; + height: 35px; + } + + .btnAktiv:after + { + top: 35px; + } + + .legende + { + font-size: 12px; + width: 100%; + } + + .wert + { + font-size: 12px; + line-height: 1.3; + width: 100%; + margin-bottom: 10px + } + + .boxzeile + { + margin-bottom: 0px + } + + .boxdaten + { + height: auto; + } + + .haftungausschluss + { + margin-bottom: 20px; + } + + .boxinhalt + { + margin-top: 0px; + } + + .boxabstandtop + { + margin-top: 20px; + } + + .boxtitel + { + padding: 7px 8px; + } + + .box + { + margin-bottom: 10px; + padding: 0; + } + + .boxabstandtop + { + margin-top: 10px; + } + + .boxdaten, + .boxdatenBlock + { + padding: 2px 0; + } + + .rechnungSp1 + { + width: 50%; + font-size: inherit; + } + + .rechnungSp2 + { + width: 15%; + } + + .rechnungSp3 + { + width: 35%; + font-size: inherit; + text-align: right; + } + + .grund + { + font-size: inherit; + } + + .titelPosition + { + font-size: 15px; + } + + .abstandUnten + { + margin-bottom: 5px; + } + + .detailsSpalte1, + .detailsSpalte2, + .detailsSpalte3 + { + font-size: inherit; + line-height: inherit; + } + } + + /* 380px und kleiner ************************************************/ + + @media screen and (max-width : 380px) { + + html, + body + { + font-size: 11px; + line-height: 100%; + } + + .btnAktiv, + .btnInaktiv, + .tab + { + font-size: 15px; + } + + .boxdaten + .boxdatenBlock + { + padding: 2px 0; + } + + .boxinhalt + { + margin-top: 0px; + } + + .boxtitel + { + padding: 5px 7px; + } + } + + + + + +
+ +
+
+
+
+
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
+
+
+
Informationen zum Käufer
-
-
Leitweg-ID:
-
-
-
-
Name:
-
MUSTER-KUNDE GMBH
-
-
-
Straße / Haus-Nr.:
-
KUNDENWEG 88
-
-
-
Adresszusatz:
-
-
-
-
Adresszusatz:
-
-
-
-
PLZ:
-
40235
-
-
-
Ort:
-
DUESSELDORF
-
-
-
Bundesland:
-
-
-
-
Land:
-
DE (Deutschland)
-
-
-
Kennung / Kunden-Nr.:
-
4304171000002
-
-
-
Schema der Kennung:
-
0088 (EAN - Location Code) -
-
-
-
Name:
-
-
-
-
Telefon:
-
-
-
-
E-Mail-Adresse:
-
-
+
+
Leitweg-ID:
+
+
+
+
Name:
+
MUSTER-KUNDE GMBH
+
+
+
Straße / Haus-Nr.:
+
KUNDENWEG 88
+
+
+
Adresszusatz:
+
+
+
+
Adresszusatz:
+
+
+
+
PLZ:
+
40235
+
+
+
Ort:
+
DUESSELDORF
+
+
+
Bundesland:
+
+
+
+
Land:
+
DE (Deutschland)
+
+
+
Kennung / Kunden-Nr.:
+
4304171000002
+
+
+
Schema der Kennung:
+
0088 (EAN Location Code)
+
+
+
Name:
+
+
+
+
Telefon:
+
+
+
+
E-Mail-Adresse:
+
+
-
-
-
+
+
+
Informationen zum Verkäufer
-
-
-
-
-
-
Firmenname:
-
MUSTERLIEFERANT GMBH
-
-
-
Straße / Haus-Nr.:
-
BAHNHOFSTRASSE 99
-
-
-
Adresszusatz:
-
-
-
-
Adresszusatz:
-
-
-
-
PLZ:
-
99199
-
-
-
Ort:
-
MUSTERHAUSEN
-
-
-
Bundesland:
-
-
-
-
Ländercode:
-
DE (Deutschland)
-
-
-
Kennung:
-
4333741000005
-
-
-
Schema der Kennung:
-
0088 (EAN - Location Code) -
-
-
-
Name:
-
-
-
-
Telefon:
-
+49 932 431 500
-
-
-
E-Mail-Adresse:
-
max.mustermann@musterlieferant.de -
-
+
+
+
+
+
+
Firmenname:
+
MUSTERLIEFERANT GMBH
+
+
+
Straße / Haus-Nr.:
+
BAHNHOFSTRASSE 99
+
+
+
Adresszusatz:
+
+
+
+
Adresszusatz:
+
+
+
+
PLZ:
+
99199
+
+
+
Ort:
+
MUSTERHAUSEN
+
+
+
Bundesland:
+
+
+
+
Ländercode:
+
DE (Deutschland)
+
+
+
Kennung:
+
4333741000005
+
+
+
Schema der Kennung:
+
0088 (EAN Location Code)
+
+
+
Name:
+
+
+
+
Telefon:
+
+49 932 431 500
+
+
+
E-Mail-Adresse:
+
max.mustermann@musterlieferant.de
+
-
-
-
-
-
-
+
+
+
+
+
+
Rechnungsdaten
-
-
-
-
Rechnungsnummer:
-
KR87654321012
-
-
-
Rechnungsdatum:
-
15.11.2024
-
-
-
Rechnungsart:
-
380 (Commercial invoice)
-
-
-
Währung
-
EUR (Euro)
-
-
-

Abrechnungszeitraum:

-
-
-
von:
-
-
-
-
bis:
-
-
-
-
-
-
-
-
-
Projektnummer:
-
-
-
-
Vertragsnummer:
-
-
-
-
Bestellnummer:
-
-
-
-
Auftragsnummer:
-
-
-
-

Vorausgegangene Rechnungen:

-
+
+
+
+
Rechnungsnummer:
+
KR87654321012
+
+
+
Rechnungsdatum:
+
15.11.2024
+
+
+
Rechnungsart:
+
380 (Commercial invoice)
+
+
+
Währung
+
EUR (Euro)
+
+
+

Abrechnungszeitraum:

+
+
+
von:
+
+
+
+
bis:
+
+
+
+
+
+
+
+
+
Projektnummer:
+
+
+
+
Vertragsnummer:
+
+
+
+
Bestellnummer:
+
+
+
+
Auftragsnummer:
+
+
+
+

Vorausgegangene Rechnungen:

+
-
-
-
-
-
-
+
+
+
+
+
+
Gesamtbeträge der Rechnung
-
-
Summe aller Positionen
-
netto
-
410,10
-
-
-
Summe Nachlässe
-
netto
-
21,55
-
-
-
Summe Zuschläge
-
netto
-
- 15,00 -
-
-
-
Gesamtsumme
-
netto
-
403,55
-
-
-
Summe Umsatzsteuer
-
-
-
-
-
Summe Umsatzsteuer in - Abrechnungswährung -
-
-
- 76,67 -
-
-
-
Gesamtsumme
-
brutto
-
480,22
-
-
-
Gezahlter Betrag
-
brutto
-
0,00
-
-
-
Rundungsbetrag
-
brutto
-
-
-
-
Fälliger Betrag
-
brutto
-
480,22 -
-
-
-
-
-
-
-
-
-
Aufschlüsselung der Umsatzsteuer auf Ebene der - Rechnung +
+
Summe aller Positionen
+
netto
+
410,10
+
+
+
Summe Nachlässe
+
netto
+
21,55
+
+
+
Summe Zuschläge
+
netto
+
15,00
+
+
+
Gesamtsumme
+
netto
+
403,55
+
+
+
Summe Umsatzsteuer
+
+
+
+
+
Summe Umsatzsteuer in Abrechnungswährung
+
+
76,67
+
+
+
Gesamtsumme
+
brutto
+
480,22
+
+
+
Gezahlter Betrag
+
brutto
+
0,00
+
+
+
Rundungsbetrag
+
brutto
+
+
+
+
Fälliger Betrag
+
brutto
+
480,22
+
+
+
+
+
+
+
+
Aufschlüsselung der Umsatzsteuer auf Ebene der Rechnung
-
-
Umsatzsteuerkategorie: S (Standard rate) -
-
-
-
-
-
Gesamtsumme
-
netto
-
403,55
-
-
-
Umsatzsteuersatz
-
-
19.00%
-
-
-
Umsatzsteuerbetrag
-
-
76,67
-
+
+
Umsatzsteuerkategorie: S (Standard rate)
+
+
+
+
+
Gesamtsumme
+
netto
+
403,55
+
+
+
Umsatzsteuersatz
+
+
19.00%
+
+
+
Umsatzsteuerbetrag
+
+
76,67
+
-
Befreiungsgrund:
-
Kennung für den Befreiungsgrund: -
+
Befreiungsgrund:
+
Kennung für den Befreiungsgrund:
-
-
-
-
-
-
+
+
+
+
+
+
Nachlass auf Ebene der Rechnung
-
-
Umsatzsteuerkategorie des Nachlasses: S (Standard rate)
-
-
-
-
-
Grundbetrag
-
netto
-
410,10
-
-
-
Prozentsatz
-
-
%
-
-
-
Nachlass
-
netto
-
21,55
-
-
-
Umsatzsteuersatz des Nachlasses
-
-
19.00
-
+
+
Umsatzsteuerkategorie des Nachlasses: S (Standard rate)
+
+
+
+
+
Grundbetrag
+
netto
+
410,10
+
+
+
Prozentsatz
+
+
%
+
+
+
Nachlass
+
netto
+
21,55
+
+
+
Umsatzsteuersatz des Nachlasses
+
+
19.00
+
-
Grund für den Nachlass: Sonderrabatt -
-
Document level allowance reason code:
+
Grund für den Nachlass: Sonderrabatt
+
Document level allowance reason code:
-
-
-
-
-
-
-
+
+
+
+
+
+
+
Versandkosten
-
-
Umsatzsteuerkategorie der Versandkosten: S (Standard rate)
-
-
-
-
-
Betrag
-
netto
-
15,00
-
-
-
Umsatzsteuersatz der Versandkosten
-
-
19.00
-
+
+
Umsatzsteuerkategorie der Versandkosten: S (Standard rate)
+
+
+
+
+
Betrag
+
netto
+
15,00
+
+
+
Umsatzsteuersatz der Versandkosten
+
+
19.00
+
-
Versandkostenbeschreibung: Transportkosten: Frachbetrag -
+
Versandkostenbeschreibung: Transportkosten: Frachbetrag
-
-
-
-
-
-
-
+
+
+
+
+
+
+
Zahlungsdaten
-
-
Skonto; weitere Zahlungsbed.:
-
#SKONTO# TAGE =10#PROZENT=2.00# - Skontovereinbarung: 2% bei Zahlung innerhalb 10 Tagen nach Rechnungsdatum -
-
-
-
Fälligkeitsdatum:
-
-
-
-
Code für das Zahlungsmittel:
-
-
-
-
Zahlungsmittel:
-
-
-
-
Verwendungszweck:
-
-
+
+
Skonto; weitere Zahlungsbed.:
+
+ #SKONTO# + TAGE + =10#PROZENT=2.00# + Skontovereinbarung: 2% bei Zahlung innerhalb 10 Tagen nach Rechnungsdatum
+
+
+
Fälligkeitsdatum:
+
+
+
+
Code für das Zahlungsmittel:
+
+
+
+
Zahlungsmittel:
+
+
+
+
Verwendungszweck:
+
+
-
-
+
+
Karteninformation
-
-
Kartennummer:
-
-
-
-
Karteninhaber:
-
-
+
+
Kartennummer:
+
+
+
+
Karteninhaber:
+
+
-
-
-
-
-
-
+
+
+
+
+
+
Lastschrift
-
-
Mandatsreferenznr.:
-
-
-
-
IBAN:
-
-
-
-
Gläubiger-ID:
-
-
+
+
Mandatsreferenznr.:
+
+
+
+
IBAN:
+
+
+
+
Gläubiger-ID:
+
+
-
-
+
+
Überweisung
-
-
+
+
+
+
+
+
+
Bemerkung zur Rechnung
+
+
+
Betreff:
+
AAK (Price conditions)
+
+
+
Bemerkung:
+
Es bestehen Rabatt- oder Bonusvereinbarungen.
+
+
+
+
+
Bemerkung zur Rechnung
+
+
+
Betreff:
+
AAJ (Additional conditions of sale/purchase)
+
+
+
Bemerkung:
+
Der Verkäufer bleibt Eigentümer der Waren bis zur vollständigen Erfüllung der Kaufpreisforderung.
+
+
+
+
+
Bemerkung zur Rechnung
+
+
+
Betreff:
+
REG (Regulatory information)
+
+
+
Bemerkung:
+
MUSTERLIEFERANT GMBH + BAHNHOFSTRASSE 99 + 99199 MUSTERHAUSEN + Geschäftsführung: + Max Mustermann + USt-IdNr: DE123456789 + Telefon: +49 932 431 0 + www.musterlieferant.de + HRB Nr. 372876 + Amtsgericht Musterstadt + GLN 4304171000002 +
+
+
+
+
+
-
-
-
-
Bemerkung zur Rechnung
-
-
-
Betreff:
-
AAK (Price conditions)
-
-
-
Bemerkung:
-
Es bestehen Rabatt- oder - Bonusvereinbarungen. -
-
-
-
-
-
Bemerkung zur Rechnung
-
-
-
Betreff:
-
AAJ (Additional conditions of - sale/purchase) -
-
-
-
Bemerkung:
-
Der Verkäufer bleibt Eigentümer der - Waren bis zur vollständigen Erfüllung der Kaufpreisforderung. -
-
-
-
-
-
Bemerkung zur Rechnung
-
-
-
Betreff:
-
REG (Regulatory information)
-
-
-
Bemerkung:
-
MUSTERLIEFERANT GMBH BAHNHOFSTRASSE - 99 99199 MUSTERHAUSEN Geschäftsführung: Max Mustermann USt-IdNr: DE123456789 - Telefon: +49 932 431 0 www.musterlieferant.de HRB Nr. 372876 Amtsgericht Musterstadt - GLN 4304171000002 -
-
-
-
-
-
-
-
-
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
-
-
-
+
+
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
+
+
+
Position1
-
-
Freitext:
-
-
-
-
Objektkennung:
-
-
-
-
Schema der Objektkennung:
-
-
-
-
Nummer der Auftragsposition:
-
-
-
-
Kontierungshinweis /Kostenstelle:
-
-
-

Abrechnungszeitraum:

-
-
von:
-
-
-
-
bis:
-
-
+
+
Freitext:
+
+
+
+
Objektkennung:
+
+
+
+
Schema der Objektkennung:
+
+
+
+
Nummer der Auftragsposition:
+
+
+
+
Kontierungshinweis /Kostenstelle:
+
+
+

Abrechnungszeitraum:

+
+
von:
+
+
+
+
bis:
+
+
-
-
+
+
Preiseinzelheiten
-
-
Menge
-
1000.0000
-
-
-
Einheit
-
KWH (kilowatt hour)
-
-
-
Preis pro Einheit (netto)
-
0,05
-
-
-
Gesamtpreis (netto)
-
52,00
-
+
+
Menge
+
1000.0000
+
+
+
Einheit
+
KWH (kilowatt hour)
+
+
+
Preis pro Einheit (netto)
+
0,05
+
+
+
Gesamtpreis (netto)
+
52,00
+
-
-
Rabatt (netto):
-
-
-
-
Listenpreis (netto):
-
0,05
-
-
-
Anzahl der Einheit:
-
-
-
-
Code der Maßeinheit:
-
-
-
-
Umsatzsteuer:
-
S (Standard rate)
-
-
-
Umsatzsteuersatz in %:
-
19%
-
+
+
Rabatt (netto):
+
0,00
+
+
+
Listenpreis (netto):
+
0,05
+
+
+
Anzahl der Einheit:
+
+
+
+
Code der Maßeinheit:
+
+
+
+
Umsatzsteuer:
+
S (Standard rate)
+
+
+
Umsatzsteuersatz in %:
+
19%
+
-
-
-
-
-
-
-
Nachlässe auf Ebene der - Rechnungsposition -
-
-
-
Zuschläge auf Ebene der - Rechnungsposition -
-
-
-
-
-
-
+
+
+
+
+
+
+
Nachlässe auf Ebene der Rechnungsposition
+
+
+
Zuschläge auf Ebene der Rechnungsposition
+
+
+
+
+
+
Artikelinformationen
-
-
-
-
-
Bezeichnung:
-
Wirkarbeit HT -
-
-
-
Beschreibung:
-
-
-
-
Artikelnummer:
-
WA997
-
-
-
Kunden-Material-Nr.:
-
-
-

Eigenschaften des Artikels:

-
-
Zählpunkt
-
- DE0001346484600000000000000100038 -
-
+
+
+
+
+
Bezeichnung:
+
Wirkarbeit HT
-
-
-
-
-
-
Artikelkennung (EAN):
-
4123456000014
-
-
-
Schema der Artikelkennung:
-
- 0088 (EAN Location Code) -
-
-
-
Code der Artikelklassifizierung:
-
-
-
-
Kennung zur Bildung des Schemas:
-
-
-
-
Version zur Bildung des Schemas:
-
-
-
-
Code des Herkunftslandes:
-
-
+
+
Beschreibung:
+
-
-
+
+
Artikelnummer:
+
WA997
+
+
+
Kunden-Material-Nr.:
+
+
+

Eigenschaften des Artikels:

+
+
Zählpunkt
+
DE0001346484600000000000000100038
+
+
+
+
+
+
+
+
Artikelkennung (EAN):
+
4123456000014
+
+
+
Schema der Artikelkennung:
+
0088 (EAN Location Code)
+
+
+
Code der Artikelklassifizierung:
+
+
+
+
Kennung zur Bildung des Schemas:
+
+
+
+
Version zur Bildung des Schemas:
+
+
+
+
Code des Herkunftslandes:
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
Position2
-
-
Freitext:
-
-
-
-
Objektkennung:
-
-
-
-
Schema der Objektkennung:
-
-
-
-
Nummer der Auftragsposition:
-
-
-
-
Kontierungshinweis /Kostenstelle:
-
-
-

Abrechnungszeitraum:

-
-
von:
-
-
-
-
bis:
-
-
+
+
Freitext:
+
+
+
+
Objektkennung:
+
+
+
+
Schema der Objektkennung:
+
+
+
+
Nummer der Auftragsposition:
+
+
+
+
Kontierungshinweis /Kostenstelle:
+
+
+

Abrechnungszeitraum:

+
+
von:
+
+
+
+
bis:
+
+
-
-
+
+
Preiseinzelheiten
-
-
Menge
-
1000.0000
-
-
-
Einheit
-
KWH (kilowatt hour)
-
-
-
Preis pro Einheit (netto)
-
0,02
-
-
-
Gesamtpreis (netto)
-
20,50
-
+
+
Menge
+
1000.0000
+
+
+
Einheit
+
KWH (kilowatt hour)
+
+
+
Preis pro Einheit (netto)
+
0,02
+
+
+
Gesamtpreis (netto)
+
20,50
+
-
-
Rabatt (netto):
-
-
-
-
Listenpreis (netto):
-
0,02
-
-
-
Anzahl der Einheit:
-
-
-
-
Code der Maßeinheit:
-
-
-
-
Umsatzsteuer:
-
S (Standard rate)
-
-
-
Umsatzsteuersatz in %:
-
19%
-
+
+
Rabatt (netto):
+
0,00
+
+
+
Listenpreis (netto):
+
0,02
+
+
+
Anzahl der Einheit:
+
+
+
+
Code der Maßeinheit:
+
+
+
+
Umsatzsteuer:
+
S (Standard rate)
+
+
+
Umsatzsteuersatz in %:
+
19%
+
-
-
-
-
-
-
-
Nachlässe auf Ebene der - Rechnungsposition -
-
-
-
Zuschläge auf Ebene der - Rechnungsposition -
-
-
-
-
-
-
+
+
+
+
+
+
+
Nachlässe auf Ebene der Rechnungsposition
+
+
+
Zuschläge auf Ebene der Rechnungsposition
+
+
+
+
+
+
Artikelinformationen
-
-
-
-
-
Bezeichnung:
-
Ökosteuer - Lieferant -
-
-
-
Beschreibung:
-
-
-
-
Artikelnummer:
-
ÖST250
-
-
-
Kunden-Material-Nr.:
-
-
-

Eigenschaften des Artikels:

-
-
-
-
-
-
Artikelkennung (EAN):
-
4123456000021
-
-
-
Schema der Artikelkennung:
-
- 0088 (EAN Location Code) -
-
-
-
Code der Artikelklassifizierung:
-
-
-
-
Kennung zur Bildung des Schemas:
-
-
-
-
Version zur Bildung des Schemas:
-
-
-
-
Code des Herkunftslandes:
-
-
+
+
+
+
+
Bezeichnung:
+
Ökosteuer Lieferant
-
-
+
+
Beschreibung:
+
+
+
+
Artikelnummer:
+
ÖST250
+
+
+
Kunden-Material-Nr.:
+
+
+

Eigenschaften des Artikels:

+
+
+
+
+
+
+
Artikelkennung (EAN):
+
4123456000021
+
+
+
Schema der Artikelkennung:
+
0088 (EAN Location Code)
+
+
+
Code der Artikelklassifizierung:
+
+
+
+
Kennung zur Bildung des Schemas:
+
+
+
+
Version zur Bildung des Schemas:
+
+
+
+
Code des Herkunftslandes:
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
Position3
-
-
Freitext:
-
-
-
-
Objektkennung:
-
-
-
-
Schema der Objektkennung:
-
-
-
-
Nummer der Auftragsposition:
-
-
-
-
Kontierungshinweis /Kostenstelle:
-
-
-

Abrechnungszeitraum:

-
-
von:
-
-
-
-
bis:
-
-
+
+
Freitext:
+
+
+
+
Objektkennung:
+
+
+
+
Schema der Objektkennung:
+
+
+
+
Nummer der Auftragsposition:
+
+
+
+
Kontierungshinweis /Kostenstelle:
+
+
+

Abrechnungszeitraum:

+
+
von:
+
+
+
+
bis:
+
+
-
-
+
+
Preiseinzelheiten
-
-
Menge
-
27.5000
-
-
-
Einheit
-
HUR (hour)
-
-
-
Preis pro Einheit (netto)
-
10,50
-
-
-
Gesamtpreis (netto)
-
288,75
-
+
+
Menge
+
27.5000
+
+
+
Einheit
+
HUR (hour)
+
+
+
Preis pro Einheit (netto)
+
10,50
+
+
+
Gesamtpreis (netto)
+
288,75
+
-
-
Rabatt (netto):
-
4,50
-
-
-
Listenpreis (netto):
-
15,00
-
-
-
Anzahl der Einheit:
-
-
-
-
Code der Maßeinheit:
-
-
-
-
Umsatzsteuer:
-
S (Standard rate)
-
-
-
Umsatzsteuersatz in %:
-
19%
-
+
+
Rabatt (netto):
+
4,50
+
+
+
Listenpreis (netto):
+
15,00
+
+
+
Anzahl der Einheit:
+
+
+
+
Code der Maßeinheit:
+
+
+
+
Umsatzsteuer:
+
S (Standard rate)
+
+
+
Umsatzsteuersatz in %:
+
19%
+
-
-
-
-
-
-
-
Nachlässe auf Ebene der - Rechnungsposition -
-
-
-
Zuschläge auf Ebene der - Rechnungsposition -
-
-
-
-
-
-
+
+
+
+
+
+
+
Nachlässe auf Ebene der Rechnungsposition
+
+
+
Zuschläge auf Ebene der Rechnungsposition
+
+
+
+
+
+
Artikelinformationen
-
-
-
-
-
Bezeichnung:
-
Kommissionierer - 1250032 D. Muster -
-
-
-
Beschreibung:
-
Besteller: Hr. Mayer, - Personalnr. 4488 -
-
-
-
Artikelnummer:
-
-
-
-
Kunden-Material-Nr.:
-
-
-

Eigenschaften des Artikels:

-
-
-
-
-
-
Artikelkennung (EAN):
-
4260331811362
-
-
-
Schema der Artikelkennung:
-
- 0088 (EAN Location Code) -
-
-
-
Code der Artikelklassifizierung:
-
-
-
-
Kennung zur Bildung des Schemas:
-
-
-
-
Version zur Bildung des Schemas:
-
-
-
-
Code des Herkunftslandes:
-
-
+
+
+
+
+
Bezeichnung:
+
Kommissionierer 1250032 D. Muster
-
-
+
+
Beschreibung:
+
Besteller: Hr. Mayer, Personalnr. 4488
+
+
+
Artikelnummer:
+
+
+
+
Kunden-Material-Nr.:
+
+
+

Eigenschaften des Artikels:

+
+
+
+
+
+
+
Artikelkennung (EAN):
+
4260331811362
+
+
+
Schema der Artikelkennung:
+
0088 (EAN Location Code)
+
+
+
Code der Artikelklassifizierung:
+
+
+
+
Kennung zur Bildung des Schemas:
+
+
+
+
Version zur Bildung des Schemas:
+
+
+
+
Code des Herkunftslandes:
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
Position4
-
-
Freitext:
-
-
-
-
Objektkennung:
-
-
-
-
Schema der Objektkennung:
-
-
-
-
Nummer der Auftragsposition:
-
-
-
-
Kontierungshinweis /Kostenstelle:
-
-
-

Abrechnungszeitraum:

-
-
von:
-
-
-
-
bis:
-
-
+
+
Freitext:
+
+
+
+
Objektkennung:
+
+
+
+
Schema der Objektkennung:
+
+
+
+
Nummer der Auftragsposition:
+
+
+
+
Kontierungshinweis /Kostenstelle:
+
+
+

Abrechnungszeitraum:

+
+
von:
+
+
+
+
bis:
+
+
-
-
+
+
Preiseinzelheiten
-
-
Menge
-
3500.0000
-
-
-
Einheit
-
H87 (piece)
-
-
-
Preis pro Einheit (netto)
-
0,01
-
-
-
Gesamtpreis (netto)
-
36,75
-
+
+
Menge
+
3500.0000
+
+
+
Einheit
+
H87 (piece)
+
+
+
Preis pro Einheit (netto)
+
0,01
+
+
+
Gesamtpreis (netto)
+
36,75
+
-
-
Rabatt (netto):
-
-
-
-
Listenpreis (netto):
-
0,01
-
-
-
Anzahl der Einheit:
-
-
-
-
Code der Maßeinheit:
-
-
-
-
Umsatzsteuer:
-
S (Standard rate)
-
-
-
Umsatzsteuersatz in %:
-
19%
-
+
+
Rabatt (netto):
+
0,00
+
+
+
Listenpreis (netto):
+
0,01
+
+
+
Anzahl der Einheit:
+
+
+
+
Code der Maßeinheit:
+
+
+
+
Umsatzsteuer:
+
S (Standard rate)
+
+
+
Umsatzsteuersatz in %:
+
19%
+
-
-
-
-
-
-
-
Nachlässe auf Ebene der - Rechnungsposition -
-
-
-
Zuschläge auf Ebene der - Rechnungsposition -
-
-
-
-
-
-
+
+
+
+
+
+
+
Nachlässe auf Ebene der Rechnungsposition
+
+
+
Zuschläge auf Ebene der Rechnungsposition
+
+
+
+
+
+
Artikelinformationen
-
-
-
-
-
Bezeichnung:
-
FALTENBEUTEL - 16x6x28 CM -
-
-
-
Beschreibung:
-
-
-
-
Artikelnummer:
-
FB05
-
-
-
Kunden-Material-Nr.:
-
-
-

Eigenschaften des Artikels:

-
-
-
-
-
-
Artikelkennung (EAN):
-
2001015001325
-
-
-
Schema der Artikelkennung:
-
- 0088 (EAN Location Code) -
-
-
-
Code der Artikelklassifizierung:
-
-
-
-
Kennung zur Bildung des Schemas:
-
-
-
-
Version zur Bildung des Schemas:
-
-
-
-
Code des Herkunftslandes:
-
-
+
+
+
+
+
Bezeichnung:
+
FALTENBEUTEL 16x6x28 CM
-
-
+
+
Beschreibung:
+
+
+
+
Artikelnummer:
+
FB05
+
+
+
Kunden-Material-Nr.:
+
+
+

Eigenschaften des Artikels:

+
+
+
+
+
+
+
Artikelkennung (EAN):
+
2001015001325
+
+
+
Schema der Artikelkennung:
+
0088 (EAN Location Code)
+
+
+
Code der Artikelklassifizierung:
+
+
+
+
Kennung zur Bildung des Schemas:
+
+
+
+
Version zur Bildung des Schemas:
+
+
+
+
Code des Herkunftslandes:
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
Position5
-
-
Freitext:
-
-
-
-
Objektkennung:
-
-
-
-
Schema der Objektkennung:
-
-
-
-
Nummer der Auftragsposition:
-
-
-
-
Kontierungshinweis /Kostenstelle:
-
-
-

Abrechnungszeitraum:

-
-
von:
-
-
-
-
bis:
-
-
+
+
Freitext:
+
+
+
+
Objektkennung:
+
+
+
+
Schema der Objektkennung:
+
+
+
+
Nummer der Auftragsposition:
+
+
+
+
Kontierungshinweis /Kostenstelle:
+
+
+

Abrechnungszeitraum:

+
+
von:
+
+
+
+
bis:
+
+
-
-
+
+
Preiseinzelheiten
-
-
Menge
-
1210.0000
-
-
-
Einheit
-
H87 (piece)
-
-
-
Preis pro Einheit (netto)
-
0,01
-
-
-
Gesamtpreis (netto)
-
12,10
-
+
+
Menge
+
1210.0000
+
+
+
Einheit
+
H87 (piece)
+
+
+
Preis pro Einheit (netto)
+
0,01
+
+
+
Gesamtpreis (netto)
+
12,10
+
-
-
Rabatt (netto):
-
-
-
-
Listenpreis (netto):
-
0,01
-
-
-
Anzahl der Einheit:
-
-
-
-
Code der Maßeinheit:
-
-
-
-
Umsatzsteuer:
-
S (Standard rate)
-
-
-
Umsatzsteuersatz in %:
-
19%
-
+
+
Rabatt (netto):
+
0,00
+
+
+
Listenpreis (netto):
+
0,01
+
+
+
Anzahl der Einheit:
+
+
+
+
Code der Maßeinheit:
+
+
+
+
Umsatzsteuer:
+
S (Standard rate)
+
+
+
Umsatzsteuersatz in %:
+
19%
+
-
-
-
-
-
-
-
Nachlässe auf Ebene der - Rechnungsposition -
-
-
-
Zuschläge auf Ebene der - Rechnungsposition -
-
-
-
-
-
-
+
+
+
+
+
+
+
Nachlässe auf Ebene der Rechnungsposition
+
+
+
Zuschläge auf Ebene der Rechnungsposition
+
+
+
+
+
+
Artikelinformationen
-
-
-
-
-
Bezeichnung:
-
Kopierpapier A4 -
-
-
-
Beschreibung:
-
Zählerstand von-bis: - 543210 - 544420 -
-
-
-
Artikelnummer:
-
KOP05
-
-
-
Kunden-Material-Nr.:
-
-
-

Eigenschaften des Artikels:

-
-
Zähler-Nr.
-
MG-X79318
-
+
+
+
+
+
Bezeichnung:
+
Kopierpapier A4
-
-
-
-
-
-
Artikelkennung (EAN):
-
4123456000038
-
-
-
Schema der Artikelkennung:
-
- 0088 (EAN Location Code) -
-
-
-
Code der Artikelklassifizierung:
-
-
-
-
Kennung zur Bildung des Schemas:
-
-
-
-
Version zur Bildung des Schemas:
-
-
-
-
Code des Herkunftslandes:
-
-
+
+
Beschreibung:
+
Zählerstand von-bis: 543210 - 544420
-
-
+
+
Artikelnummer:
+
KOP05
+
+
+
Kunden-Material-Nr.:
+
+
+

Eigenschaften des Artikels:

+
+
Zähler-Nr.
+
MG-X79318
+
+
+
+
+
+
+
+
Artikelkennung (EAN):
+
4123456000038
+
+
+
Schema der Artikelkennung:
+
0088 (EAN Location Code)
+
+
+
Code der Artikelklassifizierung:
+
+
+
+
Kennung zur Bildung des Schemas:
+
+
+
+
Version zur Bildung des Schemas:
+
+
+
+
Code des Herkunftslandes:
+
+
+
+
+
-
-
+
+
+
-
-
-
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
-
-
-
+
+
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
+
+
+
Informationen zum Verkäufer
-
-
Abweichender Handelsname:
-
-
-
-
Bundesland:
-
-
-
-
Elektronische Adresse:
-
-
-
-
Schema der elektronischen Adresse:
-
-
-
-
Register-/Registriernummer:
-
-
-
-
Umsatzsteuer-ID:
-
-
-
-
Steuernummer:
-
201/113/40209
-
-
-
Schema der Steuernummer:
-
-
-
-
Weitere rechtliche Informationen:
-
-
-
-
Code der Umsatzsteuerwährung:
-
-
+
+
Abweichender Handelsname:
+
+
+
+
Bundesland:
+
+
+
+
Elektronische Adresse:
+
+
+
+
Schema der elektronischen Adresse:
+
+
+
+
Register-/Registriernummer:
+
+
+
+
Umsatzsteuer-ID:
+
+
+
+
Steuernummer:
+
201/113/40209
+
+
+
Schema der Steuernummer:
+
+
+
+
Weitere rechtliche Informationen:
+
+
+
+
Code der Umsatzsteuerwährung:
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
Informationen zum Käufer
-
-
Abweichender Handelsname:
-
-
-
-
Bundesland:
-
-
-
-
Elektronische Adresse:
-
-
-
-
Schema der elektronischen Adresse:
-
-
-
-
Register-/Registriernummer:
-
-
-
-
Schema der Register-/Registriernummer:
-
-
-
-
Umsatzsteuer-ID:
-
-
-
-
Abrechnungsdatum der Umsatzsteuer:
-
-
-
-
Code des Umsatzsteuer-Abrechnungsdatums:
-
-
-
-
Kontierungsinformation / Kostenstelle:
-
-
+
+
Abweichender Handelsname:
+
+
+
+
Bundesland:
+
+
+
+
Elektronische Adresse:
+
+
+
+
Schema der elektronischen Adresse:
+
+
+
+
Register-/Registriernummer:
+
+
+
+
Schema der Register-/Registriernummer:
+
+
+
+
Umsatzsteuer-ID:
+
+
+
+
Abrechnungsdatum der Umsatzsteuer:
+
+
+
+
Code des Umsatzsteuer-Abrechnungsdatums:
+
+
+
+
Kontierungsinformation / Kostenstelle:
+
+
-
-
-
+
+
+
Lieferinformationen
-
-
Kennung des Lieferorts:
-
4304171088093
-
-
-
Schema der Kennung:
-
0088
-
-
-
Lieferdatum:
-
30.10.2024
-
-
-
Name des Empfängers:
-
MUSTER-MARKT
-
-
-
Straße / Haus-Nr.:
-
HAUPTSTRASSE 44
-
-
-
Adresszusatz:
-
-
-
-
Adresszusatz:
-
-
-
-
PLZ:
-
31157
-
-
-
Ort:
-
SARSTEDT
-
-
-
Bundesland:
-
-
-
-
Land:
-
DE (Deutschland)
-
+
+
Kennung des Lieferorts:
+
4304171088093
+
+
+
Schema der Kennung:
+
0088
+
+
+
Lieferdatum:
+
30.10.2024
+
+
+
Name des Empfängers:
+
MUSTER-MARKT
+
+
+
Straße / Haus-Nr.:
+
HAUPTSTRASSE 44
+
+
+
Adresszusatz:
+
+
+
+
Adresszusatz:
+
+
+
+
PLZ:
+
31157
+
+
+
Ort:
+
SARSTEDT
+
+
+
Bundesland:
+
+
+
+
Land:
+
DE (Deutschland)
+
-
-
-
-
-
-
+
+
+
+
+
+
Vertragsdaten
-
-
Vergabenummer:
-
-
-
-
Kennung der Empfangsbestätigung:
-
-
-
-
Kennung der Versandanzeige:
-
-
-
-
Kennung des Lieferscheins:
-
L87654321012 vom 31.10.2024
-
-
-
Prozesskennung:
-
-
-
-
Spezifikationskennung:
-
- urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended -
-
-
-
Objektkennung:
-
A777123
-
-
-
Schema der Objektkennung:
-
-
+
+
Vergabenummer:
+
+
+
+
Kennung der Empfangsbestätigung:
+
+
+
+
Kennung der Versandanzeige:
+
+
+
+
Kennung des Lieferscheins:
+
L87654321012 vom 31.10.2024
+
+
+
Prozesskennung:
+
+
+
+
Spezifikationskennung:
+
urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
Objektkennung:
+
A777123
+
+
+
Schema der Objektkennung:
+
+
-
-
-
+
+
+
+
-
-
-
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
-
-
-
+
+
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
+
+
+
Rechnungsbegründende Unterlagen
-
-
+
+
+
-
-
-
-
-
+
+
+
+
Bearbeitungshistorie
-
-
+
+
+
-
-
-
- - - + + \ No newline at end of file diff --git a/library/src/test/resources/factur-x-vis-ubl-creditnote.en.html b/library/src/test/resources/factur-x-vis-ubl-creditnote.en.html index 4c63e9c9..1f15ad29 100644 --- a/library/src/test/resources/factur-x-vis-ubl-creditnote.en.html +++ b/library/src/test/resources/factur-x-vis-ubl-creditnote.en.html @@ -1665,7 +1665,7 @@
Discount (net):
-
+
0,00
Net list price:
@@ -1977,7 +1977,7 @@
Discount (net):
-
+
0,00
Net list price:
@@ -2133,7 +2133,7 @@
Discount (net):
-
+
0,00
Net list price:
@@ -2629,4 +2629,4 @@ function downloadData (element_id) { }); // - + \ No newline at end of file diff --git a/library/src/test/resources/factur-x-vis-ubl.en.html b/library/src/test/resources/factur-x-vis-ubl.en.html index 4a394f1c..51259fd2 100644 --- a/library/src/test/resources/factur-x-vis-ubl.en.html +++ b/library/src/test/resources/factur-x-vis-ubl.en.html @@ -1379,7 +1379,7 @@
Discount (net):
-
+
0,00
Net list price:
@@ -1535,7 +1535,7 @@
Discount (net):
-
+
0,00
Net list price:
@@ -1758,7 +1758,7 @@
Process ID:
-
+
urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
Specification ID:
@@ -1948,4 +1948,4 @@ function downloadData (element_id) { }); // - + \ No newline at end of file diff --git a/library/src/test/resources/factur-x-vis.fr.html b/library/src/test/resources/factur-x-vis.fr.html index 5de16ae2..d3266405 100644 --- a/library/src/test/resources/factur-x-vis.fr.html +++ b/library/src/test/resources/factur-x-vis.fr.html @@ -1395,7 +1395,7 @@
Remise nette:
-
+
0,00
Prix catalogue (net):
@@ -1551,7 +1551,7 @@
Remise nette:
-
+
0,00
Prix catalogue (net):
@@ -1707,7 +1707,7 @@
Remise nette:
-
+
0,00
Prix catalogue (net):
diff --git a/library/src/test/resources/ubl-conv-ubl-output-factur-x.xml b/library/src/test/resources/ubl-conv-ubl-output-factur-x.xml index c9a9ce4f..48ece9c6 100644 --- a/library/src/test/resources/ubl-conv-ubl-output-factur-x.xml +++ b/library/src/test/resources/ubl-conv-ubl-output-factur-x.xml @@ -1,174 +1,174 @@ - - urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 - urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 - RE-20201121/508 - 2020-11-21 - 2020-12-12 - 380 - EUR - AB321 - - - - Ecke 12 - Stadthausen - 12345 - - DE - - - - DE136695976 - - VAT - - - - Bei Spiel GmbH - - - - - - - 2 - - - Bahnstr. 42 - Spielkreis - 88802 - - DE - - - - Theodor Est - - - - - 2020-11-10 - - - 42 - RE-20201121/508 - - DE88200800000970375700 - Max Mustermann - - COBADEFFXXX - - - - - Zahlbar ohne Abzug bis 12.12.2020 - - - 75.04 - - 160 - 11.2 - - S - 7 - - VAT - - - - - 336 - 63.84 - - S - 19 - - VAT - - - - - - 496 - 496 - 571.04 - 0 - 0 - 0 - 571.04 - - - 1 - 1 - 160 - - Of a sample invoice - Design (hours) - - S - 7 - - VAT - - - - - 160 - 1 - - false - 0 - 160 - - - - + + + urn:cen.eu:en16931:2017 + RE-20201121/508 + 2020-11-21 + 2020-12-12 + 380 + EUR + AB321 + + + + Ecke 12 + Stadthausen + 12345 + + DE + + + + DE136695976 + + VAT + + + + Bei Spiel GmbH + + + + + + 2 - 400 - 316 - - various colors, ~2000ml - Ballons - - S - 19 - - VAT - - - - - 0.79 - 1 - - false - 0 - 0.79 - - - - - 3 - 800 - 20 - - Hot air „heiße Luft“ (litres) - - S - 19 - - VAT - - - - - 0.025 - 1 - - false - 0 - 0.025 - - - + + + Bahnstr. 42 + Spielkreis + 88802 + + DE + + + + Theodor Est + + + + + 2020-11-10 + + + 42 + RE-20201121/508 + + DE88200800000970375700 + Max Mustermann + + COBADEFFXXX + + + + + Zahlbar ohne Abzug bis 12.12.2020 + + + 75.04 + + 160 + 11.2 + + S + 7 + + VAT + + + + + 336 + 63.84 + + S + 19 + + VAT + + + + + + 496 + 496 + 571.04 + 0 + 0 + 0 + 571.04 + + + 1 + 1 + 160 + + Of a sample invoice + Design (hours) + + S + 7 + + VAT + + + + + 160 + 1 + + false + 0 + 160 + + + + + 2 + 400 + 316 + + various colors, ~2000ml + Ballons + + S + 19 + + VAT + + + + + 0.79 + 1 + + false + 0 + 0.79 + + + + + 3 + 800 + 20 + + Hot air „heiße Luft“ (litres) + + S + 19 + + VAT + + + + + 0.025 + 1 + + false + 0 + 0.025 + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index c3dbca52..252cdccf 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.17.0-SNAPSHOT pom + 2.17.1-SNAPSHOT pom Mustang diff --git a/validator/pom.xml b/validator/pom.xml index bce750a1..19cc2e97 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.17.0-SNAPSHOT + 2.17.1-SNAPSHOT 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.17.0-SNAPSHOT + 2.17.1-SNAPSHOT @@ -38,7 +38,7 @@ ${project.groupId} library - 2.17.0-SNAPSHOT + 2.17.1-SNAPSHOT org.dom4j diff --git a/validator/src/main/java/org/mustangproject/validator/Validator.java b/validator/src/main/java/org/mustangproject/validator/Validator.java index 545ee574..c3372126 100644 --- a/validator/src/main/java/org/mustangproject/validator/Validator.java +++ b/validator/src/main/java/org/mustangproject/validator/Validator.java @@ -61,6 +61,9 @@ public abstract class Validator { Source xmlData = new StreamSource(new ByteArrayInputStream(xmlRawData)); SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); try { + schemaFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); Schema schema = schemaFactory.newSchema(schemaFile); javax.xml.validation.Validator validator = schema.newValidator(); validator.validate(xmlData);