diff --git a/History.md b/History.md
index 36878c7e..c37b08ec 100644
--- a/History.md
+++ b/History.md
@@ -1,14 +1,28 @@
-- #420
-- #441
+- 461
+- 463
+
+2.13.0
+=======
+2024-08-28
+
+- Item Attributes and Country of Origin missing on Product. #420
+- Avoid NullPointerException if dueDate is not set. #441
+- support reasoncodes #431
- Enhance Charges/Allowances with reasonCode. #432
- Fix build warnings from editing and building. #415
- ZUGFeRDVisualizer.toPDF(): generate PDF/A-3b. #400
- allow access to invoice attachments via ZUGFeRDInvoiceImporter zii.getFileAttachmentsPDF()
and XML (zii.getFileAttachmentsXML)
-- #436 and #370. (langfr)
+- No interface for required field CreditorReferenceID #436 and
+- X-Rechnung direct-debit missing mandatory field BT-90 #370. (langfr)
- refactor(ZUGFeRDVisualizer): improve PDF visualization performance #438
-
-
+- product creation without description now possible empty description
+- filename of embedded file was not xrechnung.xml when using profile xrechnung #452
+- allow legalorganisation to have a tradingbusinessname #447
+- JSon deserialization does not work with BankDetails #455
+- Fix ClassCastException in CLI (Main.java). #451
+- changed additional references by line from String to List and implemented it on Item #454
+
2.12.0
=======
2024-07-20
diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml
index 6d3b12ad..5147b159 100644
--- a/Mustang-CLI/pom.xml
+++ b/Mustang-CLI/pom.xml
@@ -4,7 +4,7 @@
org.mustangproject
core
- 2.13.1-SNAPSHOT
+ 2.14.0-SNAPSHOT
Mustang-CLI
diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java
index c7ac50af..e33b5879 100755
--- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java
+++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java
@@ -722,9 +722,6 @@ public class Main {
((ZUGFeRDExporterFromPDFA) ze).ignorePDFAErrors();
}
}
- for (FileAttachment attachment : attachments) {
- ((ZUGFeRDExporterFromA3) ze).attachFile(attachment.getFilename(), attachment.getData(), attachment.getMimetype(), attachment.getRelation());
- }
ze.load(pdfName);
ze.setProducer("Mustang-cli")
@@ -737,6 +734,10 @@ public class Main {
ze.setXML(Files.readAllBytes(Paths.get(xmlName)));
+ for (FileAttachment attachment : attachments) {
+ ze.attachFile(attachment.getFilename(), attachment.getData(), attachment.getMimetype(), attachment.getRelation());
+ }
+
ze.export(outName);
System.out.println("Written to " + outName);
diff --git a/library/pom.xml b/library/pom.xml
index e62636d5..663003d3 100644
--- a/library/pom.xml
+++ b/library/pom.xml
@@ -5,7 +5,7 @@
org.mustangproject
core
- 2.13.1-SNAPSHOT
+ 2.14.0-SNAPSHOT
library
jar
@@ -207,7 +207,7 @@
package
-
+
diff --git a/library/src/main/java/org/mustangproject/BankDetails.java b/library/src/main/java/org/mustangproject/BankDetails.java
index b72817ca..c6edcc86 100644
--- a/library/src/main/java/org/mustangproject/BankDetails.java
+++ b/library/src/main/java/org/mustangproject/BankDetails.java
@@ -1,5 +1,7 @@
package org.mustangproject;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementPayment;
/**
@@ -18,6 +20,10 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
* the "name" of the bank account (holder)
*/
protected String accountName=null;
+ /***
+ * bean constructor
+ */
+ public BankDetails() { }
/***
* constructor for IBAN only :-)
@@ -80,12 +86,14 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
* */
@Override
@Deprecated
+ @JsonIgnore
public String getOwnBIC() {
return getBIC();
}
@Override
@Deprecated
+ @JsonIgnore
public String getOwnIBAN() {
return getIBAN();
}
diff --git a/library/src/main/java/org/mustangproject/Charge.java b/library/src/main/java/org/mustangproject/Charge.java
index c1810c57..a16f5e66 100644
--- a/library/src/main/java/org/mustangproject/Charge.java
+++ b/library/src/main/java/org/mustangproject/Charge.java
@@ -116,12 +116,20 @@ 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) {
+ return totalAmount;
+ } else {
+ throw new RuntimeException("percent must be set");
+ }
+ }
+
+ public BigDecimal getTotalAmount() {
if (totalAmount!=null) {
return totalAmount;
- } else if (percent!=null) {
- return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100)));
} else {
- throw new RuntimeException("Either totalAmount or percent must be set");
+ throw new RuntimeException("totalAmount must be set");
}
}
diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java
index 321b4723..d4d417c6 100644
--- a/library/src/main/java/org/mustangproject/Item.java
+++ b/library/src/main/java/org/mustangproject/Item.java
@@ -26,6 +26,7 @@ public class Item implements IZUGFeRDExportableItem {
protected Product product;
protected ArrayList notes = null;
protected ArrayList referencedDocuments = null;
+ protected ArrayList additionalReference = null;
protected ArrayList Allowances = new ArrayList<>(),
Charges = new ArrayList<>();
@@ -63,6 +64,7 @@ public class Item implements IZUGFeRDExportableItem {
String referencedLineID = null;
ArrayList rdocs = null;
+ ArrayList addRefs = null;
// nodes.item(i).getTextContent())) {
@@ -248,6 +250,35 @@ public class Item implements IZUGFeRDExportableItem {
}
}
}
+
+ if (tradeSettlementName.equals("AdditionalReferencedDocument")) {
+ String IssuerAssignedID = "";
+ String TypeCode = "";
+ String ReferenceTypeCode = "";
+
+ NodeList refDocChilds = tradeSettlementChilds.item(tradeSettlementChildIndex).getChildNodes();
+ for (int refDocIndex = 0; refDocIndex < refDocChilds.getLength(); refDocIndex++) {
+ String localName = refDocChilds.item(refDocIndex).getLocalName();
+ if ((localName != null) && (localName.equals("IssuerAssignedID"))) {
+ IssuerAssignedID = refDocChilds.item(refDocIndex).getTextContent();
+ }
+ if ((localName != null) && (localName.equals("TypeCode"))) {
+ TypeCode = refDocChilds.item(refDocIndex).getTextContent();
+ }
+ if ((localName != null) && (localName.equals("ReferenceTypeCode"))) {
+ ReferenceTypeCode = refDocChilds.item(refDocIndex).getTextContent();
+ }
+ }
+
+ ReferencedDocument rd = new ReferencedDocument(IssuerAssignedID, TypeCode,
+ ReferenceTypeCode);
+ if (addRefs == null) {
+ addRefs = new ArrayList<>();
+ }
+ addRefs.add(rd);
+
+ }
+
}
}
}
@@ -274,6 +305,11 @@ public class Item implements IZUGFeRDExportableItem {
addReferencedDocument(rdoc);
}
}
+ if (addRefs != null) {
+ for (ReferencedDocument rdoc : addRefs) {
+ addAdditionalReference(rdoc);
+ }
+ }
addReferencedLineID( referencedLineID );
}
@@ -465,6 +501,29 @@ public class Item implements IZUGFeRDExportableItem {
return referencedDocuments.toArray(new IReferencedDocument[0]);
}
+
+ /***
+ * adds item level references along with their typecodes and issuerassignedIDs (contract ID, cost centre, ...)
+ * @param doc the ReferencedDocument to add
+ * @return fluent setter
+ */
+ public Item addAdditionalReference(ReferencedDocument doc) {
+ if (additionalReference == null) {
+ additionalReference = new ArrayList<>();
+ }
+ additionalReference.add(doc);
+ return this;
+ }
+
+ @Override
+ public IReferencedDocument[] getAdditionalReferences() {
+ if (additionalReference == null) {
+ return null;
+ }
+ return additionalReference.toArray(new IReferencedDocument[0]);
+ }
+
+
/***
* specify a item level delivery period
* (apart from the document level delivery period, and the document level
diff --git a/library/src/main/java/org/mustangproject/LegalOrganisation.java b/library/src/main/java/org/mustangproject/LegalOrganisation.java
index 9ed0aa62..320d7412 100644
--- a/library/src/main/java/org/mustangproject/LegalOrganisation.java
+++ b/library/src/main/java/org/mustangproject/LegalOrganisation.java
@@ -2,6 +2,8 @@ package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.mustangproject.ZUGFeRD.*;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/***
* A organisation, i.e. usually a company
@@ -9,35 +11,68 @@ import org.mustangproject.ZUGFeRD.*;
@JsonIgnoreProperties(ignoreUnknown = true)
public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
- protected String ID = null;
- protected String SchemeID = null;
+ protected SchemedID schemedID = null;
+ protected String tradingBusinessName = null;
public LegalOrganisation() {
}
public LegalOrganisation(String ID, String scheme) {
- this.ID=ID;
- this.SchemeID=scheme;
+ this.schemedID = new SchemedID(ID, scheme);
+ }
+
+ public LegalOrganisation(SchemedID schemedID, String tradingBusinessName) {
+ this.schemedID = schemedID;
+ this.tradingBusinessName=tradingBusinessName;
+ }
+
+ /***
+ * XML parsing constructor
+ * @param nodes the nodelist returned e.g. from xpath
+ */
+ public LegalOrganisation(NodeList nodes) {
+ if (nodes.getLength() > 0) {
+ /*
+ will parse sth like
+
+ 4711
+ Test GmbH & Co.KG
+
+ */
+ for (int nodeIndex = 0; nodeIndex < nodes.getLength(); nodeIndex++) {
+ Node currentItemNode = nodes.item(nodeIndex);
+ if (currentItemNode.getLocalName() != null) {
+ if (currentItemNode.getLocalName().equals("GlobalID")) {
+ if (currentItemNode.getAttributes().getNamedItem("schemeID") != null) {
+ SchemedID gid = new SchemedID().setScheme(currentItemNode.getAttributes().getNamedItem("schemeID").getNodeValue()).setId(currentItemNode.getTextContent());
+ this.setSchemedID(gid);
+ }
+ }
+ if (currentItemNode.getLocalName().equals("TradingBusinessName")) {
+ setTradingBusinessName(currentItemNode.getFirstChild().getNodeValue());
+ }
+ }
+ }
+ }
}
@Override
- public String getID() {
- return ID;
+ public SchemedID getSchemedID() {
+ return this.schemedID;
}
@Override
- public String getSchemeID() {
- return SchemeID;
+ public String getTradingBusinessName() {
+ return this.tradingBusinessName;
}
- public LegalOrganisation setID(String id) {
- this.ID=id;
+ public LegalOrganisation setSchemedID(SchemedID schemedID) {
+ this.schemedID = schemedID;
return this;
}
- public LegalOrganisation setSchemeID(String scheme) {
- SchemeID=scheme;
+ public LegalOrganisation setTradingBusinessName(String tradingBusinessName) {
+ this.tradingBusinessName = tradingBusinessName;
return this;
}
-
}
diff --git a/library/src/main/java/org/mustangproject/Product.java b/library/src/main/java/org/mustangproject/Product.java
index b90a70cd..73e18fd1 100644
--- a/library/src/main/java/org/mustangproject/Product.java
+++ b/library/src/main/java/org/mustangproject/Product.java
@@ -11,7 +11,10 @@ import java.util.HashMap;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Product implements IZUGFeRDExportableProduct {
- protected String unit, name, description, sellerAssignedID, buyerAssignedID;
+ protected String unit, name, sellerAssignedID, buyerAssignedID;
+ protected String description="";
+ protected String taxExemptionReason=null;
+ protected String taxCategoryCode=null;
protected BigDecimal VATPercent;
protected boolean isReverseCharge = false;
protected boolean isIntraCommunitySupply = false;
@@ -65,6 +68,44 @@ public class Product implements IZUGFeRDExportableProduct {
return this;
}
+ /***
+ *
+ * @return e.g. intra-commnunity supply or small business
+ */
+ @Override
+ public String getTaxExemptionReason() {
+ return taxExemptionReason;
+ }
+
+ /***
+ *
+ * @param taxExemptionReasonText String e.g. Kleinunternehmer gemäß §19 UStG https://github.com/ZUGFeRD/mustangproject/issues/463
+ * @return
+ */
+ public Product setTaxExemptionReason(String taxExemptionReasonText) {
+ taxExemptionReason = taxExemptionReasonText;
+ return this;
+ }
+
+ /***
+ *
+ * @return e.g. S (normal tax), Z=zero rated, E (e.g. small business) or K (intrra community supply)
+ */
+ @Override
+ public String getTaxCategoryCode() {
+ return taxCategoryCode;
+ }
+
+ /***
+ *
+ * @param code e.g. S (normal tax), Z=zero rated, E (e.g. small business) or K (intrra community supply) see also https://github.com/ZUGFeRD/mustangproject/issues/463
+ * @return
+ */
+ public Product setTaxCategoryCode(String code) {
+ taxCategoryCode = code;
+ return this;
+ }
+
@Override
public String getSellerAssignedID() {
diff --git a/library/src/main/java/org/mustangproject/TradeParty.java b/library/src/main/java/org/mustangproject/TradeParty.java
index 2580fbef..b953008c 100644
--- a/library/src/main/java/org/mustangproject/TradeParty.java
+++ b/library/src/main/java/org/mustangproject/TradeParty.java
@@ -23,6 +23,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
protected String name, zip, street, location, country;
protected String taxID = null, vatID = null;
protected String ID = null;
+ protected String description = null;
protected String additionalAddress = null;
protected String additionalAddressExtension = null;
protected List bankDetails = new ArrayList<>();
@@ -66,14 +67,14 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
Node currentItemNode = nodes.item(nodeIndex);
if (currentItemNode.getLocalName() != null) {
- String debcurrentChild = currentItemNode.getLocalName();
- if (debcurrentChild.equals("Party")) {
+ String currentUBLChild = currentItemNode.getLocalName();
+ if (currentUBLChild.equals("Party")) {
NodeList party = currentItemNode.getChildNodes();
for (int partyIndex = 0; partyIndex < party.getLength(); partyIndex++) {
if (party.item(partyIndex).getLocalName() != null) {
- String debCN = party.item(partyIndex).getLocalName();
- if (debCN.equals("PartyName")) {
+ String currentTopElementName = party.item(partyIndex).getLocalName();
+ if (currentTopElementName.equals("PartyName")) {
NodeList partyName = party.item(partyIndex).getChildNodes();
for (int partyNameIndex = 0; partyNameIndex < partyName.getLength(); partyNameIndex++) {
@@ -86,7 +87,20 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
}
}
- if (debCN.equals("PostalAddress")) {
+
+ // UBL only: formally it can have a name as well but BT27 party name *should* be stored in
+ // so overwrite if one exists
+ if (currentTopElementName.equals("PartyLegalEntity")) {
+ NodeList legal = party.item(partyIndex).getChildNodes();
+ for (int legalChildIndex = 0; legalChildIndex < legal.getLength(); legalChildIndex++) {
+ if (legal.item(legalChildIndex).getLocalName() != null) {
+ if (legal.item(legalChildIndex).getLocalName().equals("RegistrationName")) {
+ setName(legal.item(legalChildIndex).getTextContent());
+ }
+ }
+ }
+ }
+ if (currentTopElementName.equals("PostalAddress")) {
NodeList postal = party.item(partyIndex).getChildNodes();
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
@@ -144,7 +158,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
}
- if (debCN.equals("Contact")) {
+ if (currentTopElementName.equals("Contact")) {
NodeList contact = party.item(partyIndex).getChildNodes();
setContact(new Contact(contact));
@@ -155,19 +169,19 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
- if (debcurrentChild.equals("GlobalID")) {
+ if (currentUBLChild.equals("GlobalID")) {
if (nodes.item(nodeIndex).getAttributes().getNamedItem("schemeID") != null) {
SchemedID gid = new SchemedID().setScheme(nodes.item(nodeIndex).getAttributes().getNamedItem("schemeID").getNodeValue()).setId(nodes.item(nodeIndex).getTextContent());
addGlobalID(gid);
}
}
- if (debcurrentChild.equals("DefinedTradeContact")) {
+ if (currentUBLChild.equals("DefinedTradeContact")) {
NodeList contact = nodes.item(nodeIndex).getChildNodes();
setContact(new Contact(contact));
}
- if (debcurrentChild.equals("PostalTradeAddress")) {
+ if (currentUBLChild.equals("PostalTradeAddress")) {
NodeList postal = nodes.item(nodeIndex).getChildNodes();
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
if (postal.item(postalChildIndex).getLocalName() != null) {
@@ -195,7 +209,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
- if (debcurrentChild.equals("SpecifiedTaxRegistration")) {
+ if (currentUBLChild.equals("SpecifiedTaxRegistration")) {
NodeList taxChilds = nodes.item(nodeIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
if (taxChilds.item(taxChildIndex).getLocalName() != null) {
@@ -286,8 +300,8 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
for (int nodeIndex = 0; nodeIndex < nodes.getLength(); nodeIndex++) {
//nodes.item(i).getTextContent())) {
- String debLN = nodes.item(nodeIndex).getLocalName();
- if (debLN.equals("Party")) {
+ String topElementName = nodes.item(nodeIndex).getLocalName();
+ if (topElementName.equals("Party")) {
// take one step back and parse from top
parseFromUBL(nodes);
return;
@@ -302,12 +316,20 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
if (itemChilds.item(itemChildIndex).getLocalName().equals("Name")) {
setName(itemChilds.item(itemChildIndex).getTextContent());
}
+
+ if (itemChilds.item(itemChildIndex).getLocalName().equals("Description")) {
+ setDescription(itemChilds.item(itemChildIndex).getTextContent());
+ }
if (itemChilds.item(itemChildIndex).getLocalName().equals("GlobalID")) {
if (itemChilds.item(itemChildIndex).getAttributes().getNamedItem("schemeID") != null) {
SchemedID gid = new SchemedID().setScheme(itemChilds.item(itemChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue()).setId(itemChilds.item(itemChildIndex).getTextContent());
addGlobalID(gid);
}
}
+ if (itemChilds.item(itemChildIndex).getLocalName().equals("SpecifiedLegalOrganization")) {
+ NodeList organization = itemChilds.item(itemChildIndex).getChildNodes();
+ setLegalOrganisation(new LegalOrganisation(organization));
+ }
if (itemChilds.item(itemChildIndex).getLocalName().equals("DefinedTradeContact")) {
NodeList contact = itemChilds.item(itemChildIndex).getChildNodes();
setContact(new Contact(contact));
@@ -556,6 +578,26 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
+ /***
+ *
+ * @return String the description, e.g. if it's a vat exempt company
+ */
+ public String getDescription() {
+ return description;
+ }
+
+
+ /***
+ * required, usually done in the constructor: the complete name of the organisation
+ * @param description human readable description
+ * @return fluent setter
+ */
+ public TradeParty setDescription(String description) {
+ this.description = description;
+ return this;
+ }
+
+
public String getZIP() {
return zip;
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
index f6e03242..e5e25cae 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
@@ -92,12 +92,22 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
/***
* the ID of an additionally referenced document for this item
+ * @deprecated use {@link #getAdditionalReferences()} instead.
* @return the id as string
*/
+ @Deprecated
default String getAdditionalReferencedDocumentID() {
return null;
}
+ /***
+ * allows to specify multiple references (billing information)
+ * @return the referenced documents
+ */
+ default IReferencedDocument[] getAdditionalReferences() {
+ return null;
+ }
+
/***
* allows to specify multiple(!) referenced documents along with e.g. their typecodes
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTradeParty.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTradeParty.java
index 8af10dbb..a9977f01 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTradeParty.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTradeParty.java
@@ -112,12 +112,17 @@ public interface IZUGFeRDExportableTradeParty {
}
/**
- * First and last name of the recipient
+ * e.g. first and last name of the owner
*
- * @return First and last name of the recipient
+ * @return full name of the party
*/
String getName();
+ /**
+ * @return description, e.g. if it's a small company
+ */
+ default String getDescription() { return null; }
+
/**
* Postal code of the recipient
*
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExporter.java
index f056da5c..fd4ffb4c 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExporter.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExporter.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import jakarta.activation.DataSource;
+import org.mustangproject.FileAttachment;
public interface IZUGFeRDExporter extends Closeable, IExporter {
/**
@@ -64,6 +65,8 @@ public interface IZUGFeRDExporter extends Closeable, IExporter {
public String getNamespaceForVersion(int ver);
public String getPrefixForVersion(int ver) ;
public IZUGFeRDExporter disableAutoClose(boolean disableAutoClose);
+ public void attachFile(FileAttachment file);
+ public void attachFile(String filename, byte[] data, String mimetype, String relation);
public IXMLProvider getProvider();
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDLegalOrganisation.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDLegalOrganisation.java
index 9de017cf..09bf14fc 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDLegalOrganisation.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDLegalOrganisation.java
@@ -18,17 +18,19 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
-public interface IZUGFeRDLegalOrganisation {
+import org.mustangproject.SchemedID;
- /***
- *
- * @return the ID of the legal organisation
- */
- public String getID();
+public interface IZUGFeRDLegalOrganisation {
/**
*
- * @return the scheme attribute of the legal organization=the type of the identification, e.g. 0002=Siren
+ * @return the scheme attribute of the legal organization=the type of the identification, e.g. 0002=Siren, and its value
*/
- public String getSchemeID();
+ public SchemedID getSchemedID();
+
+ /***
+ *
+ * @return the TradingBusinessName of the legal organisation
+ */
+ public String getTradingBusinessName();
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlement.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlement.java
index 038c5d36..3dd18d74 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlement.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlement.java
@@ -18,12 +18,15 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
public interface IZUGFeRDTradeSettlement {
/***
* gets the applicableHeaderTradeSettlement
* @return zf2 xml
*/
+ @JsonIgnore
String getSettlementXML();
@@ -31,6 +34,7 @@ public interface IZUGFeRDTradeSettlement {
* gets the applicableHeaderTradePayment
* @return zf2 xml
*/
+ @JsonIgnore
default String getPaymentXML() {
return null;
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java
index 2247ae06..9731a9a5 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java
@@ -18,6 +18,7 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import org.mustangproject.XMLTools;
public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement {
@@ -27,6 +28,7 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
*
* @return payment information text
*/
+ @JsonIgnore
default String getOwnPaymentInfoText() {
return null;
}
@@ -59,6 +61,7 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
@Override
+ @JsonIgnore
default String getSettlementXML() {
String accountNameStr="";
if (getAccountName()!=null) {
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java
index b67e7598..4d9382ea 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java
@@ -172,6 +172,10 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
LineCalculator lc = new LineCalculator(currentItem);
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode);
+ String reasonText=currentItem.getProduct().getTaxExemptionReason();
+ if (reasonText!=null) {
+ itemVATAmount.setVatExemptionReasonText(reasonText);
+ }
VATAmount current = hm.get(percent.stripTrailingZeros());
if (current == null) {
hm.put(percent.stripTrailingZeros(), itemVATAmount);
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java b/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
index a7a82f61..2a7a7920 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
@@ -32,6 +32,16 @@ import java.math.RoundingMode;
*/
public class VATAmount {
+
+ protected BigDecimal basis, calculated, applicablePercent;
+
+ protected String categoryCode;
+
+ protected String vatExemptionReasonText;
+
+ protected String dueDateTypeCode;
+
+
public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode) {
super();
this.basis = basis;
@@ -48,35 +58,41 @@ public class VATAmount {
this.dueDateTypeCode = dueDateTypeCode;
}
- BigDecimal basis, calculated, applicablePercent;
-
- String categoryCode;
-
- String dueDateTypeCode;
-
public BigDecimal getApplicablePercent() {
return applicablePercent;
}
- public void setApplicablePercent(BigDecimal applicablePercent) {
+ public VATAmount setApplicablePercent(BigDecimal applicablePercent) {
+
this.applicablePercent = applicablePercent;
+ return this;
}
public BigDecimal getBasis() {
return basis;
}
- public void setBasis(BigDecimal basis) {
+ public VATAmount setBasis(BigDecimal basis) {
this.basis = basis.setScale(2, RoundingMode.HALF_UP);
-
+ return this;
}
public BigDecimal getCalculated() {
return calculated;
}
- public void setCalculated(BigDecimal calculated) {
+ public VATAmount setCalculated(BigDecimal calculated) {
this.calculated = calculated;
+ return this;
+ }
+
+ public String getVatExemptionReasonText() {
+ return vatExemptionReasonText;
+ }
+
+ public VATAmount setVatExemptionReasonText(String theText) {
+ this.vatExemptionReasonText = theText;
+ return this;
}
/**
@@ -94,24 +110,27 @@ public class VATAmount {
* @deprecated Use {@link #setCategoryCode(String)} instead
*/
@Deprecated
- public void setDocumentCode(String documentCode) {
+ public VATAmount setDocumentCode(String documentCode) {
this.categoryCode = documentCode;
+ return this;
}
public String getCategoryCode() {
return categoryCode;
}
- public void setCategoryCode(String categoryCode) {
+ public VATAmount setCategoryCode(String categoryCode) {
this.categoryCode = categoryCode;
+ return this;
}
public String getDueDateTypeCode() {
return dueDateTypeCode;
}
- public void setDueDateTypeCode(String dueDateTypeCode) {
+ public VATAmount setDueDateTypeCode(String dueDateTypeCode) {
this.dueDateTypeCode = dueDateTypeCode;
+ return this;
}
public VATAmount add(VATAmount v) {
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java
index ba43dd94..b98abebc 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java
@@ -387,9 +387,10 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider {
+ "" + currencyFormat(lc.getItemTotalNetAmount())
+ ""
+ "";
- if (currentItem.getAdditionalReferencedDocumentID() != null) {
+ if (currentItem.getAdditionalReferences() != null) {
+ xml += "" + currentItem.getAdditionalReferences()[0].getIssuerAssignedID() + "130";
+ } else if (currentItem.getAdditionalReferencedDocumentID() != null) {
xml += "" + currentItem.getAdditionalReferencedDocumentID() + "130";
-
}
xml += ""
+ "";
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
index 8577e5a0..1b5b0242 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
@@ -51,7 +51,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ZUGFeRD2PullProvider implements IXMLProvider {
- private static final Logger LOGGER = LoggerFactory.getLogger (ZUGFeRD2PullProvider.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRD2PullProvider.class);
protected byte[] zugferdData;
protected IExportableTransaction trans;
@@ -93,7 +93,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
try {
document = DocumentHelper.parseText(new String(zugferdData));
} catch (final DocumentException e1) {
- LOGGER.error ("Failed to parse ZUGFeRD data", e1);
+ LOGGER.error("Failed to parse ZUGFeRD data", e1);
}
try {
final OutputFormat format = OutputFormat.createPrettyPrint();
@@ -103,7 +103,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
res = sw.toString().getBytes(StandardCharsets.UTF_8);
} catch (final IOException e) {
- LOGGER.error ("Failed to write ZUGFeRD data", e);
+ LOGGER.error("Failed to write ZUGFeRD data", e);
}
return res;
@@ -138,14 +138,21 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ XMLTools.encodeXML(party.getGlobalID()) + "";
}
xml += "" + XMLTools.encodeXML(party.getName()) + "";
-
+ if (party.getDescription() != null) {
+ xml += "" + XMLTools.encodeXML(party.getDescription()) + "";
+ }
if (party.getLegalOrganisation() != null) {
xml += " ";
- xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getID()) + "";
+ if (party.getLegalOrganisation().getSchemedID() != null) {
+ xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "";
+ }
+ if (party.getLegalOrganisation().getTradingBusinessName() != null) {
+ xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getTradingBusinessName()) + "";
+ }
xml += "";
}
- if ((party.getContact() != null) && (isSender || profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
+ if ((party.getContact() != null) && (isSender || profile == Profiles.getByName("EN16931") || profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
xml += "";
if (party.getContact().getName() != null) {
xml += "" + XMLTools.encodeXML(party.getContact().getName())
@@ -318,7 +325,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
paymentTermsDescription += discount.getAsXRechnung();
}
} else if ((paymentTermsDescription == null) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CORRECTEDINVOICE) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)) {
- if ( trans.getDueDate() != null ) {
+ if (trans.getDueDate() != null) {
paymentTermsDescription = "Please remit until " + germanDateFormat.format(trans.getDueDate());
}
}
@@ -417,7 +424,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
"";
}
if (currentItem.getProduct().getAttributes() != null) {
- for ( Entry entry : currentItem.getProduct().getAttributes().entrySet() ) {
+ for (Entry entry : currentItem.getProduct().getAttributes().entrySet()) {
xml += "" +
"" + XMLTools.encodeXML(entry.getKey()) + "" +
"" + XMLTools.encodeXML(entry.getValue()) + "" +
@@ -426,8 +433,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
if (currentItem.getProduct().getCountryOfOrigin() != null) {
xml += "" +
- XMLTools.encodeXML(currentItem.getProduct().getCountryOfOrigin()) +
- "";
+ XMLTools.encodeXML(currentItem.getProduct().getCountryOfOrigin()) +
+ "";
}
xml += ""
@@ -498,9 +505,16 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ "" + currencyFormat(lc.getItemTotalNetAmount())
+ "" // currencyID=\"EUR\"
+ "";
- if (currentItem.getAdditionalReferencedDocumentID() != null) {
+ if (currentItem.getAdditionalReferences() != null) {
+ for (final IReferencedDocument currentReference : currentItem.getAdditionalReferences()) {
+ xml += "" +
+ "" + XMLTools.encodeXML(currentReference.getIssuerAssignedID()) + "" +
+ "130" +
+ "" + XMLTools.encodeXML(currentReference.getReferenceTypeCode()) + "" +
+ "";
+ }
+ } else if (currentItem.getAdditionalReferencedDocumentID() != null) {
xml += "" + currentItem.getAdditionalReferencedDocumentID() + "130";
-
}
xml += ""
+ "";
@@ -640,12 +654,17 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String amountDueDateTypeCode = amount.getDueDateTypeCode();
final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
if (getProfile() != Profiles.getByName("Minimum")) {
+ String exemptionReasonTextXML = "";
+ if ((displayExemptionReason) && (amount.getVatExemptionReasonText() != null)) {
+ exemptionReasonTextXML = "" + XMLTools.encodeXML(amount.getVatExemptionReasonText()) + "";
+
+ }
xml += ""
+ "" + currencyFormat(amount.getCalculated())
+ "" //currencyID=\"EUR\"
+ "VAT"
- + (displayExemptionReason ? exemptionReason : "")
+ + exemptionReasonTextXML
+ "" + currencyFormat(amount.getBasis()) + "" // currencyID=\"EUR\"
+ "" + amountCategoryCode + ""
+ (amountDueDateTypeCode != null ? "" + amountDueDateTypeCode + "" : "")
@@ -667,7 +686,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) {
if (profile == Profiles.getByName("XRechnung")) {
- for(IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
+ for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
xml += "" +
"" +
"true" +
@@ -710,7 +729,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((trans.getZFAllowances() != null) && (trans.getZFAllowances().length > 0)) {
if (profile == Profiles.getByName("XRechnung")) {
- for(IZUGFeRDAllowanceCharge allowance : trans.getZFAllowances()) {
+ for (IZUGFeRDAllowanceCharge allowance : trans.getZFAllowances()) {
xml += "" +
"" +
"false" +
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3.java
index 0dd548e5..dea69a6f 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3.java
@@ -85,6 +85,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
this.ignorePDFAErrors = true;
return this;
}
+
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
protected ArrayList fileAttachments = new ArrayList<>();
@@ -223,17 +224,16 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* @return the filename of the file to be embedded
*/
public String getFilenameForVersion(int ver, Profile profile) {
+ if (profile.getName().equals("XRECHNUNG")) {
+ return "xrechnung.xml";
+ }
if (isFacturX) {
return "factur-x.xml";
} else {
if (ver == 1) {
return "ZUGFeRD-invoice.xml";
} else {
- if (profile.getName().equals("XRECHNUNG")) {
- return "xrechnung.xml";
- } else {
- return "zugferd-invoice.xml";
- }
+ return "zugferd-invoice.xml";
}
}
}
@@ -247,7 +247,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* @deprecated It's now the default anyway
*/
@Deprecated
- public ZUGFeRDExporterFromA3 setFacturX() {
+ public ZUGFeRDExporterFromA3 setFacturX() {
isFacturX = true;
return this;
}
@@ -260,10 +260,9 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
*
* @param XRechnungVersion the XRechnung version
*/
- public void setXRechnungSpecificVersion(String XRechnungVersion)
- {
- this.XRechnungVersion = XRechnungVersion;
- }
+ public void setXRechnungSpecificVersion(String XRechnungVersion) {
+ this.XRechnungVersion = XRechnungVersion;
+ }
/***
@@ -308,13 +307,13 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* @throws IOException if anything is wrong in the target location
*/
@Override
- public void export(String ZUGFeRDfilename) throws IOException {
+ public void export(String ZUGFeRDfilename) throws IOException {
if (!documentPrepared) {
prepareDocument();
}
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
throw new IOException(
- "File must be attached (usually with setTransaction) before perfoming this operation");
+ "File must be attached (usually with setTransaction) before perfoming this operation");
}
doc.save(ZUGFeRDfilename, CompressParameters.NO_COMPRESSION);
if (!disableAutoClose) {
@@ -336,13 +335,13 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* @throws IOException if anything is wrong in the OutputStream
*/
@Override
- public void export(OutputStream output) throws IOException {
+ public void export(OutputStream output) throws IOException {
if (!documentPrepared) {
prepareDocument();
}
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
throw new IOException(
- "File must be attached (usually with setTransaction) before perfoming this operation");
+ "File must be attached (usually with setTransaction) before perfoming this operation");
}
doc.save(output, CompressParameters.NO_COMPRESSION);
if (!disableAutoClose) {
@@ -440,7 +439,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
cosArray.add(fs);
doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);
} else if ((AFEntry instanceof COSObject) &&
- ((COSObject) AFEntry).getObject() instanceof COSArray) {
+ ((COSObject) AFEntry).getObject() instanceof COSArray) {
COSArray cosArray = (COSArray) ((COSObject) AFEntry).getObject();
cosArray.add(fs);
} else {
@@ -534,19 +533,18 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
*/
protected void addXMP(XMPMetadata metadata) {
- String metaDataVersion = null; // default will be used
+ String metaDataVersion = null; // default will be used
- // The XRechnung version may be settable from outside.
- if ((this.XRechnungVersion != null) && (this.profile != null) &&
- this.profile.getName().equalsIgnoreCase(Profiles.getByName("XRECHNUNG").getName()))
- {
- metaDataVersion = this.XRechnungVersion;
- }
+ // The XRechnung version may be settable from outside.
+ if ((this.XRechnungVersion != null) && (this.profile != null) &&
+ this.profile.getName().equalsIgnoreCase(Profiles.getByName("XRECHNUNG").getName())) {
+ metaDataVersion = this.XRechnungVersion;
+ }
if (attachZUGFeRDHeaders) {
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, xmlProvider.getProfile(),
- getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
- getFilenameForVersion(ZFVersion, xmlProvider.getProfile()), metaDataVersion);
+ getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
+ getFilenameForVersion(ZFVersion, xmlProvider.getProfile()), metaDataVersion);
metadata.addSchema(zf);
}
@@ -557,8 +555,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
}
private void removeCidSet(PDDocument doc)
- throws IOException
- {
+ throws IOException {
// https://github.com/ZUGFeRD/mustangproject/issues/249
COSName cidSet = COSName.getPDFName("CIDSet");
@@ -577,8 +574,8 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
PDType0Font typedFont = (PDType0Font) pdFont;
if (typedFont.getDescendantFont() instanceof PDCIDFontType2) {
- @SuppressWarnings ("unused")
- PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont();
+ @SuppressWarnings("unused")
+ PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont();
PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor();
fontDescriptor.getCOSObject().removeItem(cidSet);
@@ -637,7 +634,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* @throws IOException if anything is wrong with already loaded PDF
*/
@Override
- public IExporter setTransaction(IExportableTransaction trans) throws IOException {
+ public IExporter setTransaction(IExportableTransaction trans) throws IOException {
this.trans = trans;
return prepare();
}
@@ -647,22 +644,20 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
xmlProvider.generateXML(trans);
String filename = getFilenameForVersion(ZFVersion, xmlProvider.getProfile());
- String relationship = "Alternative";
- // ZUGFeRD 2.1.1 Technical Supplement | Part A | 2.2.2. Data Relationship
- // See documentation ZUGFeRD211_EN/Documentation/ZUGFeRD-2.1.1 - Specification_TA_Part-A.pdf
- // https://www.ferd-net.de/standards/zugferd-2.1.1/index.html
- if ((this.profile != null) && (ZFVersion >= 2))
- {
- if (this.profile.getName().equalsIgnoreCase(Profiles.getByName("MINIMUM").getName()) ||
- this.profile.getName().equalsIgnoreCase(Profiles.getByName("BASICWL").getName()))
- {
- relationship = "Data";
- }
- }
+ String relationship = "Alternative";
+ // ZUGFeRD 2.1.1 Technical Supplement | Part A | 2.2.2. Data Relationship
+ // See documentation ZUGFeRD211_EN/Documentation/ZUGFeRD-2.1.1 - Specification_TA_Part-A.pdf
+ // https://www.ferd-net.de/standards/zugferd-2.1.1/index.html
+ if ((this.profile != null) && (ZFVersion >= 2)) {
+ if (this.profile.getName().equalsIgnoreCase(Profiles.getByName("MINIMUM").getName()) ||
+ this.profile.getName().equalsIgnoreCase(Profiles.getByName("BASICWL").getName())) {
+ relationship = "Data";
+ }
+ }
PDFAttachGenericFile(doc, filename, relationship,
- "Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
- "text/xml", xmlProvider.getXML());
+ "Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
+ "text/xml", xmlProvider.getXML());
for (FileAttachment attachment : fileAttachments) {
PDFAttachGenericFile(doc, attachment.getFilename(), attachment.getRelation(), attachment.getDescription(), attachment.getMimetype(), attachment.getData());
@@ -674,12 +669,12 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
/**
* Reads the XMPMetadata from the PDDocument, if it exists.
* Otherwise creates XMPMetadata.
+ *
* @return the finished XMPMetadata object
* @throws IOException when e.g. XmpParsingException
*/
protected XMPMetadata getXmpMetadata()
- throws IOException
- {
+ throws IOException {
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
if ((meta != null) && (meta.getLength() > 0)) {
try {
@@ -701,6 +696,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
/**
* Sets the producer if the overwrite flag is set or the producer is not already set.
* Sets the PDFVersion to 1.4 if the field is empty.
+ *
* @param xmp the metadata as XML
*/
protected void writeAdobePDFSchema(XMPMetadata xmp) {
@@ -823,11 +819,11 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
/**
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
+ *
* @throws IOException if the ICC file cannot be read or attached to doc
*/
protected void addSRGBOutputIntend()
- throws IOException
- {
+ throws IOException {
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
return;
}
@@ -892,12 +888,12 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
public ZUGFeRDExporterFromA3 setZUGFeRDVersion(EStandard est, int version) {
this.ZFVersion = version;
- if ((version<1) || (version>2)) {
+ if ((version < 1) || (version > 2)) {
throw new IllegalArgumentException("Version not supported");
}
- int generation=version;
- if ((est==EStandard.facturx)&&(version==1)) {
- generation=2;
+ int generation = version;
+ if ((est == EStandard.facturx) && (version == 1)) {
+ generation = 2;
}
if (generation == 1) {
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromPDFA.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromPDFA.java
index 9a4f2c2f..498ae7dc 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromPDFA.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromPDFA.java
@@ -34,6 +34,7 @@ import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
import org.apache.xmpbox.xml.DomXmpParser;
import org.apache.xmpbox.xml.XmpParsingException;
+import org.mustangproject.FileAttachment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,7 +73,8 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
}
- protected IZUGFeRDExporter getExporter() {
+
+ public IZUGFeRDExporter getExporter() {
if (theExporter==null) {
throw new RuntimeException("In ZUGFeRDExporterFromPDFA, source must always be loaded before other operations are performed.");
}
@@ -247,5 +249,14 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
public void export(OutputStream output) throws IOException {
getExporter().export(output);
}
+
+ public void attachFile(FileAttachment file) {
+ theExporter.attachFile(file);
+ }
+
+ public void attachFile(String filename, byte[] data, String mimetype, String relation) {
+ theExporter.attachFile(filename, data, mimetype, relation);
+ }
+
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
index 2029e854..4016e2a1 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
@@ -104,7 +104,7 @@ public class ZUGFeRDImporter {
/***
* return the file names of all files embedded into the PDF
- * @see for XML embedded files please use ZUGFeRDInvoiceImporter.getFileAttachmentsXML
+ * for XML embedded files please use ZUGFeRDInvoiceImporter.getFileAttachmentsXML
* @return a ArrayList of FileAttachments, empty if none
*/
public List getFileAttachmentsPDF() {
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java
index 4a28fd44..117254fb 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java
@@ -423,7 +423,7 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
/***
*
* @return the file attachments embedded in XML (using base64) decoded as byte array,
- * @see for PDF embedded files in FX use getFileAttachmentsPDF()
+ * for PDF embedded files in FX use getFileAttachmentsPDF()
*/
public List getFileAttachmentsXML() {
return fileAttachments;
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
index 185e8ba8..5223b31b 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
@@ -96,6 +96,7 @@ public class ZUGFeRDVisualizer {
private TransformerFactory mFactory = null;
private Templates mXsltXRTemplate = null;
private Templates mXsltUBLTemplate = null;
+ private Templates mXsltCIOTemplate = null;
private Templates mXsltHTMLTemplate = null;
private Templates mXsltPDFTemplate = null;
private Templates mXsltZF1HTMLTemplate = null;
@@ -151,6 +152,8 @@ public class ZUGFeRDVisualizer {
String zf2Signature = "CrossIndustryInvoice";
String ublSignature = "Invoice";
String ublCreditNoteSignature = "CreditNote";
+ String cioSignature = "SCRDMCCBDACIOMessageStructure" +
+ "";
boolean doPostProcessing = false;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
@@ -173,6 +176,10 @@ public class ZUGFeRDVisualizer {
//zf2 or fx
applyUBLCreditNote2XSLT(fis, iaos);
doPostProcessing = true;
+ } else if (root.getLocalName().equals(cioSignature)) {
+ //zf2 or fx
+ applyCIO2XSLT(fis, iaos);
+ doPostProcessing = true;
} else {
throw new IllegalArgumentException("File does not look like CII or UBL");
}
@@ -277,20 +284,6 @@ public class ZUGFeRDVisualizer {
} catch (FileNotFoundException | TransformerException e) {
LOGGER.error("Failed to apply FOP", e);
}
- /*
- FopConfParser parser = null;
- try {
- //parsing configuration
- parser = new FopConfParser(CLASS_LOADER.getResourceAsStream("fop-config.xconf"), new URI("file:///"));
-
- } catch (SAXException e) {
- throw new UncheckedIOException(new IOException(e));
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } catch (URISyntaxException e) {
- Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
- }*/
-// FopFactoryBuilder builder = parser.getFopFactoryBuilder();
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
Configuration cfg = null;
@@ -351,6 +344,17 @@ public class ZUGFeRDVisualizer {
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
}
+ protected void applyCIO2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
+ throws TransformerException {
+ if (mXsltCIOTemplate == null) {
+ mXsltCIOTemplate = mFactory.newTemplates(
+ new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cio-xr.xsl")));
+ }
+ Transformer transformer = mXsltCIOTemplate.newTransformer();
+
+ transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
+ }
+
protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
if (mXsltUBLTemplate == null) {
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 62badd8c..c400cbbc 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
@@ -30,5 +30,5 @@ public class TaxCategoryCodeTypeConstants {
public static final String UNTAXEDSERVICE = "O";
public static final String INTRACOMMUNITY = "K";
- public static Set CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE).collect(Collectors.toSet());
+ public static Set CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT).collect(Collectors.toSet());
}
diff --git a/library/src/main/resources/stylesheets/cio-xr.xsl b/library/src/main/resources/stylesheets/cio-xr.xsl
new file mode 100644
index 00000000..415e2dfe
--- /dev/null
+++ b/library/src/main/resources/stylesheets/cio-xr.xsl
@@ -0,0 +1,2225 @@
+
+
+
+
+
+ Author: KoSIT Bremen (kosit@finanzen.bremen.de)
+ Fassung vom: 2020-06-30+02:00
+ Überführt eine zur EN 16931 konforme elektronische Rechnung in der konkreten Syntax UNCEFACT.CII.D16B in eine Instanz gemäß des Schemas für den Namensraum urn:ce.eu:en16931:2017:xoev-de:kosit:standard:xrechnung-1.
+ Das Skript setzt voraus, dass das zu verarbeitende Dokument valide bzgl. des XML Schemas und der Schematron-Regeln der Quelle ist. Für nicht valide Dokumente ist das Ergebnis nicht definiert.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ILLEGAL DATE FORMAT: <para>Mit diesem Datentyp wird ein kalendarisches Datum abgebildet, wie es in der ISO 8601 Spezifikation <quote>Calendar date complete representation</quote> beschrieben ist (siehe ISO 8601:2004, Abschnitt 5.2.1.1). Das Datum beinhaltet keine Zeitangabe. Das konkret zu verwendende Format ist abhängig von der genutzten Syntax.</para>
+<para>Der Datentyp basiert auf dem Typ <quote>Date Time. Type</quote>, wie in ISO 15000-5:2014 Anhang B definiert.</para>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Liefert einen XPath-Pfad, welches $n eindeutig identifiziert.
+
+
+
+
+
+
+
+
+
+
+ Liefert einen XPath-Pfad, welches $n eindeutig identifiziert.
+
+
+
+
+ /
+
+
+ [
+
+ ]
+
+
+
+ /@
+
+
+
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java
index 4b9bbb34..d6a425d4 100644
--- a/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java
@@ -36,7 +36,7 @@ public class DeSerializationTest extends TestCase {
public void testJackson() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
- Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty("some org", "teststr", "55232", "teststadt", "DE").addTaxID("taxID")).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber("0185").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal("1"), new BigDecimal(1.0)));
+ Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty("some org", "teststr", "55232", "teststadt", "DE").addTaxID("taxID").addBankDetails(new BankDetails("DE3600000123456", "ABCDEFG1001").setAccountName("Donald Duck"))).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber("0185").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal("1"), new BigDecimal(1.0)));
String jsonArray = mapper.writeValueAsString(i);
// [{"stringValue":"a","intValue":1,"booleanValue":true},
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ProfilesMinimumBasicWLTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ProfilesMinimumBasicWLTest.java
index 016dd9f2..af75615f 100644
--- a/library/src/test/java/org/mustangproject/ZUGFeRD/ProfilesMinimumBasicWLTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ProfilesMinimumBasicWLTest.java
@@ -36,7 +36,8 @@ import java.util.Date;
*/
public class ProfilesMinimumBasicWLTest extends TestCase {
- final String TARGET_PDF_FX_MINIMUM = "./target/testout-Minimum.pdf";
+ final String TARGET_PDF_FX_MINIMUM_INV = "./target/testout-Minimum-INV.pdf";
+ final String TARGET_PDF_FX_MINIMUM_CN = "./target/testout-Minimum-CN.pdf";
public void testMinimumCreditNote() {
String ownNumber = "NUMFACTURE";
@@ -67,7 +68,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(123), new BigDecimal(1)))
.setCreditNote();
ze.setTransaction(i);
- ze.export(TARGET_PDF_FX_MINIMUM);
+ ze.export(TARGET_PDF_FX_MINIMUM_CN);
// check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("EN 16931") == -1);
@@ -79,7 +80,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
}
// now check the contents (like MustangReaderTest)
- ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM);
+ ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM_CN);
// Reading ZUGFeRD
assertEquals("146.37",zi.getAmount());
@@ -121,7 +122,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
.setNumber(ownNumber).setTotalPrepaidAmount(new BigDecimal("1"))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(123), new BigDecimal(1)));
ze.setTransaction(i);
- ze.export(TARGET_PDF_FX_MINIMUM);
+ ze.export(TARGET_PDF_FX_MINIMUM_INV);
// check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("EN 16931") == -1);
@@ -133,7 +134,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
}
// now check the contents (like MustangReaderTest)
- ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM);
+ ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM_INV);
// Reading ZUGFeRD
assertEquals("145.37",zi.getAmount());
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java
index 4235d8df..227383e6 100644
--- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java
@@ -60,7 +60,9 @@ public class ZF2PushTest extends TestCase {
final String TARGET_REVERSECHARGEPDF = "./target/testout-ZF2PushReverseCharge.pdf";
public void testPushExport() {
-
+ /***
+ * This writes to a filename like an official sample, please consider when changing (probably better not?)
+ */
// the writing part
String orgname = "Bei Spiel GmbH";
String number = "RE-20201121/508";
@@ -92,10 +94,14 @@ public class ZF2PushTest extends TestCase {
fail("Exception should not be raised");
}
+
+
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("DE88200800000970375700")); //the iban
assertTrue(zi.getUTF8().contains("Max Mustermann")); //account holder
+ assertTrue(zi.getUTF8().contains("DueDateDateTime")); //account holder
+ assertTrue(zi.getUTF8().contains("20201212")); //account holder
assertTrue(zi.getUTF8().contains("
+
+
+
+ false
+
+
+ A1
+
+
+ urn:order-x.eu:1p0:comfort
+
+
+
+ PO123456789
+ Doc Name
+ 220
+
+ 202003311232
+
+
+ false
+
+ 9
+ AC
+
+ Content of Note
+ AAI
+
+
+
+ 20200331
+
+
+ 20200630
+
+
+
+
+
+
+ 1
+
+ WEEE Tax of 0,50 euros per item included
+ TXD
+
+
+
+ 1234567890123
+ 987654321
+ 654987321
+ Product Name
+ Product Description
+ Product Batch ID (lot ID)
+ Product Brand Name
+
+ Characteristic_Code
+ Characteristic Description
+ 5 meters
+
+
+ Class_code
+ Name Class Codification
+
+
+ Product Instances Batch ID
+ Product Instances Supplier Serial ID
+
+
+ 7B
+
+ 5
+ 3
+ 1
+
+
+
+ FR
+
+
+ ADD_REF_PROD_ID
+ ADD_REF_PROD_URIID
+ 6
+ ADD_REF_PROD_Desc
+
+
+
+
+ 1
+
+
+ QUOT_125487
+ 3
+
+
+ ADD_REF_DOC_ID
+ ADD_REF_DOC_URIID
+ 5
+ 916
+ ADD_REF_DOC_Desc
+
+
+ OBJECT_125487
+ 130
+ AWV
+
+
+ 10.50
+ 1.00
+
+
+ false
+
+ 1.00
+ 95
+ DISCOUNT
+
+
+
+ true
+
+ 0.50
+ AEW
+ WEEE
+
+
+
+ 10.00
+ 1.00
+
+
+ CATALOG_REF_ID
+ 2
+
+
+ 2
+
+
+
+
+ true
+
+ 6
+ 3
+ 2
+
+
+
+ 202004150900
+
+
+ 202004301800
+
+
+
+
+
+
+ VAT
+ S
+ 20.00
+
+
+
+ false
+
+ 10.00
+ 60.00
+ 6.00
+ 64
+ SPECIAL AGREEMENT
+
+
+
+ true
+
+ 10.00
+ 60.00
+ 6.00
+ FC
+ FREIGHT SERVICES
+
+
+ 60.00
+
+
+ BUYER_ACCOUNTING_REF
+
+
+
+
+
+ 2
+
+ WEEE Tax of 0,50 euros per item included
+ TXD
+
+
+
+ 548796523
+ 598632147
+ 698569856
+ Product Name
+ Product Description
+ Product Batch ID (lot ID)
+ Product Brand Name
+
+ Characteristic_Code
+ Characteristic Description
+ 3 meters
+
+
+ Class_code
+ Name Class Codification
+
+
+ Product Instances Batch ID
+ Product Instances Supplier Serial ID
+
+
+ 7B
+
+ 2
+ 1
+ 3
+
+
+
+ FR
+
+
+ ADD_REF_PROD_ID
+ ADD_REF_PROD_URIID
+ 6
+ ADD_REF_PROD_Desc
+
+
+
+
+ 3
+
+
+ QUOT_125487
+ 2
+
+
+ ADD_REF_DOC_ID
+ ADD_REF_DOC_URIID
+ 5
+ 916
+ ADD_REF_DOC_Desc
+
+
+ OBJECT_125487
+ 130
+ AWV
+
+
+ 19.50
+ 2
+
+
+ true
+
+ 0.50
+ AEW
+ WEEE TAX
+
+
+
+ 20.00
+ 2
+
+
+ CATALOG_REF_ID
+ 2
+
+
+ 3
+
+
+
+
+ true
+
+ 10.00
+ 5
+ 2
+
+
+ 20200415
+
+
+
+
+
+ VAT
+ S
+ 20.00
+
+
+
+ false
+
+ 1.00
+ 100.00
+ 1.00
+ 64
+ SPECIAL AGREEMENT
+
+
+
+ true
+
+ 1.00
+ 100.00
+ 1.00
+ FC
+ FREIGHT SERVICES
+
+
+ 100.00
+
+
+ BUYER_ACCOUNTING_REF
+
+
+
+
+
+ 3
+
+ Content of Note
+ AAI
+
+
+
+ 854721548
+ 698325417
+ 598674321
+ Product Name
+ Product Description
+ Product Batch ID (lot ID)
+ Product Brand Name
+
+ Characteristic_Code
+ Characteristic Description
+ 3 meters
+
+
+ Class_code
+ Name Class Codification
+
+
+ Product Instances Batch ID
+ Product Instances Supplier Serial ID
+
+
+ 7B
+
+ 2
+ 1
+ 3
+
+
+
+ FR
+
+
+ ADD_REF_PROD_ID
+ ADD_REF_PROD_URIID
+ 6
+ ADD_REF_PROD_Desc
+
+
+
+
+ 4
+
+
+ QUOT_125487
+ 1
+
+
+ ADD_REF_DOC_ID
+ ADD_REF_DOC_URIID
+ 5
+ 916
+ ADD_REF_DOC_Desc
+
+
+ OBJECT_125487
+ 130
+ AWV
+
+
+ 30
+ 1
+
+
+ false
+
+ 5
+
+
+
+ 25
+ 1
+
+
+ CATALOG_REF_ID
+ 5
+
+
+ 4
+
+
+
+
+ true
+
+ 6
+ 3
+ 2
+
+
+
+ 20200415
+
+
+ 20200430
+
+
+
+
+
+
+ VAT
+ S
+ 20.00
+
+
+
+ false
+
+ 10.00
+ 150.00
+ 15.00
+ 64
+ SPECIAL AGREEMENT
+
+
+
+ true
+
+ 10.00
+ 150.00
+ 15.00
+ FC
+ FREIGHT SERVICES
+
+
+ 150.00
+
+
+ BUYER_ACCOUNTING_REF
+
+
+
+
+ BUYER_REF_BU123
+
+ SUPPLIER_ID_321654
+ 123654879
+ SELLER_NAME
+ SELLER_ADD_LEGAL_INFORMATION
+
+ 123456789
+ SELLER_TRADING_NAME
+
+
+ SELLER_CONTACT_NAME
+ SELLER_CONTACT_DEP
+ SR
+
+ +33 6 25 64 98 75
+
+
+ contact@seller.com
+
+
+
+ 75001
+ SELLER_ADDR_1
+ SELLER_ADDR_2
+ SELLER_ADDR_3
+ SELLER_CITY
+ FR
+
+
+ sales@seller.com
+
+
+ FR 32 123 456 789
+
+
+ SELLER_TAX_ID
+
+
+
+ BY_ID_9587456
+ 98765432179
+ BUYER_NAME
+
+ 987654321
+ BUYER_TRADING_NAME
+
+
+ BUYER_CONTACT_NAME
+ BUYER_CONTACT_DEP
+ LB
+
+ +33 6 65 98 75 32
+
+
+ contact@buyer.com
+
+
+
+ 69001
+ BUYER_ADDR_1
+ BUYER_ADDR_2
+ BUYER_ADDR_3
+ BUYER_CITY
+ FR
+
+
+ operation@buyer.com
+
+
+ FR 05 987 654 321
+
+
+ BUYER_TAX_ID
+
+
+
+ BUYER_REQ_ID_25987
+ 654987321
+ BUYER_REQ_NAME
+
+ 654987321
+ BUYER_REQ_TRADING_NAME
+
+
+ BUYER_REQ_CONTACT_NAME
+ BUYER_REQ_CONTACT_DEP
+ PD
+
+ +33 6 54 98 65 32
+
+
+ requisitioner@buyer.com
+
+
+
+ 69001
+ BUYER_REQ_ADDR_1
+ BUYER_REQ_ADDR_2
+ BUYER_REQ_ADDR_3
+ BUYER_REQ_CITY
+ FR
+
+
+ purchase@buyer.com
+
+
+ FR 92 654 987 321
+
+
+
+ FCA
+ Free Carrier
+ 7
+
+ DEL_TERMS_LOC_ID
+ DEL_TERMS_LOC_Name
+
+
+
+ SALES_REF_ID_459875
+
+
+ PO123456789
+
+
+ QUOT_125487
+
+
+ CONTRACT_2020-25987
+
+
+ REQ_875498
+
+
+ ADD_REF_DOC_ID
+ ADD_REF_DOC_URIID
+ 916
+ ADD_REF_DOC_Desc
+
+
+ TENDER_ID
+ 50
+
+
+ OBJECT_ID
+ 130
+ AWV
+
+
+ CATALOG_ID
+
+
+ BLANKET_ORDER_ID
+
+
+ PREV_ORDER_C_ID
+
+
+ PREV_ORDER_R_ID
+
+
+ PROJECT_ID
+ Project Reference
+
+
+
+
+ SHIP_TO_ID
+ 5897546912
+ SHIP_TO_NAME
+
+ 951632874
+ SHIP_TO_TRADING_NAME
+
+
+ SHIP_TO_CONTACT_NAME
+ SHIP_TO_CONTACT_DEP
+ SD
+
+ +33 6 85 96 32 41
+
+
+ shipto@customer.com
+
+
+
+ 69003
+ SHIP_TO_ADDR_1
+ SHIP_TO_ADDR_2
+ SHIP_TO_ADDR_3
+ SHIP_TO_CITY
+ FR
+
+
+ delivery@buyer.com
+
+
+ FR 66 951 632 874
+
+
+
+ SHIP_FROM_ID
+ 875496123
+ SHIP_FROM_NAME
+
+ 548963127
+ SHIP_FROM_TRADING_NAME
+
+
+ SHIP_FROM_CONTACT_NAME
+ SHIP_FROM_CONTACT_DEP
+ SD
+
+ +33 6 85 96 32 41
+
+
+ shipfrom@seller.com
+
+
+
+ 75003
+ SHIP_FROM_ADDR_1
+ SHIP_FROM_ADDR_2
+ SHIP_FROM_ADDR_3
+ SHIP_FROM_CITY
+ FR
+
+
+ warehouse@seller.com
+
+
+ FR 16 548 963 127
+
+
+
+
+ 20200415
+
+
+
+ 202004150900
+
+
+ 202004301800
+
+
+
+
+
+ EUR
+
+ INVOICEE_ID_9587456
+ 98765432179
+ INVOICEE_NAME
+
+ 987654321
+ INVOICEE_TRADING_NAME
+
+
+ INVOICEE_CONTACT_NAME
+ INVOICEE_CONTACT_DEP
+ LB
+
+ +33 6 65 98 75 32
+
+
+ invoicee@buyer.com
+
+
+
+ 69001
+ INVOICEE_ADDR_1
+ INVOICEE_ADDR_2
+ INVOICEE_ADDR_3
+ INVOICEE_CITY
+ FR
+
+
+ invoicee@buyer.com
+
+
+ FR 05 987 654 321
+
+
+ INVOICEE_TAX_ID
+
+
+
+ 30
+ Credit Transfer
+
+
+
+ false
+
+ 10.00
+ 310
+ 31.00
+ 64
+ SPECIAL AGREEMENT
+
+ VAT
+ S
+ 20.00
+
+
+
+
+ true
+
+ 10.00
+ 210.00
+ 21.00
+ FC
+ FREIGHT SERVICES
+
+ VAT
+ S
+ 20.00
+
+
+
+ PAYMENT_TERMS_DESC
+
+
+ 310.00
+ 21.00
+ 31.00
+ 300.00
+ 60.00
+ 360.00
+
+
+ BUYER_ACCOUNT_REF
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index eab363ea..d1d680f8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.mustangproject
core
- 2.13.1-SNAPSHOT
+ 2.14.0-SNAPSHOT
pom
Mustang
@@ -83,8 +83,7 @@
scm:git:https://github.com/ZUGFeRD/mustangproject.git
scm:git:https://github.com/ZUGFeRD/mustangproject.git
https://github.com/ZUGFeRD/mustangproject
- HEAD
-
+
@@ -248,7 +247,7 @@
package
-
+
diff --git a/validator/pom.xml b/validator/pom.xml
index 7b0152b3..8f2bdcf4 100644
--- a/validator/pom.xml
+++ b/validator/pom.xml
@@ -4,7 +4,7 @@
org.mustangproject
core
- 2.13.1-SNAPSHOT
+ 2.14.0-SNAPSHOT
validator
diff --git a/validator/src/test/java/org/mustangproject/validator/LibraryTest.java b/validator/src/test/java/org/mustangproject/validator/LibraryTest.java
index 2e1b1a17..03b7c782 100644
--- a/validator/src/test/java/org/mustangproject/validator/LibraryTest.java
+++ b/validator/src/test/java/org/mustangproject/validator/LibraryTest.java
@@ -244,8 +244,31 @@ public class LibraryTest extends ResourceCase {
.isEqualTo(0);
}
- public void testMinimumProfileValidity() {
- File tempFile = new File("../library/target/testout-Minimum.pdf");
+ public void testMinimumProfileValidityInvoice() {
+ File tempFile = new File("../library/target/testout-Minimum-INV.pdf");
+ ZUGFeRDValidator zfv = new ZUGFeRDValidator();
+
+ String res = zfv.validate(tempFile.getAbsolutePath());
+
+ assertThat(res).valueByXPath("count(//error)")
+ .asInt()
+ .isEqualTo(0);
+ assertThat(res).valueByXPath("/validation/summary/@status")
+ .asString()
+ .isEqualTo("valid");// expect to be valid because XR notices are, well, only notices
+ assertThat(res).valueByXPath("/validation/xml/summary/@status")
+ .asString()
+ .isEqualTo("valid");
+ /** end of errors due to version mismatch*/
+
+
+ assertThat(res).valueByXPath("count(//notice)")
+ .asInt()
+ .isEqualTo(0);
+ }
+
+ public void testMinimumProfileValidityCreditNote() {
+ File tempFile = new File("../library/target/testout-Minimum-CN.pdf");
ZUGFeRDValidator zfv = new ZUGFeRDValidator();
String res = zfv.validate(tempFile.getAbsolutePath());