From 6012356146f3591c90eb87333fe6c58aaa6a25c3 Mon Sep 17 00:00:00 2001 From: AlexanderSchmidt Date: Mon, 23 Nov 2015 15:42:01 +0100 Subject: [PATCH 1/3] add reference document number for invoice corrections --- .../ZUGFeRD/IZUGFeRDExportableTransaction.java | 7 +++++++ .../java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java | 7 +++++++ .../ZUGFeRD/MustangReaderWriterEdgeTest.java | 5 +++++ .../mustangproject/ZUGFeRD/MustangReaderWriterTest.java | 5 +++++ 4 files changed, 24 insertions(+) diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java index 09ab90d6..3d9af400 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java @@ -142,5 +142,12 @@ public interface IZUGFeRDExportableTransaction { */ String getPaymentTermDescription(); + /** + * get reference document number + * typically used for Invoice Corrections + * Will be added as IncludedNote in comfort profile + * @return + */ + String getReferenceNumber(); } diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java index d200b757..51e5868b 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java @@ -432,6 +432,13 @@ public class ZUGFeRDExporter { regularInfo.getContent().add(regularInfoContent); document.getIncludedNote().add(regularInfo); } + if (trans.getReferenceNumber() != null && trans.getReferenceNumber() != new String()){ + NoteType referenceInfo = xmlFactory.createNoteType(); + TextType referenceInfoContent = xmlFactory.createTextType(); + referenceInfoContent.setValue("Ursprungsbeleg: " + trans.getReferenceNumber()); + referenceInfo.getContent().add(referenceInfoContent); + document.getIncludedNote().add(referenceInfo); + } return document; } diff --git a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java index f75bd38b..8006505d 100644 --- a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java +++ b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java @@ -164,6 +164,11 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp return null; } + @Override + public String getReferenceNumber() { + return null; + } + class Contact implements IZUGFeRDExportableContact { diff --git a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java index e834f3c7..468551e2 100644 --- a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java +++ b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java @@ -166,6 +166,11 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + @Override + public String getReferenceNumber() { + return null; + } + class Contact implements IZUGFeRDExportableContact { From 04bcc7963bbb3f244899da3866248c666cbaecf5 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Fri, 21 Apr 2017 11:54:32 +0200 Subject: [PATCH 2/3] add reference document number for invoice corrections --- .../main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java index 51e5868b..8f25dee2 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java @@ -432,7 +432,7 @@ public class ZUGFeRDExporter { regularInfo.getContent().add(regularInfoContent); document.getIncludedNote().add(regularInfo); } - if (trans.getReferenceNumber() != null && trans.getReferenceNumber() != new String()){ + if (trans.getReferenceNumber() != null && !new String().equals(trans.getReferenceNumber())){ NoteType referenceInfo = xmlFactory.createNoteType(); TextType referenceInfoContent = xmlFactory.createTextType(); referenceInfoContent.setValue("Ursprungsbeleg: " + trans.getReferenceNumber()); From 8389395451d7fa6a7de56bcd07a63d47b9a2160d Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Fri, 21 Apr 2017 16:01:01 +0200 Subject: [PATCH 3/3] fixes after depedency update --- mustang/dependency-reduced-pom.xml | 66 ++++++ mustang/pom.xml | 31 ++- .../ZUGFeRD/XMPSchemaPDFAExtensions.java | 217 ++++++----------- .../ZUGFeRD/XMPSchemaZugferd.java | 61 ++--- .../ZUGFeRD/ZUGFeRDExporter.java | 218 +++++++++--------- .../ZUGFeRD/ZUGFeRDImporter.java | 7 +- .../ZUGFeRD/MustangReaderWriterEdgeTest.java | 7 +- 7 files changed, 281 insertions(+), 326 deletions(-) create mode 100644 mustang/dependency-reduced-pom.xml diff --git a/mustang/dependency-reduced-pom.xml b/mustang/dependency-reduced-pom.xml new file mode 100644 index 00000000..2c9eec48 --- /dev/null +++ b/mustang/dependency-reduced-pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + org.mustangproject.ZUGFeRD + mustang + Mustang + 2.0.0.0 + The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs + http://www.mustangproject.org/ + + + User List + https://groups.google.com/forum/?hl=de#!forum/mustangproject + + + + + Jochen St�rk + jstaerk@usegroup.de + + architect + developer + + + + Alexander Schmidt + schmidt.alexander@mail.de + + developer + + + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + A business-friendly OSS license + + + + + + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + + + + + + true + + + + + + diff --git a/mustang/pom.xml b/mustang/pom.xml index 43d45fa2..056ff406 100644 --- a/mustang/pom.xml +++ b/mustang/pom.xml @@ -1,14 +1,8 @@ 4.0.0 - - com.github.rayman2200 - mustang-sample-project - 1.3.0.1-SNAPSHOT - - org.mustangproject.ZUGFeRD mustang - 1.3.0.1-SNAPSHOT + 1.4.0.0 jar Mustang @@ -54,15 +48,20 @@ - org.apache.pdfbox - preflight - 1.8.8 - + org.apache.pdfbox + preflight + 2.0.5 + - org.apache.pdfbox - pdfbox - 1.8.8 - + org.apache.pdfbox + pdfbox + 2.0.5 + + + junit + junit + 4.12 + @@ -83,7 +82,7 @@ - Jochen Stärk + Jochen Stärk jstaerk@usegroup.de architect diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java index 2bee5ca5..442d4144 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java @@ -7,163 +7,88 @@ package org.mustangproject.ZUGFeRD; * @version 1.2.0 * @author jstaerk * */ -import org.apache.jempbox.impl.XMLUtil; -import org.apache.jempbox.xmp.XMPSchemaBasic; -import org.w3c.dom.Element; - - /** - * Additionally to adding a RDF namespace with a indication which file - * attachment if Zugferd, this namespace has to be described in a PDFA - * Extension Schema. - * - * I know there is a PDFAExtensionSchema in the context of PDFBox' XMPBOX - * but I have been using PDFBox' JempBOX so far because I could not find out - * how to write XMPBOX XMPMetadata to a PDF file. - * - * So this is my version of PDFAExtensionSchema - * for PDFBox' jempbox XMPMetadata - * - * @author jstaerk - * - */ - public class XMPSchemaPDFAExtensions extends XMPSchemaBasic { - - private void addProperty(Element listNode, String name, String type, - String category, String description) { - Element nameNode = schema.getOwnerDocument().createElement( - "pdfaProperty:name"); //$NON-NLS-1$ - XMLUtil.setStringValue(nameNode, name); - listNode.appendChild(nameNode); - - Element typeNode = schema.getOwnerDocument().createElement( - "pdfaProperty:valueType"); //$NON-NLS-1$ - XMLUtil.setStringValue(typeNode, type); - listNode.appendChild(typeNode); - - Element categoryNode = schema.getOwnerDocument().createElement( - "pdfaProperty:category"); //$NON-NLS-1$ - XMLUtil.setStringValue(categoryNode, category); - listNode.appendChild(categoryNode); - - Element descriptionNode = schema.getOwnerDocument().createElement( - "pdfaProperty:description"); //$NON-NLS-1$ - XMLUtil.setStringValue(descriptionNode, description); - listNode.appendChild(descriptionNode); - - } +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.XmpConstants; +import org.apache.xmpbox.schema.PDFAExtensionSchema; +import org.apache.xmpbox.type.ArrayProperty; +import org.apache.xmpbox.type.Attribute; +import org.apache.xmpbox.type.Cardinality; +import org.apache.xmpbox.type.ChoiceType; +import org.apache.xmpbox.type.DefinedStructuredType; +import org.apache.xmpbox.type.PDFAPropertyType; +import org.apache.xmpbox.type.PDFASchemaType; +import org.apache.xmpbox.type.StructuredType; +import org.apache.xmpbox.type.TextType; +/** + * Additionally to adding a RDF namespace with a indication which file attachment if Zugferd, this namespace has to be described in a PDFA Extension Schema. I + * know there is a PDFAExtensionSchema in the context of PDFBox' XMPBOX but I have been using PDFBox' JempBOX so far because I could not find out how to write + * XMPBOX XMPMetadata to a PDF file. So this is my version of PDFAExtensionSchema for PDFBox' jempbox XMPMetadata + * + * @author jstaerk + */ - public XMPSchemaPDFAExtensions(org.apache.jempbox.xmp.XMPMetadata parent) { - super(parent); - // add some namespaces - schema.setAttributeNS(NS_NAMESPACE, "xmlns:pdfaExtension", //$NON-NLS-1$ - "http://www.aiim.org/pdfa/ns/extension/"); //$NON-NLS-1$ +@StructuredType(preferedPrefix = "pdfaExtension", namespace = "http://www.aiim.org/pdfa/ns/extension/") + public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema { - schema.setAttributeNS(NS_NAMESPACE, "xmlns:pdfaSchema", //$NON-NLS-1$ - "http://www.aiim.org/pdfa/ns/schema#"); //$NON-NLS-1$ + public final String xmlns_pdfaSchema = "http://www.aiim.org/pdfa/ns/schema#"; + public final String prefix_pdfaSchema = "pdfaSchema"; + public final String xmlns_pdfaProperty = "http://www.aiim.org/pdfa/ns/property#"; + public final String prefix_pdfaProperty = "pdfaProperty"; - schema.setAttributeNS(NS_NAMESPACE, "xmlns:pdfaProperty", //$NON-NLS-1$ - "http://www.aiim.org/pdfa/ns/property#"); //$NON-NLS-1$ + private DefinedStructuredType addProperty(ArrayProperty parent, String name, String type, String category, String description) { + XMPMetadata metadata = getMetadata(); - // the superclass includes this two namespaces we don't need - schema.removeAttributeNS(NS_NAMESPACE, "xapGImg"); //$NON-NLS-1$ - schema.removeAttributeNS(NS_NAMESPACE, "xmp"); //$NON-NLS-1$ + DefinedStructuredType li = new DefinedStructuredType(metadata, getNamespace(), getPrefix(), XmpConstants.LIST_NAME); + li.setAttribute(new Attribute(getNamespace(), XmpConstants.PARSE_TYPE, XmpConstants.RESOURCE_NAME)); - /* - *What we attach is basically this: - *pdfaExtension:schemas-node - *+--bag - * +--rdf:li - * +--some text node (multiple) - * +--property node - * +--rdf:Seq - * +--rdf:li (multiple) attribute node - * +--some attribute property description text node (multiple) - */ - Element schemasNode = schema.getOwnerDocument().createElement( - "pdfaExtension:schemas"); //$NON-NLS-1$ + ChoiceType pdfa2 = new ChoiceType(metadata, xmlns_pdfaProperty, prefix_pdfaProperty, PDFAPropertyType.NAME, name); + li.addProperty(pdfa2); - Element bagNode = schema.getOwnerDocument() - .createElement("rdf:Bag"); //$NON-NLS-1$ + pdfa2 = new ChoiceType(metadata, xmlns_pdfaProperty, prefix_pdfaProperty, PDFAPropertyType.VALUETYPE, type); + li.addProperty(pdfa2); - Element bagListNode = schema.getOwnerDocument().createElement( - "rdf:li"); //$NON-NLS-1$ + pdfa2 = new ChoiceType(metadata, xmlns_pdfaProperty, prefix_pdfaProperty, PDFAPropertyType.CATEGORY, category); + li.addProperty(pdfa2); - bagListNode.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$ + pdfa2 = new ChoiceType(metadata, xmlns_pdfaProperty, prefix_pdfaProperty, PDFAPropertyType.DESCRIPTION, description); + li.addProperty(pdfa2); - Element schemaInfoNode = schema.getOwnerDocument().createElement( - "pdfaSchema:schema"); //$NON-NLS-1$ - XMLUtil.setStringValue(schemaInfoNode, - "ZUGFeRD PDFA Extension Schema"); //$NON-NLS-1$ - bagListNode.appendChild(schemaInfoNode); - - Element nsInfoNode = schema.getOwnerDocument().createElement( - "pdfaSchema:namespaceURI"); //$NON-NLS-1$ - XMLUtil.setStringValue(nsInfoNode, "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#"); //$NON-NLS-1$ - bagListNode.appendChild(nsInfoNode); - - Element prefixInfoNode = schema.getOwnerDocument().createElement( - "pdfaSchema:prefix"); //$NON-NLS-1$ - XMLUtil.setStringValue(prefixInfoNode, "zf"); //$NON-NLS-1$ - bagListNode.appendChild(prefixInfoNode); - - 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$ - - Element seqList1Node = schema.getOwnerDocument().createElement( - "rdf:li"); //$NON-NLS-1$ - - seqList1Node.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$ - - addProperty(seqList1Node, "DocumentFileName", "Text", "external", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - "The name of the embedded Zugferd XML invoice file"); //$NON-NLS-1$ - - sequenceNode.appendChild(seqList1Node); - - Element seqList2Node = schema.getOwnerDocument().createElement( - "rdf:li"); //$NON-NLS-1$ - seqList2Node.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$ - addProperty(seqList2Node, "DocumentType", "Text", "external", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - "INVOICE"); //$NON-NLS-1$ - sequenceNode.appendChild(seqList2Node); - - Element seqList3Node = schema.getOwnerDocument().createElement( - "rdf:li"); //$NON-NLS-1$ - seqList3Node.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$ - addProperty(seqList3Node, "Version", "Text", "external", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - "The version of the ZUGFeRD data"); //$NON-NLS-1$ - sequenceNode.appendChild(seqList3Node); - - Element seqList4Node = schema.getOwnerDocument().createElement( - "rdf:li"); //$NON-NLS-1$ - seqList4Node.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$ - addProperty(seqList4Node, "ConformanceLevel", "Text", "external", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - "The conformance level of the ZUGFeRD data, i.e. BASIC or EXTENDED"); //$NON-NLS-1$ - sequenceNode.appendChild(seqList4Node); - - propertyNode.appendChild(sequenceNode); - - bagListNode.appendChild(propertyNode); - - valueTypeNode.appendChild(seqListValueType); - bagListNode.appendChild(valueTypeNode); - - bagNode.appendChild(bagListNode); - schemasNode.appendChild(bagNode); - - schema.appendChild(schemasNode); - - } + parent.addProperty(li); + return li; } + + public XMPSchemaPDFAExtensions(XMPMetadata metadata) { + + super(metadata); + + addNamespace(xmlns_pdfaSchema, prefix_pdfaSchema); + addNamespace(xmlns_pdfaProperty, prefix_pdfaProperty); + + ArrayProperty newBag = createArrayProperty(SCHEMAS, Cardinality.Bag); + DefinedStructuredType li = new DefinedStructuredType(metadata, getNamespace(), getPrefix(), XmpConstants.LIST_NAME); + li.setAttribute(new Attribute(getNamespace(), XmpConstants.PARSE_TYPE, XmpConstants.RESOURCE_NAME)); + newBag.addProperty(li); + addProperty(newBag); + + TextType pdfa1 = new TextType(metadata, xmlns_pdfaSchema, prefix_pdfaSchema, PDFASchemaType.SCHEMA, "ZUGFeRD PDFA Extension Schema"); + li.addProperty(pdfa1); + + pdfa1 = new TextType(metadata, xmlns_pdfaSchema, prefix_pdfaSchema, PDFASchemaType.NAMESPACE_URI, "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#"); + li.addProperty(pdfa1); + + pdfa1 = new TextType(metadata, xmlns_pdfaSchema, prefix_pdfaSchema, PDFASchemaType.PREFIX, "zf"); + li.addProperty(pdfa1); + + ArrayProperty newSeq = new ArrayProperty(metadata, xmlns_pdfaSchema, prefix_pdfaSchema, PDFASchemaType.PROPERTY, Cardinality.Seq); + li.addProperty(newSeq); + + addProperty(newSeq, "DocumentFileName", "Text", "external", "name of the embedded XML invoice file"); + addProperty(newSeq, "DocumentType", "Text", "external", "INVOICE"); + addProperty(newSeq, "Version", "Text", "external", "The actual version of the ZUGFeRD XML schema"); + addProperty(newSeq, "ConformanceLevel", "Text", "external", "The conformance level of the embedded ZUGFeRD data"); + } + } \ No newline at end of file diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java index fcf9b673..0c9b2347 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java @@ -7,53 +7,22 @@ package org.mustangproject.ZUGFeRD; * @version 1.2.0s * @author jstaerk * */ -import org.apache.jempbox.impl.XMLUtil; -import org.apache.jempbox.xmp.XMPSchemaBasic; -import org.w3c.dom.Element; +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.XMPSchema; +public class XMPSchemaZugferd extends XMPSchema { -public class XMPSchemaZugferd extends XMPSchemaBasic -{ + /** + * This is what needs to be added to the RDF metadata - basically the name of the embedded Zugferd file + */ + public XMPSchemaZugferd(XMPMetadata metadata, String conformanceLevel) { + super(metadata, "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#", "zf", "ZUGFeRD Schema"); - private String conformanceLevel = "EXTENDED"; + setAboutAsSimple(""); - /** - * 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, 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 - schema.removeAttributeNS(NS_NAMESPACE, "xapGImg"); //$NON-NLS-1$ - schema.removeAttributeNS(NS_NAMESPACE, "xmp"); //$NON-NLS-1$ - Element textNode = schema.getOwnerDocument().createElement( - "zf:DocumentType"); //$NON-NLS-1$ - XMLUtil.setStringValue(textNode, "INVOICE"); //$NON-NLS-1$ - schema.appendChild(textNode); - - textNode = schema.getOwnerDocument().createElement( - "zf:DocumentFileName"); //$NON-NLS-1$ - XMLUtil.setStringValue(textNode, "ZUGFeRD-invoice.xml"); //$NON-NLS-1$ - schema.appendChild(textNode); - - textNode = schema.getOwnerDocument().createElement("zf:Version"); //$NON-NLS-1$ - XMLUtil.setStringValue(textNode, "1.0"); //$NON-NLS-1$ - schema.appendChild(textNode); - - textNode = schema.getOwnerDocument().createElement( - "zf:ConformanceLevel"); //$NON-NLS-1$ - XMLUtil.setStringValue(textNode, this.conformanceLevel); //$NON-NLS-1$ - schema.appendChild(textNode); - - } - - } \ No newline at end of file + setTextPropertyValue("ConformanceLevel", conformanceLevel); + setTextPropertyValue("DocumentType", "INVOICE"); + setTextPropertyValue("DocumentFileName", "ZUGFeRD-invoice.xml"); + setTextPropertyValue("Version", "1.0"); + } +} \ No newline at end of file diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java index fcaf9403..d0ad6974 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java @@ -11,6 +11,7 @@ package org.mustangproject.ZUGFeRD; */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; @@ -24,6 +25,8 @@ import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.activation.FileDataSource; import javax.xml.bind.JAXBContext; @@ -32,22 +35,21 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.transform.TransformerException; -import org.apache.jempbox.xmp.XMPMetadata; -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.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.XMPBasicSchema; +import org.apache.xmpbox.schema.DublinCoreSchema; +import org.apache.xmpbox.schema.AdobePDFSchema; +import org.apache.xmpbox.schema.PDFAIdentificationSchema; 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; import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary; import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode; -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; @@ -56,6 +58,8 @@ 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.apache.xmpbox.type.BadFieldValueException; +import org.apache.xmpbox.xml.XmpSerializer; import org.mustangproject.ZUGFeRD.model.*; public class ZUGFeRDExporter { @@ -388,47 +392,27 @@ public class ZUGFeRDExporter { */ 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"); - 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); - } - if (trans.getReferenceNumber() != null && !new String().equals(trans.getReferenceNumber())){ - NoteType referenceInfo = xmlFactory.createNoteType(); - TextType referenceInfoContent = xmlFactory.createTextType(); - referenceInfoContent.setValue("Ursprungsbeleg: " + trans.getReferenceNumber()); - referenceInfo.getContent().add(referenceInfoContent); - document.getIncludedNote().add(referenceInfo); + 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; + } } public void loadPDFA3(String filename) { try { - doc = PDDocument.load(filename); + + doc = PDDocument.load(new File(filename)); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + // TODO Auto-generated catch block + e.printStackTrace(); } } @@ -493,21 +477,19 @@ public class ZUGFeRDExporter { 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(); + XMPMetadata xmp = XMPMetadata.createXMPMetadata(); - XMPSchemaPDFAId pdfaid = new XMPSchemaPDFAId(xmp); - pdfaid.setAbout(""); //$NON-NLS-1$ + + PDFAIdentificationSchema pdfaid = new PDFAIdentificationSchema(xmp); + xmp.addSchema(pdfaid); - XMPSchemaDublinCore dc = xmp.addDublinCoreSchema(); + DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema(); + dc.addCreator(creator); - dc.setAbout(""); //$NON-NLS-1$ - - XMPSchemaBasic xsb = xmp.addBasicSchema(); - xsb.setAbout(""); //$NON-NLS-1$ - + + XMPBasicSchema xsb = xmp.createAndAddXMPBasicSchema(); + xsb.setCreatorTool(creator); xsb.setCreateDate(GregorianCalendar.getInstance()); // PDDocumentInformation pdi=doc.getDocumentInformation(); @@ -516,23 +498,26 @@ public class ZUGFeRDExporter { pdi.setAuthor(creator); doc.setDocumentInformation(pdi); - XMPSchemaPDF pdf = xmp.addPDFSchema(); + AdobePDFSchema pdf = xmp.createAndAddAdobePDFSchema(); 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$ + /* + * // 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. + */ + try { + pdfaid.setConformance(conformanceLevel);//$NON-NLS-1$ //$NON-NLS-1$ + } catch (BadFieldValueException ex) { + Logger.getLogger(ZUGFeRDExporter.class.getName()).log(Level.SEVERE, null, ex); + } pdfaid.setPart(3); @@ -546,7 +531,11 @@ public class ZUGFeRDExporter { } - metadata.importXMPMetadata(xmp); + XmpSerializer serializer = new XmpSerializer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + serializer.serialize(xmp, baos, false); + metadata.importXMPMetadata( baos.toByteArray() ); + return cat; } @@ -625,7 +614,7 @@ public class ZUGFeRDExporter { TextType name = xmlFactory.createTextType(); name.setValue("RECHNUNG"); document.getName().add(name); - + if (trans.getOwnOrganisationFullPlaintextInfo() != null) { NoteType regularInfo = xmlFactory.createNoteType(); CodeType regularInfoSubjectCode = xmlFactory.createCodeType(); @@ -637,6 +626,14 @@ public class ZUGFeRDExporter { regularInfo.getContent().add(regularInfoContent); document.getIncludedNote().add(regularInfo); } + + if (trans.getReferenceNumber() != null && !new String().equals(trans.getReferenceNumber())){ + NoteType referenceInfo = xmlFactory.createNoteType(); + TextType referenceInfoContent = xmlFactory.createTextType(); + referenceInfoContent.setValue("Ursprungsbeleg: " + trans.getReferenceNumber()); + referenceInfo.getContent().add(referenceInfoContent); + document.getIncludedNote().add(referenceInfo); + } return document; } @@ -1386,44 +1383,40 @@ public class ZUGFeRDExporter { 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 + 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$ + 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; - } - } + 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); + 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(); - } + try { + doc.save(ZUGFeRDfilename); + } catch (IOException ex) { + ex.printStackTrace(); + } } /** @@ -1441,14 +1434,16 @@ public class ZUGFeRDExporter { * type of the data e.g. could be "text/xml" - mime like * @param data * the binary data of the file/attachment + * @throws java.io.IOException */ 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(); + COSDictionary dict = fs.getCOSObject(); dict.setName("AFRelationship", relationship); dict.setString("UF", filename); dict.setString("Desc", description); @@ -1464,7 +1459,7 @@ public class ZUGFeRDExporter { fs.setEmbeddedFile(ef); // In addition make sure the embedded file is set under /UF - dict = fs.getCOSDictionary(); + dict = fs.getCOSObject(); COSDictionary efDict = (COSDictionary) dict .getDictionaryObject(COSName.EF); COSBase lowerLevelFile = efDict.getItem(COSName.F); @@ -1478,8 +1473,9 @@ public class ZUGFeRDExporter { efTree = new PDEmbeddedFilesNameTreeNode(); } - Map namesMap = new HashMap(); - Map oldNamesMap = efTree.getNames(); + Map namesMap = new HashMap(); + + Map oldNamesMap = efTree.getNames(); if (oldNamesMap != null) { for (String key : oldNamesMap.keySet()) { namesMap.put(key, oldNamesMap.get(key)); @@ -1493,16 +1489,16 @@ public class ZUGFeRDExporter { // AF entry (Array) in catalog with the FileSpec COSArray cosArray = (COSArray) doc.getDocumentCatalog() - .getCOSDictionary().getItem("AF"); + .getCOSObject().getItem("AF"); if (cosArray == null) { cosArray = new COSArray(); } cosArray.add(fs); - COSDictionary dict2 = doc.getDocumentCatalog().getCOSDictionary(); + COSDictionary dict2 = doc.getDocumentCatalog().getCOSObject(); COSArray array = new COSArray(); - array.add(fs.getCOSDictionary()); // see below + array.add(fs.getCOSObject()); // see below dict2.setItem("AF",array); - doc.getDocumentCatalog().getCOSDictionary().setItem("AF", cosArray); + doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray); } /** @@ -1538,11 +1534,11 @@ public class ZUGFeRDExporter { 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); } diff --git a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index dccb0d3d..142302e9 100644 --- a/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/mustang/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -49,7 +49,7 @@ public class ZUGFeRDImporter { private String IBAN; private String holder; private String amount; - private String dueDate; + private String dueDate; /** Raw XML form of the extracted data - may be directly obtained. */ private byte[] rawXML=null; private String bankName; @@ -90,7 +90,7 @@ public class ZUGFeRDImporter { doc.close(); return; } - Map efMap = etn.getNames(); + Map efMap = etn.getNames(); // String filePath = "/tmp/"; for (String filename : efMap.keySet()) { /** @@ -109,7 +109,8 @@ public class ZUGFeRDImporter { // ByteArrayOutputStream fileBytes=new // ByteArrayOutputStream(); // FileOutputStream fos = new FileOutputStream(file); - rawXML = embeddedFile.getByteArray(); + + rawXML = embeddedFile.toByteArray(); setMeta(new String(rawXML)); extracted=true; // fos.write(embeddedFile.getByteArray()); diff --git a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java index 6ce243a9..ef3f78e2 100644 --- a/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java +++ b/mustang/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java @@ -14,7 +14,6 @@ import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; -import org.apache.pdfbox.pdmodel.PDDocument; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; @@ -129,9 +128,9 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp public IZUGFeRDExportableItem[] getZFItems() { Item[] allItems = new Item[3]; - Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR", new BigDecimal("7.000000")); + Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR", new BigDecimal("7.000000")); Product balloonProduct = new Product("", "Luftballon: Bunt, ca. 500ml", "C62", new BigDecimal("19.000000")); - Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000")); + Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000")); allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct); allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct); @@ -141,7 +140,7 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp @Override public String getOwnPaymentInfoText() { - return "Überweisung"; + return "Überweisung"; } @Override