diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
index 4a54abcb..9729ce89 100644
--- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
+++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java
@@ -12,7 +12,10 @@ package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
+import java.util.Arrays;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
@@ -78,8 +81,9 @@ public class ZUGFeRDExporter {
* pass a IZUGFeRDExportableTransaction for the XML to be populated.
*/
byte[] zugferdData = null;
-
- private String currencyFormat(BigDecimal value, char decimalDelimiter) {
+
+
+ private String nDigitFormat(BigDecimal value, int scale) {
/*
* I needed 123,45, locale independent.I tried
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is
@@ -106,18 +110,30 @@ public class ZUGFeRDExporter {
*
* results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00
*/
- value=value.setScale( 2, BigDecimal.ROUND_HALF_UP ); // first, round so that e.g. 1.189999999999999946709294817992486059665679931640625 becomes 1.19
- long totalCent = value.multiply(new BigDecimal(100)).intValue(); //now get the cents
- long eurOnly = value.longValue();
- long centOnly = Math.abs(totalCent % 100);
- StringBuffer res = new StringBuffer();
- res.append(eurOnly);
- res.append(decimalDelimiter);
- if (centOnly < 10) {
- res.append('0');
- }
- res.append(centOnly);
- return res.toString();
+ 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');
+
+ DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
+ otherSymbols.setDecimalSeparator('.');
+ DecimalFormat dec = new DecimalFormat("0."+new String(repeat), otherSymbols);
+ return dec.format(value);
+
+ }
+
+ private String vatFormat(BigDecimal value) {
+ return nDigitFormat(value, 2);
+ }
+
+ private String currencyFormat(BigDecimal value) {
+ return nDigitFormat(value, 2);
+ }
+
+ private String priceFormat(BigDecimal value) {
+ return nDigitFormat(value, 2);
+ }
+ private String quantityFormat(BigDecimal value) {
+ return nDigitFormat(value, 2);
}
/**
@@ -218,7 +234,7 @@ public class ZUGFeRDExporter {
+ " \n" //$NON-NLS-1$
+ " false\n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
- + " urn:ferd:invoice:rc:comfort\n" //$NON-NLS-1$
+ + " urn:ferd:CrossIndustryDocument:invoice:1p0:comfort\n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
@@ -361,14 +377,16 @@ public class ZUGFeRDExporter {
+ " "+zugferdDateFormat.format(trans.getDueDate())+"\n"//20130704 //$NON-NLS-1$ //$NON-NLS-2$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
- + " "+currencyFormat(trans.getTotal(), '.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " 0.00\n" //$NON-NLS-1$
+ + " 0.00\n" //$NON-NLS-1$
+ + " "+currencyFormat(trans.getTotal())+"\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " 5.80\n"
// + " 14.73\n"
- + " "+currencyFormat(trans.getTotal(), '.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$
- + " "+currencyFormat(trans.getTotalGross().subtract(trans.getTotal()), '.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$
- + " "+currencyFormat(trans.getTotalGross(), '.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " "+currencyFormat(trans.getTotal())+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " "+currencyFormat(trans.getTotalGross().subtract(trans.getTotal()))+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " "+currencyFormat(trans.getTotalGross())+"\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " 0.00\n"
- + " "+currencyFormat(trans.getTotalGross(), '.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " "+currencyFormat(trans.getTotalGross())+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " \n" //$NON-NLS-1$
+ " \n"; //$NON-NLS-1$
// + " \n"
@@ -390,8 +408,8 @@ public class ZUGFeRDExporter {
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
- + " "+currencyFormat(currentItem.getPriceGross(),'.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$
- + " 1\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " "+priceFormat(currentItem.getPriceGross())+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " 1.0000\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " \n"
// + " false\n"
// + " 0.6667\n"
@@ -399,22 +417,22 @@ public class ZUGFeRDExporter {
// + " \n"
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
- + " "+currencyFormat(currentItem.getPrice(),'.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$
- + " 1\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " "+priceFormat(currentItem.getPrice())+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " 1.0000\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
- + " "+currentItem.getQuantity()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ + " "+quantityFormat(currentItem.getQuantity())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
+ " VAT\n" //$NON-NLS-1$
+ " S\n" //$NON-NLS-1$
- + " "+currentItem.getProduct().getVATPercent()+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " "+vatFormat(currentItem.getProduct().getVATPercent())+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
- + " "+currencyFormat(currentItem.getTotalGross(),'.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ + " "+currencyFormat(currentItem.getTotalGross())+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
+ " \n" //$NON-NLS-1$
@@ -445,20 +463,6 @@ public class ZUGFeRDExporter {
*/
public void PDFattachZugferdFile(PDDocument doc, IZUGFeRDExportableTransaction trans) throws IOException {
- // embedded files are stored in a named tree
- PDEmbeddedFilesNameTreeNode efTree = new PDEmbeddedFilesNameTreeNode();
-
- String filename="ZUGFeRD-invoice.xml"; //$NON-NLS-1$
- // first create the file specification, which holds the embedded file
- PDComplexFileSpecification fs = new PDComplexFileSpecification();
- fs.setFile(filename);
-
- COSDictionary dict = fs.getCOSDictionary();
- // Relation "Source" for linking with eg. catalog
- dict.setName("AFRelationship", "Alternative"); // as defined in Zugferd standard //$NON-NLS-1$ //$NON-NLS-2$
-
- dict.setString("UF", filename); //$NON-NLS-1$
-
if (zugferdData == null) // XML ZUGFeRD data not set externally, needs to be built
{
// create a dummy file stream, this would probably normally be a
@@ -475,34 +479,8 @@ public class ZUGFeRDExporter {
}
}
- ByteArrayInputStream fakeFile = new ByteArrayInputStream(zugferdData);
- PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
- // now lets some of the optional parameters
- ef.setSubtype("text/xml");// as defined in Zugferd standard //$NON-NLS-1$
- ef.setSize(zugferdData.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.
- efTree.setNames(Collections.singletonMap(filename, fs));
- PDDocumentNameDictionary names = new PDDocumentNameDictionary(
- doc.getDocumentCatalog());
- names.setEmbeddedFiles(efTree);
- doc.getDocumentCatalog().setNames(names);
- // AF entry (Array) in catalog with the FileSpec
- COSArray cosArray = new COSArray();
- cosArray.add(fs);
- doc.getDocumentCatalog().getCOSDictionary().setItem("AF", cosArray); //$NON-NLS-1$
+ 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);
}
@@ -511,18 +489,21 @@ public class ZUGFeRDExporter {
*
* @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 subType, byte[] data)
+ 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", "Alternative");
+ dict.setName("AFRelationship", relationship);
dict.setString("UF", filename);
+ dict.setString("Desc", description);
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);