diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java index bf0086ab..a32214ec 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java @@ -12,15 +12,24 @@ import org.apache.jempbox.xmp.XMPSchemaBasic; import org.w3c.dom.Element; -public class XMPSchemaZugferd extends XMPSchemaBasic { +public class XMPSchemaZugferd extends XMPSchemaBasic +{ + + private String conformanceLevel = "COMFORT"; /** * This is what needs to be added to the RDF metadata - basically the name of the embedded * Zugferd file * */ - public XMPSchemaZugferd(org.apache.jempbox.xmp.XMPMetadata parent) { + public XMPSchemaZugferd(org.apache.jempbox.xmp.XMPMetadata parent, String conformanceLevel) + { super(parent); + if (conformanceLevel != null) + { + this.conformanceLevel = conformanceLevel; + } + schema.setAttributeNS(NS_NAMESPACE, "xmlns:zf", //$NON-NLS-1$ "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#"); //$NON-NLS-1$ // the superclass includes this two namespaces we don't need @@ -42,7 +51,7 @@ public class XMPSchemaZugferd extends XMPSchemaBasic { textNode = schema.getOwnerDocument().createElement( "zf:ConformanceLevel"); //$NON-NLS-1$ - XMLUtil.setStringValue(textNode, "COMFORT"); //$NON-NLS-1$ + XMLUtil.setStringValue(textNode, this.conformanceLevel); //$NON-NLS-1$ schema.appendChild(textNode); } diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java index c8fa3d20..211d64aa 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java @@ -38,8 +38,8 @@ import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; public class ZUGFeRDExporter { /*** - * You will need Apache PDFBox. To use the ZUGFeRD exporter, - implement IZUGFeRDExportableTransaction in yourTransaction + * 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); @@ -55,22 +55,26 @@ public class ZUGFeRDExporter { * */ - - + + //// MAIN CLASS - + private String conformanceLevel="U"; private String versionStr="1.0"; + // BASIC, COMFORT etc - may be set from outside. + private String ZUGFeRDConformanceLevel = null; + + /** * 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 String currencyFormat(BigDecimal value, char decimalDelimiter) { /* * I needed 123,45, locale independent.I tried @@ -81,12 +85,12 @@ public class ZUGFeRDExporter { * 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"), @@ -95,10 +99,10 @@ public class ZUGFeRDExporter { * ",")+"\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( 2, BigDecimal.ROUND_HALF_UP ); // first, round so that e.g. 1.189999999999999946709294817992486059665679931640625 becomes 1.19 + 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); @@ -114,28 +118,28 @@ public class ZUGFeRDExporter { /** 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 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; } - - + + /** * 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, + public PDDocumentCatalog PDFmakeA3compliant(PDDocument doc, String producer, String creator, boolean attachZugferdHeaders) throws IOException, TransformerException { String fullProducer=producer + " (via mustangproject.org " + versionStr + ")"; @@ -177,13 +181,13 @@ public class ZUGFeRDExporter { 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. + * + 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) { @@ -198,11 +202,11 @@ public class ZUGFeRDExporter { metadata.importXMPMetadata(xmp); return cat; } - + private String getZugferdXMLForTransaction(IZUGFeRDExportableTransaction trans) { SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$ String xml= "\n" //$NON-NLS-1$ - + + ""+trans.getOwnBankName()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ + " \n" //$NON-NLS-1$ + " \n"; //$NON-NLS-1$ - - + + /* HashMap VATPercentAmountMap=trans.getVATPercentAmountMap(); for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { @@ -312,7 +316,7 @@ public class ZUGFeRDExporter { + " \n"; //$NON-NLS-1$ - + } }*/ /* xml+= " @@ -347,7 +351,7 @@ public class ZUGFeRDExporter { + " 7\n" + " \n" + " \n"*/ - + xml=xml+ " \n" //$NON-NLS-1$ // + " Zahlbar innerhalb 30 Tagen netto bis 04.07.2013, 3% Skonto innerhalb 10 Tagen bis 15.06.2013\n" + " "+zugferdDateFormat.format(trans.getDueDate())+"\n"//20130704 //$NON-NLS-1$ //$NON-NLS-2$ @@ -370,8 +374,8 @@ public class ZUGFeRDExporter { // + " \n" // + " \n" // + " \n"; - - + + int lineID=0; for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { lineID++; @@ -379,7 +383,7 @@ public class ZUGFeRDExporter { " \n" //$NON-NLS-1$ + " "+lineID+"\n" //$NON-NLS-1$ //$NON-NLS-2$ + " \n" //$NON-NLS-1$ - + + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " "+currencyFormat(currentItem.getPriceGross(),'.')+"\n" //$NON-NLS-1$ //$NON-NLS-2$ @@ -395,7 +399,7 @@ public class ZUGFeRDExporter { + " 1\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$ + " \n" //$NON-NLS-1$ @@ -417,12 +421,12 @@ public class ZUGFeRDExporter { + " "+currentItem.getProduct().getDescription()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ + " \n" //$NON-NLS-1$ + " \n"; //$NON-NLS-1$ - - - + + + } - - + + xml=xml + " \n" //$NON-NLS-1$ + ""; //$NON-NLS-1$ return xml; @@ -450,12 +454,12 @@ public class ZUGFeRDExporter { 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 // FileInputStream - + byte[] zugferdRaw = getZugferdXMLForTransaction(trans).getBytes("UTF-8"); //$NON-NLS-1$ if ((zugferdRaw[0]==(byte)0xEF)&&(zugferdRaw[1]==(byte)0xBB)&&(zugferdRaw[2]==(byte)0xBF)) { @@ -463,10 +467,10 @@ public class ZUGFeRDExporter { zugferdData=new byte[zugferdRaw.length-3]; System.arraycopy(zugferdRaw,3,zugferdData,0,zugferdRaw.length-3); } else { - zugferdData=zugferdRaw; + zugferdData=zugferdRaw; } } - + ByteArrayInputStream fakeFile = new ByteArrayInputStream(zugferdData); PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile); // now lets some of the optional parameters @@ -494,7 +498,7 @@ public class ZUGFeRDExporter { /** * 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) @@ -502,14 +506,25 @@ public class ZUGFeRDExporter { 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 + * 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); + XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, this.ZUGFeRDConformanceLevel); zf.setAbout(""); //$NON-NLS-1$ metadata.addSchema(zf);