diff --git a/mustang/doc/MustangDev.en.odt b/mustang/doc/MustangDev.en.odt
index 7cc7c98d..c9bbe3b7 100644
Binary files a/mustang/doc/MustangDev.en.odt and b/mustang/doc/MustangDev.en.odt differ
diff --git a/mustang/doc/MustangWriter.java b/mustang/doc/MustangWriter.java
index ceed24e7..0f440de9 100644
--- a/mustang/doc/MustangWriter.java
+++ b/mustang/doc/MustangWriter.java
@@ -167,7 +167,7 @@ public class MustangWriter implements IZUGFeRDExportableTransaction {
@Override
public String getOwnBIC() {
- return "COBADEFXXX";
+ return "COBADEFFXXX";
}
@Override
diff --git a/mustang/doc/ZugferdDev.de.odt b/mustang/doc/ZugferdDev.de.odt
index 29d40ea6..0db0d097 100644
Binary files a/mustang/doc/ZugferdDev.de.odt and b/mustang/doc/ZugferdDev.de.odt differ
diff --git a/mustang/doc/ZugferdDev.de.pdf b/mustang/doc/ZugferdDev.de.pdf
index b6166af7..19877b94 100644
Binary files a/mustang/doc/ZugferdDev.de.pdf and b/mustang/doc/ZugferdDev.de.pdf differ
diff --git a/mustang/doc/ZugferdDev.en.odt b/mustang/doc/ZugferdDev.en.odt
index c47a9034..1377da4d 100644
Binary files a/mustang/doc/ZugferdDev.en.odt and b/mustang/doc/ZugferdDev.en.odt differ
diff --git a/mustang/doc/ZugferdDev.en.pdf b/mustang/doc/ZugferdDev.en.pdf
index 9c680f8f..d2d7722b 100644
Binary files a/mustang/doc/ZugferdDev.en.pdf and b/mustang/doc/ZugferdDev.en.pdf differ
diff --git a/mustang/doc/konikmustangvergleich.odt b/mustang/doc/konikmustangvergleich.odt
new file mode 100644
index 00000000..4f9a749b
Binary files /dev/null and b/mustang/doc/konikmustangvergleich.odt differ
diff --git a/mustang/pom.xml b/mustang/pom.xml
index 9d09a237..43d45fa2 100644
--- a/mustang/pom.xml
+++ b/mustang/pom.xml
@@ -3,24 +3,66 @@
com.github.rayman2200
mustang-sample-project
- 1.3.0-SNAPSHOT
+ 1.3.0.1-SNAPSHOT
org.mustangproject.ZUGFeRD
mustang
- 1.3.0-SNAPSHOT
+ 1.3.0.1-SNAPSHOT
jar
Mustang
The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs
http://www.mustangproject.org/
-
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 2.4.3
+
+ true
+
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
+
+
+
+
+
+
org.glassfish.jaxb
jaxb-runtime
2.2.11
+
+
+ org.apache.pdfbox
+ preflight
+ 1.8.8
+
+
+ org.apache.pdfbox
+ pdfbox
+ 1.8.8
+
@@ -56,5 +98,4 @@
-
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java
index 8c49a4d6..1f80dad2 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java
@@ -4,7 +4,7 @@ package org.mustangproject.ZUGFeRD;
* Neccessary interface for ZUGFeRD exporter
* Licensed under the APLv2
* @date 2014-05-10
- * @version 1.0
+ * @version 1.2.0
* @author jstaerk
* */
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
index 99044349..9e9c06bd 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
@@ -4,7 +4,7 @@ package org.mustangproject.ZUGFeRD;
* Neccessary interface for ZUGFeRD exporter
* Licensed under the APLv2
* @date 2014-05-10
- * @version 1.0
+ * @version 1.2.0
* @author jstaerk
* */
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java
index 8f552eb2..5cc43930 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java
@@ -5,7 +5,7 @@ import java.math.BigDecimal;
* Necessary interface for ZUGFeRD exporter
* Licensed under the APLv2
* @date 2014-05-10
- * @version 1.0
+ * @version 1.2.0
* @author jstaerk
* */
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java
index 3d9af400..fb48e203 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java
@@ -4,7 +4,7 @@ package org.mustangproject.ZUGFeRD;
* Neccessary interface for ZUGFeRD exporter
* Licensed under the APLv2
* @date 2014-05-10 to 2014-06-25
- * @version 1.0.2
+ * @version 1.2.0
* @author jstaerk
* */
@@ -127,7 +127,7 @@ public interface IZUGFeRDExportableTransaction {
* get main invoice currency used on the invoice
* @return
*/
- String getInvoiceCurrency();
+ String getCurrency();
/**
* get payment information text. e.g. Bank transfer
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
index 2c7eac5e..ab120d12 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
@@ -1,7 +1,14 @@
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
-
+/**
+ * Mustangproject's ZUGFeRD implementation
+ * ZUGFeRD exporter helper class
+ * Licensed under the APLv2
+ * @date 2015-10-29
+ * @version 1.2.0
+ * @author jstaerk
+ * */
public class VATAmount {
public VATAmount(BigDecimal basis, BigDecimal calculated) {
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java
index 9d055c9b..2bee5ca5 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java
@@ -4,7 +4,7 @@ package org.mustangproject.ZUGFeRD;
* ZUGFeRD exporter helper class
* Licensed under the APLv2
* @date 2014-05-10
- * @version 1.0
+ * @version 1.2.0
* @author jstaerk
* */
import org.apache.jempbox.impl.XMLUtil;
@@ -112,6 +112,12 @@ import org.w3c.dom.Element;
Element propertyNode = schema.getOwnerDocument().createElement(
"pdfaSchema:property"); //$NON-NLS-1$
+ Element valueTypeNode = schema.getOwnerDocument().createElement(
+ "pdfaSchema:valueType"); //$NON-NLS-1$
+
+ Element seqListValueType = schema.getOwnerDocument().createElement(
+ "rdf:Seq"); //$NON-NLS-1$
+
Element sequenceNode = schema.getOwnerDocument().createElement(
"rdf:Seq"); //$NON-NLS-1$
@@ -150,6 +156,9 @@ import org.w3c.dom.Element;
bagListNode.appendChild(propertyNode);
+ valueTypeNode.appendChild(seqListValueType);
+ bagListNode.appendChild(valueTypeNode);
+
bagNode.appendChild(bagListNode);
schemasNode.appendChild(bagNode);
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java
index a32214ec..fcf9b673 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java
@@ -4,7 +4,7 @@ package org.mustangproject.ZUGFeRD;
* ZUGFeRD exporter helper class
* Licensed under the APLv2
* @date 2014-05-10
- * @version 1.0
+ * @version 1.2.0s
* @author jstaerk
* */
import org.apache.jempbox.impl.XMLUtil;
@@ -15,7 +15,7 @@ import org.w3c.dom.Element;
public class XMPSchemaZugferd extends XMPSchemaBasic
{
- private String conformanceLevel = "COMFORT";
+ private String conformanceLevel = "EXTENDED";
/**
* This is what needs to be added to the RDF metadata - basically the name of the embedded
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
index 8f25dee2..fcaf9403 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
@@ -5,13 +5,14 @@ package org.mustangproject.ZUGFeRD;
* APLv2
*
* @date 2014-07-12
- * @version 1.1
+ * @version 1.2.0
* @author jstaerk
*
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
@@ -23,11 +24,12 @@ import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+
+import javax.activation.FileDataSource;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
-
import javax.xml.transform.TransformerException;
import org.apache.jempbox.xmp.XMPMetadata;
@@ -39,6 +41,7 @@ import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
@@ -48,375 +51,353 @@ import org.apache.pdfbox.pdmodel.common.COSObjectable;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
+import org.apache.pdfbox.preflight.PreflightDocument;
+import org.apache.pdfbox.preflight.ValidationResult;
+import org.apache.pdfbox.preflight.exception.ValidationException;
+import org.apache.pdfbox.preflight.parser.PreflightParser;
+import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
import org.mustangproject.ZUGFeRD.model.*;
public class ZUGFeRDExporter {
- /**
- * *
- * You will need Apache PDFBox. To use the ZUGFeRD exporter, implement
- * IZUGFeRDExportableTransaction in yourTransaction (which will require you
- * to implement Product, Item and Contact) then call doc =
- * PDDocument.load(PDFfilename); // automatically add Zugferd to all
- * outgoing invoices ZUGFeRDExporter ze = new ZUGFeRDExporter();
- * ze.PDFmakeA3compliant(doc, "Your application name",
- * System.getProperty("user.name"), true); ze.PDFattachZugferdFile(doc,
- * yourTransaction);
- *
- * doc.save(PDFfilename);
- *
- * @author jstaerk
- * @throws javax.xml.bind.JAXBException
- *
- */
- public ZUGFeRDExporter() throws JAXBException {
- jaxbContext = JAXBContext.newInstance("org.mustangproject.ZUGFeRD.model");
- marshaller = jaxbContext.createMarshaller();
- marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
- marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
- }
+ /**
+ * * You will need Apache PDFBox. To use the ZUGFeRD exporter, implement
+ * IZUGFeRDExportableTransaction in yourTransaction (which will require you
+ * to implement Product, Item and Contact) then call doc =
+ * PDDocument.load(PDFfilename); // automatically add Zugferd to all
+ * outgoing invoices ZUGFeRDExporter ze = new ZUGFeRDExporter();
+ * ze.PDFmakeA3compliant(doc, "Your application name",
+ * System.getProperty("user.name"), true); ze.PDFattachZugferdFile(doc,
+ * yourTransaction);
+ *
+ * doc.save(PDFfilename);
+ *
+ * @author jstaerk
+ * @throws javax.xml.bind.JAXBException
+ *
+ */
+ public ZUGFeRDExporter() throws JAXBException {
+ jaxbContext = JAXBContext
+ .newInstance("org.mustangproject.ZUGFeRD.model");
+ marshaller = jaxbContext.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+ }
- private class LineCalc {
+ private class LineCalc {
- private BigDecimal totalGross;
- private BigDecimal itemTotalNetAmount;
- private BigDecimal itemTotalVATAmount;
- private BigDecimal itemNetAmount;
+ private BigDecimal totalGross;
+ private BigDecimal itemTotalNetAmount;
+ private BigDecimal itemTotalVATAmount;
+ private BigDecimal itemNetAmount;
- public LineCalc(IZUGFeRDExportableItem currentItem) {
- BigDecimal totalAllowance = BigDecimal.ZERO;
- BigDecimal totalCharge = BigDecimal.ZERO;
-
- if(currentItem.getItemAllowances() != null){
- for(IZUGFeRDAllowanceCharge itemAllowance : currentItem.getItemAllowances()){
- totalAllowance = itemAllowance.getTotalAmount().add(totalAllowance);
- }
- }
-
- if(currentItem.getItemCharges() != null){
- for(IZUGFeRDAllowanceCharge itemCharge : currentItem.getItemCharges()){
- totalCharge = itemCharge.getTotalAmount().add(totalCharge);
- }
- }
-
- BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100), 4, BigDecimal.ROUND_HALF_UP).add(BigDecimal.ONE);
-// priceGross=currentItem.getPrice().multiply(multiplicator);
-
- totalGross = currentItem.getPrice().multiply(currentItem.getQuantity()).subtract(totalAllowance).add(totalCharge).multiply(multiplicator);
- itemTotalNetAmount = currentItem.getPrice().multiply(currentItem.getQuantity()).subtract(totalAllowance).add(totalCharge).setScale(2, BigDecimal.ROUND_HALF_UP);
- itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount);
- itemNetAmount = currentItem.getPrice().multiply(currentItem.getQuantity()).subtract(totalAllowance).add(totalCharge).divide(currentItem.getQuantity(), 4, BigDecimal.ROUND_HALF_UP);
- }
+ public LineCalc(IZUGFeRDExportableItem currentItem) {
+ BigDecimal totalAllowance = BigDecimal.ZERO;
+ BigDecimal totalCharge = BigDecimal.ZERO;
- public BigDecimal getItemTotalNetAmount() {
- return itemTotalNetAmount;
- }
+ if (currentItem.getItemAllowances() != null) {
+ for (IZUGFeRDAllowanceCharge itemAllowance : currentItem
+ .getItemAllowances()) {
+ totalAllowance = itemAllowance.getTotalAmount().add(
+ totalAllowance);
+ }
+ }
- public BigDecimal getItemTotalVATAmount() {
- return itemTotalVATAmount;
- }
-
- public BigDecimal getItemNetAmount(){
- return itemNetAmount;
- }
+ if (currentItem.getItemCharges() != null) {
+ for (IZUGFeRDAllowanceCharge itemCharge : currentItem
+ .getItemCharges()) {
+ totalCharge = itemCharge.getTotalAmount().add(totalCharge);
+ }
+ }
- }
-
- private class Totals{
- private BigDecimal totalNetAmount;
- private BigDecimal totalGrossAmount;
- private BigDecimal lineTotalAmount;
- private BigDecimal totalTaxAmount;
-
- public Totals(){
- BigDecimal res = BigDecimal.ZERO;
- for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
- LineCalc lc = new LineCalc(currentItem);
- res = res.add(lc.getItemTotalNetAmount());
- }
- // Set line total
- this.lineTotalAmount = res;
+ BigDecimal multiplicator = currentItem.getProduct().getVATPercent()
+ .divide(new BigDecimal(100), 4, BigDecimal.ROUND_HALF_UP)
+ .add(BigDecimal.ONE);
+ // priceGross=currentItem.getPrice().multiply(multiplicator);
- if(trans.getZFAllowances() != null){
- for (IZUGFeRDAllowanceCharge headerAllowance : trans.getZFAllowances()){
- res = res.subtract(headerAllowance.getTotalAmount());
- }
- }
+ totalGross = currentItem.getPrice()
+ .multiply(currentItem.getQuantity())
+ .subtract(totalAllowance).add(totalCharge)
+ .multiply(multiplicator);
+ itemTotalNetAmount = currentItem.getPrice()
+ .multiply(currentItem.getQuantity())
+ .subtract(totalAllowance).add(totalCharge)
+ .setScale(2, BigDecimal.ROUND_HALF_UP);
+ itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount);
+ itemNetAmount = currentItem
+ .getPrice()
+ .multiply(currentItem.getQuantity())
+ .subtract(totalAllowance)
+ .add(totalCharge)
+ .divide(currentItem.getQuantity(), 4,
+ BigDecimal.ROUND_HALF_UP);
+ }
- if(trans.getZFLogisticsServiceCharges()!= null){
- for (IZUGFeRDAllowanceCharge logisticsServiceCharge : trans.getZFLogisticsServiceCharges()){
- res = res.add(logisticsServiceCharge.getTotalAmount());
- }
- }
+ public BigDecimal getItemTotalNetAmount() {
+ return itemTotalNetAmount;
+ }
- if(trans.getZFCharges()!= null){
- for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()){
- res = res.add(charge.getTotalAmount());
- }
- }
-
- // Set total net amount
- this.totalNetAmount = res;
+ public BigDecimal getItemTotalVATAmount() {
+ return itemTotalVATAmount;
+ }
- HashMap VATPercentAmountMap = getVATPercentAmountMap();
- for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
- VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
- res = res.add(amount.getCalculated());
- }
-
- // Set total gross amount
- this.totalGrossAmount = res;
-
- this.totalTaxAmount = this.totalGrossAmount.subtract(this.totalNetAmount);
- }
-
- public BigDecimal getTotalNet(){
- return totalNetAmount;
- }
-
- public BigDecimal getTotalGross(){
- return totalGrossAmount;
- }
-
- public BigDecimal getLineTotal(){
- return lineTotalAmount;
- }
-
- public BigDecimal getTaxTotal(){
- return totalTaxAmount;
- }
-
-
- }
+ public BigDecimal getItemNetAmount() {
+ return itemNetAmount;
+ }
- //// MAIN CLASS
- private String conformanceLevel = "U";
- private String versionStr = "1.3.0";
+ }
- // BASIC, COMFORT etc - may be set from outside.
- private String ZUGFeRDConformanceLevel = null;
+ private class Totals {
+ private BigDecimal totalNetAmount;
+ private BigDecimal totalGrossAmount;
+ private BigDecimal lineTotalAmount;
+ private BigDecimal totalTaxAmount;
- /**
- * Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally
- * set, in which case passing a IZUGFeRDExportableTransaction is not
- * necessary. By default it is null meaning the caller needs to pass a
- * IZUGFeRDExportableTransaction for the XML to be populated.
- */
- byte[] zugferdData = null;
- private boolean isTest;
- IZUGFeRDExportableTransaction trans = null;
+ public Totals() {
+ BigDecimal res = BigDecimal.ZERO;
+ for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
+ LineCalc lc = new LineCalc(currentItem);
+ res = res.add(lc.getItemTotalNetAmount());
+ }
+ // Set line total
+ this.lineTotalAmount = res;
- private BigDecimal nDigitFormat(BigDecimal value, int scale) {
- /*
- * I needed 123,45, locale independent.I tried
- * NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is
- * locale specific.I also tried DecimalFormat df = new DecimalFormat(
- * "0,00" ); df.setDecimalSeparatorAlwaysShown(true);
- * df.setGroupingUsed(false); DecimalFormatSymbols symbols = new
- * DecimalFormatSymbols(); symbols.setDecimalSeparator(',');
- * symbols.setGroupingSeparator(' ');
- * df.setDecimalFormatSymbols(symbols);
- *
- * but that would not switch off grouping. Although I liked very much
- * the (incomplete) "BNF diagram" in
- * http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html
- * in the end I decided to calculate myself and take eur+sparator+cents
- *
- * This function will cut off, i.e. floor() subcent values Tests:
- * System.err.println(utils.currencyFormat(new BigDecimal(0),
- * ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"),
- * ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"),
- * ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"),
- * ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"),
- * ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"),
- * ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ","));
- *
- * results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00
- */
- value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); // first, round so that e.g. 1.189999999999999946709294817992486059665679931640625 becomes 1.19
- char[] repeat = new char[scale];
- Arrays.fill(repeat, '0');
+ if (trans.getZFAllowances() != null) {
+ for (IZUGFeRDAllowanceCharge headerAllowance : trans
+ .getZFAllowances()) {
+ res = res.subtract(headerAllowance.getTotalAmount());
+ }
+ }
- DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
- otherSymbols.setDecimalSeparator('.');
- DecimalFormat dec = new DecimalFormat("0." + new String(repeat), otherSymbols);
- return new BigDecimal(dec.format(value));
+ if (trans.getZFLogisticsServiceCharges() != null) {
+ for (IZUGFeRDAllowanceCharge logisticsServiceCharge : trans
+ .getZFLogisticsServiceCharges()) {
+ res = res.add(logisticsServiceCharge.getTotalAmount());
+ }
+ }
- }
+ if (trans.getZFCharges() != null) {
+ for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
+ res = res.add(charge.getTotalAmount());
+ }
+ }
- private BigDecimal vatFormat(BigDecimal value) {
- return nDigitFormat(value, 2);
- }
+ // Set total net amount
+ this.totalNetAmount = res;
- private BigDecimal currencyFormat(BigDecimal value) {
- return nDigitFormat(value, 2);
- }
+ HashMap VATPercentAmountMap = getVATPercentAmountMap();
+ for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
+ VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
+ res = res.add(amount.getCalculated());
+ }
- private BigDecimal priceFormat(BigDecimal value) {
- return nDigitFormat(value, 4);
- }
+ // Set total gross amount
+ this.totalGrossAmount = res;
- private BigDecimal quantityFormat(BigDecimal value) {
- return nDigitFormat(value, 4);
- }
+ this.totalTaxAmount = this.totalGrossAmount
+ .subtract(this.totalNetAmount);
+ }
- /**
- * All files are PDF/A-3, setConformance refers to the level conformance.
- *
- * PDF/A-3 has three coformance levels, called "A", "U" and "B".
- *
- * PDF/A-3-B where B means only visually preservable, U -standard for
- * Mustang- means visually and unicode preservable and A means full
- * compliance, i.e. visually, unicode and structurally preservable and
- * tagged PDF, i.e. useful metainformation for blind people.
- *
- * Feel free to pass "A" as new level if you know what you are doing :-)
- *
- *
- */
- public void setConformanceLevel(String newLevel) {
- conformanceLevel = newLevel;
- }
+ public BigDecimal getTotalNet() {
+ return totalNetAmount;
+ }
- /**
- * enables the flag to indicate a test invoice in the XML structure
- *
- */
- public void setTest() {
- isTest = true;
- }
+ public BigDecimal getTotalGross() {
+ return totalGrossAmount;
+ }
- /**
- * Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on
- * the metadata level, this will not e.g. convert graphics to JPG-2000)
- *
- */
- public PDDocumentCatalog PDFmakeA3compliant(PDDocument doc, String producer, String creator,
- boolean attachZugferdHeaders) throws IOException,
- TransformerException {
- String fullProducer = producer + " (via mustangproject.org " + versionStr + ")";
- PDDocumentCatalog cat = doc.getDocumentCatalog();
- PDMetadata metadata = new PDMetadata(doc);
- cat.setMetadata(metadata);
- // we're using the jempbox org.apache.jempbox.xmp.XMPMetadata version,
- // not the xmpbox one
- XMPMetadata xmp = new XMPMetadata();
+ public BigDecimal getLineTotal() {
+ return lineTotalAmount;
+ }
- XMPSchemaPDFAId pdfaid = new XMPSchemaPDFAId(xmp);
- pdfaid.setAbout(""); //$NON-NLS-1$
- xmp.addSchema(pdfaid);
+ public BigDecimal getTaxTotal() {
+ return totalTaxAmount;
+ }
- XMPSchemaDublinCore dc = xmp.addDublinCoreSchema();
- dc.addCreator(creator);
- dc.setAbout(""); //$NON-NLS-1$
+ }
- XMPSchemaBasic xsb = xmp.addBasicSchema();
- xsb.setAbout(""); //$NON-NLS-1$
+ // // MAIN CLASS
+ private String conformanceLevel = "U";
+ private String versionStr = "1.3.0";
- xsb.setCreatorTool(creator);
- xsb.setCreateDate(GregorianCalendar.getInstance());
- // PDDocumentInformation pdi=doc.getDocumentInformation();
- PDDocumentInformation pdi = new PDDocumentInformation();
- pdi.setProducer(fullProducer);
- pdi.setAuthor(creator);
- doc.setDocumentInformation(pdi);
+ // BASIC, COMFORT etc - may be set from outside.
+ private String ZUGFeRDConformanceLevel = null;
- XMPSchemaPDF pdf = xmp.addPDFSchema();
- pdf.setProducer(fullProducer);
- pdf.setAbout(""); //$NON-NLS-1$
+ /**
+ * Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally
+ * set, in which case passing a IZUGFeRDExportableTransaction is not
+ * necessary. By default it is null meaning the caller needs to pass a
+ * IZUGFeRDExportableTransaction for the XML to be populated.
+ */
+ byte[] zugferdData = null;
+ private boolean isTest;
+ IZUGFeRDExportableTransaction trans = null;
+ private boolean ignoreA1Errors;
+ private PDDocument doc;
+ private String currency = "EUR";
- /*
- // Mandatory: PDF/A3-a is tagged PDF which has to be expressed using a
- // MarkInfo dictionary (PDF A/3 Standard sec. 6.7.2.2)
- PDMarkInfo markinfo = new PDMarkInfo();
- markinfo.setMarked(true);
- doc.getDocumentCatalog().setMarkInfo(markinfo);
- */
- /*
- *
- To be on the safe side, we use level B without Markinfo because we can not
- guarantee that the user correctly tagged the templates for the PDF.
+ private BigDecimal nDigitFormat(BigDecimal value, int scale) {
+ /*
+ * I needed 123,45, locale independent.I tried
+ * NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is
+ * locale specific.I also tried DecimalFormat df = new DecimalFormat(
+ * "0,00" ); df.setDecimalSeparatorAlwaysShown(true);
+ * df.setGroupingUsed(false); DecimalFormatSymbols symbols = new
+ * DecimalFormatSymbols(); symbols.setDecimalSeparator(',');
+ * symbols.setGroupingSeparator(' ');
+ * df.setDecimalFormatSymbols(symbols);
+ *
+ * but that would not switch off grouping. Although I liked very much
+ * the (incomplete) "BNF diagram" in
+ * http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html
+ * in the end I decided to calculate myself and take eur+sparator+cents
+ *
+ * This function will cut off, i.e. floor() subcent values Tests:
+ * System.err.println(utils.currencyFormat(new BigDecimal(0),
+ * ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"),
+ * ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"),
+ * ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"),
+ * ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"),
+ * ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"),
+ * ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ","));
+ *
+ * results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00
+ */
+ value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); // first, round
+ // so that
+ // e.g.
+ // 1.189999999999999946709294817992486059665679931640625
+ // becomes
+ // 1.19
+ char[] repeat = new char[scale];
+ Arrays.fill(repeat, '0');
- * */
- pdfaid.setConformance(conformanceLevel);//$NON-NLS-1$ //$NON-NLS-1$
+ DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
+ otherSymbols.setDecimalSeparator('.');
+ DecimalFormat dec = new DecimalFormat("0." + new String(repeat),
+ otherSymbols);
+ return new BigDecimal(dec.format(value));
- pdfaid.setPart(3);
+ }
- if (attachZugferdHeaders) {
- addZugferdXMP(xmp); /*
- * this is the only line where we do something
- * Zugferd-specific, i.e. add PDF metadata
- * specifically for Zugferd, not generically for
- * a embedded file
- */
+ private BigDecimal vatFormat(BigDecimal value) {
+ return nDigitFormat(value, 2);
+ }
- }
+ private BigDecimal currencyFormat(BigDecimal value) {
+ return nDigitFormat(value, 2);
+ }
- metadata.importXMPMetadata(xmp);
- return cat;
- }
+ private BigDecimal priceFormat(BigDecimal value) {
+ return nDigitFormat(value, 4);
+ }
- private static final ObjectFactory xmlFactory = new ObjectFactory();
- private final JAXBContext jaxbContext;
- private final Marshaller marshaller;
- private static final SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); //$NON-NLS-1$
- private static final SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$
-
- private Totals totals;
+ private BigDecimal quantityFormat(BigDecimal value) {
+ return nDigitFormat(value, 4);
+ }
- private String getZugferdXMLForTransaction(IZUGFeRDExportableTransaction trans) throws JAXBException {
- this.trans = trans;
-
- this.totals = new Totals();
+ /**
+ * All files are PDF/A-3, setConformance refers to the level conformance.
+ *
+ * PDF/A-3 has three coformance levels, called "A", "U" and "B".
+ *
+ * PDF/A-3-B where B means only visually preservable, U -standard for
+ * Mustang- means visually and unicode preservable and A means full
+ * compliance, i.e. visually, unicode and structurally preservable and
+ * tagged PDF, i.e. useful metainformation for blind people.
+ *
+ * Feel free to pass "A" as new level if you know what you are doing :-)
+ *
+ *
+ */
+ public void setConformanceLevel(String newLevel) {
+ conformanceLevel = newLevel;
+ }
- CrossIndustryDocumentType invoice = xmlFactory.createCrossIndustryDocumentType();
+ /**
+ * enables the flag to indicate a test invoice in the XML structure
+ *
+ */
+ public void setTest() {
+ isTest = true;
+ }
- invoice.setSpecifiedExchangedDocumentContext(this.getDocumentContext());
- invoice.setHeaderExchangedDocument(this.getDocument());
- invoice.setSpecifiedSupplyChainTradeTransaction(this.getTradeTransaction());
+ public void ignoreA1Errors() {
+ ignoreA1Errors = true;
+ }
- JAXBElement jaxElement = xmlFactory.createCrossIndustryDocument(invoice);
+ private boolean getA1ParserValidationResult(PreflightParser parser) {
+ ValidationResult result = null;
- ByteArrayOutputStream outputXml = new ByteArrayOutputStream();
- marshaller.marshal(jaxElement, outputXml);
+ try {
- return outputXml.toString();
- }
+ /*
+ * Parse the PDF file with PreflightParser that inherits from the
+ * NonSequentialParser. Some additional controls are present to
+ * check a set of PDF/A requirements. (Stream length consistency,
+ * EOL after some Keyword...)
+ */
+ parser.parse();
- private ExchangedDocumentContextType getDocumentContext() {
+ /*
+ * Once the syntax validation is done, the parser can provide a
+ * PreflightDocument (that inherits from PDDocument) This document
+ * process the end of PDF/A validation.
+ */
+ PreflightDocument document = parser.getPreflightDocument();
+ document.validate();
- ExchangedDocumentContextType context = xmlFactory.createExchangedDocumentContextType();
- DocumentContextParameterType contextParameter = xmlFactory.createDocumentContextParameterType();
- IDType idType = xmlFactory.createIDType();
- idType.setValue(DocumentContextParameterType.COMFORT);
- contextParameter.setID(idType);
- context.getGuidelineSpecifiedDocumentContextParameter().add(contextParameter);
-
- IndicatorType testIndicator = xmlFactory.createIndicatorType();
- testIndicator.setIndicator(isTest);
- context.setTestIndicator(testIndicator);
+ // Get validation result
+ result = document.getResult();
+ document.close();
- return context;
- }
+ } catch (ValidationException e) {
+ /*
+ * the parse method can throw a SyntaxValidationException if the PDF
+ * file can't be parsed. In this case, the exception contains an
+ * instance of ValidationResult
+ */
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
- private ExchangedDocumentType getDocument() {
+ // display validation result
+ return result.isValid();
- ExchangedDocumentType document = xmlFactory.createExchangedDocumentType();
+ }
- IDType id = xmlFactory.createIDType();
- id.setValue(trans.getNumber());
- document.setID(id);
+ public boolean isValidA1(String filename) {
+ FileDataSource fd = new FileDataSource(filename);
+ PreflightParser parser;
+ try {
+ parser = new PreflightParser(fd);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return false;
+ }
- DateTimeType issueDateTime = xmlFactory.createDateTimeType();
- DateTimeType.DateTimeString issueDateTimeString = xmlFactory.createDateTimeTypeDateTimeString();
- issueDateTimeString.setFormat(DateTimeType.DateTimeString.DATE);
- issueDateTimeString.setValue(zugferdDateFormat.format(trans.getIssueDate()));
- issueDateTime.setDateTimeString(issueDateTimeString);
- document.setIssueDateTime(issueDateTime);
+ return getA1ParserValidationResult(parser);
+ }
- DocumentCodeType documentCodeType = xmlFactory.createDocumentCodeType();
- documentCodeType.setValue(DocumentCodeType.INVOICE);
- document.setTypeCode(documentCodeType);
+ /***
+ * Will return a boolean if the inputstream is valid PDF/A-1 and close the input stream
+ * @param file
+ * @return
+ */
+ public boolean isValidA1(InputStream file) {
+
+ ByteArrayDataSource fd;
+ try {
+ fd = new ByteArrayDataSource(file);
+ PreflightParser parser = new PreflightParser(fd);
+ return getA1ParserValidationResult(parser);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return false;
+ }
TextType name = xmlFactory.createTextType();
name.setValue("RECHNUNG");
@@ -440,785 +421,1139 @@ public class ZUGFeRDExporter {
document.getIncludedNote().add(referenceInfo);
}
- return document;
- }
+ public void loadPDFA3(String filename) {
+
+ try {
+ doc = PDDocument.load(filename);
+
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ public void loadPDFA3(InputStream file) {
+
+ try {
+ doc = PDDocument.load(file);
+
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on
+ * the metadata level, this will not e.g. convert graphics to JPG-2000)
+ *
+ */
+ public PDDocumentCatalog PDFmakeA3compliant(String filename,
+ String producer, String creator, boolean attachZugferdHeaders)
+ throws IOException, TransformerException {
+
+ if (!ignoreA1Errors && !isValidA1(filename)) {
+ throw new IOException("File is not a valid PDF/A-1 input file");
+ }
+ loadPDFA3(filename);
+
+ return makeDocPDFA3compliant(producer, creator, attachZugferdHeaders);
+ }
+
+ public PDDocumentCatalog PDFmakeA3compliant(InputStream file,
+ String producer, String creator, boolean attachZugferdHeaders)
+ throws IOException, TransformerException {
+ /* cache the file content in memory, unfortunately the next step, isValidA1,
+ * will close the input stream but the step thereafter (loadPDFA3) needs
+ * and open one*/
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buf = new byte[1024];
+ int n = 0;
+ while ((n = file.read(buf)) >= 0)
+ baos.write(buf, 0, n);
+ byte[] content = baos.toByteArray();
+
+ InputStream is1 = new ByteArrayInputStream(content);
+ if (!ignoreA1Errors && !isValidA1(is1)) {
+ throw new IOException("File is not a valid PDF/A-1 input file");
+ }
+ InputStream is2 = new ByteArrayInputStream(content);
+ loadPDFA3(is2);
+
+ return makeDocPDFA3compliant(producer, creator, attachZugferdHeaders);
+ }
+ private PDDocumentCatalog makeDocPDFA3compliant(String producer,
+ String creator, boolean attachZugferdHeaders) throws IOException,
+ TransformerException {
+ String fullProducer = producer + " (via mustangproject.org "
+ + versionStr + ")";
+
+ PDDocumentCatalog cat = doc.getDocumentCatalog();
+ PDMetadata metadata = new PDMetadata(doc);
+ cat.setMetadata(metadata);
+ // we're using the jempbox org.apache.jempbox.xmp.XMPMetadata version,
+ // not the xmpbox one
+ XMPMetadata xmp = new XMPMetadata();
+
+ XMPSchemaPDFAId pdfaid = new XMPSchemaPDFAId(xmp);
+ pdfaid.setAbout(""); //$NON-NLS-1$
+ xmp.addSchema(pdfaid);
+
+ XMPSchemaDublinCore dc = xmp.addDublinCoreSchema();
+ dc.addCreator(creator);
+ dc.setAbout(""); //$NON-NLS-1$
+
+ XMPSchemaBasic xsb = xmp.addBasicSchema();
+ xsb.setAbout(""); //$NON-NLS-1$
+
+ xsb.setCreatorTool(creator);
+ xsb.setCreateDate(GregorianCalendar.getInstance());
+ // PDDocumentInformation pdi=doc.getDocumentInformation();
+ PDDocumentInformation pdi = new PDDocumentInformation();
+ pdi.setProducer(fullProducer);
+ pdi.setAuthor(creator);
+ doc.setDocumentInformation(pdi);
+
+ XMPSchemaPDF pdf = xmp.addPDFSchema();
+ pdf.setProducer(fullProducer);
+ pdf.setAbout(""); //$NON-NLS-1$
+
+ /*
+ * // Mandatory: PDF/A3-a is tagged PDF which has to be expressed using
+ * a // MarkInfo dictionary (PDF A/3 Standard sec. 6.7.2.2) PDMarkInfo
+ * markinfo = new PDMarkInfo(); markinfo.setMarked(true);
+ * doc.getDocumentCatalog().setMarkInfo(markinfo);
+ */
+ /*
+ *
+ * To be on the safe side, we use level B without Markinfo because we
+ * can not guarantee that the user correctly tagged the templates for
+ * the PDF.
+ */
+ pdfaid.setConformance(conformanceLevel);//$NON-NLS-1$ //$NON-NLS-1$
+
+ pdfaid.setPart(3);
+
+ if (attachZugferdHeaders) {
+ addZugferdXMP(xmp); /*
+ * this is the only line where we do something
+ * Zugferd-specific, i.e. add PDF metadata
+ * specifically for Zugferd, not generically for
+ * a embedded file
+ */
+
+ }
+
+ metadata.importXMPMetadata(xmp);
+ return cat;
+ }
+
+ private static final ObjectFactory xmlFactory = new ObjectFactory();
+ private final JAXBContext jaxbContext;
+ private final Marshaller marshaller;
+ private static final SimpleDateFormat zugferdDateFormat = new SimpleDateFormat(
+ "yyyyMMdd"); //$NON-NLS-1$
+
+ private Totals totals;
+
+ private String getZugferdXMLForTransaction(
+ IZUGFeRDExportableTransaction trans) throws JAXBException {
+ this.trans = trans;
+ this.totals = new Totals();
+ currency = trans.getCurrency();
+
+ CrossIndustryDocumentType invoice = xmlFactory
+ .createCrossIndustryDocumentType();
+
+ invoice.setSpecifiedExchangedDocumentContext(this.getDocumentContext());
+ invoice.setHeaderExchangedDocument(this.getDocument());
+ invoice.setSpecifiedSupplyChainTradeTransaction(this
+ .getTradeTransaction());
+
+ JAXBElement jaxElement = xmlFactory
+ .createCrossIndustryDocument(invoice);
+
+ ByteArrayOutputStream outputXml = new ByteArrayOutputStream();
+ marshaller.marshal(jaxElement, outputXml);
+
+ return outputXml.toString();
+ }
+
+ private ExchangedDocumentContextType getDocumentContext() {
+
+ ExchangedDocumentContextType context = xmlFactory
+ .createExchangedDocumentContextType();
+ DocumentContextParameterType contextParameter = xmlFactory
+ .createDocumentContextParameterType();
+ IDType idType = xmlFactory.createIDType();
+ idType.setValue(DocumentContextParameterType.EXTENDED);
+ contextParameter.setID(idType);
+ context.getGuidelineSpecifiedDocumentContextParameter().add(
+ contextParameter);
+
+ IndicatorType testIndicator = xmlFactory.createIndicatorType();
+ testIndicator.setIndicator(isTest);
+ context.setTestIndicator(testIndicator);
+
+ return context;
+ }
+
+ private ExchangedDocumentType getDocument() {
+
+ ExchangedDocumentType document = xmlFactory
+ .createExchangedDocumentType();
+
+ IDType id = xmlFactory.createIDType();
+ id.setValue(trans.getNumber());
+ document.setID(id);
+
+ DateTimeType issueDateTime = xmlFactory.createDateTimeType();
+ DateTimeType.DateTimeString issueDateTimeString = xmlFactory
+ .createDateTimeTypeDateTimeString();
+ issueDateTimeString.setFormat(DateTimeType.DateTimeString.DATE);
+ issueDateTimeString.setValue(zugferdDateFormat.format(trans
+ .getIssueDate()));
+ issueDateTime.setDateTimeString(issueDateTimeString);
+ document.setIssueDateTime(issueDateTime);
+
+ DocumentCodeType documentCodeType = xmlFactory.createDocumentCodeType();
+ documentCodeType.setValue(DocumentCodeType.INVOICE);
+ document.setTypeCode(documentCodeType);
+
+ TextType name = xmlFactory.createTextType();
+ name.setValue("RECHNUNG");
+ document.getName().add(name);
+
+ if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
+ NoteType regularInfo = xmlFactory.createNoteType();
+ CodeType regularInfoSubjectCode = xmlFactory.createCodeType();
+ regularInfoSubjectCode.setValue(NoteType.REGULARINFO);
+ regularInfo.setSubjectCode(regularInfoSubjectCode);
+ TextType regularInfoContent = xmlFactory.createTextType();
+ regularInfoContent.setValue(trans
+ .getOwnOrganisationFullPlaintextInfo());
+ regularInfo.getContent().add(regularInfoContent);
+ document.getIncludedNote().add(regularInfo);
+ }
+
+ return document;
+ }
+
+ private SupplyChainTradeTransactionType getTradeTransaction() {
+
+ SupplyChainTradeTransactionType transaction = xmlFactory
+ .createSupplyChainTradeTransactionType();
+ transaction.getApplicableSupplyChainTradeAgreement().add(
+ this.getTradeAgreement());
+ transaction.setApplicableSupplyChainTradeDelivery(this
+ .getTradeDelivery());
+ transaction.setApplicableSupplyChainTradeSettlement(this
+ .getTradeSettlement());
+ transaction.getIncludedSupplyChainTradeLineItem().addAll(
+ this.getLineItems());
+
+ return transaction;
+ }
+
+ private SupplyChainTradeAgreementType getTradeAgreement() {
+
+ SupplyChainTradeAgreementType tradeAgreement = xmlFactory
+ .createSupplyChainTradeAgreementType();
+
+ tradeAgreement.setBuyerTradeParty(this.getBuyer());
+ tradeAgreement.setSellerTradeParty(this.getSeller());
+
+ return tradeAgreement;
+ }
+
+ private TradePartyType getBuyer() {
+
+ TradePartyType buyerTradeParty = xmlFactory.createTradePartyType();
+ TextType buyerName = xmlFactory.createTextType();
+ buyerName.setValue(trans.getRecipient().getName());
+ buyerTradeParty.setName(buyerName);
+
+ TradeAddressType buyerAddressType = xmlFactory.createTradeAddressType();
+ TextType buyerCityName = xmlFactory.createTextType();
+ buyerCityName.setValue(trans.getRecipient().getLocation());
+ buyerAddressType.setCityName(buyerCityName);
+
+ CountryIDType buyerCountryId = xmlFactory.createCountryIDType();
+ buyerCountryId.setValue(trans.getRecipient().getCountry());
+ buyerAddressType.setCountryID(buyerCountryId);
+
+ TextType buyerAddress = xmlFactory.createTextType();
+ buyerAddress.setValue(trans.getRecipient().getStreet());
+ buyerAddressType.setLineOne(buyerAddress);
+
+ CodeType buyerPostcode = xmlFactory.createCodeType();
+ buyerPostcode.setValue(trans.getRecipient().getZIP());
+ buyerAddressType.getPostcodeCode().add(buyerPostcode);
+
+ buyerTradeParty.setPostalTradeAddress(buyerAddressType);
+
+ // Ust-ID
+ TaxRegistrationType buyerTaxRegistration = xmlFactory
+ .createTaxRegistrationType();
+ IDType buyerUstId = xmlFactory.createIDType();
+ buyerUstId.setValue(trans.getRecipient().getVATID());
+ buyerUstId.setSchemeID(TaxRegistrationType.USTID);
+ buyerTaxRegistration.setID(buyerUstId);
+ buyerTradeParty.getSpecifiedTaxRegistration().add(buyerTaxRegistration);
+
+ return buyerTradeParty;
+ }
+
+ private TradePartyType getSeller() {
+
+ TradePartyType sellerTradeParty = xmlFactory.createTradePartyType();
+ TextType sellerName = xmlFactory.createTextType();
+ sellerName.setValue(trans.getOwnOrganisationName());
+ sellerTradeParty.setName(sellerName);
+
+ TradeAddressType sellerAddressType = xmlFactory
+ .createTradeAddressType();
+ TextType sellerCityName = xmlFactory.createTextType();
+ sellerCityName.setValue(trans.getOwnLocation());
+ sellerAddressType.setCityName(sellerCityName);
+
+ CountryIDType sellerCountryId = xmlFactory.createCountryIDType();
+ sellerCountryId.setValue(trans.getOwnCountry());
+ sellerAddressType.setCountryID(sellerCountryId);
+
+ TextType sellerAddress = xmlFactory.createTextType();
+ sellerAddress.setValue(trans.getOwnStreet());
+ sellerAddressType.setLineOne(sellerAddress);
+
+ CodeType sellerPostcode = xmlFactory.createCodeType();
+ sellerPostcode.setValue(trans.getOwnZIP());
+ sellerAddressType.getPostcodeCode().add(sellerPostcode);
+
+ sellerTradeParty.setPostalTradeAddress(sellerAddressType);
+
+ // Steuernummer
+ TaxRegistrationType sellerTaxRegistration = xmlFactory
+ .createTaxRegistrationType();
+ IDType sellerTaxId = xmlFactory.createIDType();
+ sellerTaxId.setValue(trans.getOwnTaxID());
+ sellerTaxId.setSchemeID(TaxRegistrationType.TAXID);
+ sellerTaxRegistration.setID(sellerTaxId);
+ sellerTradeParty.getSpecifiedTaxRegistration().add(
+ sellerTaxRegistration);
+
+ // Ust-ID
+ sellerTaxRegistration = xmlFactory.createTaxRegistrationType();
+ IDType sellerUstId = xmlFactory.createIDType();
+ sellerUstId.setValue(trans.getOwnVATID());
+ sellerUstId.setSchemeID(TaxRegistrationType.USTID);
+ sellerTaxRegistration.setID(sellerUstId);
+ sellerTradeParty.getSpecifiedTaxRegistration().add(
+ sellerTaxRegistration);
+
+ return sellerTradeParty;
+ }
+
+ private SupplyChainTradeDeliveryType getTradeDelivery() {
+
+ SupplyChainTradeDeliveryType tradeDelivery = xmlFactory
+ .createSupplyChainTradeDeliveryType();
+ SupplyChainEventType deliveryEvent = xmlFactory
+ .createSupplyChainEventType();
+ DateTimeType deliveryDate = xmlFactory.createDateTimeType();
+ DateTimeType.DateTimeString deliveryDateString = xmlFactory
+ .createDateTimeTypeDateTimeString();
+ deliveryDateString.setFormat(DateTimeType.DateTimeString.DATE);
+ deliveryDateString.setValue(zugferdDateFormat.format(trans
+ .getDeliveryDate()));
+ deliveryDate.setDateTimeString(deliveryDateString);
+ deliveryEvent.getOccurrenceDateTime().add(deliveryDate);
+ tradeDelivery.getActualDeliverySupplyChainEvent().add(deliveryEvent);
+
+ return tradeDelivery;
+ }
+
+ private SupplyChainTradeSettlementType getTradeSettlement() {
+ SupplyChainTradeSettlementType tradeSettlement = xmlFactory
+ .createSupplyChainTradeSettlementType();
+
+ TextType paymentReference = xmlFactory.createTextType();
+ paymentReference.setValue(trans.getNumber());
+ tradeSettlement.getPaymentReference().add(paymentReference);
+
+ CodeType currencyCode = xmlFactory.createCodeType();
+ currencyCode.setValue(currency);
+ tradeSettlement.setInvoiceCurrencyCode(currencyCode);
+
+ tradeSettlement.getSpecifiedTradeSettlementPaymentMeans().add(
+ this.getPaymentData());
+ tradeSettlement.getApplicableTradeTax().addAll(this.getTradeTax());
+ tradeSettlement.getSpecifiedTradePaymentTerms().addAll(
+ this.getPaymentTerms());
+ if (trans.getZFAllowances() != null) {
+ tradeSettlement.getSpecifiedTradeAllowanceCharge().addAll(
+ this.getHeaderAllowances());
+ }
+ if (trans.getZFLogisticsServiceCharges() != null) {
+ tradeSettlement.getSpecifiedLogisticsServiceCharge().addAll(
+ this.getHeaderLogisticsServiceCharges());
+ }
+ if (trans.getZFCharges() != null) {
+ tradeSettlement.getSpecifiedTradeAllowanceCharge().addAll(
+ this.getHeaderCharges());
+ }
+
+ tradeSettlement.setSpecifiedTradeSettlementMonetarySummation(this
+ .getMonetarySummation());
+
+ return tradeSettlement;
+ }
+
+ private TradeSettlementPaymentMeansType getPaymentData() {
+ TradeSettlementPaymentMeansType paymentData = xmlFactory
+ .createTradeSettlementPaymentMeansType();
+ PaymentMeansCodeType paymentDataType = xmlFactory
+ .createPaymentMeansCodeType();
+ paymentDataType.setValue(PaymentMeansCodeType.BANKACCOUNT);
+ paymentData.setTypeCode(paymentDataType);
+
+ TextType paymentInfo = xmlFactory.createTextType();
+ String paymentInfoText = trans.getOwnPaymentInfoText();
+ if (paymentInfoText == null) {
+ paymentInfoText = "";
+ }
+ paymentInfo.setValue(paymentInfoText);
+ paymentData.getInformation().add(paymentInfo);
+
+ CreditorFinancialAccountType bankAccount = xmlFactory
+ .createCreditorFinancialAccountType();
+ IDType iban = xmlFactory.createIDType();
+ iban.setValue(trans.getOwnIBAN());
+ bankAccount.setIBANID(iban);
+ paymentData.setPayeePartyCreditorFinancialAccount(bankAccount);
+
+ CreditorFinancialInstitutionType bankData = xmlFactory
+ .createCreditorFinancialInstitutionType();
+ IDType bicId = xmlFactory.createIDType();
+ bicId.setValue(trans.getOwnBIC());
+ bankData.setBICID(bicId);
+ TextType bankName = xmlFactory.createTextType();
+ bankName.setValue(trans.getOwnBankName());
+ bankData.setName(bankName);
+ paymentData.setPayeeSpecifiedCreditorFinancialInstitution(bankData);
+ return paymentData;
+ }
+
+ private Collection getTradeTax() {
+ List tradeTaxTypes = new ArrayList();
+
+ HashMap VATPercentAmountMap = this
+ .getVATPercentAmountMap();
+ for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
+
+ TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
+ TaxTypeCodeType taxTypeCode = xmlFactory.createTaxTypeCodeType();
+ taxTypeCode.setValue(TaxTypeCodeType.SALESTAX);
+ tradeTax.setTypeCode(taxTypeCode);
+
+ TaxCategoryCodeType taxCategoryCode = xmlFactory
+ .createTaxCategoryCodeType();
+ taxCategoryCode.setValue(TaxCategoryCodeType.STANDARDRATE);
+ tradeTax.setCategoryCode(taxCategoryCode);
+
+ VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
+
+ PercentType taxPercent = xmlFactory.createPercentType();
+ taxPercent.setValue(vatFormat(currentTaxPercent));
+ tradeTax.setApplicablePercent(taxPercent);
+
+ AmountType calculatedTaxAmount = xmlFactory.createAmountType();
+ calculatedTaxAmount.setCurrencyID(currency);
+ calculatedTaxAmount
+ .setValue(currencyFormat(amount.getCalculated()));
+ tradeTax.getCalculatedAmount().add(calculatedTaxAmount);
+
+ AmountType basisTaxAmount = xmlFactory.createAmountType();
+ basisTaxAmount.setCurrencyID(currency);
+ basisTaxAmount.setValue(currencyFormat(amount.getBasis()));
+ tradeTax.getBasisAmount().add(basisTaxAmount);
+
+ tradeTaxTypes.add(tradeTax);
+ }
+
+ return tradeTaxTypes;
+ }
+
+ private Collection getHeaderAllowances() {
+ List headerAllowances = new ArrayList();
+
+ for (IZUGFeRDAllowanceCharge iAllowance : trans.getZFAllowances()) {
+
+ TradeAllowanceChargeType allowance = xmlFactory
+ .createTradeAllowanceChargeType();
+
+ IndicatorType chargeIndicator = xmlFactory.createIndicatorType();
+ chargeIndicator.setIndicator(false);
+ allowance.setChargeIndicator(chargeIndicator);
+
+ AmountType actualAmount = xmlFactory.createAmountType();
+ actualAmount.setCurrencyID(currency);
+ actualAmount.setValue(currencyFormat(iAllowance.getTotalAmount()));
+ allowance.getActualAmount().add(actualAmount);
+
+ TextType reason = xmlFactory.createTextType();
+ reason.setValue(iAllowance.getReason());
+ allowance.setReason(reason);
+
+ TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
+
+ PercentType vatPercent = xmlFactory.createPercentType();
+ vatPercent.setValue(currencyFormat(iAllowance.getTaxPercent()));
+ tradeTax.setApplicablePercent(vatPercent);
+
+ /*
+ * Only in extended AmountType basisAmount =
+ * xmlFactory.createAmountType();
+ * basisAmount.setCurrencyID(trans.getInvoiceCurrency());
+ * basisAmount.setValue(amount.getBasis());
+ * allowance.setBasisAmount(basisAmount);
+ */
+ TaxCategoryCodeType taxType = xmlFactory
+ .createTaxCategoryCodeType();
+ taxType.setValue(TaxCategoryCodeType.STANDARDRATE);
+ tradeTax.setCategoryCode(taxType);
+
+ TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
+ taxCode.setValue(TaxTypeCodeType.SALESTAX);
+ tradeTax.setTypeCode(taxCode);
+
+ allowance.getCategoryTradeTax().add(tradeTax);
+ headerAllowances.add(allowance);
+
+ }
+
+ return headerAllowances;
+ }
+
+ private Collection getHeaderCharges() {
+ List headerCharges = new ArrayList();
- private SupplyChainTradeTransactionType getTradeTransaction() {
+ for (IZUGFeRDAllowanceCharge iCharge : trans.getZFCharges()) {
- SupplyChainTradeTransactionType transaction = xmlFactory.createSupplyChainTradeTransactionType();
- transaction.getApplicableSupplyChainTradeAgreement().add(this.getTradeAgreement());
- transaction.setApplicableSupplyChainTradeDelivery(this.getTradeDelivery());
- transaction.setApplicableSupplyChainTradeSettlement(this.getTradeSettlement());
- transaction.getIncludedSupplyChainTradeLineItem().addAll(this.getLineItems());
+ TradeAllowanceChargeType charge = xmlFactory
+ .createTradeAllowanceChargeType();
- return transaction;
- }
+ IndicatorType chargeIndicator = xmlFactory.createIndicatorType();
+ chargeIndicator.setIndicator(true);
+ charge.setChargeIndicator(chargeIndicator);
+
+ AmountType actualAmount = xmlFactory.createAmountType();
+ actualAmount.setCurrencyID(currency);
+ actualAmount.setValue(currencyFormat(iCharge.getTotalAmount()));
+ charge.getActualAmount().add(actualAmount);
+
+ TextType reason = xmlFactory.createTextType();
+ reason.setValue(iCharge.getReason());
+ charge.setReason(reason);
+
+ TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
+
+ PercentType vatPercent = xmlFactory.createPercentType();
+ vatPercent.setValue(currencyFormat(iCharge.getTaxPercent()));
+ tradeTax.setApplicablePercent(vatPercent);
- private SupplyChainTradeAgreementType getTradeAgreement() {
-
- SupplyChainTradeAgreementType tradeAgreement = xmlFactory.createSupplyChainTradeAgreementType();
-
- tradeAgreement.setBuyerTradeParty(this.getBuyer());
- tradeAgreement.setSellerTradeParty(this.getSeller());
-
- return tradeAgreement;
- }
-
- private TradePartyType getBuyer() {
-
- TradePartyType buyerTradeParty = xmlFactory.createTradePartyType();
- TextType buyerName = xmlFactory.createTextType();
- buyerName.setValue(trans.getRecipient().getName());
- buyerTradeParty.setName(buyerName);
-
- TradeAddressType buyerAddressType = xmlFactory.createTradeAddressType();
- TextType buyerCityName = xmlFactory.createTextType();
- buyerCityName.setValue(trans.getRecipient().getLocation());
- buyerAddressType.setCityName(buyerCityName);
-
- CountryIDType buyerCountryId = xmlFactory.createCountryIDType();
- buyerCountryId.setValue(trans.getRecipient().getCountry());
- buyerAddressType.setCountryID(buyerCountryId);
-
- TextType buyerAddress = xmlFactory.createTextType();
- buyerAddress.setValue(trans.getRecipient().getStreet());
- buyerAddressType.setLineOne(buyerAddress);
-
- CodeType buyerPostcode = xmlFactory.createCodeType();
- buyerPostcode.setValue(trans.getRecipient().getZIP());
- buyerAddressType.getPostcodeCode().add(buyerPostcode);
-
- buyerTradeParty.setPostalTradeAddress(buyerAddressType);
-
- // Ust-ID
- TaxRegistrationType buyerTaxRegistration = xmlFactory.createTaxRegistrationType();
- IDType buyerUstId = xmlFactory.createIDType();
- buyerUstId.setValue(trans.getRecipient().getVATID());
- buyerUstId.setSchemeID(TaxRegistrationType.USTID);
- buyerTaxRegistration.setID(buyerUstId);
- buyerTradeParty.getSpecifiedTaxRegistration().add(buyerTaxRegistration);
-
- return buyerTradeParty;
- }
-
- private TradePartyType getSeller() {
-
- TradePartyType sellerTradeParty = xmlFactory.createTradePartyType();
- TextType sellerName = xmlFactory.createTextType();
- sellerName.setValue(trans.getOwnOrganisationName());
- sellerTradeParty.setName(sellerName);
-
- TradeAddressType sellerAddressType = xmlFactory.createTradeAddressType();
- TextType sellerCityName = xmlFactory.createTextType();
- sellerCityName.setValue(trans.getOwnLocation());
- sellerAddressType.setCityName(sellerCityName);
-
- CountryIDType sellerCountryId = xmlFactory.createCountryIDType();
- sellerCountryId.setValue(trans.getOwnCountry());
- sellerAddressType.setCountryID(sellerCountryId);
-
- TextType sellerAddress = xmlFactory.createTextType();
- sellerAddress.setValue(trans.getOwnStreet());
- sellerAddressType.setLineOne(sellerAddress);
-
- CodeType sellerPostcode = xmlFactory.createCodeType();
- sellerPostcode.setValue(trans.getOwnZIP());
- sellerAddressType.getPostcodeCode().add(sellerPostcode);
-
- sellerTradeParty.setPostalTradeAddress(sellerAddressType);
-
- // Steuernummer
- TaxRegistrationType sellerTaxRegistration = xmlFactory.createTaxRegistrationType();
- IDType sellerTaxId = xmlFactory.createIDType();
- sellerTaxId.setValue(trans.getOwnTaxID());
- sellerTaxId.setSchemeID(TaxRegistrationType.TAXID);
- sellerTaxRegistration.setID(sellerTaxId);
- sellerTradeParty.getSpecifiedTaxRegistration().add(sellerTaxRegistration);
-
- // Ust-ID
- sellerTaxRegistration = xmlFactory.createTaxRegistrationType();
- IDType sellerUstId = xmlFactory.createIDType();
- sellerUstId.setValue(trans.getOwnVATID());
- sellerUstId.setSchemeID(TaxRegistrationType.USTID);
- sellerTaxRegistration.setID(sellerUstId);
- sellerTradeParty.getSpecifiedTaxRegistration().add(sellerTaxRegistration);
-
- return sellerTradeParty;
- }
-
- private SupplyChainTradeDeliveryType getTradeDelivery() {
-
- SupplyChainTradeDeliveryType tradeDelivery = xmlFactory.createSupplyChainTradeDeliveryType();
- SupplyChainEventType deliveryEvent = xmlFactory.createSupplyChainEventType();
- DateTimeType deliveryDate = xmlFactory.createDateTimeType();
- DateTimeType.DateTimeString deliveryDateString = xmlFactory.createDateTimeTypeDateTimeString();
- deliveryDateString.setFormat(DateTimeType.DateTimeString.DATE);
- deliveryDateString.setValue(zugferdDateFormat.format(trans.getDeliveryDate()));
- deliveryDate.setDateTimeString(deliveryDateString);
- deliveryEvent.getOccurrenceDateTime().add(deliveryDate);
- tradeDelivery.getActualDeliverySupplyChainEvent().add(deliveryEvent);
-
- return tradeDelivery;
- }
-
- private SupplyChainTradeSettlementType getTradeSettlement() {
- SupplyChainTradeSettlementType tradeSettlement = xmlFactory.createSupplyChainTradeSettlementType();
-
- TextType paymentReference = xmlFactory.createTextType();
- paymentReference.setValue(trans.getNumber());
- tradeSettlement.getPaymentReference().add(paymentReference);
-
- CodeType currencyCode = xmlFactory.createCodeType();
- currencyCode.setValue(trans.getInvoiceCurrency());
- tradeSettlement.setInvoiceCurrencyCode(currencyCode);
-
- tradeSettlement.getSpecifiedTradeSettlementPaymentMeans().add(this.getPaymentData());
- tradeSettlement.getApplicableTradeTax().addAll(this.getTradeTax());
- tradeSettlement.getSpecifiedTradePaymentTerms().addAll(this.getPaymentTerms());
- if(trans.getZFAllowances() != null){
- tradeSettlement.getSpecifiedTradeAllowanceCharge().addAll(this.getHeaderAllowances());
- }
- if(trans.getZFLogisticsServiceCharges()!= null){
- tradeSettlement.getSpecifiedLogisticsServiceCharge().addAll(this.getHeaderLogisticsServiceCharges());
- }
- if(trans.getZFCharges()!= null){
- tradeSettlement.getSpecifiedTradeAllowanceCharge().addAll(this.getHeaderCharges());
- }
-
- tradeSettlement.setSpecifiedTradeSettlementMonetarySummation(this.getMonetarySummation());
-
- return tradeSettlement;
- }
-
- private TradeSettlementPaymentMeansType getPaymentData() {
- TradeSettlementPaymentMeansType paymentData = xmlFactory.createTradeSettlementPaymentMeansType();
- PaymentMeansCodeType paymentDataType = xmlFactory.createPaymentMeansCodeType();
- paymentDataType.setValue(PaymentMeansCodeType.BANKACCOUNT);
- paymentData.setTypeCode(paymentDataType);
-
- TextType paymentInfo = xmlFactory.createTextType();
- paymentInfo.setValue(trans.getOwnPaymentInfoText());
- paymentData.getInformation().add(paymentInfo);
-
- CreditorFinancialAccountType bankAccount = xmlFactory.createCreditorFinancialAccountType();
- IDType iban = xmlFactory.createIDType();
- iban.setValue(trans.getOwnIBAN());
- bankAccount.setIBANID(iban);
- paymentData.setPayeePartyCreditorFinancialAccount(bankAccount);
-
- CreditorFinancialInstitutionType bankData = xmlFactory.createCreditorFinancialInstitutionType();
- IDType bicId = xmlFactory.createIDType();
- bicId.setValue(trans.getOwnBIC());
- bankData.setBICID(bicId);
- TextType bankName = xmlFactory.createTextType();
- bankName.setValue(trans.getOwnBankName());
- bankData.setName(bankName);
- paymentData.setPayeeSpecifiedCreditorFinancialInstitution(bankData);
- return paymentData;
- }
-
- private Collection getTradeTax() {
- List tradeTaxTypes = new ArrayList();
-
- HashMap VATPercentAmountMap = this.getVATPercentAmountMap();
- for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
-
- TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
- TaxTypeCodeType taxTypeCode = xmlFactory.createTaxTypeCodeType();
- taxTypeCode.setValue(TaxTypeCodeType.SALESTAX);
- tradeTax.setTypeCode(taxTypeCode);
-
- TaxCategoryCodeType taxCategoryCode = xmlFactory.createTaxCategoryCodeType();
- taxCategoryCode.setValue(TaxCategoryCodeType.STANDARDRATE);
- tradeTax.setCategoryCode(taxCategoryCode);
-
- VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
-
- PercentType taxPercent = xmlFactory.createPercentType();
- taxPercent.setValue(vatFormat(currentTaxPercent));
- tradeTax.setApplicablePercent(taxPercent);
-
- AmountType calculatedTaxAmount = xmlFactory.createAmountType();
- calculatedTaxAmount.setCurrencyID(trans.getInvoiceCurrency());
- calculatedTaxAmount.setValue(currencyFormat(amount.getCalculated()));
- tradeTax.getCalculatedAmount().add(calculatedTaxAmount);
-
- AmountType basisTaxAmount = xmlFactory.createAmountType();
- basisTaxAmount.setCurrencyID(trans.getInvoiceCurrency());
- basisTaxAmount.setValue(currencyFormat(amount.getBasis()));
- tradeTax.getBasisAmount().add(basisTaxAmount);
-
- tradeTaxTypes.add(tradeTax);
- }
-
- return tradeTaxTypes;
- }
-
- private Collection getHeaderAllowances() {
- List headerAllowances = new ArrayList();
-
- for (IZUGFeRDAllowanceCharge iAllowance : trans.getZFAllowances()) {
-
- TradeAllowanceChargeType allowance = xmlFactory.createTradeAllowanceChargeType();
-
- IndicatorType chargeIndicator = xmlFactory.createIndicatorType();
- chargeIndicator.setIndicator(false);
- allowance.setChargeIndicator(chargeIndicator);
-
- AmountType actualAmount = xmlFactory.createAmountType();
- actualAmount.setCurrencyID(trans.getInvoiceCurrency());
- actualAmount.setValue(currencyFormat(iAllowance.getTotalAmount()));
- allowance.getActualAmount().add(actualAmount);
-
- TextType reason = xmlFactory.createTextType();
- reason.setValue(iAllowance.getReason());
- allowance.setReason(reason);
-
- TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
-
- PercentType vatPercent = xmlFactory.createPercentType();
- vatPercent.setValue(currencyFormat(iAllowance.getTaxPercent()));
- tradeTax.setApplicablePercent(vatPercent);
-
- /* Only in extended
- AmountType basisAmount = xmlFactory.createAmountType();
- basisAmount.setCurrencyID(trans.getInvoiceCurrency());
- basisAmount.setValue(amount.getBasis());
- allowance.setBasisAmount(basisAmount);
- */
- TaxCategoryCodeType taxType = xmlFactory.createTaxCategoryCodeType();
- taxType.setValue(TaxCategoryCodeType.STANDARDRATE);
- tradeTax.setCategoryCode(taxType);
-
- TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
- taxCode.setValue(TaxTypeCodeType.SALESTAX);
- tradeTax.setTypeCode(taxCode);
-
- allowance.getCategoryTradeTax().add(tradeTax);
- headerAllowances.add(allowance);
-
- }
-
- return headerAllowances;
- }
-
- private Collection getHeaderCharges() {
- List headerCharges = new ArrayList();
-
- for (IZUGFeRDAllowanceCharge iCharge : trans.getZFCharges()) {
-
- TradeAllowanceChargeType charge = xmlFactory.createTradeAllowanceChargeType();
-
- IndicatorType chargeIndicator = xmlFactory.createIndicatorType();
- chargeIndicator.setIndicator(true);
- charge.setChargeIndicator(chargeIndicator);
-
- AmountType actualAmount = xmlFactory.createAmountType();
- actualAmount.setCurrencyID(trans.getInvoiceCurrency());
- actualAmount.setValue(currencyFormat(iCharge.getTotalAmount()));
- charge.getActualAmount().add(actualAmount);
-
- TextType reason = xmlFactory.createTextType();
- reason.setValue(iCharge.getReason());
- charge.setReason(reason);
-
- TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
-
- PercentType vatPercent = xmlFactory.createPercentType();
- vatPercent.setValue(currencyFormat(iCharge.getTaxPercent()));
- tradeTax.setApplicablePercent(vatPercent);
-
- /* Only in extended
- AmountType basisAmount = xmlFactory.createAmountType();
- basisAmount.setCurrencyID(trans.getInvoiceCurrency());
- basisAmount.setValue(amount.getBasis());
- allowance.setBasisAmount(basisAmount);
- */
- TaxCategoryCodeType taxType = xmlFactory.createTaxCategoryCodeType();
- taxType.setValue(TaxCategoryCodeType.STANDARDRATE);
- tradeTax.setCategoryCode(taxType);
-
- TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
- taxCode.setValue(TaxTypeCodeType.SALESTAX);
- tradeTax.setTypeCode(taxCode);
-
- charge.getCategoryTradeTax().add(tradeTax);
- headerCharges.add(charge);
-
- }
-
- return headerCharges;
- }
-
- private Collection getHeaderLogisticsServiceCharges() {
- List headerServiceCharge = new ArrayList();
-
- for (IZUGFeRDAllowanceCharge iServiceCharge : trans.getZFLogisticsServiceCharges()) {
-
- LogisticsServiceChargeType serviceCharge = xmlFactory.createLogisticsServiceChargeType();
-
- AmountType actualAmount = xmlFactory.createAmountType();
- actualAmount.setCurrencyID(trans.getInvoiceCurrency());
- actualAmount.setValue(currencyFormat(iServiceCharge.getTotalAmount()));
- serviceCharge.getAppliedAmount().add(actualAmount);
-
- TextType reason = xmlFactory.createTextType();
- reason.setValue(iServiceCharge.getReason());
- serviceCharge.getDescription().add(reason);
-
- TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
-
- PercentType vatPercent = xmlFactory.createPercentType();
- vatPercent.setValue(currencyFormat(iServiceCharge.getTaxPercent()));
- tradeTax.setApplicablePercent(vatPercent);
-
- /* Only in extended
- AmountType basisAmount = xmlFactory.createAmountType();
- basisAmount.setCurrencyID(trans.getInvoiceCurrency());
- basisAmount.setValue(amount.getBasis());
- allowance.setBasisAmount(basisAmount);
- */
- TaxCategoryCodeType taxType = xmlFactory.createTaxCategoryCodeType();
- taxType.setValue(TaxCategoryCodeType.STANDARDRATE);
- tradeTax.setCategoryCode(taxType);
-
- TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
- taxCode.setValue(TaxTypeCodeType.SALESTAX);
- tradeTax.setTypeCode(taxCode);
-
-
-
- serviceCharge.getAppliedTradeTax().add(tradeTax);
- headerServiceCharge.add(serviceCharge);
-
- }
-
- return headerServiceCharge;
- }
-
- private Collection getPaymentTerms() {
- List paymentTerms = new ArrayList();
-
- TradePaymentTermsType paymentTerm = xmlFactory.createTradePaymentTermsType();
- DateTimeType dueDate = xmlFactory.createDateTimeType();
- DateTimeType.DateTimeString dueDateString = xmlFactory.createDateTimeTypeDateTimeString();
- dueDateString.setFormat(DateTimeType.DateTimeString.DATE);
- dueDateString.setValue(zugferdDateFormat.format(trans.getDueDate()));
- dueDate.setDateTimeString(dueDateString);
- paymentTerm.setDueDateDateTime(dueDate);
-
- TextType paymentTermDescr = xmlFactory.createTextType();
-
- paymentTermDescr.setValue(trans.getPaymentTermDescription());
- paymentTerm.getDescription().add(paymentTermDescr);
-
- paymentTerms.add(paymentTerm);
-
- return paymentTerms;
- }
-
- private TradeSettlementMonetarySummationType getMonetarySummation() {
- TradeSettlementMonetarySummationType monetarySummation = xmlFactory.createTradeSettlementMonetarySummationType();
-
- // AllowanceTotalAmount = sum of all allowances
- AmountType allowanceTotalAmount = xmlFactory.createAmountType();
- allowanceTotalAmount.setCurrencyID(trans.getInvoiceCurrency());
- if(trans.getZFAllowances() != null){
- BigDecimal totalHeaderAllowance = BigDecimal.ZERO;
- for(IZUGFeRDAllowanceCharge headerAllowance : trans.getZFAllowances()){
- totalHeaderAllowance = headerAllowance.getTotalAmount().add(totalHeaderAllowance);
- }
- allowanceTotalAmount.setValue(currencyFormat(totalHeaderAllowance));
- }else{
- allowanceTotalAmount.setValue(currencyFormat(BigDecimal.ZERO));
- }
- monetarySummation.getAllowanceTotalAmount().add(allowanceTotalAmount);
-
- // ChargeTotalAmount = sum of all Logistic service charges + normal charges
- BigDecimal totalCharge = BigDecimal.ZERO;
- AmountType totalChargeAmount = xmlFactory.createAmountType();
- totalChargeAmount.setCurrencyID(trans.getInvoiceCurrency());
- if(trans.getZFLogisticsServiceCharges()!= null){
- for(IZUGFeRDAllowanceCharge logisticsServiceCharge : trans.getZFLogisticsServiceCharges()){
- totalCharge = logisticsServiceCharge.getTotalAmount().add(totalCharge);
- }
- }
- if(trans.getZFCharges()!= null){
- for(IZUGFeRDAllowanceCharge charge : trans.getZFCharges()){
- totalCharge = charge.getTotalAmount().add(totalCharge);
- }
- }
-
- totalChargeAmount.setValue(currencyFormat(totalCharge));
-
- monetarySummation.getChargeTotalAmount().add(totalChargeAmount);
-
- /*AmountType chargeTotalAmount = xmlFactory.createAmountType();
- chargeTotalAmount.setCurrencyID(trans.getInvoiceCurrency());
- chargeTotalAmount.setValue(currencyFormat(BigDecimal.ZERO));
- monetarySummation.getChargeTotalAmount().add(chargeTotalAmount);*/
-
- AmountType lineTotalAmount = xmlFactory.createAmountType();
- lineTotalAmount.setCurrencyID(trans.getInvoiceCurrency());
- lineTotalAmount.setValue(currencyFormat(totals.getLineTotal()));
- monetarySummation.getLineTotalAmount().add(lineTotalAmount);
-
- AmountType taxBasisTotalAmount = xmlFactory.createAmountType();
- taxBasisTotalAmount.setCurrencyID(trans.getInvoiceCurrency());
- taxBasisTotalAmount.setValue(currencyFormat(totals.getTotalNet()));
- monetarySummation.getTaxBasisTotalAmount().add(taxBasisTotalAmount);
-
- AmountType taxTotalAmount = xmlFactory.createAmountType();
- taxTotalAmount.setCurrencyID(trans.getInvoiceCurrency());
- taxTotalAmount.setValue(currencyFormat(totals.getTaxTotal()));
- monetarySummation.getTaxTotalAmount().add(taxTotalAmount);
-
- AmountType grandTotalAmount = xmlFactory.createAmountType();
- grandTotalAmount.setCurrencyID(trans.getInvoiceCurrency());
- grandTotalAmount.setValue(currencyFormat(totals.getTotalGross()));
- monetarySummation.getGrandTotalAmount().add(grandTotalAmount);
-
- AmountType duePayableAmount = xmlFactory.createAmountType();
- duePayableAmount.setCurrencyID(trans.getInvoiceCurrency());
- duePayableAmount.setValue(currencyFormat(totals.getTotalGross()));
- monetarySummation.getDuePayableAmount().add(duePayableAmount);
-
- return monetarySummation;
- }
-
- private Collection getLineItems() {
-
- ArrayList lineItems = new ArrayList();
- int lineID = 0;
- for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
- lineID++;
- LineCalc lc = new LineCalc(currentItem);
- SupplyChainTradeLineItemType lineItem = xmlFactory.createSupplyChainTradeLineItemType();
-
- DocumentLineDocumentType lineDocument = xmlFactory.createDocumentLineDocumentType();
- IDType lineNumber = xmlFactory.createIDType();
- lineNumber.setValue(Integer.toString(lineID));
- lineDocument.setLineID(lineNumber);
- lineItem.setAssociatedDocumentLineDocument(lineDocument);
-
- SupplyChainTradeAgreementType tradeAgreement = xmlFactory.createSupplyChainTradeAgreementType();
- TradePriceType grossTradePrice = xmlFactory.createTradePriceType();
- QuantityType grossQuantity = xmlFactory.createQuantityType();
- grossQuantity.setUnitCode(currentItem.getProduct().getUnit());
- grossQuantity.setValue(quantityFormat(BigDecimal.ONE));
- grossTradePrice.setBasisQuantity(grossQuantity);
-
- AmountType grossChargeAmount = xmlFactory.createAmountType();
- grossChargeAmount.setCurrencyID(trans.getInvoiceCurrency());
- grossChargeAmount.setValue(priceFormat(currentItem.getPrice()));
- grossTradePrice.getChargeAmount().add(grossChargeAmount);
- tradeAgreement.getGrossPriceProductTradePrice().add(grossTradePrice);
-
- if(currentItem.getItemAllowances() != null){
- for(IZUGFeRDAllowanceCharge itemAllowance : currentItem.getItemAllowances()){
- TradeAllowanceChargeType eItemAllowance = xmlFactory.createTradeAllowanceChargeType();
- IndicatorType chargeIndicator = xmlFactory.createIndicatorType();
- chargeIndicator.setIndicator(false);
- eItemAllowance.setChargeIndicator(chargeIndicator);
- AmountType actualAmount = xmlFactory.createAmountType();
- actualAmount.setCurrencyID(trans.getInvoiceCurrency());
- actualAmount.setValue(priceFormat(itemAllowance.getTotalAmount().divide(currentItem.getQuantity(), 4, BigDecimal.ROUND_HALF_UP)));
- eItemAllowance.getActualAmount().add(actualAmount);
- TextType reason = xmlFactory.createTextType();
- reason.setValue(itemAllowance.getReason());
- eItemAllowance.setReason(reason);
- grossTradePrice.getAppliedTradeAllowanceCharge().add(eItemAllowance);
- }
- }
-
- if(currentItem.getItemCharges() != null){
- for(IZUGFeRDAllowanceCharge itemCharge : currentItem.getItemCharges()){
- TradeAllowanceChargeType eItemCharge = xmlFactory.createTradeAllowanceChargeType();
- AmountType actualAmount = xmlFactory.createAmountType();
- actualAmount.setCurrencyID(trans.getInvoiceCurrency());
- actualAmount.setValue(priceFormat(itemCharge.getTotalAmount().divide(currentItem.getQuantity(), 4, BigDecimal.ROUND_HALF_UP)));
- eItemCharge.getActualAmount().add(actualAmount);
- TextType reason = xmlFactory.createTextType();
- reason.setValue(itemCharge.getReason());
- eItemCharge.setReason(reason);
- IndicatorType chargeIndicator = xmlFactory.createIndicatorType();
- chargeIndicator.setIndicator(true);
- eItemCharge.setChargeIndicator(chargeIndicator);
- grossTradePrice.getAppliedTradeAllowanceCharge().add(eItemCharge);
- }
- }
-
- TradePriceType netTradePrice = xmlFactory.createTradePriceType();
- QuantityType netQuantity = xmlFactory.createQuantityType();
- netQuantity.setUnitCode(currentItem.getProduct().getUnit());
- netQuantity.setValue(quantityFormat(BigDecimal.ONE));
- netTradePrice.setBasisQuantity(netQuantity);
-
- AmountType netChargeAmount = xmlFactory.createAmountType();
- netChargeAmount.setCurrencyID(trans.getInvoiceCurrency());
- netChargeAmount.setValue(priceFormat(lc.getItemNetAmount()));
- netTradePrice.getChargeAmount().add(netChargeAmount);
- tradeAgreement.getNetPriceProductTradePrice().add(netTradePrice);
-
- lineItem.setSpecifiedSupplyChainTradeAgreement(tradeAgreement);
-
- SupplyChainTradeDeliveryType tradeDelivery = xmlFactory.createSupplyChainTradeDeliveryType();
- QuantityType billedQuantity = xmlFactory.createQuantityType();
- billedQuantity.setUnitCode(currentItem.getProduct().getUnit());
- billedQuantity.setValue(quantityFormat(currentItem.getQuantity()));
- tradeDelivery.setBilledQuantity(billedQuantity);
- lineItem.setSpecifiedSupplyChainTradeDelivery(tradeDelivery);
-
- SupplyChainTradeSettlementType tradeSettlement = xmlFactory.createSupplyChainTradeSettlementType();
- TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
-
- TaxCategoryCodeType taxCategoryCode = xmlFactory.createTaxCategoryCodeType();
- taxCategoryCode.setValue(TaxCategoryCodeType.STANDARDRATE);
- tradeTax.setCategoryCode(taxCategoryCode);
-
- TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
- taxCode.setValue(TaxTypeCodeType.SALESTAX);
- tradeTax.setTypeCode(taxCode);
-
- PercentType taxPercent = xmlFactory.createPercentType();
- taxPercent.setValue(vatFormat(currentItem.getProduct().getVATPercent()));
- tradeTax.setApplicablePercent(taxPercent);
- tradeSettlement.getApplicableTradeTax().add(tradeTax);
-
- TradeSettlementMonetarySummationType monetarySummation = xmlFactory.createTradeSettlementMonetarySummationType();
- AmountType itemAmount = xmlFactory.createAmountType();
- itemAmount.setCurrencyID(trans.getInvoiceCurrency());
- itemAmount.setValue(currencyFormat(lc.getItemTotalNetAmount()));
- monetarySummation.getLineTotalAmount().add(itemAmount);
- tradeSettlement.setSpecifiedTradeSettlementMonetarySummation(monetarySummation);
-
- lineItem.setSpecifiedSupplyChainTradeSettlement(tradeSettlement);
-
- TradeProductType tradeProduct = xmlFactory.createTradeProductType();
- TextType productName = xmlFactory.createTextType();
- productName.setValue(currentItem.getProduct().getName());
- tradeProduct.getName().add(productName);
-
- TextType productDescription = xmlFactory.createTextType();
- productDescription.setValue(currentItem.getProduct().getDescription());
- tradeProduct.getDescription().add(productDescription);
- lineItem.setSpecifiedTradeProduct(tradeProduct);
-
- lineItems.add(lineItem);
- }
-
- return lineItems;
-
- }
-
- /**
- * which taxes have been used with which amounts in this transaction, empty
- * for no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to
- * 19% VAT (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT)
- * 190 Eur
- *
- * @return
- *
- */
- private HashMap getVATPercentAmountMap() {
- return getVATPercentAmountMap(false);
- }
-
- private HashMap getVATPercentAmountMap(Boolean itemOnly){
- HashMap hm = new HashMap();
-
- for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
- BigDecimal percent = currentItem.getProduct().getVATPercent();
- LineCalc lc = new LineCalc(currentItem);
- VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount());
- VATAmount current = hm.get(percent);
- if (current == null) {
- hm.put(percent, itemVATAmount);
- } else {
- hm.put(percent, current.add(itemVATAmount));
- }
- }
- if(itemOnly){
- return hm;
- }
- if(trans.getZFAllowances() != null){
- for (IZUGFeRDAllowanceCharge headerAllowance : trans.getZFAllowances()){
- BigDecimal percent = headerAllowance.getTaxPercent();
- VATAmount itemVATAmount = new VATAmount(headerAllowance.getTotalAmount(), headerAllowance.getTotalAmount().multiply(percent).divide(new BigDecimal(100)));
- VATAmount current = hm.get(percent);
- if (current == null) {
- hm.put(percent, itemVATAmount);
- } else {
- hm.put(percent, current.subtract(itemVATAmount));
- }
- }
- }
-
- if(trans.getZFLogisticsServiceCharges()!= null){
- for (IZUGFeRDAllowanceCharge logisticsServiceCharge : trans.getZFLogisticsServiceCharges()){
- BigDecimal percent = logisticsServiceCharge.getTaxPercent();
- VATAmount itemVATAmount = new VATAmount(logisticsServiceCharge.getTotalAmount(), logisticsServiceCharge.getTotalAmount().multiply(percent).divide(new BigDecimal(100)));
- VATAmount current = hm.get(percent);
- if (current == null) {
- hm.put(percent, itemVATAmount);
- } else {
- hm.put(percent, current.add(itemVATAmount));
- }
- }
- }
-
- if(trans.getZFCharges()!= null){
- for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()){
- BigDecimal percent = charge.getTaxPercent();
- VATAmount itemVATAmount = new VATAmount(charge.getTotalAmount(), charge.getTotalAmount().multiply(percent).divide(new BigDecimal(100)));
- VATAmount current = hm.get(percent);
- if (current == null) {
- hm.put(percent, itemVATAmount);
- } else {
- hm.put(percent, current.add(itemVATAmount));
- }
- }
- }
-
- return hm;
- }
-
- /**
- * Embeds the Zugferd XML structure in a file named ZUGFeRD-invoice.xml.
- *
- * @param doc PDDocument to attach an XML invoice to
- * @param trans a IZUGFeRDExportableTransaction that provides the data-model
- * to populate the XML. This parameter may be null, if so the XML data
- * should hav ebeen set via
- * setZUGFeRDXMLData(byte[] zugferdData)
- */
- public void PDFattachZugferdFile(PDDocument doc, IZUGFeRDExportableTransaction trans) throws IOException, JAXBException {
-
- if (zugferdData == null) // XML ZUGFeRD data not set externally, needs to be built
- {
- // create a dummy file stream, this would probably normally be a
- // FileInputStream
-
- byte[] zugferdRaw = getZugferdXMLForTransaction(trans).getBytes(); //$NON-NLS-1$
-
- if ((zugferdRaw[0] == (byte) 0xEF) && (zugferdRaw[1] == (byte) 0xBB) && (zugferdRaw[2] == (byte) 0xBF)) {
- // I don't like BOMs, lets remove it
- zugferdData = new byte[zugferdRaw.length - 3];
- System.arraycopy(zugferdRaw, 3, zugferdData, 0, zugferdRaw.length - 3);
- } else {
- zugferdData = zugferdRaw;
- }
- }
-
- PDFAttachGenericFile(doc, "ZUGFeRD-invoice.xml", "Alternative", "Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)", "text/xml", zugferdData);
- }
-
- /**
- * Embeds an external file (generic - any type allowed) in the PDF.
- *
- * @param doc PDDocument to attach the file to.
- * @param filename name of the file that will become attachment name in the
- * PDF
- * @param relationship how the file relates to the content, e.g.
- * "Alternative"
- * @param description Human-readable description of the file content
- * @param subType type of the data e.g. could be "text/xml" - mime like
- * @param data the binary data of the file/attachment
- */
- public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description, String subType, byte[] data)
- throws IOException {
- PDComplexFileSpecification fs = new PDComplexFileSpecification();
- fs.setFile(filename);
-
- COSDictionary dict = fs.getCOSDictionary();
- dict.setName("AFRelationship", relationship);
- dict.setString("UF", filename);
- dict.setString("Desc", description);
-
- ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
- PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
- ef.setSubtype(subType);
- ef.setSize(data.length);
- ef.setCreationDate(new GregorianCalendar());
-
- ef.setModDate(GregorianCalendar.getInstance());
-
- fs.setEmbeddedFile(ef);
-
- // In addition make sure the embedded file is set under /UF
- dict = fs.getCOSDictionary();
- COSDictionary efDict = (COSDictionary) dict.getDictionaryObject(COSName.EF);
- COSBase lowerLevelFile = efDict.getItem(COSName.F);
- efDict.setItem(COSName.UF, lowerLevelFile);
-
- // now add the entry to the embedded file tree and set in the document.
- PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
- PDEmbeddedFilesNameTreeNode efTree = names.getEmbeddedFiles();
- if (efTree == null) {
- efTree = new PDEmbeddedFilesNameTreeNode();
- }
-
- Map namesMap = new HashMap();
- Map oldNamesMap = efTree.getNames();
- if (oldNamesMap != null) {
- for (String key : oldNamesMap.keySet()) {
- namesMap.put(key, oldNamesMap.get(key));
- }
- }
- namesMap.put(filename, fs);
- efTree.setNames(namesMap);
-
- names.setEmbeddedFiles(efTree);
- doc.getDocumentCatalog().setNames(names);
-
- // AF entry (Array) in catalog with the FileSpec
- COSArray cosArray = (COSArray) doc.getDocumentCatalog().getCOSDictionary().getItem("AF");
- if (cosArray == null) {
- cosArray = new COSArray();
- }
- cosArray.add(fs);
- doc.getDocumentCatalog().getCOSDictionary().setItem("AF", cosArray);
- }
-
- /**
- * Sets the ZUGFeRD XML data to be attached as a single byte array. This is
- * useful for use-cases where the XML has already been produced by some
- * external API or component.
- *
- * @param zugferdData XML data to be set as a byte array (XML file in raw
- * form).
- */
- public void setZUGFeRDXMLData(byte[] zugferdData) {
- this.zugferdData = zugferdData;
- }
-
- /**
- * Sets the ZUGFeRD conformance level (override).
- *
- * @param ZUGFeRDConformanceLevel the new conformance level
- */
- public void setZUGFeRDConformanceLevel(String ZUGFeRDConformanceLevel) {
- this.ZUGFeRDConformanceLevel = ZUGFeRDConformanceLevel;
- }
-
- /**
- * *
- * This will add both the RDF-indication which embedded file is Zugferd and
- * the neccessary PDF/A schema extension description to be able to add this
- * information to RDF
- *
- * @param metadata
- */
- private void addZugferdXMP(XMPMetadata metadata) {
-
- XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, this.ZUGFeRDConformanceLevel);
- zf.setAbout(""); //$NON-NLS-1$
- metadata.addSchema(zf);
-
- XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata);
- pdfaex.setAbout(""); //$NON-NLS-1$
- metadata.addSchema(pdfaex);
-
- }
+ /*
+ * Only in extended AmountType basisAmount =
+ * xmlFactory.createAmountType();
+ * basisAmount.setCurrencyID(trans.getInvoiceCurrency());
+ * basisAmount.setValue(amount.getBasis());
+ * allowance.setBasisAmount(basisAmount);
+ */
+ TaxCategoryCodeType taxType = xmlFactory
+ .createTaxCategoryCodeType();
+ taxType.setValue(TaxCategoryCodeType.STANDARDRATE);
+ tradeTax.setCategoryCode(taxType);
+
+ TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
+ taxCode.setValue(TaxTypeCodeType.SALESTAX);
+ tradeTax.setTypeCode(taxCode);
+
+ charge.getCategoryTradeTax().add(tradeTax);
+ headerCharges.add(charge);
+
+ }
+
+ return headerCharges;
+ }
+
+ private Collection getHeaderLogisticsServiceCharges() {
+ List headerServiceCharge = new ArrayList();
+
+ for (IZUGFeRDAllowanceCharge iServiceCharge : trans
+ .getZFLogisticsServiceCharges()) {
+
+ LogisticsServiceChargeType serviceCharge = xmlFactory
+ .createLogisticsServiceChargeType();
+
+ AmountType actualAmount = xmlFactory.createAmountType();
+ actualAmount.setCurrencyID(currency);
+ actualAmount.setValue(currencyFormat(iServiceCharge
+ .getTotalAmount()));
+ serviceCharge.getAppliedAmount().add(actualAmount);
+
+ TextType reason = xmlFactory.createTextType();
+ reason.setValue(iServiceCharge.getReason());
+ serviceCharge.getDescription().add(reason);
+
+ TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
+
+ PercentType vatPercent = xmlFactory.createPercentType();
+ vatPercent.setValue(currencyFormat(iServiceCharge.getTaxPercent()));
+ tradeTax.setApplicablePercent(vatPercent);
+
+ /*
+ * Only in extended AmountType basisAmount =
+ * xmlFactory.createAmountType();
+ * basisAmount.setCurrencyID(trans.getInvoiceCurrency());
+ * basisAmount.setValue(amount.getBasis());
+ * allowance.setBasisAmount(basisAmount);
+ */
+ TaxCategoryCodeType taxType = xmlFactory
+ .createTaxCategoryCodeType();
+ taxType.setValue(TaxCategoryCodeType.STANDARDRATE);
+ tradeTax.setCategoryCode(taxType);
+
+ TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
+ taxCode.setValue(TaxTypeCodeType.SALESTAX);
+ tradeTax.setTypeCode(taxCode);
+
+ serviceCharge.getAppliedTradeTax().add(tradeTax);
+ headerServiceCharge.add(serviceCharge);
+
+ }
+
+ return headerServiceCharge;
+ }
+
+ private Collection getPaymentTerms() {
+ List paymentTerms = new ArrayList();
+
+ TradePaymentTermsType paymentTerm = xmlFactory
+ .createTradePaymentTermsType();
+ DateTimeType dueDate = xmlFactory.createDateTimeType();
+ DateTimeType.DateTimeString dueDateString = xmlFactory
+ .createDateTimeTypeDateTimeString();
+ dueDateString.setFormat(DateTimeType.DateTimeString.DATE);
+ dueDateString.setValue(zugferdDateFormat.format(trans.getDueDate()));
+ dueDate.setDateTimeString(dueDateString);
+ paymentTerm.setDueDateDateTime(dueDate);
+
+ TextType paymentTermDescr = xmlFactory.createTextType();
+
+ String paymentTermDescription = trans.getPaymentTermDescription();
+ if (paymentTermDescription == null) {
+ paymentTermDescription = "";
+ }
+ paymentTermDescr.setValue(paymentTermDescription);
+ paymentTerm.getDescription().add(paymentTermDescr);
+
+ paymentTerms.add(paymentTerm);
+
+ return paymentTerms;
+ }
+
+ private TradeSettlementMonetarySummationType getMonetarySummation() {
+ TradeSettlementMonetarySummationType monetarySummation = xmlFactory
+ .createTradeSettlementMonetarySummationType();
+
+ // AllowanceTotalAmount = sum of all allowances
+ AmountType allowanceTotalAmount = xmlFactory.createAmountType();
+ allowanceTotalAmount.setCurrencyID(currency);
+ if (trans.getZFAllowances() != null) {
+ BigDecimal totalHeaderAllowance = BigDecimal.ZERO;
+ for (IZUGFeRDAllowanceCharge headerAllowance : trans
+ .getZFAllowances()) {
+ totalHeaderAllowance = headerAllowance.getTotalAmount().add(
+ totalHeaderAllowance);
+ }
+ allowanceTotalAmount.setValue(currencyFormat(totalHeaderAllowance));
+ } else {
+ allowanceTotalAmount.setValue(currencyFormat(BigDecimal.ZERO));
+ }
+ monetarySummation.getAllowanceTotalAmount().add(allowanceTotalAmount);
+
+ // ChargeTotalAmount = sum of all Logistic service charges + normal
+ // charges
+ BigDecimal totalCharge = BigDecimal.ZERO;
+ AmountType totalChargeAmount = xmlFactory.createAmountType();
+ totalChargeAmount.setCurrencyID(currency);
+ if (trans.getZFLogisticsServiceCharges() != null) {
+ for (IZUGFeRDAllowanceCharge logisticsServiceCharge : trans
+ .getZFLogisticsServiceCharges()) {
+ totalCharge = logisticsServiceCharge.getTotalAmount().add(
+ totalCharge);
+ }
+ }
+ if (trans.getZFCharges() != null) {
+ for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
+ totalCharge = charge.getTotalAmount().add(totalCharge);
+ }
+ }
+
+ totalChargeAmount.setValue(currencyFormat(totalCharge));
+
+ monetarySummation.getChargeTotalAmount().add(totalChargeAmount);
+
+ /*
+ * AmountType chargeTotalAmount = xmlFactory.createAmountType();
+ * chargeTotalAmount.setCurrencyID(trans.getInvoiceCurrency());
+ * chargeTotalAmount.setValue(currencyFormat(BigDecimal.ZERO));
+ * monetarySummation.getChargeTotalAmount().add(chargeTotalAmount);
+ */
+
+ AmountType lineTotalAmount = xmlFactory.createAmountType();
+ lineTotalAmount.setCurrencyID(currency);
+ lineTotalAmount.setValue(currencyFormat(totals.getLineTotal()));
+ monetarySummation.getLineTotalAmount().add(lineTotalAmount);
+
+ AmountType taxBasisTotalAmount = xmlFactory.createAmountType();
+ taxBasisTotalAmount.setCurrencyID(currency);
+ taxBasisTotalAmount.setValue(currencyFormat(totals.getTotalNet()));
+ monetarySummation.getTaxBasisTotalAmount().add(taxBasisTotalAmount);
+
+ AmountType taxTotalAmount = xmlFactory.createAmountType();
+ taxTotalAmount.setCurrencyID(currency);
+ taxTotalAmount.setValue(currencyFormat(totals.getTaxTotal()));
+ monetarySummation.getTaxTotalAmount().add(taxTotalAmount);
+
+ AmountType grandTotalAmount = xmlFactory.createAmountType();
+ grandTotalAmount.setCurrencyID(currency);
+ grandTotalAmount.setValue(currencyFormat(totals.getTotalGross()));
+ monetarySummation.getGrandTotalAmount().add(grandTotalAmount);
+
+ AmountType duePayableAmount = xmlFactory.createAmountType();
+ duePayableAmount.setCurrencyID(currency);
+ duePayableAmount.setValue(currencyFormat(totals.getTotalGross()));
+ monetarySummation.getDuePayableAmount().add(duePayableAmount);
+
+ return monetarySummation;
+ }
+
+ private Collection getLineItems() {
+
+ ArrayList lineItems = new ArrayList();
+ int lineID = 0;
+ for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
+ lineID++;
+ LineCalc lc = new LineCalc(currentItem);
+ SupplyChainTradeLineItemType lineItem = xmlFactory
+ .createSupplyChainTradeLineItemType();
+
+ DocumentLineDocumentType lineDocument = xmlFactory
+ .createDocumentLineDocumentType();
+ IDType lineNumber = xmlFactory.createIDType();
+ lineNumber.setValue(Integer.toString(lineID));
+ lineDocument.setLineID(lineNumber);
+ lineItem.setAssociatedDocumentLineDocument(lineDocument);
+
+ SupplyChainTradeAgreementType tradeAgreement = xmlFactory
+ .createSupplyChainTradeAgreementType();
+ TradePriceType grossTradePrice = xmlFactory.createTradePriceType();
+ QuantityType grossQuantity = xmlFactory.createQuantityType();
+ grossQuantity.setUnitCode(currentItem.getProduct().getUnit());
+ grossQuantity.setValue(quantityFormat(BigDecimal.ONE));
+ grossTradePrice.setBasisQuantity(grossQuantity);
+
+ AmountType grossChargeAmount = xmlFactory.createAmountType();
+ grossChargeAmount.setCurrencyID(currency);
+ grossChargeAmount.setValue(priceFormat(currentItem.getPrice()));
+ grossTradePrice.getChargeAmount().add(grossChargeAmount);
+ tradeAgreement.getGrossPriceProductTradePrice()
+ .add(grossTradePrice);
+
+ if (currentItem.getItemAllowances() != null) {
+ for (IZUGFeRDAllowanceCharge itemAllowance : currentItem
+ .getItemAllowances()) {
+ TradeAllowanceChargeType eItemAllowance = xmlFactory
+ .createTradeAllowanceChargeType();
+ IndicatorType chargeIndicator = xmlFactory
+ .createIndicatorType();
+ chargeIndicator.setIndicator(false);
+ eItemAllowance.setChargeIndicator(chargeIndicator);
+ AmountType actualAmount = xmlFactory.createAmountType();
+ actualAmount.setCurrencyID(currency);
+ actualAmount.setValue(priceFormat(itemAllowance
+ .getTotalAmount().divide(currentItem.getQuantity(),
+ 4, BigDecimal.ROUND_HALF_UP)));
+ eItemAllowance.getActualAmount().add(actualAmount);
+ TextType reason = xmlFactory.createTextType();
+ reason.setValue(itemAllowance.getReason());
+ eItemAllowance.setReason(reason);
+ grossTradePrice.getAppliedTradeAllowanceCharge().add(
+ eItemAllowance);
+ }
+ }
+
+ if (currentItem.getItemCharges() != null) {
+ for (IZUGFeRDAllowanceCharge itemCharge : currentItem
+ .getItemCharges()) {
+ TradeAllowanceChargeType eItemCharge = xmlFactory
+ .createTradeAllowanceChargeType();
+ AmountType actualAmount = xmlFactory.createAmountType();
+ actualAmount.setCurrencyID(currency);
+ actualAmount.setValue(priceFormat(itemCharge
+ .getTotalAmount().divide(currentItem.getQuantity(),
+ 4, BigDecimal.ROUND_HALF_UP)));
+ eItemCharge.getActualAmount().add(actualAmount);
+ TextType reason = xmlFactory.createTextType();
+ reason.setValue(itemCharge.getReason());
+ eItemCharge.setReason(reason);
+ IndicatorType chargeIndicator = xmlFactory
+ .createIndicatorType();
+ chargeIndicator.setIndicator(true);
+ eItemCharge.setChargeIndicator(chargeIndicator);
+ grossTradePrice.getAppliedTradeAllowanceCharge().add(
+ eItemCharge);
+ }
+ }
+
+ TradePriceType netTradePrice = xmlFactory.createTradePriceType();
+ QuantityType netQuantity = xmlFactory.createQuantityType();
+ netQuantity.setUnitCode(currentItem.getProduct().getUnit());
+ netQuantity.setValue(quantityFormat(BigDecimal.ONE));
+ netTradePrice.setBasisQuantity(netQuantity);
+
+ AmountType netChargeAmount = xmlFactory.createAmountType();
+ netChargeAmount.setCurrencyID(currency);
+ netChargeAmount.setValue(priceFormat(lc.getItemNetAmount()));
+ netTradePrice.getChargeAmount().add(netChargeAmount);
+ tradeAgreement.getNetPriceProductTradePrice().add(netTradePrice);
+
+ lineItem.setSpecifiedSupplyChainTradeAgreement(tradeAgreement);
+
+ SupplyChainTradeDeliveryType tradeDelivery = xmlFactory
+ .createSupplyChainTradeDeliveryType();
+ QuantityType billedQuantity = xmlFactory.createQuantityType();
+ billedQuantity.setUnitCode(currentItem.getProduct().getUnit());
+ billedQuantity.setValue(quantityFormat(currentItem.getQuantity()));
+ tradeDelivery.setBilledQuantity(billedQuantity);
+ lineItem.setSpecifiedSupplyChainTradeDelivery(tradeDelivery);
+
+ SupplyChainTradeSettlementType tradeSettlement = xmlFactory
+ .createSupplyChainTradeSettlementType();
+ TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
+
+ TaxCategoryCodeType taxCategoryCode = xmlFactory
+ .createTaxCategoryCodeType();
+ taxCategoryCode.setValue(TaxCategoryCodeType.STANDARDRATE);
+ tradeTax.setCategoryCode(taxCategoryCode);
+
+ TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
+ taxCode.setValue(TaxTypeCodeType.SALESTAX);
+ tradeTax.setTypeCode(taxCode);
+
+ PercentType taxPercent = xmlFactory.createPercentType();
+ taxPercent.setValue(vatFormat(currentItem.getProduct()
+ .getVATPercent()));
+ tradeTax.setApplicablePercent(taxPercent);
+ tradeSettlement.getApplicableTradeTax().add(tradeTax);
+
+ TradeSettlementMonetarySummationType monetarySummation = xmlFactory
+ .createTradeSettlementMonetarySummationType();
+ AmountType itemAmount = xmlFactory.createAmountType();
+ itemAmount.setCurrencyID(currency);
+ itemAmount.setValue(currencyFormat(lc.getItemTotalNetAmount()));
+ monetarySummation.getLineTotalAmount().add(itemAmount);
+ tradeSettlement
+ .setSpecifiedTradeSettlementMonetarySummation(monetarySummation);
+
+ lineItem.setSpecifiedSupplyChainTradeSettlement(tradeSettlement);
+
+ TradeProductType tradeProduct = xmlFactory.createTradeProductType();
+ TextType productName = xmlFactory.createTextType();
+ productName.setValue(currentItem.getProduct().getName());
+ tradeProduct.getName().add(productName);
+
+ TextType productDescription = xmlFactory.createTextType();
+ productDescription.setValue(currentItem.getProduct()
+ .getDescription());
+ tradeProduct.getDescription().add(productDescription);
+ lineItem.setSpecifiedTradeProduct(tradeProduct);
+
+ lineItems.add(lineItem);
+ }
+
+ return lineItems;
+
+ }
+
+ /**
+ * which taxes have been used with which amounts in this transaction, empty
+ * for no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to
+ * 19% VAT (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT)
+ * 190 Eur
+ *
+ * @return
+ *
+ */
+ private HashMap getVATPercentAmountMap() {
+ return getVATPercentAmountMap(false);
+ }
+
+ private HashMap getVATPercentAmountMap(
+ Boolean itemOnly) {
+ HashMap hm = new HashMap();
+
+ for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
+ BigDecimal percent = currentItem.getProduct().getVATPercent();
+ LineCalc lc = new LineCalc(currentItem);
+ VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(),
+ lc.getItemTotalVATAmount());
+ VATAmount current = hm.get(percent);
+ if (current == null) {
+ hm.put(percent, itemVATAmount);
+ } else {
+ hm.put(percent, current.add(itemVATAmount));
+ }
+ }
+ if (itemOnly) {
+ return hm;
+ }
+ if (trans.getZFAllowances() != null) {
+ for (IZUGFeRDAllowanceCharge headerAllowance : trans
+ .getZFAllowances()) {
+ BigDecimal percent = headerAllowance.getTaxPercent();
+ VATAmount itemVATAmount = new VATAmount(
+ headerAllowance.getTotalAmount(), headerAllowance
+ .getTotalAmount().multiply(percent)
+ .divide(new BigDecimal(100)));
+ VATAmount current = hm.get(percent);
+ if (current == null) {
+ hm.put(percent, itemVATAmount);
+ } else {
+ hm.put(percent, current.subtract(itemVATAmount));
+ }
+ }
+ }
+
+ if (trans.getZFLogisticsServiceCharges() != null) {
+ for (IZUGFeRDAllowanceCharge logisticsServiceCharge : trans
+ .getZFLogisticsServiceCharges()) {
+ BigDecimal percent = logisticsServiceCharge.getTaxPercent();
+ VATAmount itemVATAmount = new VATAmount(
+ logisticsServiceCharge.getTotalAmount(),
+ logisticsServiceCharge.getTotalAmount()
+ .multiply(percent).divide(new BigDecimal(100)));
+ VATAmount current = hm.get(percent);
+ if (current == null) {
+ hm.put(percent, itemVATAmount);
+ } else {
+ hm.put(percent, current.add(itemVATAmount));
+ }
+ }
+ }
+
+ if (trans.getZFCharges() != null) {
+ for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
+ BigDecimal percent = charge.getTaxPercent();
+ VATAmount itemVATAmount = new VATAmount(
+ charge.getTotalAmount(), charge.getTotalAmount()
+ .multiply(percent).divide(new BigDecimal(100)));
+ VATAmount current = hm.get(percent);
+ if (current == null) {
+ hm.put(percent, itemVATAmount);
+ } else {
+ hm.put(percent, current.add(itemVATAmount));
+ }
+ }
+ }
+
+ return hm;
+ }
+
+ /**
+ * Embeds the Zugferd XML structure in a file named ZUGFeRD-invoice.xml.
+ *
+ * @param doc
+ * PDDocument to attach an XML invoice to
+ * @param trans
+ * a IZUGFeRDExportableTransaction that provides the data-model
+ * to populate the XML. This parameter may be null, if so the XML
+ * data should hav ebeen set via
+ * setZUGFeRDXMLData(byte[] zugferdData)
+ */
+ public void PDFattachZugferdFile(IZUGFeRDExportableTransaction trans)
+ throws IOException, JAXBException {
+
+ if (zugferdData == null) // XML ZUGFeRD data not set externally, needs
+ // to be built
+ {
+ // create a dummy file stream, this would probably normally be a
+ // FileInputStream
+
+ byte[] zugferdRaw = getZugferdXMLForTransaction(trans).getBytes(); //$NON-NLS-1$
+
+ if ((zugferdRaw[0] == (byte) 0xEF)
+ && (zugferdRaw[1] == (byte) 0xBB)
+ && (zugferdRaw[2] == (byte) 0xBF)) {
+ // I don't like BOMs, lets remove it
+ zugferdData = new byte[zugferdRaw.length - 3];
+ System.arraycopy(zugferdRaw, 3, zugferdData, 0,
+ zugferdRaw.length - 3);
+ } else {
+ zugferdData = zugferdRaw;
+ }
+ }
+
+ PDFAttachGenericFile(
+ doc,
+ "ZUGFeRD-invoice.xml",
+ "Alternative",
+ "Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
+ "text/xml", zugferdData);
+ }
+
+ public void export(String ZUGFeRDfilename) {
+ try {
+ doc.save(ZUGFeRDfilename);
+ } catch (COSVisitorException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Embeds an external file (generic - any type allowed) in the PDF.
+ *
+ * @param doc
+ * PDDocument to attach the file to.
+ * @param filename
+ * name of the file that will become attachment name in the PDF
+ * @param relationship
+ * how the file relates to the content, e.g. "Alternative"
+ * @param description
+ * Human-readable description of the file content
+ * @param subType
+ * type of the data e.g. could be "text/xml" - mime like
+ * @param data
+ * the binary data of the file/attachment
+ */
+ public void PDFAttachGenericFile(PDDocument doc, String filename,
+ String relationship, String description, String subType, byte[] data)
+ throws IOException {
+ PDComplexFileSpecification fs = new PDComplexFileSpecification();
+ fs.setFile(filename);
+
+ COSDictionary dict = fs.getCOSDictionary();
+ dict.setName("AFRelationship", relationship);
+ dict.setString("UF", filename);
+ dict.setString("Desc", description);
+
+ ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
+ PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
+ ef.setSubtype(subType);
+ ef.setSize(data.length);
+ ef.setCreationDate(new GregorianCalendar());
+
+ ef.setModDate(GregorianCalendar.getInstance());
+
+ fs.setEmbeddedFile(ef);
+
+ // In addition make sure the embedded file is set under /UF
+ dict = fs.getCOSDictionary();
+ COSDictionary efDict = (COSDictionary) dict
+ .getDictionaryObject(COSName.EF);
+ COSBase lowerLevelFile = efDict.getItem(COSName.F);
+ efDict.setItem(COSName.UF, lowerLevelFile);
+
+ // now add the entry to the embedded file tree and set in the document.
+ PDDocumentNameDictionary names = new PDDocumentNameDictionary(
+ doc.getDocumentCatalog());
+ PDEmbeddedFilesNameTreeNode efTree = names.getEmbeddedFiles();
+ if (efTree == null) {
+ efTree = new PDEmbeddedFilesNameTreeNode();
+ }
+
+ Map namesMap = new HashMap();
+ Map oldNamesMap = efTree.getNames();
+ if (oldNamesMap != null) {
+ for (String key : oldNamesMap.keySet()) {
+ namesMap.put(key, oldNamesMap.get(key));
+ }
+ }
+ namesMap.put(filename, fs);
+ efTree.setNames(namesMap);
+
+ names.setEmbeddedFiles(efTree);
+ doc.getDocumentCatalog().setNames(names);
+
+ // AF entry (Array) in catalog with the FileSpec
+ COSArray cosArray = (COSArray) doc.getDocumentCatalog()
+ .getCOSDictionary().getItem("AF");
+ if (cosArray == null) {
+ cosArray = new COSArray();
+ }
+ cosArray.add(fs);
+ COSDictionary dict2 = doc.getDocumentCatalog().getCOSDictionary();
+ COSArray array = new COSArray();
+ array.add(fs.getCOSDictionary()); // see below
+ dict2.setItem("AF",array);
+ doc.getDocumentCatalog().getCOSDictionary().setItem("AF", cosArray);
+ }
+
+ /**
+ * Sets the ZUGFeRD XML data to be attached as a single byte array. This is
+ * useful for use-cases where the XML has already been produced by some
+ * external API or component.
+ *
+ * @param zugferdData
+ * XML data to be set as a byte array (XML file in raw form).
+ */
+ public void setZUGFeRDXMLData(byte[] zugferdData) {
+ this.zugferdData = zugferdData;
+ }
+
+ /**
+ * Sets the ZUGFeRD conformance level (override).
+ *
+ * @param ZUGFeRDConformanceLevel
+ * the new conformance level
+ */
+ public void setZUGFeRDConformanceLevel(String ZUGFeRDConformanceLevel) {
+ this.ZUGFeRDConformanceLevel = ZUGFeRDConformanceLevel;
+ }
+
+ /**
+ * * This will add both the RDF-indication which embedded file is Zugferd
+ * and the neccessary PDF/A schema extension description to be able to add
+ * this information to RDF
+ *
+ * @param metadata
+ */
+ private void addZugferdXMP(XMPMetadata metadata) {
+
+ XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata,
+ this.ZUGFeRDConformanceLevel);
+ zf.setAbout(""); //$NON-NLS-1$
+ metadata.addSchema(zf);
+
+ XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata);
+ pdfaex.setAbout(""); //$NON-NLS-1$
+ metadata.addSchema(pdfaex);
+
+ }
+
+ /****
+ * Returns the PDFBox PDF Document
+ *
+ * @return
+ */
+ public PDDocument getDoc() {
+ return doc;
+ }
}
diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
index 10c32cc1..dccb0d3d 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java
@@ -15,6 +15,7 @@ import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.util.Map;
+import javax.management.RuntimeErrorException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -34,12 +35,12 @@ import org.xml.sax.SAXException;
public class ZUGFeRDImporter {
/*
- call extract(importFilename).
- containsMeta() will return if ZUGFeRD data has been found,
+ call extract(importFilename).
+ containsMeta() will return if ZUGFeRD data has been found,
afterwards you can call getBIC(), getIBAN() etc.
*/
-
+
/**@var if metadata has been found */
private boolean containsMeta=false;
/**@var the reference (i.e. invoice number) of the sender */
@@ -48,16 +49,20 @@ public class ZUGFeRDImporter {
private String IBAN;
private String holder;
private String amount;
+ private String dueDate;
/** Raw XML form of the extracted data - may be directly obtained. */
private byte[] rawXML=null;
private String bankName;
private boolean amountFound;
-
+ private boolean extracted=false;
+ private boolean parsed=false;
+
+
/**
* Extracts a ZUGFeRD invoice from a PDF document represented by a file name.
* Errors are just logged to STDOUT.
*/
- public void extract(String pdfFilename)
+ public void extract(String pdfFilename)
{
try
{
@@ -66,7 +71,7 @@ public class ZUGFeRDImporter {
{
ioe.printStackTrace();
}
- }
+ }
/**
* Extracts a ZUGFeRD invoice from a PDF document represented by an input stream.
@@ -106,6 +111,7 @@ public class ZUGFeRDImporter {
// FileOutputStream fos = new FileOutputStream(file);
rawXML = embeddedFile.getByteArray();
setMeta(new String(rawXML));
+ extracted=true;
// fos.write(embeddedFile.getByteArray());
// fos.close();
}
@@ -123,12 +129,16 @@ public class ZUGFeRDImporter {
}
}
-
+
public void parse() {
DocumentBuilderFactory factory = null;
DocumentBuilder builder = null;
Document document = null;
+ if (!extracted) {
+ throw new RuntimeException("extract() or extractLowLevel() must be used before parsing.");
+ }
+
factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); //otherwise we can not act namespace independend, i.e. use document.getElementsByTagNameNS("*",...
try {
@@ -147,17 +157,17 @@ public class ZUGFeRDImporter {
ex2.printStackTrace();
}
NodeList ndList ;
-
+
// rootNode = document.getDocumentElement();
// ApplicableSupplyChainTradeSettlement
ndList = document.getDocumentElement()
.getElementsByTagNameNS("*","PaymentReference"); //$NON-NLS-1$
-
+
for (int bookingIndex = 0; bookingIndex < ndList
.getLength(); bookingIndex++) {
Node booking = ndList.item(bookingIndex);
// if there is a attribute in the tag number:value
-
+
setForeignReference(booking.getTextContent());
}
@@ -189,7 +199,7 @@ public class ZUGFeRDImporter {
DE5656565
Commerzbank
-
+
*/
ndList = document.getElementsByTagNameNS("*","PayeePartyCreditorFinancialAccount"); //$NON-NLS-1$
@@ -200,7 +210,7 @@ public class ZUGFeRDImporter {
// there are many "name" elements, so get the one below
// SellerTradeParty
NodeList bookingDetails = booking.getChildNodes();
-
+
for (int detailIndex = 0; detailIndex < bookingDetails
.getLength(); detailIndex++) {
@@ -208,7 +218,7 @@ public class ZUGFeRDImporter {
if ((detail.getLocalName()!=null)&&(detail.getLocalName().equals("IBANID"))) { //$NON-NLS-1$
setIBAN(detail.getTextContent());
- }
+ }
}
}
@@ -266,7 +276,7 @@ public class ZUGFeRDImporter {
if (!amountFound) {
- /* there is apparently no requirement to mention DuePayableAmount,,
+ /* there is apparently no requirement to mention DuePayableAmount,,
* if it's not there, check for GrandTotalAmount
*/
ndList = document.getElementsByTagNameNS("*","GrandTotalAmount"); //$NON-NLS-1$
@@ -278,10 +288,28 @@ public class ZUGFeRDImporter {
setAmount(booking.getTextContent());
}
-
- }
-
+ }
+
+ ndList = document.getElementsByTagNameNS("*","SpecifiedTradePaymentTerms"); //$NON-NLS-1$
+
+ for (int bookingIndex = 0; bookingIndex < ndList
+ .getLength(); bookingIndex++) {
+ Node booking = ndList.item(bookingIndex);
+ // there are many "name" elements, so get the one below
+ // SellerTradeParty
+ NodeList bookingDetails = booking.getChildNodes();
+ for (int detailIndex = 0; detailIndex < bookingDetails
+ .getLength(); detailIndex++) {
+ Node detail = bookingDetails.item(detailIndex);
+ if ((detail.getLocalName()!=null)&&(detail.getLocalName().equals("DueDateDateTime"))) { //$NON-NLS-1$
+ setDueDate(detail.getTextContent().trim());
+ }
+ }
+
+ }
+
+ parsed=true;
}
@@ -290,18 +318,24 @@ public class ZUGFeRDImporter {
}
public String getForeignReference() {
+ if (!parsed) {
+ throw new RuntimeException("use parse() before requesting a value");
+ }
return foreignReference;
}
- public void setForeignReference(String foreignReference) {
+ private void setForeignReference(String foreignReference) {
this.foreignReference = foreignReference;
}
public String getBIC() {
+ if (!parsed) {
+ throw new RuntimeException("use parse() before requesting a value");
+ }
return BIC;
}
@@ -312,6 +346,11 @@ public class ZUGFeRDImporter {
}
+ private void setDueDate(String dueDate) {
+ this.dueDate = dueDate;
+ }
+
+
private void setBankName(String bankname) {
this.bankName = bankname;
}
@@ -319,23 +358,32 @@ public class ZUGFeRDImporter {
public String getIBAN() {
+ if (!parsed) {
+ throw new RuntimeException("use parse() before requesting a value");
+ }
return IBAN;
}
public String getBankName() {
+ if (!parsed) {
+ throw new RuntimeException("use parse() before requesting a value");
+ }
return bankName;
}
- public void setIBAN(String IBAN) {
+ private void setIBAN(String IBAN) {
this.IBAN = IBAN;
}
public String getHolder() {
+ if (rawXML==null) {
+ throw new RuntimeException("use parse() before requesting a value");
+ }
return holder;
}
@@ -348,9 +396,18 @@ public class ZUGFeRDImporter {
public String getAmount() {
+ if (rawXML==null) {
+ throw new RuntimeException("use parse() before requesting a value");
+ }
return amount;
}
+ public String getDueDate() {
+ if (rawXML==null) {
+ throw new RuntimeException("use parse() before requesting a value");
+ }
+ return dueDate;
+ }
private void setAmount(String amount) {
this.amount = amount;
@@ -362,7 +419,7 @@ public class ZUGFeRDImporter {
public String getMeta() {
if (rawXML==null){
- return null;
+ return null;
} else {
return new String(rawXML);
}
@@ -372,7 +429,7 @@ public class ZUGFeRDImporter {
/**
* Returns the raw XML data as extracted from the ZUGFeRD PDF file.
*/
- public byte[] getRawXML()
+ public byte[] getRawXML()
{
return rawXML;
}
@@ -381,8 +438,8 @@ public class ZUGFeRDImporter {
* will return true if the metadata (just extract-ed or set with setMeta) contains ZUGFeRD XML
* */
public boolean canParse() {
-
-
+
+
//SpecifiedExchangedDocumentContext is in the schema, so a relatively good indication if zugferd is present - better than just invoice
String meta=getMeta();
return (meta!=null)&&( meta.length()>0)&&( meta.contains("SpecifiedExchangedDocumentContext")); //$NON-NLS-1$
diff --git a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java
index 8006505d..6ce243a9 100644
--- a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java
+++ b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java
@@ -49,7 +49,7 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
@Override
public String getOwnBIC()
{
- return "COBADEFXXX";
+ return "COBADEFFXXX";
}
@Override
@@ -118,7 +118,13 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
{
return null;
}
-
+
+ @Override
+ public String getCurrency()
+ {
+ return "EUR";
+ }
+
@Override
public IZUGFeRDExportableItem[] getZFItems()
{
@@ -133,11 +139,6 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
return allItems;
}
- @Override
- public String getInvoiceCurrency() {
- return "EUR";
- }
-
@Override
public String getOwnPaymentInfoText() {
return "Überweisung";
@@ -258,7 +259,7 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
@Override
public IZUGFeRDAllowanceCharge[] getItemAllowances() {
- return null;
+ return null;
}
@Override
@@ -330,7 +331,7 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
/**
* Create the test case
- *
+ *
* @param testName
* name of the test case
*/
@@ -353,7 +354,7 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
* The importer test imports from ./src/test/MustangGnuaccountingBeispielRE-20151008_504.pdf to check the values.
* --> as only Name Ascending is supported for Test Unit sequence, I renamed the this test-A-Export to run before
* testZExport
- *
+ *
* @throws IOException
*/
@@ -368,6 +369,7 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
String iban = null;
String holder = null;
String ref = null;
+ String dueDate = null;
if (zi.canParse())
{
@@ -376,6 +378,7 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
bic = zi.getBIC();
iban = zi.getIBAN();
holder = zi.getHolder();
+ dueDate = zi.getDueDate();
ref = zi.getForeignReference();
}
@@ -383,6 +386,8 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
assertEquals(bic, getOwnBIC());
assertEquals(iban, getOwnIBAN());
assertEquals(holder, getOwnOrganisationName());
+
+ assertEquals(dueDate, "20141029");
assertEquals(ref, getNumber());
}
@@ -401,16 +406,13 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20151008_504newEdge.pdf";
// the writing part
- PDDocument doc;
try
{
- doc = PDDocument.load(SOURCE_PDF);
// automatically add Zugferd to all outgoing invoices
ZUGFeRDExporter ze = new ZUGFeRDExporter();
- ze.PDFmakeA3compliant(doc, "My Application", System.getProperty("user.name"), true);
- ze.PDFattachZugferdFile(doc, this);
- doc.save(TARGET_PDF);
- doc.close();
+ ze.PDFmakeA3compliant(SOURCE_PDF, "My Application", System.getProperty("user.name"), true);
+ ze.PDFattachZugferdFile(this);
+ ze.export(TARGET_PDF);
}
catch (IOException e)
{
diff --git a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java
index 468551e2..c0d6b1ea 100644
--- a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java
+++ b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java
@@ -49,7 +49,7 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
@Override
public String getOwnBIC()
{
- return "COBADEFXXX";
+ return "COBADEFFXXX";
}
@Override
@@ -118,6 +118,12 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
return null;
}
+ @Override
+ public String getCurrency()
+ {
+ return "EUR";
+ }
+
@Override
public IZUGFeRDExportableItem[] getZFItems()
{
@@ -132,11 +138,6 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
return allItems;
}
- @Override
- public String getInvoiceCurrency() {
- return "EUR";
- }
-
@Override
public String getOwnPaymentInfoText() {
return "Überweisung";
@@ -257,16 +258,16 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
{
this.product = product;
}
-
+
@Override
public IZUGFeRDAllowanceCharge[] getItemAllowances() {
- return null;
+ return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getItemCharges() {
return null;
- }
+ }
}
@@ -332,7 +333,7 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
/**
* Create the test case
- *
+ *
* @param testName
* name of the test case
*/
@@ -355,7 +356,7 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
* The importer test imports from ./src/test/MustangGnuaccountingBeispielRE-20151008_504.pdf to check the values.
* --> as only Name Ascending is supported for Test Unit sequence, I renamed the this test-A-Export to run before
* testZExport
- *
+ *
* @throws IOException
*/
@@ -403,16 +404,13 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20151008_504new.pdf";
// the writing part
- PDDocument doc;
try
{
- doc = PDDocument.load(SOURCE_PDF);
// automatically add Zugferd to all outgoing invoices
ZUGFeRDExporter ze = new ZUGFeRDExporter();
- ze.PDFmakeA3compliant(doc, "My Application", System.getProperty("user.name"), true);
- ze.PDFattachZugferdFile(doc, this);
- doc.save(TARGET_PDF);
- doc.close();
+ ze.PDFmakeA3compliant(SOURCE_PDF, "My Application", System.getProperty("user.name"), true);
+ ze.PDFattachZugferdFile(this);
+ ze.export(TARGET_PDF);
}
catch (IOException e)
{
diff --git a/mustang/src/test/resources/MustangGnuaccountingBeispielRE-20151008_504.pdf b/mustang/src/test/resources/MustangGnuaccountingBeispielRE-20151008_504.pdf
index 236ea091..1771974d 100644
Binary files a/mustang/src/test/resources/MustangGnuaccountingBeispielRE-20151008_504.pdf and b/mustang/src/test/resources/MustangGnuaccountingBeispielRE-20151008_504.pdf differ
diff --git a/mustang/toecount/pom.xml b/mustang/toecount/pom.xml
index 01a276b5..cedff06d 100755
--- a/mustang/toecount/pom.xml
+++ b/mustang/toecount/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.mustangproject.ZUGFeRD
toecount
- 0.0.6-SNAPSHOT
+ 0.0.8-SNAPSHOT
ZUGFeRD PDF checker
Shows statistics on how many PDFs in a directory are ZUGFeRD-Compliant
@@ -27,7 +27,7 @@
org.mustangproject.ZUGFeRD
mustang
- 1.2.1-SNAPSHOT
+ 1.3.0-SNAPSHOT
org.apache.pdfbox
diff --git a/mustang/toecount/src/main/java/toecount/FileChecker.java b/mustang/toecount/src/main/java/toecount/FileChecker.java
index c1ad9d64..33fe0dc0 100755
--- a/mustang/toecount/src/main/java/toecount/FileChecker.java
+++ b/mustang/toecount/src/main/java/toecount/FileChecker.java
@@ -30,11 +30,34 @@ public class FileChecker {
return false;
}
ZUGFeRDImporter zi=new ZUGFeRDImporter();
- zi.extract(filename);
- if (zi.canParse()) {
- thisRun.incZUGFeRDCount();
- return true;
- } else {
+ try {
+ zi.extract(filename);
+ if (zi.canParse()) {
+ thisRun.incZUGFeRDCount();
+ return true;
+ } else {
+ return false;
+ }
+ } catch (NullPointerException e) {
+ // something really rare happened -- corrupted ZF?
+ /***
+ * e.g. Exception in thread "main" java.lang.NullPointerException
+ at org.mustangproject.ZUGFeRD.ZUGFeRDImporter.extractLowLevel(ZUGFeRDImporter.java:90)
+ at org.mustangproject.ZUGFeRD.ZUGFeRDImporter.extract(ZUGFeRDImporter.java:64)
+ at toecount.FileChecker.checkForZUGFeRD(FileChecker.java:33)
+ at toecount.Toecount.main(Toecount.java:111)
+ *
+ */
+ // Ignore nevertheless, most likely we're batch processing
+ return false;
+ } catch (Exception e2) {
+ /**
+ * probably thrown up from
+ AM org.apache.pdfbox.pdfparser.PDFParser parse, most likely
+ INFORMATION: Document is encrypted
+ but also other internal PDF errors possible like
+ ..Okt 23, 2015 11:17:53 AM org.apache.pdfbox.pdfparser.XrefTrailerResolver setStartxref
+ */
return false;
}
}
diff --git a/mustang/toecount/src/main/java/toecount/Toecount.java b/mustang/toecount/src/main/java/toecount/Toecount.java
index 6c0c412e..50c8d2a4 100755
--- a/mustang/toecount/src/main/java/toecount/Toecount.java
+++ b/mustang/toecount/src/main/java/toecount/Toecount.java
@@ -22,7 +22,7 @@ public class Toecount {
}
private static void printHelp() {
System.out
- .println("Mustangproject.org's Toecount 0.0.6 \r\n"
+ .println("Mustangproject.org's Toecount 0.0.7 \r\n"
+ "A Apache Public License command line tool for statistics on PDF invoices with\r\n"
+ "ZUGFeRD Metadata (http://www.zugferd.de)\r\n"
+ "\r\n"
diff --git a/pdfa3-sample/pom.xml b/pdfa3-sample/pom.xml
index aa81da5c..913f5bf1 100644
--- a/pdfa3-sample/pom.xml
+++ b/pdfa3-sample/pom.xml
@@ -3,8 +3,8 @@
com.github.rayman2200
mustang-sample-project
- 1.3.0-SNAPSHOT
+ 1.3.0.1-SNAPSHOT
- pdfa3-samples
-
\ No newline at end of file
+ pdfa3-samples
+
diff --git a/pdfa3-sample/src/main/java/pdfbox/PDFA3FileAttachment.java b/pdfa3-sample/src/main/java/pdfbox/PDFA3FileAttachment.java
index 8b609d40..164218ce 100644
--- a/pdfa3-sample/src/main/java/pdfbox/PDFA3FileAttachment.java
+++ b/pdfa3-sample/src/main/java/pdfbox/PDFA3FileAttachment.java
@@ -30,6 +30,7 @@ import org.apache.jempbox.xmp.XMPSchemaBasic;
import org.apache.jempbox.xmp.XMPSchemaDublinCore;
import org.apache.jempbox.xmp.XMPSchemaPDF;
import org.apache.jempbox.xmp.pdfa.XMPSchemaPDFAId;
+import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
@@ -120,6 +121,10 @@ public class PDFA3FileAttachment
// cosArray.add(fs);
// catalog.setItem("AF", cosArray);
+ COSDictionary dict2 = catalog.getCOSDictionary();
+ COSArray array = new COSArray();
+ array.add(fs.getCOSDictionary()); // see below
+ dict2.setItem("AF",array);
}
/**
diff --git a/pom.xml b/pom.xml
index 5bb6a839..161fb086 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,13 +2,13 @@
4.0.0
com.github.rayman2200
mustang-sample-project
- 1.3.0-SNAPSHOT
+ 1.3.3-SNAPSHOT
pom
- scm:git:https://github.com/AlexanderSchmidt/PDFA3.git
- scm:git:https://github.com/AlexanderSchmidt/PDFA3.git
- https://github.com/AlexanderSchmidt/PDFA3.git
+ scm:git:https://github.com/jstaerk/mustangproject.git
+ scm:git:https://github.com/jstaerk/mustangproject.git
+ https://github.com/jstaerk/mustangproject
HEAD
@@ -24,6 +24,7 @@
UTF-8
github
-Xdoclint:none
+ 1.6
@@ -35,7 +36,7 @@
org.apache.pdfbox
pdfbox
- 1.8.10
+ 1.8.8
junit
@@ -47,15 +48,6 @@
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.2
-
- 1.6
- 1.6
-
-
maven-deploy-plugin
2.8.2
@@ -76,8 +68,8 @@
**/*
true
- PDFA3
- AlexanderSchmidt
+ mustangproject
+ jstaerk