" //$NON-NLS-1$
+ + " " //$NON-NLS-1$
+ currencyFormat(getTotalGross().subtract(getTotal())) + "\n" //$NON-NLS-1$
+ " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$
// //
// currencyID=\"EUR\"
- + " " + currencyFormat(getTotalPrepaid()) + "\n"
+ + " " + currencyFormat(getTotalPrepaid()) + "\n"
+ " " + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "\n" //$NON-NLS-1$ //$NON-NLS-2$
// //
// currencyID=\"EUR\"
@@ -558,8 +540,52 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
zugferdData = zugferdRaw;
}
} catch (UnsupportedEncodingException e) {
- Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
+ Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
} // $NON-NLS-1$
}
+ private String buildPaymentTermsXml() {
+ String paymentTermsXml = "";
+
+ IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
+ IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
+ IZUGFeRDDate dueDate = paymentTerms.getDueDate();
+ if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
+ throw new IllegalStateException(
+ "if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
+ }
+ paymentTermsXml += "" + paymentTerms.getDescription() + "";
+ if (dueDate != null) {
+ paymentTermsXml += "";
+ paymentTermsXml += ""
+ + dueDate.getFormat().getFormatter().format(dueDate.getDate()) + "";
+ paymentTermsXml += "";
+ }
+
+ if (discountTerms != null) {
+ paymentTermsXml += "";
+ String currency = trans.getCurrency();
+ String basisAmount = currencyFormat(getTotalGross());
+ paymentTermsXml += "" + basisAmount + "";
+ paymentTermsXml += "" + discountTerms.getCalculationPercentage().toString()
+ + "";
+
+ if (discountTerms.getBaseDate() != null) {
+ Date baseDate = discountTerms.getBaseDate().getDate();
+ ZUGFeRDDateFormat baseDateFormat = discountTerms.getBaseDate().getFormat();
+ paymentTermsXml += "";
+ paymentTermsXml += "" + baseDateFormat.getFormatter().format(baseDate) + "";
+ paymentTermsXml += "";
+
+ paymentTermsXml += ""
+ + discountTerms.getBasePeriodMeasure() + "";
+ }
+
+ paymentTermsXml += "";
+ }
+
+ paymentTermsXml += "";
+ return paymentTermsXml;
+ }
+
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PushProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PushProvider.java
new file mode 100644
index 00000000..4d47c89d
--- /dev/null
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PushProvider.java
@@ -0,0 +1,413 @@
+/**
+ * *********************************************************************
+ *
+ * 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;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+
+public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
+
+ protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownTaxID = null, ownVATID = null, ownForeignOrganisationID = null, ownOrganisationName = null, ownStreet = null, ownZIP = null, ownLocation = null, ownCountry = null, currency = null, paymentTermDescription = null;
+ protected Date issueDate = null, dueDate = null, deliveryDate = null;
+ protected BigDecimal totalPrepaidAmount = null;
+ protected IZUGFeRDExportableContact ownContact = null, recipient = null, deliveryAddress = null;
+ protected ArrayList ZFItems = null;
+
+ protected IZUGFeRDAllowanceCharge[] ZFAllowances = null, ZFCharges = null, ZFLogisticsServiceCharges = null;
+ protected IZUGFeRDTradeSettlement[] getTradeSettlement = null;
+ protected IZUGFeRDPaymentTerms paymentTerms = null;
+
+
+ public ZUGFeRD2PushProvider() {
+ ZFItems = new ArrayList();
+ }
+
+ @Override
+ public String getDocumentName() {
+ return documentName;
+ }
+
+ public ZUGFeRD2PushProvider setDocumentName(String documentName) {
+ this.documentName = documentName;
+ return this;
+ }
+
+ @Override
+ public String getDocumentCode() {
+ return documentCode;
+ }
+
+ public ZUGFeRD2PushProvider setDocumentCode(String documentCode) {
+ this.documentCode = documentCode;
+ return this;
+ }
+
+ @Override
+ public String getNumber() {
+ return number;
+ }
+
+ public ZUGFeRD2PushProvider setNumber(String number) {
+ this.number = number;
+ return this;
+ }
+
+ @Override
+ public String getOwnOrganisationFullPlaintextInfo() {
+ return ownOrganisationFullPlaintextInfo;
+ }
+
+ public ZUGFeRD2PushProvider setOwnOrganisationFullPlaintextInfo(String ownOrganisationFullPlaintextInfo) {
+ this.ownOrganisationFullPlaintextInfo = ownOrganisationFullPlaintextInfo;
+ return this;
+ }
+
+ @Override
+ public String getReferenceNumber() {
+ return referenceNumber;
+ }
+
+ public ZUGFeRD2PushProvider setReferenceNumber(String referenceNumber) {
+ this.referenceNumber = referenceNumber;
+ return this;
+ }
+
+ @Override
+ public String getShipToOrganisationID() {
+ return shipToOrganisationID;
+ }
+
+ public ZUGFeRD2PushProvider setShipToOrganisationID(String shipToOrganisationID) {
+ this.shipToOrganisationID = shipToOrganisationID;
+ return this;
+ }
+
+ @Override
+ public String getShipToOrganisationName() {
+ return shipToOrganisationName;
+ }
+
+ public ZUGFeRD2PushProvider setShipToOrganisationName(String shipToOrganisationName) {
+ this.shipToOrganisationName = shipToOrganisationName;
+ return this;
+ }
+
+ @Override
+ public String getShipToStreet() {
+ return shipToStreet;
+ }
+
+ public ZUGFeRD2PushProvider setShipToStreet(String shipToStreet) {
+ this.shipToStreet = shipToStreet;
+ return this;
+ }
+
+ @Override
+ public String getShipToZIP() {
+ return shipToZIP;
+ }
+
+ public ZUGFeRD2PushProvider setShipToZIP(String shipToZIP) {
+ this.shipToZIP = shipToZIP;
+ return this;
+ }
+
+ @Override
+ public String getShipToLocation() {
+ return shipToLocation;
+ }
+
+ public ZUGFeRD2PushProvider setShipToLocation(String shipToLocation) {
+ this.shipToLocation = shipToLocation;
+ return this;
+ }
+
+ @Override
+ public String getShipToCountry() {
+ return shipToCountry;
+ }
+
+ public ZUGFeRD2PushProvider setShipToCountry(String shipToCountry) {
+ this.shipToCountry = shipToCountry;
+ return this;
+ }
+
+ @Override
+ public String getBuyerOrderReferencedDocumentID() {
+ return buyerOrderReferencedDocumentID;
+ }
+
+ public ZUGFeRD2PushProvider setBuyerOrderReferencedDocumentID(String buyerOrderReferencedDocumentID) {
+ this.buyerOrderReferencedDocumentID = buyerOrderReferencedDocumentID;
+ return this;
+ }
+
+ @Override
+ public String getBuyerOrderReferencedDocumentIssueDateTime() {
+ return buyerOrderReferencedDocumentIssueDateTime;
+ }
+
+ public ZUGFeRD2PushProvider setBuyerOrderReferencedDocumentIssueDateTime(String buyerOrderReferencedDocumentIssueDateTime) {
+ this.buyerOrderReferencedDocumentIssueDateTime = buyerOrderReferencedDocumentIssueDateTime;
+ return this;
+ }
+
+ @Override
+ public String getOwnTaxID() {
+ return ownTaxID;
+ }
+
+ public ZUGFeRD2PushProvider setOwnTaxID(String ownTaxID) {
+ this.ownTaxID = ownTaxID;
+ return this;
+ }
+
+ @Override
+ public String getOwnVATID() {
+ return ownVATID;
+ }
+
+ public ZUGFeRD2PushProvider setOwnVATID(String ownVATID) {
+ this.ownVATID = ownVATID;
+ return this;
+ }
+
+ @Override
+ public String getOwnForeignOrganisationID() {
+ return ownForeignOrganisationID;
+ }
+
+ public ZUGFeRD2PushProvider setOwnForeignOrganisationID(String ownForeignOrganisationID) {
+ this.ownForeignOrganisationID = ownForeignOrganisationID;
+ return this;
+ }
+
+ @Override
+ public String getOwnOrganisationName() {
+ return ownOrganisationName;
+ }
+
+ public ZUGFeRD2PushProvider setOwnOrganisationName(String ownOrganisationName) {
+ this.ownOrganisationName = ownOrganisationName;
+ return this;
+ }
+
+ @Override
+ public String getOwnStreet() {
+ return ownStreet;
+ }
+
+ public ZUGFeRD2PushProvider setOwnStreet(String ownStreet) {
+ this.ownStreet = ownStreet;
+ return this;
+ }
+
+ @Override
+ public String getOwnZIP() {
+ return ownZIP;
+ }
+
+ public ZUGFeRD2PushProvider setOwnZIP(String ownZIP) {
+ this.ownZIP = ownZIP;
+ return this;
+ }
+
+ public String getOwnLocation() {
+ return ownLocation;
+ }
+
+ public ZUGFeRD2PushProvider setOwnLocation(String getOwnLocation) {
+ this.ownLocation = getOwnLocation;
+ return this;
+ }
+
+ public String getOwnCountry() {
+ return ownCountry;
+ }
+
+ public ZUGFeRD2PushProvider setOwnCountry(String getOwnCountry) {
+ this.ownCountry = getOwnCountry;
+ return this;
+ }
+
+ @Override
+ public String getCurrency() {
+ return currency;
+ }
+
+ public ZUGFeRD2PushProvider setCurrency(String currency) {
+ this.currency = currency;
+ return this;
+ }
+
+ @Override
+ public String getPaymentTermDescription() {
+ return paymentTermDescription;
+ }
+
+ public ZUGFeRD2PushProvider setPaymentTermDescription(String paymentTermDescription) {
+ this.paymentTermDescription = paymentTermDescription;
+ return this;
+ }
+
+ @Override
+ public Date getIssueDate() {
+ return issueDate;
+ }
+
+ public ZUGFeRD2PushProvider setIssueDate(Date issueDate) {
+ this.issueDate = issueDate;
+ return this;
+ }
+
+ @Override
+ public Date getDueDate() {
+ return dueDate;
+ }
+
+ public ZUGFeRD2PushProvider setDueDate(Date dueDate) {
+ this.dueDate = dueDate;
+ return this;
+ }
+
+ @Override
+ public Date getDeliveryDate() {
+ return deliveryDate;
+ }
+
+ public ZUGFeRD2PushProvider setDeliveryDate(Date deliveryDate) {
+ this.deliveryDate = deliveryDate;
+ return this;
+ }
+
+ @Override
+ public BigDecimal getTotalPrepaidAmount() {
+ return totalPrepaidAmount;
+ }
+
+ public ZUGFeRD2PushProvider setTotalPrepaidAmount(BigDecimal totalPrepaidAmount) {
+ this.totalPrepaidAmount = totalPrepaidAmount;
+ return this;
+ }
+
+ @Override
+ public IZUGFeRDExportableContact getOwnContact() {
+ return ownContact;
+ }
+
+ public ZUGFeRD2PushProvider setOwnContact(IZUGFeRDExportableContact ownContact) {
+ this.ownContact = ownContact;
+ return this;
+ }
+
+ @Override
+ public IZUGFeRDExportableContact getRecipient() {
+ return recipient;
+ }
+
+ public ZUGFeRD2PushProvider setRecipient(IZUGFeRDExportableContact recipient) {
+ this.recipient = recipient;
+ return this;
+ }
+
+ @Override
+ public IZUGFeRDAllowanceCharge[] getZFAllowances() {
+ return ZFAllowances;
+ }
+
+ public ZUGFeRD2PushProvider setZFAllowances(IZUGFeRDAllowanceCharge[] ZFAllowances) {
+ this.ZFAllowances = ZFAllowances;
+ return this;
+ }
+
+ @Override
+ public IZUGFeRDAllowanceCharge[] getZFCharges() {
+ return ZFCharges;
+ }
+
+ public ZUGFeRD2PushProvider setZFCharges(IZUGFeRDAllowanceCharge[] ZFCharges) {
+ this.ZFCharges = ZFCharges;
+ return this;
+ }
+
+ @Override
+ public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
+ return ZFLogisticsServiceCharges;
+ }
+
+ public ZUGFeRD2PushProvider setZFLogisticsServiceCharges(IZUGFeRDAllowanceCharge[] ZFLogisticsServiceCharges) {
+ this.ZFLogisticsServiceCharges = ZFLogisticsServiceCharges;
+ return this;
+ }
+
+ public IZUGFeRDTradeSettlement[] getGetTradeSettlement() {
+ return getTradeSettlement;
+ }
+
+ public ZUGFeRD2PushProvider setGetTradeSettlement(IZUGFeRDTradeSettlement[] getTradeSettlement) {
+ this.getTradeSettlement = getTradeSettlement;
+ return this;
+ }
+
+ @Override
+ public IZUGFeRDPaymentTerms getPaymentTerms() {
+ return paymentTerms;
+ }
+
+ public ZUGFeRD2PushProvider setPaymentTerms(IZUGFeRDPaymentTerms paymentTerms) {
+ this.paymentTerms = paymentTerms;
+ return this;
+ }
+
+ @Override
+ public IZUGFeRDExportableContact getDeliveryAddress() {
+ return deliveryAddress;
+ }
+
+ public ZUGFeRD2PushProvider setDeliveryAddress(IZUGFeRDExportableContact deliveryAddress) {
+ this.deliveryAddress = deliveryAddress;
+ return this;
+ }
+
+ @Override
+ public IZUGFeRDExportableItem[] getZFItems() {
+ return ZFItems.toArray(new IZUGFeRDExportableItem[0]);
+ }
+
+ public ZUGFeRD2PushProvider addItem(IZUGFeRDExportableItem item) {
+ ZFItems.add(item);
+ return this;
+ }
+
+
+ public boolean isValid() {
+ return (dueDate != null) && (ownZIP != null) && (ownStreet != null) && (ownLocation != null) && (ownCountry != null) && (ownTaxID != null) && (ownVATID != null) && (recipient != null);
+ //contact
+ // this.phone = phone;
+ // this.email = email;
+ // this.street = street;
+ // this.zip = zip;
+ // this.location = location;
+ // this.country = country;
+ }
+
+}
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java
similarity index 93%
rename from src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java
index d59b2f40..b4d9f186 100644
--- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java
@@ -19,5 +19,5 @@
package org.mustangproject.ZUGFeRD;
public enum ZUGFeRDConformanceLevel {
- BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS
+ BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS, XRECHNUNG
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDDateFormat.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDDateFormat.java
new file mode 100644
index 00000000..3457fe18
--- /dev/null
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDDateFormat.java
@@ -0,0 +1,28 @@
+package org.mustangproject.ZUGFeRD;
+
+import java.text.SimpleDateFormat;
+
+import org.mustangproject.ZUGFeRD.model.DateTimeTypeConstants;
+
+public enum ZUGFeRDDateFormat {
+
+ MONTH_OF_YEAR(DateTimeTypeConstants.MONTH, new SimpleDateFormat("yyyyMM")),
+ WEEK_OF_YEAR(DateTimeTypeConstants.WEEK, new SimpleDateFormat("yyyyww")),
+ DATE(DateTimeTypeConstants.DATE, new SimpleDateFormat("yyyyMMdd"));
+
+ private String dateTimeType;
+ private SimpleDateFormat formatter;
+
+ private ZUGFeRDDateFormat(String dateTimeType, SimpleDateFormat formatter) {
+ this.dateTimeType = dateTimeType;
+ this.formatter = formatter;
+ }
+
+ public String getDateTimeType() {
+ return dateTimeType;
+ }
+
+ public SimpleDateFormat getFormatter() {
+ return formatter;
+ }
+}
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExportException.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExportException.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExportException.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExportException.java
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
similarity index 97%
rename from src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
index 19467a47..2d31038a 100644
--- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
@@ -54,9 +54,9 @@ import java.util.Map;
public class ZUGFeRDExporter implements Closeable {
- public static final int DefaultZUGFeRDVersion = 1;
+ public static final int DefaultZUGFeRDVersion = 2;
- private boolean isFacturX = false;
+ private boolean isFacturX = true;
/**
* To use the ZUGFeRD exporter, implement IZUGFeRDExportableTransaction in
@@ -80,7 +80,7 @@ public class ZUGFeRDExporter implements Closeable {
// BASIC, COMFORT etc - may be set from outside.
@Deprecated
- private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EXTENDED;
+ private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EN16931;
/**
* Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set,
@@ -132,8 +132,8 @@ public class ZUGFeRDExporter implements Closeable {
/**
* Adds additional file attachments into the ZF
- * @param filename
- * @param filecontent
+ * @param filename the name of the attachment
+ * @param filecontent the bytearray with the file contents
*/
public void addAdditionalFile(String filename, byte[] filecontent) {
additionalFiles.put(filename, filecontent);
@@ -192,6 +192,7 @@ public class ZUGFeRDExporter implements Closeable {
public void setZUGFeRDVersion(int ver) {
if (ver == 1) {
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
+ disableFacturX();
this.xmlProvider = z1p;
} else if (ver == 2) {
ZUGFeRD2PullProvider z2p = new ZUGFeRD2PullProvider();
@@ -210,11 +211,21 @@ public class ZUGFeRDExporter implements Closeable {
setZUGFeRDVersion(DefaultZUGFeRDVersion);
}
+ /**
+ * Factur-X is now set by default since ZF 2.1, you have to disable it if you dont wont it
+ * Generate ZF2.1 files with filename factur-x.xml
+ * @deprecated
+ * */
public void setFacturX() {
- setZUGFeRDVersion(2);
isFacturX = true;
}
+ /***
+ * Generate ZF2.0/2.1 files with filename zugferd-invoice.xml instead of factur-x.xml
+ */
+ public void disableFacturX() {
+ isFacturX = false;
+ }
/**
* All files are PDF/A-3, setConformance refers to the level conformance.
*
@@ -464,6 +475,7 @@ public class ZUGFeRDExporter implements Closeable {
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
+// ef.addCompression();
ef.setSubtype(subType);
ef.setSize(data.length);
ef.setCreationDate(new GregorianCalendar());
@@ -583,7 +595,7 @@ public class ZUGFeRDExporter implements Closeable {
protected void addXMP(XMPMetadata metadata) {
if (attachZUGFeRDHeaders) {
- XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, profile,
+ XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, profile,
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
getFilenameForVersion(ZFVersion));
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA1Factory.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA1Factory.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA1Factory.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA1Factory.java
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
similarity index 55%
rename from src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
index 2179cfe7..d0712407 100644
--- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
@@ -1,452 +1,719 @@
-/**
- * ********************************************************************** 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;
-/**
- * Mustangproject's ZUGFeRD implementation ZUGFeRD importer Licensed under the APLv2
- *
- * @date 2014-07-07
- * @version 1.1.0
- * @author jstaerk
- */
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-
-import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
-import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
-import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
-import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
-import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-public class ZUGFeRDImporter {
-
- /**
- * if metadata has been found
- */
- private boolean containsMeta = false;
- /**
- * map filenames of additional XML files to their contents
- */
- private HashMap additionalXMLs = new HashMap<>();
- /**
- * Raw XML form of the extracted data - may be directly obtained.
- */
- private byte[] rawXML = null;
- /**
- * XMP metadata
- */
- private String xmpString = null; // XMP metadata
- /**
- * parsed Document
- */
- private Document document;
-
-
- public ZUGFeRDImporter(String pdfFilename) {
- try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
- extractLowLevel(bis);
- } catch (IOException e) {
- Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
- throw new ZUGFeRDExportException(e);
- }
- }
-
-
- public ZUGFeRDImporter(InputStream pdfStream) {
- try {
- extractLowLevel(pdfStream);
- } catch (IOException e) {
- Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
- throw new ZUGFeRDExportException(e);
- }
- }
-
-
- /**
- * Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling.
- *
- * @param pdfStream a inputstream of a pdf file
- */
- private void extractLowLevel(InputStream pdfStream) throws IOException {
- try (PDDocument doc = PDDocument.load(pdfStream)) {
- // PDDocumentInformation info = doc.getDocumentInformation();
- PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
- //start
-
- if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
- Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.INFO, "no-xmlpart");
- return;
- }
-
- InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
- xmpString = convertStreamToString(XMP);
-
- PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
- if (etn == null) {
- return;
- }
-
- Map efMap = etn.getNames();
- // String filePath = "/tmp/";
-
- if (efMap != null) {
- extractFiles(efMap); // see
- // https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
- } else {
-
- List> kids = etn.getKids();
- for (PDNameTreeNode node : kids) {
- Map namesL = node.getNames();
- extractFiles(namesL);
- }
- }
- }
- }
-
-
- private void extractFiles(Map names) throws IOException {
- for (String alias : names.keySet()) {
-
- PDComplexFileSpecification fileSpec = names.get(alias);
- String filename = fileSpec.getFilename();
- /**
- * filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
- */
- if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$
- containsMeta = true;
-
- PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
- // String embeddedFilename = filePath + filename;
- // File file = new File(filePath + filename);
- // System.out.println("Writing " + embeddedFilename);
- // ByteArrayOutputStream fileBytes=new
- // ByteArrayOutputStream();
- // FileOutputStream fos = new FileOutputStream(file);
-
- setRawXML(embeddedFile.toByteArray());
-
- // fos.write(embeddedFile.getByteArray());
- // fos.close();
- }
- if (filename.startsWith("additional_data")) {
- PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
- additionalXMLs.put(filename, embeddedFile.toByteArray());
- }
- }
- }
-
-
- private Document getDocument() {
- return document;
- }
-
-
- private void setDocument() throws ParserConfigurationException, IOException, SAXException {
- DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
- xmlFact.setNamespaceAware(false);
- DocumentBuilder builder = xmlFact.newDocumentBuilder();
- ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
- is.skip(guessBOMSize(is));
- document = builder.parse(is);
- }
-
-
- public void setRawXML(byte[] rawXML) throws IOException {
- this.rawXML = rawXML;
- try {
- setDocument();
- } catch (ParserConfigurationException | SAXException e) {
- Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
- throw new ZUGFeRDExportException(e);
- }
- }
-
-
- /**
- * Skips over a BOM at the beginning of the given ByteArrayInputStream, if one exists.
- *
- * @param is the ByteArrayInputStream used
- * @throws IOException if can not be read from is
- * @see Autodetection of Character Encodings
- */
- private int guessBOMSize(ByteArrayInputStream is) throws IOException {
- byte[] pad = new byte[4];
- is.read(pad);
- is.reset();
- int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF);
- int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF);
- int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF);
- //
- if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) {
- // UCS-4: BOM takes 4 bytes
- return 4;
- } else if (test3 == 0xEFBBFF) {
- // UTF-8: BOM takes 3 bytes
- return 3;
- } else if (test2 == 0xFEFF || test2 == 0xFFFE) {
- // UTF-16: BOM takes 2 bytes
- return 2;
- }
- return 0;
- }
-
-
- private String extractString(String xpathStr) {
- if (!containsMeta) {
- throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
- }
- String result;
- try {
- Document document = getDocument();
- XPathFactory xpathFact = XPathFactory.newInstance();
- XPath xpath = xpathFact.newXPath();
- result = xpath.evaluate(xpathStr, document);
- } catch (XPathExpressionException e) {
- Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
- throw new ZUGFeRDExportException(e);
- }
- return result;
- }
-
-
- /**
- * @return the reference (purpose) the sender specified for this invoice
- */
- public String getForeignReference() {
- String result = extractString("//ApplicableHeaderTradeSettlement/PaymentReference");
- if (result == null || result.isEmpty()) {
- result = extractString("//ApplicableSupplyChainTradeSettlement/PaymentReference");
- }
- return result;
- }
-
-
- /**
- * @return the document code
- */
- public String getDocumentCode() {
- return extractString("//HeaderExchangedDocument/TypeCode");
- }
-
-
- /**
- * @return the referred document
- */
- public String getReference() {
- return extractString("//ApplicableHeaderTradeAgreement/BuyerReference");
- }
-
-
- /**
- * @return the sender's bank's BLZ code
- * @deprecated use BIC and IBAN instead of BLZ and KTO
- */
- @Deprecated
- public String getBLZ() {
- return extractString("//PayeeSpecifiedCreditorFinancialInstitution/GermanBankleitzahlID");
- }
-
-
- /**
- * @return the sender's account number
- * @deprecated use BIC and IBAN instead of BLZ and KTO
- */
- @Deprecated
- public String getKTO() {
- return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID");
- }
-
-
- /**
- * @return the sender's bank's BIC code
- */
- public String getBIC() {
- return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID");
- }
-
-
- /**
- * @return the sender's bank name
- */
- public String getBankName() {
- return extractString("//PayeeSpecifiedCreditorFinancialInstitution/Name");
- }
-
-
- /**
- * @return the sender's account IBAN code
- */
- public String getIBAN() {
- return extractString("//PayeePartyCreditorFinancialAccount/IBANID");
- }
-
-
- public String getHolder() {
- return extractString("//SellerTradeParty/Name");
- }
-
-
- /**
- * @return the total payable amount
- */
- public String getAmount() {
- String result = extractString("//SpecifiedTradeSettlementHeaderMonetarySummation/DuePayableAmount");
- if (result == null || result.isEmpty()) {
- result = extractString("//SpecifiedTradeSettlementMonetarySummation/GrandTotalAmount");
- }
- return result;
- }
-
-
- /**
- * @return when the payment is due
- */
- public String getDueDate() {
- return extractString("//SpecifiedTradePaymentTerms/DueDateDateTime/DateTimeString");
- }
-
-
- public HashMap getAdditionalData() {
- return additionalXMLs;
- }
-
-
- /**
- * get xmp metadata of the PDF, null if not available
- *
- * @return string
- */
- public String getXMP() {
- return xmpString;
- }
-
-
- /**
- * @return if export found parseable ZUGFeRD data
- */
- public boolean containsMeta() {
- return containsMeta;
- }
-
-
- /**
- * @param meta raw XML to be set
- * @throws IOException if raw can not be set
- */
- public void setMeta(String meta) throws IOException {
- setRawXML(meta.getBytes());
- }
-
-
- /**
- * @return raw XML of the invoice
- */
- public String getMeta() {
- if (rawXML == null) {
- return null;
- }
-
- return new String(rawXML);
- }
-
-
- public int getVersion() throws Exception {
- if (!containsMeta) {
- throw new Exception("Not yet parsed");
- }
- if (getUTF8().contains(" 0) && ((meta.contains("SpecifiedExchangedDocumentContext") //$NON-NLS-1$
- /* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */));
- }
-
-
- static String convertStreamToString(java.io.InputStream is) {
- // source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to
- // https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks
- Scanner s = new Scanner(is, "UTF-8").useDelimiter("\\A");
- return s.hasNext() ? s.next() : "";
- }
-
-}
+/**
+ * ********************************************************************** 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;
+/**
+ * Mustangproject's ZUGFeRD implementation ZUGFeRD importer Licensed under the APLv2
+ *
+ * @date 2014-07-07
+ * @version 1.1.0
+ * @author jstaerk
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.*;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
+import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
+import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
+import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
+import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+public class ZUGFeRDImporter {
+
+ /**
+ * if metadata has been found
+ */
+ private boolean containsMeta = false;
+ /**
+ * map filenames of additional XML files to their contents
+ */
+ private HashMap additionalXMLs = new HashMap<>();
+ /**
+ * Raw XML form of the extracted data - may be directly obtained.
+ */
+ private byte[] rawXML = null;
+ /**
+ * XMP metadata
+ */
+ private String xmpString = null; // XMP metadata
+ /**
+ * parsed Document
+ */
+ private Document document;
+
+
+ public ZUGFeRDImporter(String pdfFilename) {
+ try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
+ extractLowLevel(bis);
+ } catch (IOException e) {
+ Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
+ throw new ZUGFeRDExportException(e);
+ }
+ }
+
+
+ public ZUGFeRDImporter(InputStream pdfStream) {
+ try {
+ extractLowLevel(pdfStream);
+ } catch (IOException e) {
+ Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
+ throw new ZUGFeRDExportException(e);
+ }
+ }
+
+
+ /**
+ * Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling.
+ *
+ * @param pdfStream a inputstream of a pdf file
+ */
+ private void extractLowLevel(InputStream pdfStream) throws IOException {
+ try (PDDocument doc = PDDocument.load(pdfStream)) {
+ // PDDocumentInformation info = doc.getDocumentInformation();
+ PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
+ //start
+
+ if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
+ Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.INFO, "no-xmlpart");
+ return;
+ }
+
+ InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
+ xmpString = convertStreamToString(XMP);
+
+ PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
+ if (etn == null) {
+ return;
+ }
+
+ Map efMap = etn.getNames();
+ // String filePath = "/tmp/";
+
+ if (efMap != null) {
+ extractFiles(efMap); // see
+ // https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
+ } else {
+
+ List> kids = etn.getKids();
+ for (PDNameTreeNode node : kids) {
+ Map namesL = node.getNames();
+ extractFiles(namesL);
+ }
+ }
+ }
+ }
+
+
+ private void extractFiles(Map names) throws IOException {
+ for (String alias : names.keySet()) {
+
+ PDComplexFileSpecification fileSpec = names.get(alias);
+ String filename = fileSpec.getFilename();
+ /**
+ * filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
+ */
+ if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$
+ containsMeta = true;
+
+ PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
+ // String embeddedFilename = filePath + filename;
+ // File file = new File(filePath + filename);
+ // System.out.println("Writing " + embeddedFilename);
+ // ByteArrayOutputStream fileBytes=new
+ // ByteArrayOutputStream();
+ // FileOutputStream fos = new FileOutputStream(file);
+
+ setRawXML(embeddedFile.toByteArray());
+
+ // fos.write(embeddedFile.getByteArray());
+ // fos.close();
+ }
+ if (filename.startsWith("additional_data")) {
+ PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
+ additionalXMLs.put(filename, embeddedFile.toByteArray());
+ }
+ }
+ }
+
+
+ protected Document getDocument() {
+ return document;
+ }
+
+
+ private void setDocument() throws ParserConfigurationException, IOException, SAXException {
+ DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
+ xmlFact.setNamespaceAware(false);
+ DocumentBuilder builder = xmlFact.newDocumentBuilder();
+ ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
+ is.skip(guessBOMSize(is));
+ document = builder.parse(is);
+ }
+
+
+ public void setRawXML(byte[] rawXML) throws IOException {
+ this.rawXML = rawXML;
+ try {
+ setDocument();
+ } catch (ParserConfigurationException | SAXException e) {
+ Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
+ throw new ZUGFeRDExportException(e);
+ }
+ }
+
+
+ /**
+ * Skips over a BOM at the beginning of the given ByteArrayInputStream, if one exists.
+ *
+ * @param is the ByteArrayInputStream used
+ * @throws IOException if can not be read from is
+ * @see Autodetection of Character Encodings
+ */
+ private int guessBOMSize(ByteArrayInputStream is) throws IOException {
+ byte[] pad = new byte[4];
+ is.read(pad);
+ is.reset();
+ int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF);
+ int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF);
+ int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF);
+ //
+ if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) {
+ // UCS-4: BOM takes 4 bytes
+ return 4;
+ } else if (test3 == 0xEFBBFF) {
+ // UTF-8: BOM takes 3 bytes
+ return 3;
+ } else if (test2 == 0xFEFF || test2 == 0xFFFE) {
+ // UTF-16: BOM takes 2 bytes
+ return 2;
+ }
+ return 0;
+ }
+
+
+ protected String extractString(String xpathStr) {
+ if (!containsMeta) {
+ throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
+ }
+ String result;
+ try {
+ Document document = getDocument();
+ XPathFactory xpathFact = XPathFactory.newInstance();
+ XPath xpath = xpathFact.newXPath();
+ result = xpath.evaluate(xpathStr, document);
+ } catch (XPathExpressionException e) {
+ Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
+ throw new ZUGFeRDExportException(e);
+ }
+ return result;
+ }
+
+
+ /**
+ * Wrapper for protected method exracteString
+ * @return the extracted String for the specific path in the document
+ */
+ public String wExtractString(String xpathStr) {
+ return extractString(xpathStr);
+ }
+
+
+ /**
+ * @return the reference (purpose) the sender specified for this invoice
+ */
+ public String getForeignReference() {
+ String result = extractString("//ApplicableHeaderTradeSettlement/PaymentReference");
+ if (result == null || result.isEmpty()) {
+ result = extractString("//ApplicableSupplyChainTradeSettlement/PaymentReference");
+ }
+ return result;
+ }
+
+
+ /**
+ * @return the document code
+ */
+ public String getDocumentCode() {
+ try {
+ if (getVersion() == 1) {
+ return extractString("//HeaderExchangedDocument/TypeCode");
+ } else {
+ return extractString("//ExchangedDocument/TypeCode");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+
+ /**
+ * @return the referred document
+ */
+ public String getReference() {
+ try {
+ if (getVersion() == 1) {
+ return extractString("//ApplicableSupplyChainTradeAgreement/BuyerReference");
+ } else {
+ return extractString("//ApplicableHeaderTradeAgreement/BuyerReference");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+
+ /**
+ * @return the sender's bank's BIC code
+ */
+ public String getBIC() {
+ return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID");
+ }
+
+
+ /**
+ * @return the sender's bank name
+ */
+ public String getBankName() {
+ return extractString("//PayeeSpecifiedCreditorFinancialInstitution/Name");
+ }
+
+
+ /**
+ * @return the sender's account IBAN code
+ */
+ public String getIBAN() {
+ return extractString("//PayeePartyCreditorFinancialAccount/IBANID");
+ }
+
+
+ public String getHolder() {
+ return extractString("//SellerTradeParty/Name");
+ }
+
+
+ /**
+ * @return the total payable amount
+ */
+ public String getAmount() {
+ String result = extractString("//SpecifiedTradeSettlementHeaderMonetarySummation/DuePayableAmount");
+ if (result == null || result.isEmpty()) {
+ result = extractString("//SpecifiedTradeSettlementMonetarySummation/GrandTotalAmount");
+ }
+ return result;
+ }
+
+
+ /**
+ * @return when the payment is due
+ */
+ public String getDueDate() {
+ return extractString("//SpecifiedTradePaymentTerms/DueDateDateTime/DateTimeString");
+ }
+
+
+ public HashMap getAdditionalData() {
+ return additionalXMLs;
+ }
+
+
+ /**
+ * get xmp metadata of the PDF, null if not available
+ *
+ * @return string
+ */
+ public String getXMP() {
+ return xmpString;
+ }
+
+
+ /**
+ * @return if export found parseable ZUGFeRD data
+ */
+ public boolean containsMeta() {
+ return containsMeta;
+ }
+
+
+ /**
+ * @param meta raw XML to be set
+ * @throws IOException if raw can not be set
+ */
+ public void setMeta(String meta) throws IOException {
+ setRawXML(meta.getBytes());
+ }
+
+
+ /**
+ * @return raw XML of the invoice
+ */
+ public String getMeta() {
+ if (rawXML == null) {
+ return null;
+ }
+
+ return new String(rawXML);
+ }
+
+
+ public int getVersion() throws Exception {
+ if (!containsMeta) {
+ throw new Exception("Not yet parsed");
+ }
+ if (getUTF8().contains(" 0) && ((meta.contains("SpecifiedExchangedDocumentContext") //$NON-NLS-1$
+ /* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */));
+ }
+
+
+ static String convertStreamToString(java.io.InputStream is) {
+ // source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to
+ // https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks
+ Scanner s = new Scanner(is, "UTF-8").useDelimiter("\\A");
+ return s.hasNext() ? s.next() : "";
+ }
+
+ /**
+ * returns an instance of PostalTradeAddress for SellerTradeParty section
+ * @return an instance of PostalTradeAddress
+ */
+ public PostalTradeAddress getSellerTradePartyAddress() {
+
+ NodeList nl = null;
+ PostalTradeAddress address = new PostalTradeAddress();
+
+ try {
+ if (getVersion() == 1) {
+ nl = getNodeListByPath("//CrossIndustryDocument//SpecifiedSupplyChainTradeTransaction//ApplicableSupplyChainTradeAgreement//SellerTradeParty//PostalTradeAddress");
+ } else {
+ nl = getNodeListByPath("//CrossIndustryInvoice//SupplyChainTradeTransaction//ApplicableHeaderTradeAgreement//SellerTradeParty//PostalTradeAddress");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return address;
+ }
+
+ if (nl != null) {
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node n = nl.item(i);
+ NodeList nodes = n.getChildNodes();
+ for (int j = 0; j < nodes.getLength(); j++) {
+ n = nodes.item(j);
+ short nodeType = n.getNodeType();
+ if (nodeType==Node.ELEMENT_NODE){
+ switch (n.getNodeName()) {
+ case "ram:PostcodeCode":
+ address.setPostCodeCode(n.getFirstChild().getNodeValue());
+ break;
+ case "ram:LineOne":
+ address.setLineOne(n.getFirstChild().getNodeValue());
+ break;
+ case "ram:LineTwo":
+ address.setLineTwo(n.getFirstChild().getNodeValue());
+ break;
+ case "ram:LineThree":
+ address.setLineThree(n.getFirstChild().getNodeValue());
+ break;
+ case "ram:CityName":
+ address.setCityName(n.getFirstChild().getNodeValue());
+ break;
+ case "ram:CountryID":
+ address.setCountryID(n.getFirstChild().getNodeValue());
+ break;
+ case "ram:CountrySubDivisionName":
+ address.setCountrySubDivisionName(n.getFirstChild().getNodeValue());
+ break;
+ }
+ }
+ }
+ }
+ }
+ return address;
+ }
+
+
+ /**
+ * returns a list of LineItems
+ * @return a List of LineItem instances
+ */
+ public List- getLineItemList() {
+ List nodeList = getLineItemNodes();
+ List
- lineItemList = new ArrayList<>();
+
+ for (Node n: nodeList
+ ) {
+ Item lineItem = new Item(null, null, null);
+ lineItem.setProduct(new Product(null,null,null,null));
+
+ NodeList nl = n.getChildNodes();
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node nn = nl.item(i);
+ Node node = null;
+ switch (nn.getNodeName()) {
+ case "ram:SpecifiedLineTradeAgreement":
+ case "ram:SpecifiedSupplyChainTradeAgreement":
+
+ node = getNodeByName(nn.getChildNodes(), "ram:NetPriceProductTradePrice");
+ if (node != null) {
+ node = getNodeByName(node.getChildNodes(), "ram:ChargeAmount");
+ lineItem.setPrice(tryBigDecimal(getNodeValue(node)));
+ }
+
+ node = getNodeByName(nn.getChildNodes(), "ram:GrossPriceProductTradePrice");
+ if (node != null) {
+ node = getNodeByName(node.getChildNodes(), "ram:ChargeAmount");
+ lineItem.setGrossPrice(tryBigDecimal(getNodeValue(node)));
+ }
+ break;
+
+ case "ram:AssociatedDocumentLineDocument":
+
+ node = getNodeByName(nn.getChildNodes(), "ram:LineID");
+ lineItem.setId(getNodeValue(node));
+ break;
+
+ case "ram:SpecifiedTradeProduct":
+
+ node = getNodeByName(nn.getChildNodes(), "ram:SellerAssignedID");
+ lineItem.product.setSellerAssignedID(getNodeValue(node));
+
+ node = getNodeByName(nn.getChildNodes(), "ram:BuyerAssignedID");
+ lineItem.product.setBuyerAssignedID(getNodeValue(node));
+
+ node = getNodeByName(nn.getChildNodes(), "ram:Name");
+ lineItem.product.setName(getNodeValue(node));
+
+ node = getNodeByName(nn.getChildNodes(), "ram:Description");
+ lineItem.product.setDescription(getNodeValue(node));
+ break;
+
+ case "ram:SpecifiedLineTradeDelivery":
+ case "ram:SpecifiedSupplyChainTradeDelivery":
+ node = getNodeByName(nn.getChildNodes(), "ram:BilledQuantity");
+ lineItem.setQuantity(tryBigDecimal(getNodeValue(node)));
+ break;
+
+ case "ram:SpecifiedLineTradeSettlement":
+
+ node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax");
+ if (node != null) {
+ node = getNodeByName(node.getChildNodes(), "ram:RateApplicablePercent");
+ lineItem.product.setVATPercent(tryBigDecimal(getNodeValue(node)));
+ }
+
+ node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax");
+ if (node != null) {
+ node = getNodeByName(node.getChildNodes(), "ram:CalculatedAmount");
+ lineItem.setTax(tryBigDecimal(getNodeValue(node)));
+ }
+
+ node = getNodeByName(nn.getChildNodes(), "ram:SpecifiedTradeSettlementLineMonetarySummation");
+ if (node != null) {
+ node = getNodeByName(node.getChildNodes(), "ram:LineTotalAmount");
+ lineItem.setLineTotalAmount(tryBigDecimal(getNodeValue(node)));
+ }
+ break;
+ case "ram:SpecifiedSupplyChainTradeSettlement":
+ //ZF 1!
+
+ node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax");
+ if (node != null) {
+ node = getNodeByName(node.getChildNodes(), "ram:ApplicablePercent");
+ lineItem.product.setVATPercent(tryBigDecimal(getNodeValue(node)));
+ }
+
+ node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax");
+ if (node != null) {
+ node = getNodeByName(node.getChildNodes(), "ram:CalculatedAmount");
+ lineItem.setTax(tryBigDecimal(getNodeValue(node)));
+ }
+
+ node = getNodeByName(nn.getChildNodes(), "ram:SpecifiedTradeSettlementMonetarySummation");
+ if (node != null) {
+ node = getNodeByName(node.getChildNodes(), "ram:LineTotalAmount");
+ lineItem.setLineTotalAmount(tryBigDecimal(getNodeValue(node)));
+ }
+ break;
+ }
+ }
+ lineItemList.add(lineItem);
+ }
+ return lineItemList;
+ }
+
+ /**
+ * returns a List of LineItem Nodes from ZUGFeRD XML
+ * @return a List of Node instances
+ */
+ public List getLineItemNodes() {
+ List lineItemNodes = new ArrayList<>();
+ NodeList nl = null;
+ try {
+ if (getVersion() == 1) {
+ nl = getNodeListByPath("//CrossIndustryDocument//SpecifiedSupplyChainTradeTransaction//IncludedSupplyChainTradeLineItem");
+ } else {
+ nl = getNodeListByPath("//CrossIndustryInvoice//SupplyChainTradeTransaction//IncludedSupplyChainTradeLineItem");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node n = nl.item(i);
+ lineItemNodes.add(n);
+ }
+ return lineItemNodes;
+ }
+
+ /**
+ * Returns a node, found by name. If more nodes with the same name are present, the first occurence will be returned
+ * @param nl - A NodeList which may contains the searched node
+ * @param name The nodes name
+ * @return a Node or null, if nothing is found
+ */
+ private Node getNodeByName(NodeList nl, String name) {
+ for (int i = 0; i < nl.getLength(); i++) {
+ if (nl.item(i).getNodeName() == name) {
+ return nl.item(i);
+ } else if (nl.item(i).getChildNodes().getLength() > 0) {
+ Node node = getNodeByName(nl.item(i).getChildNodes(), name);
+ if (node != null) {
+ return node;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get a NodeList by providing an path
+ * @param path a compliable Path
+ * @return a Nodelist or null, if an error occurs
+ */
+ public NodeList getNodeListByPath(String path) {
+
+ XPathFactory xpathFact = XPathFactory.newInstance();
+ XPath xPath = xpathFact.newXPath();
+ String s = path;
+
+ try {
+ XPathExpression xpr = xPath.compile(s);
+ return (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * returns the value of an node
+ * @param node the Node to get the value from
+ * @return A String or empty String, if no value was found
+ */
+ private String getNodeValue(Node node) {
+ if (node != null) {
+ if (node.getFirstChild() != null) {
+ return node.getFirstChild().getNodeValue();
+ }
+ }
+ return "";
+ }
+
+ /**
+ * tries to convert an String to BigDecimal.
+ * @param nodeValue The value as String
+ * @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
+ */
+ private BigDecimal tryBigDecimal(String nodeValue) {
+ try {
+ return new BigDecimal(nodeValue);
+ } catch (Exception e) {
+ try {
+ return new BigDecimal(Float.valueOf(nodeValue));
+ } catch (Exception ex) {
+ return new BigDecimal("0.00");
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporterException.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporterException.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporterException.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporterException.java
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java
new file mode 100644
index 00000000..7960e9ce
--- /dev/null
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java
@@ -0,0 +1,71 @@
+package org.mustangproject.ZUGFeRD;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.xml.xpath.*;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
+ public ZUGFeRDInvoiceImporter(String filename) {
+ super(filename);
+ }
+ public ZUGFeRD2PushProvider extractInvoice() {
+
+ String number="AB123";
+ ZUGFeRD2PushProvider zpp=new ZUGFeRD2PushProvider().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setOwnStreet("teststr").setOwnZIP("55232").setOwnLocation("teststadt").setOwnCountry("DE").setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new Contact("Franz Müller", "0177123456", "fmueller@test.com", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number);
+//.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),amount,new BigDecimal(1.0)))
+ zpp.setOwnOrganisationName(extractString("//SellerTradeParty/Name"));
+
+ XPathFactory xpathFact = XPathFactory.newInstance();
+ XPath xpath = xpathFact.newXPath();
+ try {
+
+ XPathExpression xpr = xpath.compile(
+ "//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]");
+ NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
+
+ if (nodes.getLength() == 0) {
+ } else {
+ for (int i = 0; i < nodes.getLength(); i++) {
+ //nodes.item(i).getTextContent())) {
+ Node currentItemNode=nodes.item(i);
+ NodeList itemChilds=currentItemNode.getChildNodes();
+ String price="0";
+ for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
+ if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeAgreement")) {
+ NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes();
+ for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) {
+ if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram:NetPriceProductTradePrice")) {
+ NodeList netChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes();
+ for (int netIndex = 0; netIndex < netChilds.getLength(); netIndex++) {
+ if (netChilds.item(netIndex).getNodeName().equals("ram:ChargeAmount")) {
+ price = netChilds.item(netIndex).getTextContent();//ram:ChargeAmount
+
+ }
+ }
+ }
+ }
+ }
+ }
+// Logger.getLogger(ZUGFeRDInvoiceImporter.class.getName()).log(Level.INFO, "deb "+price);
+
+ zpp.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),new BigDecimal(price),new BigDecimal(1.0)));
+ }
+
+ }
+
+
+ } catch (XPathExpressionException e) {
+ e.printStackTrace();
+ }
+
+ return zpp;
+ }
+
+
+}
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/DateTimeTypeConstants.java b/library/src/main/java/org/mustangproject/ZUGFeRD/model/DateTimeTypeConstants.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/model/DateTimeTypeConstants.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/model/DateTimeTypeConstants.java
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentCodeTypeConstants.java b/library/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentCodeTypeConstants.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/model/DocumentCodeTypeConstants.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentCodeTypeConstants.java
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentContextParameterTypeConstants.java b/library/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentContextParameterTypeConstants.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/model/DocumentContextParameterTypeConstants.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentContextParameterTypeConstants.java
diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java b/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
similarity index 100%
rename from src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
rename to library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/BackwardCompatibilityTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/BackwardCompatibilityTest.java
new file mode 100644
index 00000000..f8fef6a9
--- /dev/null
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/BackwardCompatibilityTest.java
@@ -0,0 +1,432 @@
+/** **********************************************************************
+ *
+ * Copyright 2019 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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import junit.framework.TestCase;
+
+/***
+ * This is a test to confirm the minimum steps to implement a interface are still sufficient
+ *
+ * @author jstaerk
+ *
+ */
+public class BackwardCompatibilityTest extends TestCase implements IZUGFeRDExportableTransaction{
+
+ final String TARGET_PDF_ZF1 = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf1.pdf";
+ final String TARGET_PDF_ZF2 = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf2.pdf";
+ final String TARGET_PDF_FX = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506fx.pdf";
+
+ /**
+ * The exporter test bases on @{code
+ * ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds
+ * metadata, writes to @{code ./target/testout-*} and then imports to check the
+ * values. It would not make sense to have it run before the less complex
+ * importer test (which is probably redundant). As only Name Ascending is
+ * supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export
+ */
+ public void testZF1Export() {
+
+
+ // the writing part
+ try (InputStream SOURCE_PDF = this.getClass()
+ .getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
+
+ ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(1).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) {
+
+ ze.PDFattachZugferdFile(this);
+ ze.disableAutoClose(true);
+ ze.export(TARGET_PDF_ZF1);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ze.export(baos);
+ ze.close();
+ String pdfContent = baos.toString("UTF-8");
+ assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
+ // check for pdf-a schema extension
+// assertFalse(pdfContent.indexOf("EN 16931") == -1);
+// assertFalse(pdfContent.indexOf("zf") == -1);
+// assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1);
+
+ } catch (IOException e) {
+ fail("IOException should not happen in testZExport");
+ }
+
+ // now check the contents (like MustangReaderTest)
+ ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_ZF1);
+
+ // Reading ZUGFeRD
+ assertEquals(zi.getAmount(), "571.04");
+ assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
+ assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
+ assertEquals(zi.getHolder(), getOwnOrganisationName());
+ assertEquals(zi.getForeignReference(), getNumber());
+
+
+ }
+
+ public void testZF2Export() {
+
+
+ // the writing part
+ try (InputStream SOURCE_PDF = this.getClass()
+ .getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
+
+ ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) {
+
+ ze.PDFattachZugferdFile(this);
+ ze.disableAutoClose(true);
+ ze.export(TARGET_PDF_ZF2);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ze.export(baos);
+ ze.close();
+ String pdfContent = baos.toString("UTF-8");
+ assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
+ // check for pdf-a schema extension
+// assertFalse(pdfContent.indexOf("EN 16931") == -1);
+// assertFalse(pdfContent.indexOf("zf") == -1);
+// assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1);
+
+ } catch (IOException e) {
+ fail("IOException should not happen in testZExport");
+ }
+
+ // now check the contents (like MustangReaderTest)
+ ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_ZF2);
+
+ // Reading ZUGFeRD
+ assertEquals(zi.getAmount(), "571.04");
+ assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
+ assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
+ assertEquals(zi.getHolder(), getOwnOrganisationName());
+ assertEquals(zi.getForeignReference(), getNumber());
+
+
+ }
+ public void testFXExport() {
+
+ // the writing part
+ try (InputStream SOURCE_PDF = this.getClass()
+ .getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
+
+ ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) {
+
+ ze.setFacturX();
+ ze.PDFattachZugferdFile(this);
+ ze.disableAutoClose(true);
+ ze.export(TARGET_PDF_FX);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ze.export(baos);
+ ze.close();
+ String pdfContent = baos.toString("UTF-8");
+ assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
+ // check for pdf-a schema extension
+// assertFalse(pdfContent.indexOf("EN 16931") == -1);
+// assertFalse(pdfContent.indexOf("zf") == -1);
+// assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1);
+
+ } catch (IOException e) {
+ fail("IOException should not happen in testZExport");
+ }
+
+ // now check the contents (like MustangReaderTest)
+ ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX);
+
+ // Reading ZUGFeRD
+ assertEquals(zi.getAmount(), "571.04");
+ assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
+ assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
+ assertEquals(zi.getHolder(), getOwnOrganisationName());
+ assertEquals(zi.getForeignReference(), getNumber());
+
+
+ }
+ class Contact implements IZUGFeRDExportableContact {
+ 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 Payment implements IZUGFeRDTradeSettlementPayment {
+
+ @Override
+ public String getOwnBIC() {
+ return "bla";
+ }
+
+ @Override
+ public String getOwnBankName() {
+ return "bla";
+ }
+
+ @Override
+ public String getOwnIBAN() {
+ return "bla";
+ }
+
+ }
+
+ 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;
+ }
+ }
+
+ @Override
+ public Date getDeliveryDate() {
+ return new GregorianCalendar(2019, Calendar.JUNE, 10).getTime();
+ }
+
+
+
+ @Override
+ public IZUGFeRDExportableContact getRecipient() {
+ return new Contact();
+ }
+
+
+ //
+ public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
+ Payment P = new Payment();
+ IZUGFeRDTradeSettlementPayment[] allP = new Payment[1];
+ allP[0] = P;
+ return allP;
+
+ }
+
+ public IZUGFeRDAllowanceCharge[] getZFAllowances() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public IZUGFeRDAllowanceCharge[] getZFCharges() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public IZUGFeRDExportableItem[] getZFItems() {
+ Item[] allItems = new Item[3];
+ Product designProduct = new Product("", "Design (hours): Of a sample invoice", "HUR",
+ new BigDecimal("7.000000"));
+ Product balloonProduct = new Product("", "Ballons: various colors, ~2000ml", "C62", new BigDecimal("19.000000"));
+ Product airProduct = new Product("", "Hot air „heiße Luft“ (litres)", "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.025"), new BigDecimal("800"), airProduct);
+ return allItems;
+ }
+
+ public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Date getDueDate() {
+ return new GregorianCalendar(2019, Calendar.JULY, 1).getTime();
+ }
+
+ @Override
+ public Date getIssueDate() {
+ return new GregorianCalendar(2019, Calendar.JUNE, 10).getTime();
+ }
+
+
+ @Override
+ public String getNumber() {
+ return "RE-20190610/507";
+ }
+
+
+
+ public String getOwnBIC() {
+ return "COBADEFFXXX";
+ }
+
+ public String getOwnBankName() {
+ return "Commerzbank";
+ }
+
+
+ @Override
+ public String getOwnCountry() {
+ return "DE";
+ }
+
+ public String getOwnIBAN() {
+ return "DE88 2008 0000 0970 3757 00";
+ }
+
+
+ @Override
+ public String getOwnLocation() {
+ return "Stadthausen";
+ }
+
+ @Override
+ public String getOwnOrganisationFullPlaintextInfo() {
+ return "Bei Spiel GmbH\n" + "Ecke 12\n" + "12345 Stadthausen\n" + "Geschäftsführer: Max Mustermann";
+ }
+
+
+ @Override
+ public String getOwnOrganisationName() {
+ return "Bei Spiel GmbH";
+ }
+
+ @Override
+ public String getOwnStreet() {
+ return "Ecke 12";
+ }
+
+ @Override
+ public String getOwnTaxID() {
+ return "22/815/0815/4";
+ }
+
+ @Override
+ public String getOwnVATID() {
+ return "DE136695976";
+ }
+
+ @Override
+ public String getOwnZIP() {
+ return "12345";
+ }
+
+
+
+
+}
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java
similarity index 65%
rename from src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java
index 8d3152b6..9695fc0e 100644
--- a/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java
@@ -32,6 +32,7 @@ import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
+import org.mustangproject.XMLTools;
public class BaseTest extends TestCase {
/**
@@ -51,15 +52,15 @@ public class BaseTest extends TestCase {
}
public void testCorrectDigits() {
- assertEquals("0.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal(0),2));
- assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.10"),2));
- assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.1"),2));
- assertEquals("-1.01", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.01"),2));
- assertEquals("20000123.35", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3489"),2));
- assertEquals("20000123.34", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),2));
- assertEquals("12.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),2));
- assertEquals("12", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),0));
- assertEquals("20000123.342", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),3));
+ assertEquals("0.00", XMLTools.nDigitFormat(new BigDecimal(0),2));
+ assertEquals("-1.10", XMLTools.nDigitFormat(new BigDecimal("-1.10"),2));
+ assertEquals("-1.10", XMLTools.nDigitFormat(new BigDecimal("-1.1"),2));
+ assertEquals("-1.01", XMLTools.nDigitFormat(new BigDecimal("-1.01"),2));
+ assertEquals("20000123.35", XMLTools.nDigitFormat(new BigDecimal("20000123.3489"),2));
+ assertEquals("20000123.34", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),2));
+ assertEquals("12.00", XMLTools.nDigitFormat(new BigDecimal("12"),2));
+ assertEquals("12", XMLTools.nDigitFormat(new BigDecimal("12"),0));
+ assertEquals("20000123.342", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),3));
}
}
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceChargeImpl.java b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceChargeImpl.java
similarity index 100%
rename from src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceChargeImpl.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceChargeImpl.java
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDDateImpl.java b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDDateImpl.java
new file mode 100644
index 00000000..01a4d19c
--- /dev/null
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDDateImpl.java
@@ -0,0 +1,30 @@
+package org.mustangproject.ZUGFeRD;
+
+import java.util.Date;
+
+public class IZUGFeRDDateImpl implements IZUGFeRDDate {
+
+ private Date date;
+ private ZUGFeRDDateFormat format = ZUGFeRDDateFormat.DATE;
+
+ public IZUGFeRDDateImpl setDate(Date date) {
+ this.date = date;
+ return this;
+ }
+
+ public IZUGFeRDDateImpl setFormat(ZUGFeRDDateFormat format) {
+ this.format = format;
+ return this;
+ }
+
+ @Override
+ public Date getDate() {
+ return date;
+ }
+
+ @Override
+ public ZUGFeRDDateFormat getFormat() {
+ return format;
+ }
+
+}
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContactImpl.java b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContactImpl.java
similarity index 100%
rename from src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContactImpl.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContactImpl.java
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItemImpl.java b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItemImpl.java
similarity index 100%
rename from src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItemImpl.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItemImpl.java
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProductImpl.java b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProductImpl.java
similarity index 100%
rename from src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProductImpl.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProductImpl.java
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java
similarity index 95%
rename from src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java
index f1d5d001..eda39ae0 100644
--- a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java
@@ -32,6 +32,7 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
private IZUGFeRDExportableItem[] zFItems;
private IZUGFeRDExportableContact recipient;
private IZUGFeRDTradeSettlementPayment[] settlementPayments;
+ private IZUGFeRDDate zfDeliveryDate;
private String ownTaxID;
private String ownVATID;
private String ownOrganisationName;
@@ -149,6 +150,11 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
return referenceNumber;
}
+ @Override
+ public IZUGFeRDDate getZFDeliveryDate() {
+ return zfDeliveryDate;
+ }
+
public IZUGFeRDExportableTransactionImpl setNumber(String number) {
this.number = number;
return this;
@@ -234,6 +240,11 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
return this;
}
+ public IZUGFeRDExportableTransactionImpl setZfDeliveryDate(IZUGFeRDDate zfDeliveryDate) {
+ this.zfDeliveryDate = zfDeliveryDate;
+ return this;
+ }
+
public IZUGFeRDExportableTransactionImpl setCurrency(String currency) {
this.currency = currency;
return this;
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPaymentImpl.java b/library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPaymentImpl.java
similarity index 100%
rename from src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPaymentImpl.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPaymentImpl.java
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java
similarity index 87%
rename from src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java
index 9b74f570..4252e2cb 100644
--- a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java
@@ -22,6 +22,8 @@ import junit.framework.TestCase;
import java.math.BigDecimal;
+import org.mustangproject.ZUGFeRD.MustangReaderTestCase.Item;
+
public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRDExportableTransaction {
public MustangReaderTestCase(String testName) {
@@ -125,7 +127,7 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
protected class Item implements IZUGFeRDExportableItem {
- public Item(BigDecimal price, BigDecimal quantity, Product product) {
+ public Item(BigDecimal price, BigDecimal quantity, IZUGFeRDExportableProduct product) {
super();
this.price = price;
this.quantity = quantity;
@@ -133,7 +135,12 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
}
private BigDecimal price, quantity;
- private Product product;
+ private IZUGFeRDExportableProduct product;
+ private String addReference=null;
+
+ public String getAdditionalReferencedDocumentID() {
+ return addReference;
+ }
@Override
public BigDecimal getPrice() {
@@ -154,11 +161,11 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
}
@Override
- public Product getProduct() {
+ public IZUGFeRDExportableProduct getProduct() {
return product;
}
- public void setProduct(Product product) {
+ public void setProduct(IZUGFeRDExportableProduct product) {
this.product = product;
}
@@ -172,6 +179,15 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
return null;
}
+ public String getAddReference() {
+ return addReference;
+ }
+
+ public void setAddReference(String addReference) {
+ this.addReference = addReference;
+ }
+
+
}
protected class Product implements IZUGFeRDExportableProduct {
diff --git a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java
similarity index 99%
rename from src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java
rename to library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java
index e1908c7b..d44fd848 100644
--- a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java
@@ -257,7 +257,6 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
"