diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..2d283f09 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# Tab indentation (no size specified) +[*.java] +indent_style = tab + +# 2 space indentation +[*.xsd,*.xsl,*.xml] +indent_style = space +indent_size = 2 + +# all x** Files +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/src/main/java-templates/org/mustangproject/ZUGFeRD/Version.java b/src/main/java-templates/org/mustangproject/ZUGFeRD/Version.java index a85d0222..f669dfe4 100644 --- a/src/main/java-templates/org/mustangproject/ZUGFeRD/Version.java +++ b/src/main/java-templates/org/mustangproject/ZUGFeRD/Version.java @@ -19,5 +19,5 @@ package org.mustangproject.ZUGFeRD; public final class Version { - public static final String VERSION = "${project.version}"; + public static final String VERSION = "${project.version}"; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/CustomXMLProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/CustomXMLProvider.java index f5b9825c..dfd8be88 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/CustomXMLProvider.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/CustomXMLProvider.java @@ -28,12 +28,12 @@ public class CustomXMLProvider implements IXMLProvider { } public void setXML(byte[] newData) { - String zf=new String(newData); + String zf = new String(newData); if (!zf.contains(" + * Lieferant GmbH + * Lieferantenstraße 20 + * 80333 München + * Deutschland + * Geschäftsführer: Hans Muster + * Handelsregisternummer: H A 123 * - Lieferant GmbH - Lieferantenstraße 20 - 80333 München - Deutschland - Geschäftsführer: Hans Muster - Handelsregisternummer: H A 123 * @return null or full sender institution name, details, manager and tax registration */ String getOwnOrganisationFullPlaintextInfo(); /** * when the invoice is to be paid + * * @return when the invoice is to be paid */ Date getDueDate(); - IZUGFeRDAllowanceCharge[] getZFAllowances(); - IZUGFeRDAllowanceCharge[] getZFCharges(); - IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges(); + IZUGFeRDAllowanceCharge[] getZFAllowances(); + + IZUGFeRDAllowanceCharge[] getZFCharges(); + + IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges(); IZUGFeRDExportableItem[] getZFItems(); - /*** + /** * the recipient + * * @return the recipient of the invoice */ IZUGFeRDExportableContact getRecipient(); - /*** + /** * BIC of the sender + * * @return the BIC code of the recipient sender's bank */ String getOwnBIC(); - /*** - * BLZ of the sender - * @return the BLZ code of the recipient sender's bank - */ - String getOwnBLZ(); + /** + * BLZ of the sender + * + * @return the BLZ code of the recipient sender's bank + */ + String getOwnBLZ(); - /*** + /** * Bank name of the sender + * * @return the name of the sender's bank */ String getOwnBankName(); /** * IBAN of the sender - * @return the IBAN of the invoice sender's bank account + * + * @return the IBAN of the invoice sender's bank account */ String getOwnIBAN(); - /** - * IBAN of the sender - * @return the Account Number of the invoice sender's bank account - */ - String getOwnKto(); + /** + * IBAN of the sender + * + * @return the Account Number of the invoice sender's bank account + */ + String getOwnKto(); - /** + /** * Tax ID (not VAT ID) of the sender - * @return Tax ID (not VAT ID) of the sender + * + * @return Tax ID (not VAT ID) of the sender */ String getOwnTaxID(); /** * VAT ID (Umsatzsteueridentifikationsnummer) of the sender + * * @return VAT ID (Umsatzsteueridentifikationsnummer) of the sender */ String getOwnVATID(); /** * own name + * * @return the sender's organisation name */ String getOwnOrganisationName(); /** * own street address + * * @return sender street address */ String getOwnStreet(); /** * own street postal code + * * @return sender postal code */ String getOwnZIP(); /** * own city + * * @return the invoice sender's city */ String getOwnLocation(); /** * own two digit country code + * * @return the invoice senders two character country iso code */ String getOwnCountry(); /** * get delivery date + * * @return the day the goods have been delivered */ Date getDeliveryDate(); - /** + /** * get main invoice currency used on the invoice + * * @return three character currency of this invoice */ - String getCurrency(); + String getCurrency(); - /** + /** * get payment information text. e.g. Bank transfer + * * @return payment information text */ - String getOwnPaymentInfoText(); + String getOwnPaymentInfoText(); - /** + /** * get payment term descriptional text - * e.g. Bis zum 22.10.2015 ohne Abzug + * e.g. Bis zum 22.10.2015 ohne Abzug + * * @return get payment terms */ - String getPaymentTermDescription(); + String getPaymentTermDescription(); - /** - * get reference document number - * typically used for Invoice Corrections - * Will be added as IncludedNote in comfort profile - * @return the ID of the document this document refers to - */ - String getReferenceNumber(); + /** + * get reference document number + * typically used for Invoice Corrections + * Will be added as IncludedNote in comfort profile + * + * @return the ID of the document this document refers to + */ + String getReferenceNumber(); } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/PDFAConformanceLevel.java b/src/main/java/org/mustangproject/ZUGFeRD/PDFAConformanceLevel.java index 65fc8599..47cfaeb6 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/PDFAConformanceLevel.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/PDFAConformanceLevel.java @@ -19,24 +19,24 @@ package org.mustangproject.ZUGFeRD; public enum PDFAConformanceLevel { - ACCESSIBLE("A"), BASIC("B"), UNICODE("U"); + ACCESSIBLE("A"), BASIC("B"), UNICODE("U"); - private final String letter; + private final String letter; - PDFAConformanceLevel(String letter) { - this.letter = letter; - } + PDFAConformanceLevel(String letter) { + this.letter = letter; + } - public String getLetter() { - return letter; - } + public String getLetter() { + return letter; + } - public static PDFAConformanceLevel findByLetter(String letter) { - for (PDFAConformanceLevel candidate : values()) { - if (candidate.letter.equals(letter)) { - return candidate; - } - } - throw new IllegalArgumentException("PDF conformance level <" + letter + "> is unknown."); - } + public static PDFAConformanceLevel findByLetter(String letter) { + for (PDFAConformanceLevel candidate : values()) { + if (candidate.letter.equals(letter)) { + return candidate; + } + } + throw new IllegalArgumentException("PDF conformance level <" + letter + "> is unknown."); + } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java b/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java index 275f75d9..32d180ca 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java @@ -19,46 +19,48 @@ 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 - * */ + * @version 1.2.0 + * @date 2015-10-29 + */ public class VATAmount { - public VATAmount(BigDecimal basis, BigDecimal calculated) { - super(); - this.basis = basis; - this.calculated = calculated; - } + public VATAmount(BigDecimal basis, BigDecimal calculated) { + super(); + this.basis = basis; + this.calculated = calculated; + } - BigDecimal basis, calculated; + BigDecimal basis, calculated; - public BigDecimal getBasis() { - return basis; - } + public BigDecimal getBasis() { + return basis; + } - public void setBasis(BigDecimal basis) { - this.basis = basis; - } + public void setBasis(BigDecimal basis) { + this.basis = basis; + } - public BigDecimal getCalculated() { - return calculated; - } + public BigDecimal getCalculated() { + return calculated; + } - public void setCalculated(BigDecimal calculated) { - this.calculated = calculated; - } + public void setCalculated(BigDecimal calculated) { + this.calculated = calculated; + } - public VATAmount add(VATAmount v) { - return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated())); - } + public VATAmount add(VATAmount v) { + return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated())); + } - public VATAmount subtract(VATAmount v) { - return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated())); - } + public VATAmount subtract(VATAmount v) { + return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated())); + } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java b/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java index 242f7705..131638db 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java @@ -55,13 +55,13 @@ public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema { protected void setZUGFeRDVersion(int ver) { - namespace=ZUGFeRDExporter.getNamespaceForVersion(ver); - prefix=ZUGFeRDExporter.getPrefixForVersion(ver); + namespace = ZUGFeRDExporter.getNamespaceForVersion(ver); + prefix = ZUGFeRDExporter.getPrefixForVersion(ver); } private DefinedStructuredType addProperty(ArrayProperty parent, String name, String type, String category, - String description) { + String description) { XMPMetadata metadata = getMetadata(); DefinedStructuredType li = new DefinedStructuredType(metadata, getNamespace(), getPrefix(), @@ -133,4 +133,4 @@ public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema { "The selected ZUGFeRD profile completeness"); } } -} \ No newline at end of file +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java b/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java index ef6eb8ba..57cc5197 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java @@ -25,28 +25,29 @@ package org.mustangproject.ZUGFeRD; * @version 1.2.0s * @author jstaerk * */ + import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.schema.XMPSchema; public class XMPSchemaZugferd extends XMPSchema { - /** - * This is what needs to be added to the RDF metadata - basically the name of the embedded Zugferd file - */ - public XMPSchemaZugferd(XMPMetadata metadata, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) { - super(metadata, URN, prefix, "ZUGFeRD Schema"); + /** + * This is what needs to be added to the RDF metadata - basically the name of the embedded Zugferd file + */ + public XMPSchemaZugferd(XMPMetadata metadata, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) { + super(metadata, URN, prefix, "ZUGFeRD Schema"); - setAboutAsSimple(""); + setAboutAsSimple(""); - String conformanceLevelValue=conformanceLevel.name(); - if (conformanceLevelValue.equals("BASICWL")) { - conformanceLevelValue="BASIC WL"; - } else if (conformanceLevelValue.equals("EN16931")) { - conformanceLevelValue="EN 16931"; - } - setTextPropertyValue("ConformanceLevel", conformanceLevelValue); - setTextPropertyValue("DocumentType", "INVOICE"); - setTextPropertyValue("DocumentFileName", filename); - setTextPropertyValue("Version", "1.0"); - } + String conformanceLevelValue = conformanceLevel.name(); + if (conformanceLevelValue.equals("BASICWL")) { + conformanceLevelValue = "BASIC WL"; + } else if (conformanceLevelValue.equals("EN16931")) { + conformanceLevelValue = "EN 16931"; + } + setTextPropertyValue("ConformanceLevel", conformanceLevelValue); + setTextPropertyValue("DocumentType", "INVOICE"); + setTextPropertyValue("DocumentFileName", filename); + setTextPropertyValue("Version", "1.0"); + } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java index 2b649642..3c782866 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java @@ -36,14 +36,13 @@ public class ZUGFeRD1PullProvider implements IXMLProvider { private boolean isTest; - /** * enables the flag to indicate a test invoice in the XML structure - * */ public void setTest() { isTest = true; } + public ZUGFeRD1PullProvider() { // TODO Auto-generated constructor stub try { @@ -51,16 +50,16 @@ public class ZUGFeRD1PullProvider implements IXMLProvider { marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new ZFNamespacePrefixMapper()); - } catch (JAXBException e) { - throw new ZUGFeRDExportException("Could not initialize JAXB", e); - } + } catch (JAXBException e) { + throw new ZUGFeRDExportException("Could not initialize JAXB", e); + } } private String createZugferdXMLForTransaction(IZUGFeRDExportableTransaction trans) { JAXBElement jaxElement = - new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).convertToModel(); + new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).convertToModel(); try { return marshalJaxToXMLString(jaxElement); @@ -84,23 +83,22 @@ public class ZUGFeRD1PullProvider implements IXMLProvider { @Override public void generateXML(IZUGFeRDExportableTransaction trans) { - // create a dummy file stream, this would probably normally be a - // FileInputStream + // create a dummy file stream, this would probably normally be a + // FileInputStream - byte[] zugferdRaw = createZugferdXMLForTransaction(trans).getBytes(); //$NON-NLS-1$ + byte[] zugferdRaw = createZugferdXMLForTransaction(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; + } } - } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index dfac61cc..2fb91343 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -29,18 +29,18 @@ import java.util.HashMap; public class ZUGFeRD2PullProvider implements IXMLProvider { private class LineCalc { - private IZUGFeRDExportableItem currentItem=null; + private IZUGFeRDExportableItem currentItem = null; private BigDecimal totalGross; private BigDecimal itemTotalNetAmount; private BigDecimal itemTotalVATAmount; public LineCalc(IZUGFeRDExportableItem currentItem) { - this.currentItem=currentItem; - BigDecimal multiplicator=currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)).add(new BigDecimal(1)); + this.currentItem = currentItem; + BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)).add(new BigDecimal(1)); // priceGross=currentItem.getPrice().multiply(multiplicator); - totalGross=currentItem.getPrice().multiply(multiplicator).multiply(currentItem.getQuantity()); - itemTotalNetAmount=currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2,BigDecimal.ROUND_HALF_UP); - itemTotalVATAmount=totalGross.subtract(itemTotalNetAmount); + totalGross = currentItem.getPrice().multiply(multiplicator).multiply(currentItem.getQuantity()); + itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2, BigDecimal.ROUND_HALF_UP); + itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount); } public BigDecimal getItemTotalNetAmount() { @@ -54,7 +54,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } - //// MAIN CLASS protected byte[] zugferdData; @@ -63,7 +62,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { /** * enables the flag to indicate a test invoice in the XML structure - * */ public void setTest() { isTest = true; @@ -96,13 +94,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { * * 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 + 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); + DecimalFormat dec = new DecimalFormat("0." + new String(repeat), otherSymbols); return dec.format(value); } @@ -118,6 +116,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { private String priceFormat(BigDecimal value) { return nDigitFormat(value, 4); } + private String quantityFormat(BigDecimal value) { return nDigitFormat(value, 4); } @@ -129,11 +128,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { private BigDecimal getTotalGross() { - BigDecimal res=getTotal(); - HashMap VATPercentAmountMap=getVATPercentAmountMap(); + BigDecimal res = getTotal(); + HashMap VATPercentAmountMap = getVATPercentAmountMap(); for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); - res=res.add(amount.getCalculated()); + res = res.add(amount.getCalculated()); } @@ -141,10 +140,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } private BigDecimal getTotal() { - BigDecimal res=new BigDecimal(0); + BigDecimal res = new BigDecimal(0); for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { - LineCalc lc=new LineCalc(currentItem); - res=res.add(lc.getItemTotalNetAmount()); + LineCalc lc = new LineCalc(currentItem); + res = res.add(lc.getItemTotalNetAmount()); } return res; } @@ -154,18 +153,18 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { * 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 which taxes have been used with which amounts in this invoice * - */ + * @return which taxes have been used with which amounts in this invoice + */ private HashMap getVATPercentAmountMap() { - HashMap hm=new HashMap (); + 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) { + 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)); @@ -180,17 +179,17 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { @Override public void generateXML(IZUGFeRDExportableTransaction trans) { - this.trans=trans; + this.trans = trans; SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); //$NON-NLS-1$ SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$ - String testBooleanStr="false"; + String testBooleanStr = "false"; if (isTest) { - testBooleanStr="true"; + testBooleanStr = "true"; } - String senderReg=""; - if (trans.getOwnOrganisationFullPlaintextInfo()!=null) { - senderReg="" + String senderReg = ""; + if (trans.getOwnOrganisationFullPlaintextInfo() != null) { + senderReg = "" + "\n" + " \n" + trans.getOwnOrganisationFullPlaintextInfo() @@ -201,25 +200,24 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } + String xml = "\n" //$NON-NLS-1$ - String xml= "\n" //$NON-NLS-1$ - - + "\n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ + + " xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\"" + + " xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">\n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ // + " "+testBooleanStr+"\n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931\n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+trans.getNumber()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931\n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + trans.getNumber() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // + " RECHNUNG\n" //$NON-NLS-1$ - + " 380\n" //$NON-NLS-1$ - + " "+zugferdDateFormat.format(trans.getIssueDate())+"\n" //date format was 20130605 //$NON-NLS-1$ //$NON-NLS-2$ - + senderReg + + " 380\n" //$NON-NLS-1$ + + " " + zugferdDateFormat.format(trans.getIssueDate()) + "\n" //date format was 20130605 //$NON-NLS-1$ //$NON-NLS-2$ + + senderReg // + " \n" // + " \n" // + "Rechnung gemäß Bestellung Nr. 2013-471331 vom 01.03.2013.\n" @@ -232,145 +230,142 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { // + " \n" // + " AAK\n" // + " \n" - + " \n" //$NON-NLS-1$ - + " \n"; //$NON-NLS-1$ - int lineID=0; - for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { - lineID++; + + " \n" //$NON-NLS-1$ + + " \n"; //$NON-NLS-1$ + int lineID = 0; + for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { + lineID++; - LineCalc lc=new LineCalc(currentItem); - xml=xml+ " \n"+ //$NON-NLS-1$ - " \n" //$NON-NLS-1$ - + " "+lineID+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ + LineCalc lc = new LineCalc(currentItem); + xml = xml + " \n" + //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + + " " + lineID + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ // + " 4012345001235\n" // + " KR3M\n" // + " 55T01\n" - + " "+currentItem.getProduct().getName()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " "+currentItem.getProduct().getDescription()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ + + " " + currentItem.getProduct().getName() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + currentItem.getProduct().getDescription() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+priceFormat(currentItem.getPrice())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ //currencyID=\"EUR\" - + " 1.0000\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + priceFormat(currentItem.getPrice()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ //currencyID=\"EUR\" + + " 1.0000\n" //$NON-NLS-1$ //$NON-NLS-2$ // + " \n" // + " false\n" // + " 0.6667\n" // + " Rabatt\n" // + " \n" - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+priceFormat(currentItem.getPrice())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" - + " 1.0000\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + priceFormat(currentItem.getPrice()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" + + " 1.0000\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+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$ - + " "+vatFormat(currentItem.getProduct().getVATPercent())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+currencyFormat(lc.getItemTotalNetAmount())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " \n"; //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + 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$ + + " " + vatFormat(currentItem.getProduct().getVATPercent()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + currencyFormat(lc.getItemTotalNetAmount()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " \n"; //$NON-NLS-1$ + } - } - - xml=xml+ " \n" //$NON-NLS-1$ + xml = xml + " \n" //$NON-NLS-1$ // + " AB-312\n" - + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ // + " 4000001123452\n" - + " "+trans.getOwnOrganisationName()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" - + " "+trans.getOwnZIP()+"\n" - + " "+trans.getOwnStreet()+"\n" - + " "+trans.getOwnLocation()+"\n" - + " "+trans.getOwnCountry()+"\n" - + " \n" - + " \n" //$NON-NLS-1$ - + " "+trans.getOwnTaxID()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+trans.getOwnVATID()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ + + " " + trans.getOwnOrganisationName() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" + + " " + trans.getOwnZIP() + "\n" + + " " + trans.getOwnStreet() + "\n" + + " " + trans.getOwnLocation() + "\n" + + " " + trans.getOwnCountry() + "\n" + + " \n" + + " \n" //$NON-NLS-1$ + + " " + trans.getOwnTaxID() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + trans.getOwnVATID() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ // + " GE2020211\n" // + " 4000001987658\n" - + " "+trans.getRecipient().getName()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + trans.getRecipient().getName() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // + " \n" // + " xxx\n" // + " \n" - + " \n" //$NON-NLS-1$ - + " "+trans.getRecipient().getZIP()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " "+trans.getRecipient().getStreet()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " "+trans.getRecipient().getLocation()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " "+trans.getRecipient().getCountry()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+trans.getRecipient().getVATID()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + trans.getRecipient().getZIP() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + trans.getRecipient().getStreet() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + trans.getRecipient().getLocation() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + trans.getRecipient().getCountry() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + trans.getRecipient().getVATID() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ // + " \n" // + " 20130301\n" // + " 2013-471331\n" // + " \n" - + " \n" //$NON-NLS-1$ - + " \n" - + " \n" - + " "+zugferdDateFormat.format(trans.getDeliveryDate())+"\n" - + " \n" + + " \n" //$NON-NLS-1$ + + " \n" + + " \n" + + " " + zugferdDateFormat.format(trans.getDeliveryDate()) + "\n" + + " \n" /* + " \n" + " 20130603\n" + " 2013-51112\n" + " \n" */ - + " \n" - + " \n" //$NON-NLS-1$ - + " "+trans.getNumber()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " EUR\n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " 42\n" //$NON-NLS-1$ - + " Überweisung\n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+trans.getOwnIBAN()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " "+trans.getOwnKto()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+trans.getOwnBIC()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " "+ trans.getOwnBLZ()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" + + " \n" //$NON-NLS-1$ + + " " + trans.getNumber() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " EUR\n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " 42\n" //$NON-NLS-1$ + + " Überweisung\n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + trans.getOwnIBAN() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + trans.getOwnKto() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + trans.getOwnBIC() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + trans.getOwnBLZ() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // + " "+trans.getOwnBankName()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n"; //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " \n"; //$NON-NLS-1$ - - HashMap VATPercentAmountMap=getVATPercentAmountMap(); - for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { - VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); - if (amount != null) { - xml += " \n" //$NON-NLS-1$ - + " "+currencyFormat(amount.getCalculated())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ //currencyID=\"EUR\" - + " VAT\n" //$NON-NLS-1$ - + " "+currencyFormat(amount.getBasis())+"\n" // currencyID=\"EUR\" - + " S\n" //$NON-NLS-1$ - + " "+vatFormat(currentTaxPercent)+"\n" //$NON-NLS-1$ - + " \n"; //$NON-NLS-1$ + HashMap VATPercentAmountMap = getVATPercentAmountMap(); + for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { + VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); + if (amount != null) { + xml += " \n" //$NON-NLS-1$ + + " " + currencyFormat(amount.getCalculated()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ //currencyID=\"EUR\" + + " VAT\n" //$NON-NLS-1$ + + " " + currencyFormat(amount.getBasis()) + "\n" // currencyID=\"EUR\" + + " S\n" //$NON-NLS-1$ + + " " + vatFormat(currentTaxPercent) + "\n" //$NON-NLS-1$ + + " \n"; //$NON-NLS-1$ - - } } + } /* xml+= " + " \n" + " false\n" @@ -404,23 +399,23 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + " \n" + " \n"*/ - xml=xml+ " \n" //$NON-NLS-1$ - + " Zahlbar ohne Abzug bis "+germanDateFormat.format(trans.getDueDate())+"\n" - + " "+zugferdDateFormat.format(trans.getDueDate())+"\n"//20130704 //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " "+currencyFormat(getTotal())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ currencyID=\"EUR\" - + " 0.00\n" //$NON-NLS-1$ currencyID=\"EUR\" - + " 0.00\n" //$NON-NLS-1$ // currencyID=\"EUR\" + xml = xml + " \n" //$NON-NLS-1$ + + " Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate()) + "\n" + + " " + zugferdDateFormat.format(trans.getDueDate()) + "\n"//20130704 //$NON-NLS-1$ //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ currencyID=\"EUR\" + + " 0.00\n" //$NON-NLS-1$ currencyID=\"EUR\" + + " 0.00\n" //$NON-NLS-1$ // currencyID=\"EUR\" // + " 5.80\n" // + " 14.73\n" - + " "+currencyFormat(getTotal())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" - + " "+currencyFormat(getTotalGross().subtract(getTotal()))+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " "+currencyFormat(getTotalGross())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" + + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" + + " " + currencyFormat(getTotalGross().subtract(getTotal())) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" // + " 0.00\n" - + " "+currencyFormat(getTotalGross())+"\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" - + " \n" //$NON-NLS-1$ - + " \n"; //$NON-NLS-1$ + + " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" + + " \n" //$NON-NLS-1$ + + " \n"; //$NON-NLS-1$ // + " \n" // + " \n" // + " \n" @@ -430,26 +425,24 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { // + " \n"; + xml = xml + " \n" //$NON-NLS-1$ + + ""; //$NON-NLS-1$ + byte[] zugferdRaw; + try { + zugferdRaw = xml.getBytes("UTF-8"); - xml=xml + " \n" //$NON-NLS-1$ - + ""; //$NON-NLS-1$ - - byte[] zugferdRaw; - try { - zugferdRaw = xml.getBytes("UTF-8"); - - 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; - } - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } //$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; + } + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } //$NON-NLS-1$ } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java index 432c24c6..7705697b 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java @@ -19,6 +19,5 @@ package org.mustangproject.ZUGFeRD; public enum ZUGFeRDConformanceLevel { - BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS - ; + BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExportException.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExportException.java index f5b493c0..c318fccd 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExportException.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExportException.java @@ -19,23 +19,23 @@ package org.mustangproject.ZUGFeRD; public class ZUGFeRDExportException extends RuntimeException { - /** + /** * */ private static final long serialVersionUID = 1L; public ZUGFeRDExportException() { - } + } - public ZUGFeRDExportException(String message) { - super(message); - } + public ZUGFeRDExportException(String message) { + super(message); + } - public ZUGFeRDExportException(String message, Throwable cause) { - super(message, cause); - } + public ZUGFeRDExportException(String message, Throwable cause) { + super(message, cause); + } - public ZUGFeRDExportException(Throwable cause) { - super(cause); - } + public ZUGFeRDExportException(Throwable cause) { + super(cause); + } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java index ae6fc1f5..925217ce 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java @@ -1,652 +1,644 @@ - -/** ********************************************************************** - * - * Copyright 2018 Jochen Staerk - * - * Use is subject to license terms. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *********************************************************************** */ -package org.mustangproject.ZUGFeRD; - -/* - * Mustangproject's ZUGFeRD implementation ZUGFeRD exporter Licensed under the - * APLv2 - * - * @date 2014-07-12 - * @version 1.2.0 - * @author jstaerk - * - */ - -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.pdmodel.*; -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.xmpbox.XMPMetadata; -import org.apache.xmpbox.schema.AdobePDFSchema; -import org.apache.xmpbox.schema.DublinCoreSchema; -import org.apache.xmpbox.schema.PDFAIdentificationSchema; -import org.apache.xmpbox.schema.XMPBasicSchema; -import org.apache.xmpbox.type.BadFieldValueException; -import org.apache.xmpbox.xml.XmpSerializer; - -import javax.xml.transform.TransformerException; -import java.io.*; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; - -public class ZUGFeRDExporter implements Closeable { - - public static final int DefaultZUGFeRDVersion = 1; - - private static boolean isFacturX=false; - - /** - * 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 - * @deprecated Use the factory methods {@link #createFromPDFA3(String)}, - * {@link #createFromPDFA3(InputStream)} or the - * {@link ZUGFeRDExporterFromA1Factory} instead - * - */ - // // MAIN CLASS - @Deprecated - private PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE; - - // BASIC, COMFORT etc - may be set from outside. - @Deprecated - private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EXTENDED; - - /** - * 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. - */ - IXMLProvider xmlProvider; - protected PDMetadata metadata = null; - protected PDFAIdentificationSchema pdfaid = null; - protected XMPMetadata xmp = null; - /** Producer attribute for PDF */ - protected String producer = "mustangproject"; - /** Author/Creator attribute for PDF for PDF */ - protected String creator = "mustangproject"; - /** CreatorTool */ - protected String creatorTool = "mustangproject"; - - @Deprecated - private boolean ignoreA1Errors; - protected boolean ensurePDFisUpgraded = true; - private PDDocument doc; - int ZFVersion; - - private HashMap additionalXMLs=new HashMap(); - - - private boolean disableAutoClose; - - private boolean fileAttached = false; - protected boolean attachZUGFeRDHeaders = true; - - private boolean documentPrepared=false; - - public ZUGFeRDExporter() { - init(); - } - - public ZUGFeRDExporter(PDDocument doc2) { - doc = doc2; - init(); - } - - public void addAdditonalXML(String filename, byte[] xml) { - additionalXMLs.put(filename, xml); - } - - public static String getNamespaceForVersion(int ver) { - if (ver == 1) { - return "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#"; - } else if (ver == 2) { - return "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#"; - } else { - throw new IllegalArgumentException("Version not supported"); - } - } - - public static String getPrefixForVersion(int ver) { - if (ver == 1) { - return "zf"; - } else if (ver == 2) { - return "fx"; - } else { - throw new IllegalArgumentException("Version not supported"); - } - } - - public static String getFilenameForVersion(int ver) { - if (ver == 1) { - return "ZUGFeRD-invoice.xml"; - } else if ((ver == 2) || (isFacturX)) { - return "factur-x.xml"; - } else { - throw new IllegalArgumentException("Version not supported"); - } - } - - @Deprecated - public void setZUGFeRDVersion(int ver) { - if (ver == 1) { - ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider(); - this.xmlProvider = z1p; - } else if (ver == 2) { - ZUGFeRD2PullProvider z2p = new ZUGFeRD2PullProvider(); - this.xmlProvider = z2p; - } else { - throw new IllegalArgumentException("Version not supported"); - } - ZFVersion = ver; - } - - public IXMLProvider getProvider() { - return xmlProvider; - } - - private void init() { - setZUGFeRDVersion(DefaultZUGFeRDVersion); - } - - public void setFacturX() { - setZUGFeRDVersion(2); - isFacturX=true; - } - - /** - * All files are PDF/A-3, setConformance refers to the level conformance. - * - * PDF/A-3 has three conformance 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 :-) - * - * @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead - */ - @Deprecated - public void setConformanceLevel(PDFAConformanceLevel newLevel) { - if (newLevel == null) { - throw new NullPointerException("pdf conformance level"); - } - conformanceLevel = newLevel; - } - - /** - * All files are PDF/A-3, setConformance refers to the level conformance. - * - * PDF/A-3 has three conformance 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 :-) - * - * @deprecated Use - * {@link #setConformanceLevel(org.mustangproject.ZUGFeRD.PDFAConformanceLevel)} - * instead - */ - @Deprecated - public void setConformanceLevel(String newLevel) { - conformanceLevel = PDFAConformanceLevel.findByLetter(newLevel); - } - - /** - * enables the flag to indicate a test invoice in the XML structure - * - */ - public void setTest() { - xmlProvider.setTest(); - } - - /** - * @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead - */ - @Deprecated - public void ignoreA1Errors() { - ignoreA1Errors = true; - } - - /** - * @deprecated Use the factory method {@link #createFromPDFA3(String)} instead - */ - @Deprecated - public void loadPDFA3(String filename) throws IOException { - doc = PDDocument.load(new File(filename)); - } - - public static ZUGFeRDExporter createFromPDFA3(String filename) throws IOException { - return new ZUGFeRDExporter(PDDocument.load(new File(filename))); - } - - /** - * @deprecated Use the factory method {@link #createFromPDFA3(InputStream)} - * instead - */ - @Deprecated - public void loadPDFA3(InputStream file) throws IOException { - doc = PDDocument.load(file); - } - - public static ZUGFeRDExporter createFromPDFA3(InputStream pdfSource) throws IOException { - return new ZUGFeRDExporter(PDDocument.load(pdfSource)); - } - - /** - * 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) - * - * @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead - * - */ - @Deprecated - public PDDocumentCatalog PDFmakeA3compliant(String filename, String producer, String creator, - boolean attachZugferdHeaders) throws IOException, TransformerException { - - doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(filename).doc; - - return doc.getDocumentCatalog(); - } - - /** - * @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead - */ - @Deprecated - public PDDocumentCatalog PDFmakeA3compliant(InputStream file, String producer, String creator, - boolean attachZugferdHeaders) throws IOException, TransformerException { - - doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(file).doc; - - return doc.getDocumentCatalog(); - } - - private IExporterFactory createPDFA1Factory() { - ZUGFeRDExporterFromA1Factory factory = new ZUGFeRDExporterFromA1Factory(); - if (ignoreA1Errors) { - factory.ignorePDFAErrors(); - } - return factory.setZUGFeRDConformanceLevel(profile).setConformanceLevel(conformanceLevel); - } - - @Override - public void close() throws IOException { - if (doc != null) { - doc.close(); - } - } - - /** - * Embeds the Zugferd XML structure in a file named ZUGFeRD-invoice.xml. - * - * @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 { - prepareDocument(); - - xmlProvider.generateXML(trans); - String filename = getFilenameForVersion(ZFVersion); - PDFAttachGenericFile(doc, filename, "Alternative", - "Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)", - "text/xml", xmlProvider.getXML()); - for (String filenameAdditional : additionalXMLs.keySet()) { - PDFAttachGenericFile(doc, filenameAdditional, "Supplement", "ZUGFeRD extension/additional data", "text/xml", additionalXMLs.get(filenameAdditional)); - } - } - - public void export(String ZUGFeRDfilename) throws IOException { - if (!documentPrepared) { - prepareDocument(); - } - if ((!fileAttached)&&(attachZUGFeRDHeaders)) { - throw new IOException( - "File must be attached (usually with PDFattachZugferdFile) before perfoming this operation"); - } - doc.save(ZUGFeRDfilename); - if (!disableAutoClose) { - close(); - } - } - - public void export(OutputStream output) throws IOException { - if (!fileAttached) { - throw new IOException( - "File must be attached (usually with PDFattachZugferdFile) before perfoming this operation"); - } - doc.save(output); - if (!disableAutoClose) { - close(); - } - } - - /** - * 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 - * @throws java.io.IOException - */ - public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description, - String subType, byte[] data) throws IOException { - fileAttached = true; - - PDComplexFileSpecification fs = new PDComplexFileSpecification(); - fs.setFile(filename); - - COSDictionary dict = fs.getCOSObject(); - 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.getCOSObject(); - 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().getCOSObject().getItem("AF"); - if (cosArray == null) { - cosArray = new COSArray(); - } - cosArray.add(fs); - COSDictionary dict2 = doc.getDocumentCatalog().getCOSObject(); - COSArray array = new COSArray(); - array.add(fs.getCOSObject()); // see below - dict2.setItem("AF", array); - doc.getDocumentCatalog().getCOSObject().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) throws IOException { - CustomXMLProvider cus = new CustomXMLProvider(); - cus.setXML(zugferdData); - this.xmlProvider = cus; - PDFattachZugferdFile(null); - - } - - /** - * Sets the ZUGFeRD conformance level (override). - * - * @param zUGFeRDConformanceLevel - * the new conformance level - * - * @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead - */ - @Deprecated - public void setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zUGFeRDConformanceLevel) { - if (zUGFeRDConformanceLevel == null) { - throw new NullPointerException("ZUGFeRD conformance level"); - } - this.profile = zUGFeRDConformanceLevel; - } - - /** - * Sets the ZUGFeRD conformance level (override). - * - * @param zUGFeRDConformanceLevel - * the new conformance level - * - * @deprecated Use {@link #setConformanceLevel(PDFAConformanceLevel)} instead - */ - @Deprecated - public void setZUGFeRDConformanceLevel(String zUGFeRDConformanceLevel) { - this.profile = ZUGFeRDConformanceLevel.valueOf(zUGFeRDConformanceLevel); - } - - /**** - * Returns the PDFBox PDF Document - * - * @return PDDocument the PDFBox PDF - */ - public PDDocument getDoc() { - return doc; - } - - /** - * 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 - */ - protected void addXMP(XMPMetadata metadata) { - - if (attachZUGFeRDHeaders) { - XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, profile, - ZUGFeRDExporter.getNamespaceForVersion(ZFVersion), ZUGFeRDExporter.getPrefixForVersion(ZFVersion), - ZUGFeRDExporter.getFilenameForVersion(ZFVersion)); - - metadata.addSchema(zf); - } - - XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata, ZFVersion, attachZUGFeRDHeaders); - pdfaex.setZUGFeRDVersion(ZFVersion); - metadata.addSchema(pdfaex); - - } - - protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException { - XmpSerializer serializer = new XmpSerializer(); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - String prefix = ""; - String suffix = ""; - - try { - buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44 - serializer.serialize(xmpMetadata, buffer, false); - buffer.write(suffix.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return buffer.toByteArray(); - } - - protected void prepareDocument() throws IOException { - String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")"; - - PDDocumentCatalog cat = doc.getDocumentCatalog(); - metadata = new PDMetadata(doc); - cat.setMetadata(metadata); - - xmp = XMPMetadata.createXMPMetadata(); - - pdfaid = new PDFAIdentificationSchema(xmp); - - xmp.addSchema(pdfaid); - - DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema(); - - dc.addCreator(creator); - - XMPBasicSchema xsb = xmp.createAndAddXMPBasicSchema(); - - xsb.setCreatorTool(creatorTool); - xsb.setCreateDate(GregorianCalendar.getInstance()); - // PDDocumentInformation pdi=doc.getDocumentInformation(); - PDDocumentInformation pdi = new PDDocumentInformation(); - pdi.setProducer(fullProducer); - pdi.setAuthor(creator); - doc.setDocumentInformation(pdi); - - AdobePDFSchema pdf = xmp.createAndAddAdobePDFSchema(); - pdf.setProducer(fullProducer); - if (ensurePDFisUpgraded) { - try { - pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$ //$NON-NLS-1$ - } catch (BadFieldValueException ex) { - // This should be impossible, because it would occur only if an illegal - // conformance level is supplied, - // however the enum enforces that the conformance level is valid. - throw new Error(ex); - } - - pdfaid.setPart(3); - } - addXMP(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 - */ - - - try { - metadata.importXMPMetadata(serializeXmpMetadata(xmp)); - - } catch (TransformerException e) { - throw new ZUGFeRDExportException("Could not export XmpMetadata", e); - } - documentPrepared=true; - } - - /** - * - * @return if pdf file will be automatically closed after adding ZF - */ - public boolean isAutoCloseDisabled() { - return disableAutoClose; - } - - /** - * - * @param disableAutoClose prevent PDF file from being closed after adding ZF - */ - public void disableAutoClose(boolean disableAutoClose) { - this.disableAutoClose = disableAutoClose; - } - - /** - * the human author (use factory method instead) - * @param creator - */ - @Deprecated - public void setCreator(String creator) { - this.creator = creator; - } - /** - * the CreatorTool attribute for the PDF - * @param creator - */ - protected void setCreatorTool(String creatorTool) { - this.creatorTool = creatorTool; - } - - /** - * the authoring software (use factory method instead) - * @param producer - */ - @Deprecated - public void setProducer(String producer) { - this.producer = producer; - } - - /** - * - * @param ensurePDFisUpgraded if not set the PDF/A won't be relabelled A/3, e.g. if it already is one - */ - public void setPDFA3(boolean ensurePDFisUpgraded) { - this.ensurePDFisUpgraded = ensurePDFisUpgraded; - } - - /** - * - * @param attachZUGFeRDHeaders if false the ZUGFeRD XMP metadata won't be added, e.g. if it's not the first file - */ - public void setAttachZUGFeRDHeaders(boolean attachZUGFeRDHeaders) { - this.attachZUGFeRDHeaders=attachZUGFeRDHeaders; - } - -} + +/** ********************************************************************** + * + * Copyright 2018 Jochen Staerk + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +/* + * Mustangproject's ZUGFeRD implementation ZUGFeRD exporter Licensed under the + * APLv2 + * + * @date 2014-07-12 + * @version 1.2.0 + * @author jstaerk + * + */ + +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.pdmodel.*; +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.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.AdobePDFSchema; +import org.apache.xmpbox.schema.DublinCoreSchema; +import org.apache.xmpbox.schema.PDFAIdentificationSchema; +import org.apache.xmpbox.schema.XMPBasicSchema; +import org.apache.xmpbox.type.BadFieldValueException; +import org.apache.xmpbox.xml.XmpSerializer; + +import javax.xml.transform.TransformerException; +import java.io.*; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; + +public class ZUGFeRDExporter implements Closeable { + + public static final int DefaultZUGFeRDVersion = 1; + + private static boolean isFacturX = false; + + /** + * 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 + * @deprecated Use the factory methods {@link #createFromPDFA3(String)}, + * {@link #createFromPDFA3(InputStream)} or the + * {@link ZUGFeRDExporterFromA1Factory} instead + */ + // // MAIN CLASS + @Deprecated + private PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE; + + // BASIC, COMFORT etc - may be set from outside. + @Deprecated + private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EXTENDED; + + /** + * 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. + */ + IXMLProvider xmlProvider; + protected PDMetadata metadata = null; + protected PDFAIdentificationSchema pdfaid = null; + protected XMPMetadata xmp = null; + /** + * Producer attribute for PDF + */ + protected String producer = "mustangproject"; + /** + * Author/Creator attribute for PDF for PDF + */ + protected String creator = "mustangproject"; + /** + * CreatorTool + */ + protected String creatorTool = "mustangproject"; + + @Deprecated + private boolean ignoreA1Errors; + protected boolean ensurePDFisUpgraded = true; + private PDDocument doc; + int ZFVersion; + + private HashMap additionalXMLs = new HashMap(); + + + private boolean disableAutoClose; + + private boolean fileAttached = false; + protected boolean attachZUGFeRDHeaders = true; + + private boolean documentPrepared = false; + + public ZUGFeRDExporter() { + init(); + } + + public ZUGFeRDExporter(PDDocument doc2) { + doc = doc2; + init(); + } + + public void addAdditonalXML(String filename, byte[] xml) { + additionalXMLs.put(filename, xml); + } + + public static String getNamespaceForVersion(int ver) { + if (ver == 1) { + return "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#"; + } else if (ver == 2) { + return "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#"; + } else { + throw new IllegalArgumentException("Version not supported"); + } + } + + public static String getPrefixForVersion(int ver) { + if (ver == 1) { + return "zf"; + } else if (ver == 2) { + return "fx"; + } else { + throw new IllegalArgumentException("Version not supported"); + } + } + + public static String getFilenameForVersion(int ver) { + if (ver == 1) { + return "ZUGFeRD-invoice.xml"; + } else if ((ver == 2) || (isFacturX)) { + return "factur-x.xml"; + } else { + throw new IllegalArgumentException("Version not supported"); + } + } + + @Deprecated + public void setZUGFeRDVersion(int ver) { + if (ver == 1) { + ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider(); + this.xmlProvider = z1p; + } else if (ver == 2) { + ZUGFeRD2PullProvider z2p = new ZUGFeRD2PullProvider(); + this.xmlProvider = z2p; + } else { + throw new IllegalArgumentException("Version not supported"); + } + ZFVersion = ver; + } + + public IXMLProvider getProvider() { + return xmlProvider; + } + + private void init() { + setZUGFeRDVersion(DefaultZUGFeRDVersion); + } + + public void setFacturX() { + setZUGFeRDVersion(2); + isFacturX = true; + } + + /** + * All files are PDF/A-3, setConformance refers to the level conformance. + *

+ * PDF/A-3 has three conformance 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 :-) + * + * @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead + */ + @Deprecated + public void setConformanceLevel(PDFAConformanceLevel newLevel) { + if (newLevel == null) { + throw new NullPointerException("pdf conformance level"); + } + conformanceLevel = newLevel; + } + + /** + * All files are PDF/A-3, setConformance refers to the level conformance. + *

+ * PDF/A-3 has three conformance 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 :-) + * + * @deprecated Use + * {@link #setConformanceLevel(org.mustangproject.ZUGFeRD.PDFAConformanceLevel)} + * instead + */ + @Deprecated + public void setConformanceLevel(String newLevel) { + conformanceLevel = PDFAConformanceLevel.findByLetter(newLevel); + } + + /** + * enables the flag to indicate a test invoice in the XML structure + */ + public void setTest() { + xmlProvider.setTest(); + } + + /** + * @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead + */ + @Deprecated + public void ignoreA1Errors() { + ignoreA1Errors = true; + } + + /** + * @deprecated Use the factory method {@link #createFromPDFA3(String)} instead + */ + @Deprecated + public void loadPDFA3(String filename) throws IOException { + doc = PDDocument.load(new File(filename)); + } + + public static ZUGFeRDExporter createFromPDFA3(String filename) throws IOException { + return new ZUGFeRDExporter(PDDocument.load(new File(filename))); + } + + /** + * @deprecated Use the factory method {@link #createFromPDFA3(InputStream)} + * instead + */ + @Deprecated + public void loadPDFA3(InputStream file) throws IOException { + doc = PDDocument.load(file); + } + + public static ZUGFeRDExporter createFromPDFA3(InputStream pdfSource) throws IOException { + return new ZUGFeRDExporter(PDDocument.load(pdfSource)); + } + + /** + * 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) + * + * @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead + */ + @Deprecated + public PDDocumentCatalog PDFmakeA3compliant(String filename, String producer, String creator, + boolean attachZugferdHeaders) throws IOException, TransformerException { + + doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(filename).doc; + + return doc.getDocumentCatalog(); + } + + /** + * @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead + */ + @Deprecated + public PDDocumentCatalog PDFmakeA3compliant(InputStream file, String producer, String creator, + boolean attachZugferdHeaders) throws IOException, TransformerException { + + doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(file).doc; + + return doc.getDocumentCatalog(); + } + + private IExporterFactory createPDFA1Factory() { + ZUGFeRDExporterFromA1Factory factory = new ZUGFeRDExporterFromA1Factory(); + if (ignoreA1Errors) { + factory.ignorePDFAErrors(); + } + return factory.setZUGFeRDConformanceLevel(profile).setConformanceLevel(conformanceLevel); + } + + @Override + public void close() throws IOException { + if (doc != null) { + doc.close(); + } + } + + /** + * Embeds the Zugferd XML structure in a file named ZUGFeRD-invoice.xml. + * + * @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 { + prepareDocument(); + + xmlProvider.generateXML(trans); + String filename = getFilenameForVersion(ZFVersion); + PDFAttachGenericFile(doc, filename, "Alternative", + "Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)", + "text/xml", xmlProvider.getXML()); + for (String filenameAdditional : additionalXMLs.keySet()) { + PDFAttachGenericFile(doc, filenameAdditional, "Supplement", "ZUGFeRD extension/additional data", "text/xml", additionalXMLs.get(filenameAdditional)); + } + } + + public void export(String ZUGFeRDfilename) throws IOException { + if (!documentPrepared) { + prepareDocument(); + } + if ((!fileAttached) && (attachZUGFeRDHeaders)) { + throw new IOException( + "File must be attached (usually with PDFattachZugferdFile) before perfoming this operation"); + } + doc.save(ZUGFeRDfilename); + if (!disableAutoClose) { + close(); + } + } + + public void export(OutputStream output) throws IOException { + if (!fileAttached) { + throw new IOException( + "File must be attached (usually with PDFattachZugferdFile) before perfoming this operation"); + } + doc.save(output); + if (!disableAutoClose) { + close(); + } + } + + /** + * 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 + * @throws java.io.IOException + */ + public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description, + String subType, byte[] data) throws IOException { + fileAttached = true; + + PDComplexFileSpecification fs = new PDComplexFileSpecification(); + fs.setFile(filename); + + COSDictionary dict = fs.getCOSObject(); + 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.getCOSObject(); + 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().getCOSObject().getItem("AF"); + if (cosArray == null) { + cosArray = new COSArray(); + } + cosArray.add(fs); + COSDictionary dict2 = doc.getDocumentCatalog().getCOSObject(); + COSArray array = new COSArray(); + array.add(fs.getCOSObject()); // see below + dict2.setItem("AF", array); + doc.getDocumentCatalog().getCOSObject().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) throws IOException { + CustomXMLProvider cus = new CustomXMLProvider(); + cus.setXML(zugferdData); + this.xmlProvider = cus; + PDFattachZugferdFile(null); + + } + + /** + * Sets the ZUGFeRD conformance level (override). + * + * @param zUGFeRDConformanceLevel the new conformance level + * @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead + */ + @Deprecated + public void setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zUGFeRDConformanceLevel) { + if (zUGFeRDConformanceLevel == null) { + throw new NullPointerException("ZUGFeRD conformance level"); + } + this.profile = zUGFeRDConformanceLevel; + } + + /** + * Sets the ZUGFeRD conformance level (override). + * + * @param zUGFeRDConformanceLevel the new conformance level + * @deprecated Use {@link #setConformanceLevel(PDFAConformanceLevel)} instead + */ + @Deprecated + public void setZUGFeRDConformanceLevel(String zUGFeRDConformanceLevel) { + this.profile = ZUGFeRDConformanceLevel.valueOf(zUGFeRDConformanceLevel); + } + + /** + * * + * Returns the PDFBox PDF Document + * + * @return PDDocument the PDFBox PDF + */ + public PDDocument getDoc() { + return doc; + } + + /** + * 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 + */ + protected void addXMP(XMPMetadata metadata) { + + if (attachZUGFeRDHeaders) { + XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, profile, + ZUGFeRDExporter.getNamespaceForVersion(ZFVersion), ZUGFeRDExporter.getPrefixForVersion(ZFVersion), + ZUGFeRDExporter.getFilenameForVersion(ZFVersion)); + + metadata.addSchema(zf); + } + + XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata, ZFVersion, attachZUGFeRDHeaders); + pdfaex.setZUGFeRDVersion(ZFVersion); + metadata.addSchema(pdfaex); + + } + + protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException { + XmpSerializer serializer = new XmpSerializer(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + String prefix = ""; + String suffix = ""; + + try { + buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44 + serializer.serialize(xmpMetadata, buffer, false); + buffer.write(suffix.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return buffer.toByteArray(); + } + + protected void prepareDocument() throws IOException { + String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")"; + + PDDocumentCatalog cat = doc.getDocumentCatalog(); + metadata = new PDMetadata(doc); + cat.setMetadata(metadata); + + xmp = XMPMetadata.createXMPMetadata(); + + pdfaid = new PDFAIdentificationSchema(xmp); + + xmp.addSchema(pdfaid); + + DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema(); + + dc.addCreator(creator); + + XMPBasicSchema xsb = xmp.createAndAddXMPBasicSchema(); + + xsb.setCreatorTool(creatorTool); + xsb.setCreateDate(GregorianCalendar.getInstance()); + // PDDocumentInformation pdi=doc.getDocumentInformation(); + PDDocumentInformation pdi = new PDDocumentInformation(); + pdi.setProducer(fullProducer); + pdi.setAuthor(creator); + doc.setDocumentInformation(pdi); + + AdobePDFSchema pdf = xmp.createAndAddAdobePDFSchema(); + pdf.setProducer(fullProducer); + if (ensurePDFisUpgraded) { + try { + pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$ //$NON-NLS-1$ + } catch (BadFieldValueException ex) { + // This should be impossible, because it would occur only if an illegal + // conformance level is supplied, + // however the enum enforces that the conformance level is valid. + throw new Error(ex); + } + + pdfaid.setPart(3); + } + addXMP(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 + */ + + + try { + metadata.importXMPMetadata(serializeXmpMetadata(xmp)); + + } catch (TransformerException e) { + throw new ZUGFeRDExportException("Could not export XmpMetadata", e); + } + documentPrepared = true; + } + + /** + * @return if pdf file will be automatically closed after adding ZF + */ + public boolean isAutoCloseDisabled() { + return disableAutoClose; + } + + /** + * @param disableAutoClose prevent PDF file from being closed after adding ZF + */ + public void disableAutoClose(boolean disableAutoClose) { + this.disableAutoClose = disableAutoClose; + } + + /** + * the human author (use factory method instead) + * + * @param creator + */ + @Deprecated + public void setCreator(String creator) { + this.creator = creator; + } + + /** + * the CreatorTool attribute for the PDF + * + * @param creator + */ + protected void setCreatorTool(String creatorTool) { + this.creatorTool = creatorTool; + } + + /** + * the authoring software (use factory method instead) + * + * @param producer + */ + @Deprecated + public void setProducer(String producer) { + this.producer = producer; + } + + /** + * @param ensurePDFisUpgraded if not set the PDF/A won't be relabelled A/3, e.g. if it already is one + */ + public void setPDFA3(boolean ensurePDFisUpgraded) { + this.ensurePDFisUpgraded = ensurePDFisUpgraded; + } + + /** + * @param attachZUGFeRDHeaders if false the ZUGFeRD XMP metadata won't be added, e.g. if it's not the first file + */ + public void setAttachZUGFeRDHeaders(boolean attachZUGFeRDHeaders) { + this.attachZUGFeRDHeaders = attachZUGFeRDHeaders; + } + +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA1Factory.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA1Factory.java index 7862f53e..7e61b8c3 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA1Factory.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA1Factory.java @@ -19,9 +19,9 @@ package org.mustangproject.ZUGFeRD; -public class ZUGFeRDExporterFromA1Factory extends ZUGFeRDExporterFromA3Factory implements IExporterFactory { +public class ZUGFeRDExporterFromA1Factory extends ZUGFeRDExporterFromA3Factory implements IExporterFactory { public ZUGFeRDExporterFromA1Factory() { - ensurePDFisUpgraded=true; + ensurePDFisUpgraded = true; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java index fabae2e5..a0a5cb20 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java @@ -34,25 +34,31 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { protected boolean ignorePDFAErrors = false; protected ZUGFeRDConformanceLevel zugferdConformanceLevel = ZUGFeRDConformanceLevel.EXTENDED; protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE; - /** Producer (attribute for PDF */ + /** + * Producer (attribute for PDF + */ protected String producer = "mustangproject"; - /** Human creator (attribute for PDF) */ + /** + * Human creator (attribute for PDF) + */ protected String creator = "mustangproject"; - /** Creator tool (attribute for PDF) */ + /** + * Creator tool (attribute for PDF) + */ protected String creatorTool = null; - - private HashMap additionalXMLs=new HashMap(); - - protected int ZFVersion=ZUGFeRDExporter.DefaultZUGFeRDVersion; - protected boolean ensurePDFisUpgraded=false; - private boolean attachZUGFeRDHeaders=true; + private HashMap additionalXMLs = new HashMap(); + + + protected int ZFVersion = ZUGFeRDExporter.DefaultZUGFeRDVersion; + protected boolean ensurePDFisUpgraded = false; + private boolean attachZUGFeRDHeaders = true; + /** * 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) * - * @param pdfFilename - * filename of an PDF/A1 compliant document + * @param pdfFilename filename of an PDF/A1 compliant document */ public ZUGFeRDExporter load(String pdfFilename) throws IOException { @@ -74,13 +80,11 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { } - /** * 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) * - * @param pdfBinary - * binary of a PDF/A1 compliant document + * @param pdfBinary binary of a PDF/A1 compliant document */ public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException { ensurePDFIsValidPDFA(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary))); @@ -97,17 +101,16 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { return zugFeRDExporter; } - public ZUGFeRDExporterFromA3Factory () { + public ZUGFeRDExporterFromA3Factory() { - ensurePDFisUpgraded=false; + ensurePDFisUpgraded = false; } /** * 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) * - * @param pdfSource - * source to read a PDF/A1 compliant document from + * @param pdfSource source to read a PDF/A1 compliant document from */ public ZUGFeRDExporter load(InputStream pdfSource) throws IOException { return load(readAllBytes(pdfSource)); @@ -124,6 +127,7 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { IOUtils.copy(in, buffer); return buffer.toByteArray(); } + private static boolean isValidA1(DataSource dataSource) throws IOException { return getPDFAParserValidationResult(new PreflightParser(dataSource)); } @@ -131,8 +135,7 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { /** * Sets the ZUGFeRD conformance level (override). * - * @param zugferdConformanceLevel - * the new conformance level + * @param zugferdConformanceLevel the new conformance level */ public IExporterFactory setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zugferdConformanceLevel) { this.zugferdConformanceLevel = zugferdConformanceLevel; @@ -170,17 +173,15 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { /** * 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 IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel) { conformanceLevel = newLevel; @@ -197,7 +198,7 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { this.creator = creator; return this; } - + public IExporterFactory setCreatorTool(String creatorTool) { this.creatorTool = creatorTool; return this; @@ -207,6 +208,7 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { this.producer = producer; return this; } + public IExporterFactory setAttachZUGFeRDHeaders(boolean attachHeaders) { this.attachZUGFeRDHeaders = attachHeaders; return this; @@ -215,7 +217,7 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { @Override public IExporterFactory setZUGFeRDVersion(int version) { - this.ZFVersion=version; + this.ZFVersion = version; return this; } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index 7061d77b..f6bd06a5 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -1,616 +1,607 @@ -/** ********************************************************************** - * - * Copyright 2018 Jochen Staerk - * - * Use is subject to license terms. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *********************************************************************** */ -package org.mustangproject.ZUGFeRD; -/** - * Mustangproject's ZUGFeRD implementation - * ZUGFeRD importer - * Licensed under the APLv2 - * @date 2014-07-07 - * @version 1.1.0 - * @author jstaerk - * */ - -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary; -import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode; -import org.apache.pdfbox.pdmodel.common.PDNameTreeNode; -import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification; -import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -//root.setNamespace(Namespace.getNamespace("http://www.energystar.gov/manageBldgs/req")); - -public class ZUGFeRDImporter { - /* - * 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 */ - private String foreignReference; - private String BLZ; - private String BIC; - private String IBAN; - private String KTO; - private String holder; - private String amount; - private String dueDate; - private HashMap additionalXMLs=new HashMap(); - /** Raw XML form of the extracted data - may be directly obtained. */ - private byte[] rawXML = null; - private String bankName; - private boolean amountFound; - private boolean extractAttempt = false; - private boolean parsed = false; - private String xmpString = null; // XMP metadata - private static final Logger LOG = Logger.getLogger(ZUGFeRDImporter.class.getName()); - - /** - * Extracts a ZUGFeRD invoice from a PDF document represented by a file name. - * Errors are just logged to STDOUT. - * - * @param pdfFilename - * the filename of the pdf - */ - public void extract(String pdfFilename) { - try { - BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pdfFilename)); - - extractLowLevel(bis); - bis.close(); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } - - static String convertStreamToString(java.io.InputStream is) { - // source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to - // https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks - java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); - return s.hasNext() ? s.next() : ""; - } - - /*** - * get xmp metadata of the PDF, null if not available - * @return string - */ - public String getXMP() { - return xmpString; - } - - /** - * Extracts a ZUGFeRD invoice from a PDF document represented by an input - * stream. Errors are reported via exception handling. - * - * @param pdfStream - * a inputstream of a pdf file - */ - public void extractLowLevel(InputStream pdfStream) throws IOException { - PDEmbeddedFilesNameTreeNode etn; - extractAttempt = true; - try (PDDocument doc = PDDocument.load(pdfStream)) { - // PDDocumentInformation info = doc.getDocumentInformation(); - PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog()); - //start - InputStream XMP=doc.getDocumentCatalog().getMetadata().exportXMPMetadata(); - - xmpString=convertStreamToString(XMP); - etn = names.getEmbeddedFiles(); - if (etn == null) { - return; - } - - Map efMap = etn.getNames(); - // String filePath = "/tmp/"; - - if (efMap != null) { - extractFiles(efMap); // see - // https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/ - } else { - - List> kids = etn.getKids(); - for (PDNameTreeNode node : kids) { - Map namesL = node.getNames(); - extractFiles(namesL); - } - } - } - } - - - private void extractFiles(Map names) throws IOException { - for (String filename : names.keySet()) { - /** - * currently (in the release candidate of version 1) only one attached file with - * the name ZUGFeRD-invoice.xml is allowed - */ - if ((filename.equals("ZUGFeRD-invoice.xml") || filename.equals("factur-x.xml"))) { //$NON-NLS-1$ - containsMeta = true; - - PDComplexFileSpecification fileSpec = names.get(filename); - PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); - // String embeddedFilename = filePath + filename; - // File file = new File(filePath + filename); - // System.out.println("Writing " + embeddedFilename); - // ByteArrayOutputStream fileBytes=new - // ByteArrayOutputStream(); - // FileOutputStream fos = new FileOutputStream(file); - - rawXML = embeddedFile.toByteArray(); - setMeta(new String(rawXML)); - - // fos.write(embeddedFile.getByteArray()); - // fos.close(); - } - if (filename.startsWith("additional_data")) { - - PDComplexFileSpecification fileSpec = names.get(filename); - PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); - additionalXMLs.put(filename, embeddedFile.toByteArray()); - - } - } - } - - public HashMap getAdditionalData() { - return additionalXMLs; - } - - /** - * needs to be called to be able to call the getters - */ - public void parse() { - DocumentBuilderFactory factory = null; - DocumentBuilder builder = null; - Document document = null; - - if (!extractAttempt) { - throw new RuntimeException("extract() or extractLowLevel() must be used before parsing."); - } - if (!containsMeta) { - throw new RuntimeException("No suitable data/ZUGFeRD file could be found."); - } - - factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); // otherwise we can not act namespace independently, i.e. use - // document.getElementsByTagNameNS("*",... - try { - builder = factory.newDocumentBuilder(); - } catch (ParserConfigurationException ex3) { - // TODO Auto-generated catch block - ex3.printStackTrace(); - } - - try { - InputStream bais = new ByteArrayInputStream(rawXML); - document = builder.parse(bais); - } catch (SAXException ex1) { - ex1.printStackTrace(); - } catch (IOException ex2) { - 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()); - - } - /* - * ndList = document .getElementsByTagName("GermanBankleitzahlID"); - * //$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 setBIC(booking.getTextContent()); - * - * } - * - * ndList = document.getElementsByTagName("ProprietaryID"); //$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 setIBAN(booking.getTextContent()); - * - * } DE1234 - * - * - * DE5656565 Commerzbank - * - * - */ - - /*** - * we should switch to xpath like this // Create XPathFactory object - * XPathFactory xpathFactory = XPathFactory.newInstance(); - * - * // Create XPath object XPath xpath = xpathFactory.newXPath(); XPathExpression - * expr = - * xpath.compile("//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/[local-name()=\"ID\"]"); - * //evaluate expression result on XML document ndList = (NodeList) - * expr.evaluate(doc, XPathConstants.NODESET); - * - */ - - ndList = document.getElementsByTagNameNS("*", "PayeePartyCreditorFinancialAccount"); //$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("IBANID"))) { //$NON-NLS-1$ - setIBAN(detail.getTextContent()); - } - if ((detail.getLocalName() != null) && (detail.getLocalName().equals("ProprietaryID"))) { //$NON-NLS-1$ - setKTO(detail.getTextContent()); - - } - } - - } - ndList = document.getElementsByTagNameNS("*", "PayeeSpecifiedCreditorFinancialInstitution");// ZF1 //$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("BICID"))) { //$NON-NLS-1$ - setBIC(detail.getTextContent()); - } - if ((detail.getLocalName() != null) && (detail.getLocalName().equals("GermanBankleitzahlID"))) { //$NON-NLS-1$ - setBLZ(detail.getTextContent()); - } - if ((detail.getLocalName() != null) && (detail.getLocalName().equals("Name"))) { //$NON-NLS-1$ - setBankName(detail.getTextContent()); - } - } - - } - - ndList = document.getElementsByTagNameNS("*", "SellerTradeParty"); //$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("Name"))) { //$NON-NLS-1$ - setHolder(detail.getTextContent()); - } - } - - } - - ndList = document.getElementsByTagNameNS("*", "DuePayableAmount"); //$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 - amountFound = true; - setAmount(booking.getTextContent()); - - } - - if (!amountFound) { - /* - * there is apparently no requirement to mention DuePayableAmount,, if it's not - * there, check for GrandTotalAmount - */ - ndList = document.getElementsByTagNameNS("*", "GrandTotalAmount"); //$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 - amountFound = true; - 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; - } - - /** - * - * @return if export found parseable ZUGFeRD data - */ - public boolean containsMeta() { - return containsMeta; - } - - /** - * - * @return the reference (purpose) the sender specified for this invoice - */ - public String getForeignReference() { - if (!parsed) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (foreignReference==null) { - parse(); - } - return foreignReference; - } - - private void setForeignReference(String foreignReference) { - this.foreignReference = foreignReference; - } - - /** - * - * @return the sender's bank's BLZ code - */ - public String getBLZ() { - if (!parsed) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (BLZ==null) { - parse(); - } - return BLZ; - } - - private void setBLZ(String blz) { - this.BLZ = blz; - } - - /** - * - * @return the sender's bank's BIC code - */ - public String getBIC() { - if (!parsed) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (BIC==null) { - parse(); - } - return BIC; - } - - private void setBIC(String bic) { - this.BIC = bic; - } - - private void setDueDate(String dueDate) { - this.dueDate = dueDate; - } - - private void setBankName(String bankname) { - this.bankName = bankname; - } - - /** - * - * @return the sender's IBAN - */ - public String getIBAN() { - if (!parsed) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (IBAN==null) { - parse(); - } - return IBAN; - } - - /** - * - * @return the sender's KTO - */ - public String getKTO() { - if (!parsed) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (KTO==null) { - parse(); - } - return KTO; - } - - /** - * - * @return the sender's bank name - */ - public String getBankName() { - if (!parsed) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (bankName==null) { - parse(); - } - return bankName; - } - - private void setIBAN(String IBAN) { - this.IBAN = IBAN; - } - - private void setKTO(String KTO) { - this.KTO = KTO; - } - - /** - * - * @return the name of the owner of the sender's bank account - */ - public String getHolder() { - if (rawXML == null) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (holder==null) { - parse(); - } - return holder; - } - - private void setHolder(String holder) { - this.holder = holder; - } - - /** - * - * @return the total payable amount - */ - public String getAmount() { - if (rawXML == null) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (amount==null) { - parse(); - } - return amount; - } - - /** - * - * @return when the payment is due - */ - public String getDueDate() { - if (rawXML == null) { - throw new RuntimeException("use extract() before requesting a value"); - } - if (dueDate==null) { - parse(); - } - return dueDate; - } - - private void setAmount(String amount) { - this.amount = amount; - } - - /** - * - * @param meta - * raw XML to be set - */ - public void setMeta(String meta) { - this.rawXML = meta.getBytes(); - } - - /** - * - * @return raw XML of the invoice - */ - public String getMeta() { - if (rawXML == null) { - return null; - } - - return new String(rawXML); - } - - - /** - * - * @return return UTF8 XML (without BOM) of the invoice - */ - public String getUTF8() { - if (rawXML == null) { - return null; - } - if (rawXML.length<3) { - return new String(rawXML); - } - - - byte[] bomlessData; - - if ((rawXML[0] == (byte) 0xEF) - && (rawXML[1] == (byte) 0xBB) - && (rawXML[2] == (byte) 0xBF)) { - // I don't like BOMs, lets remove it - bomlessData = new byte[rawXML.length - 3]; - System.arraycopy(rawXML, 3, bomlessData, 0, - rawXML.length - 3); - } else { - bomlessData = rawXML; - } - - return new String(bomlessData); - } - - /** - * Returns the raw XML data as extracted from the ZUGFeRD PDF file. - */ - public byte[] getRawXML() { - return rawXML; - } - - /** - * will return true if the metadata (just extract-ed or set with setMeta) - * contains ZUGFeRD XML - * - * @return true if the invoice 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$ - /* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */)); - } -} +/** ********************************************************************** + * + * Copyright 2018 Jochen Staerk + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; +/** + * Mustangproject's ZUGFeRD implementation + * ZUGFeRD importer + * Licensed under the APLv2 + * @date 2014-07-07 + * @version 1.1.0 + * @author jstaerk + * */ + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary; +import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode; +import org.apache.pdfbox.pdmodel.common.PDNameTreeNode; +import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification; +import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +//root.setNamespace(Namespace.getNamespace("http://www.energystar.gov/manageBldgs/req")); + +public class ZUGFeRDImporter { + /* + * 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 + */ + private String foreignReference; + private String BLZ; + private String BIC; + private String IBAN; + private String KTO; + private String holder; + private String amount; + private String dueDate; + private HashMap additionalXMLs = new HashMap(); + /** + * Raw XML form of the extracted data - may be directly obtained. + */ + private byte[] rawXML = null; + private String bankName; + private boolean amountFound; + private boolean extractAttempt = false; + private boolean parsed = false; + private String xmpString = null; // XMP metadata + private static final Logger LOG = Logger.getLogger(ZUGFeRDImporter.class.getName()); + + /** + * Extracts a ZUGFeRD invoice from a PDF document represented by a file name. + * Errors are just logged to STDOUT. + * + * @param pdfFilename the filename of the pdf + */ + public void extract(String pdfFilename) { + try { + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pdfFilename)); + + extractLowLevel(bis); + bis.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + + static String convertStreamToString(java.io.InputStream is) { + // source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to + // https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks + java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); + return s.hasNext() ? s.next() : ""; + } + + /** + * get xmp metadata of the PDF, null if not available + * + * @return string + */ + public String getXMP() { + return xmpString; + } + + /** + * Extracts a ZUGFeRD invoice from a PDF document represented by an input + * stream. Errors are reported via exception handling. + * + * @param pdfStream a inputstream of a pdf file + */ + public void extractLowLevel(InputStream pdfStream) throws IOException { + PDEmbeddedFilesNameTreeNode etn; + extractAttempt = true; + try (PDDocument doc = PDDocument.load(pdfStream)) { + // PDDocumentInformation info = doc.getDocumentInformation(); + PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog()); + //start + InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata(); + + xmpString = convertStreamToString(XMP); + etn = names.getEmbeddedFiles(); + if (etn == null) { + return; + } + + Map efMap = etn.getNames(); + // String filePath = "/tmp/"; + + if (efMap != null) { + extractFiles(efMap); // see + // https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/ + } else { + + List> kids = etn.getKids(); + for (PDNameTreeNode node : kids) { + Map namesL = node.getNames(); + extractFiles(namesL); + } + } + } + } + + + private void extractFiles(Map names) throws IOException { + for (String filename : names.keySet()) { + /** + * currently (in the release candidate of version 1) only one attached file with + * the name ZUGFeRD-invoice.xml is allowed + */ + if ((filename.equals("ZUGFeRD-invoice.xml") || filename.equals("factur-x.xml"))) { //$NON-NLS-1$ + containsMeta = true; + + PDComplexFileSpecification fileSpec = names.get(filename); + PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); + // String embeddedFilename = filePath + filename; + // File file = new File(filePath + filename); + // System.out.println("Writing " + embeddedFilename); + // ByteArrayOutputStream fileBytes=new + // ByteArrayOutputStream(); + // FileOutputStream fos = new FileOutputStream(file); + + rawXML = embeddedFile.toByteArray(); + setMeta(new String(rawXML)); + + // fos.write(embeddedFile.getByteArray()); + // fos.close(); + } + if (filename.startsWith("additional_data")) { + + PDComplexFileSpecification fileSpec = names.get(filename); + PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); + additionalXMLs.put(filename, embeddedFile.toByteArray()); + + } + } + } + + public HashMap getAdditionalData() { + return additionalXMLs; + } + + /** + * needs to be called to be able to call the getters + */ + public void parse() { + DocumentBuilderFactory factory = null; + DocumentBuilder builder = null; + Document document = null; + + if (!extractAttempt) { + throw new RuntimeException("extract() or extractLowLevel() must be used before parsing."); + } + if (!containsMeta) { + throw new RuntimeException("No suitable data/ZUGFeRD file could be found."); + } + + factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); // otherwise we can not act namespace independently, i.e. use + // document.getElementsByTagNameNS("*",... + try { + builder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException ex3) { + // TODO Auto-generated catch block + ex3.printStackTrace(); + } + + try { + InputStream bais = new ByteArrayInputStream(rawXML); + document = builder.parse(bais); + } catch (SAXException ex1) { + ex1.printStackTrace(); + } catch (IOException ex2) { + 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()); + + } + /* + * ndList = document .getElementsByTagName("GermanBankleitzahlID"); + * //$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 setBIC(booking.getTextContent()); + * + * } + * + * ndList = document.getElementsByTagName("ProprietaryID"); //$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 setIBAN(booking.getTextContent()); + * + * } DE1234 + * + * + * DE5656565 Commerzbank + * + * + */ + + /*** + * we should switch to xpath like this // Create XPathFactory object + * XPathFactory xpathFactory = XPathFactory.newInstance(); + * + * // Create XPath object XPath xpath = xpathFactory.newXPath(); XPathExpression + * expr = + * xpath.compile("//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/[local-name()=\"ID\"]"); + * //evaluate expression result on XML document ndList = (NodeList) + * expr.evaluate(doc, XPathConstants.NODESET); + * + */ + + ndList = document.getElementsByTagNameNS("*", "PayeePartyCreditorFinancialAccount"); //$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("IBANID"))) { //$NON-NLS-1$ + setIBAN(detail.getTextContent()); + } + if ((detail.getLocalName() != null) && (detail.getLocalName().equals("ProprietaryID"))) { //$NON-NLS-1$ + setKTO(detail.getTextContent()); + + } + } + + } + ndList = document.getElementsByTagNameNS("*", "PayeeSpecifiedCreditorFinancialInstitution");// ZF1 //$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("BICID"))) { //$NON-NLS-1$ + setBIC(detail.getTextContent()); + } + if ((detail.getLocalName() != null) && (detail.getLocalName().equals("GermanBankleitzahlID"))) { //$NON-NLS-1$ + setBLZ(detail.getTextContent()); + } + if ((detail.getLocalName() != null) && (detail.getLocalName().equals("Name"))) { //$NON-NLS-1$ + setBankName(detail.getTextContent()); + } + } + + } + + ndList = document.getElementsByTagNameNS("*", "SellerTradeParty"); //$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("Name"))) { //$NON-NLS-1$ + setHolder(detail.getTextContent()); + } + } + + } + + ndList = document.getElementsByTagNameNS("*", "DuePayableAmount"); //$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 + amountFound = true; + setAmount(booking.getTextContent()); + + } + + if (!amountFound) { + /* + * there is apparently no requirement to mention DuePayableAmount,, if it's not + * there, check for GrandTotalAmount + */ + ndList = document.getElementsByTagNameNS("*", "GrandTotalAmount"); //$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 + amountFound = true; + 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; + } + + /** + * @return if export found parseable ZUGFeRD data + */ + public boolean containsMeta() { + return containsMeta; + } + + /** + * @return the reference (purpose) the sender specified for this invoice + */ + public String getForeignReference() { + if (!parsed) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (foreignReference == null) { + parse(); + } + return foreignReference; + } + + private void setForeignReference(String foreignReference) { + this.foreignReference = foreignReference; + } + + /** + * @return the sender's bank's BLZ code + */ + public String getBLZ() { + if (!parsed) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (BLZ == null) { + parse(); + } + return BLZ; + } + + private void setBLZ(String blz) { + this.BLZ = blz; + } + + /** + * @return the sender's bank's BIC code + */ + public String getBIC() { + if (!parsed) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (BIC == null) { + parse(); + } + return BIC; + } + + private void setBIC(String bic) { + this.BIC = bic; + } + + private void setDueDate(String dueDate) { + this.dueDate = dueDate; + } + + private void setBankName(String bankname) { + this.bankName = bankname; + } + + /** + * @return the sender's IBAN + */ + public String getIBAN() { + if (!parsed) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (IBAN == null) { + parse(); + } + return IBAN; + } + + /** + * @return the sender's KTO + */ + public String getKTO() { + if (!parsed) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (KTO == null) { + parse(); + } + return KTO; + } + + /** + * @return the sender's bank name + */ + public String getBankName() { + if (!parsed) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (bankName == null) { + parse(); + } + return bankName; + } + + private void setIBAN(String IBAN) { + this.IBAN = IBAN; + } + + private void setKTO(String KTO) { + this.KTO = KTO; + } + + /** + * @return the name of the owner of the sender's bank account + */ + public String getHolder() { + if (rawXML == null) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (holder == null) { + parse(); + } + return holder; + } + + private void setHolder(String holder) { + this.holder = holder; + } + + /** + * @return the total payable amount + */ + public String getAmount() { + if (rawXML == null) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (amount == null) { + parse(); + } + return amount; + } + + /** + * @return when the payment is due + */ + public String getDueDate() { + if (rawXML == null) { + throw new RuntimeException("use extract() before requesting a value"); + } + if (dueDate == null) { + parse(); + } + return dueDate; + } + + private void setAmount(String amount) { + this.amount = amount; + } + + /** + * @param meta raw XML to be set + */ + public void setMeta(String meta) { + this.rawXML = meta.getBytes(); + } + + /** + * @return raw XML of the invoice + */ + public String getMeta() { + if (rawXML == null) { + return null; + } + + return new String(rawXML); + } + + + /** + * @return return UTF8 XML (without BOM) of the invoice + */ + public String getUTF8() { + if (rawXML == null) { + return null; + } + if (rawXML.length < 3) { + return new String(rawXML); + } + + + byte[] bomlessData; + + if ((rawXML[0] == (byte) 0xEF) + && (rawXML[1] == (byte) 0xBB) + && (rawXML[2] == (byte) 0xBF)) { + // I don't like BOMs, lets remove it + bomlessData = new byte[rawXML.length - 3]; + System.arraycopy(rawXML, 3, bomlessData, 0, + rawXML.length - 3); + } else { + bomlessData = rawXML; + } + + return new String(bomlessData); + } + + /** + * Returns the raw XML data as extracted from the ZUGFeRD PDF file. + */ + public byte[] getRawXML() { + return rawXML; + } + + /** + * will return true if the metadata (just extract-ed or set with setMeta) + * contains ZUGFeRD XML + * + * @return true if the invoice 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$ + /* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */)); + } +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java index 5bf1f25b..3b232c17 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java @@ -27,10 +27,10 @@ import java.util.logging.Logger; public class ZUGFeRDMigrator { - static final ClassLoader CLASS_LOADER = ZUGFeRDMigrator.class.getClassLoader(); - private static final String RESOURCE_PATH = ""; //$NON-NLS-1$ - private static final Logger LOG = Logger.getLogger(ZUGFeRDMigrator.class.getName()); -// private static File createTempFileResult(final Transformer transformer, final StreamSource toTransform, + static final ClassLoader CLASS_LOADER = ZUGFeRDMigrator.class.getClassLoader(); + private static final String RESOURCE_PATH = ""; //$NON-NLS-1$ + private static final Logger LOG = Logger.getLogger(ZUGFeRDMigrator.class.getName()); + // private static File createTempFileResult(final Transformer transformer, final StreamSource toTransform, // final String suffix) throws TransformerException, IOException { // File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$ // result.deleteOnExit(); @@ -40,48 +40,48 @@ public class ZUGFeRDMigrator { // } // return result; // } - private TransformerFactory mFactory = null; - private Templates mXsltTemplate = null; + private TransformerFactory mFactory = null; + private Templates mXsltTemplate = null; - public ZUGFeRDMigrator() { - mFactory = new net.sf.saxon.TransformerFactoryImpl(); - //fact = TransformerFactory.newInstance(); - mFactory.setURIResolver(new ClasspathResourceURIResolver()); - try { - mXsltTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "COMFORTtoEN16931.xsl"))); - } catch (TransformerConfigurationException ex) { - LOG.log(Level.SEVERE, null, ex); - } - } + public ZUGFeRDMigrator() { + mFactory = new net.sf.saxon.TransformerFactoryImpl(); + //fact = TransformerFactory.newInstance(); + mFactory.setURIResolver(new ClasspathResourceURIResolver()); + try { + mXsltTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "COMFORTtoEN16931.xsl"))); + } catch (TransformerConfigurationException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } - public String migrateFromV1ToV2(String xmlFilename) throws FileNotFoundException, TransformerException, UnsupportedEncodingException { - /** - * * - * http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf - * http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf - * http://countwordsfree.com/xmlviewer - */ - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - applySchematronXsl(new FileInputStream(xmlFilename), baos); - String res = null; - res = baos.toString("UTF-8"); - return res; - } + public String migrateFromV1ToV2(String xmlFilename) throws FileNotFoundException, TransformerException, UnsupportedEncodingException { + /** + * * + * http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf + * http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf + * http://countwordsfree.com/xmlviewer + */ + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + applySchematronXsl(new FileInputStream(xmlFilename), baos); + String res = null; + res = baos.toString("UTF-8"); + return res; + } - public void applySchematronXsl(final InputStream xmlFile, - final OutputStream EN16931Outstream) throws TransformerException { - Transformer transformer = mXsltTemplate.newTransformer(); - transformer.transform(new StreamSource(xmlFile), new StreamResult(EN16931Outstream)); - } + public void applySchematronXsl(final InputStream xmlFile, + final OutputStream EN16931Outstream) throws TransformerException { + Transformer transformer = mXsltTemplate.newTransformer(); + transformer.transform(new StreamSource(xmlFile), new StreamResult(EN16931Outstream)); + } - private static class ClasspathResourceURIResolver implements URIResolver { - ClasspathResourceURIResolver() { - // Do nothing, just prevents synthetic access warning. - } + private static class ClasspathResourceURIResolver implements URIResolver { + ClasspathResourceURIResolver() { + // Do nothing, just prevents synthetic access warning. + } - @Override - public Source resolve(String href, String base) throws TransformerException { - return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + href)); - } - } + @Override + public Source resolve(String href, String base) throws TransformerException { + return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + href)); + } + } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java index 08813ab7..e21fed1d 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java @@ -1,1060 +1,1059 @@ -/** ********************************************************************** - * - * Copyright 2018 Jochen Staerk - * - * Use is subject to license terms. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - * - *********************************************************************** */ -package org.mustangproject.ZUGFeRD; - -import org.mustangproject.ZUGFeRD.model.*; - -import javax.xml.bind.JAXBElement; -import java.math.BigDecimal; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.*; - -class ZUGFeRDTransactionModelConverter { - private static final SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); - private static final ObjectFactory xmlFactory = new ObjectFactory(); - - private final IZUGFeRDExportableTransaction trans; - private final Totals totals; - private boolean isTest; - private String currency = "EUR"; - - ZUGFeRDTransactionModelConverter(IZUGFeRDExportableTransaction trans) { - this.trans = trans; - totals = new Totals(); - this.currency = trans.getCurrency() != null ? trans.getCurrency(): currency; - } - - - JAXBElement convertToModel() { - CrossIndustryDocumentType invoice = xmlFactory - .createCrossIndustryDocumentType(); - - invoice.setSpecifiedExchangedDocumentContext(this.getDocumentContext()); - invoice.setHeaderExchangedDocument(this.getDocument()); - invoice.setSpecifiedSupplyChainTradeTransaction(this - .getTradeTransaction()); - - return xmlFactory - .createCrossIndustryDocument(invoice); - } - - private ExchangedDocumentContextType getDocumentContext() { - - ExchangedDocumentContextType context = xmlFactory - .createExchangedDocumentContextType(); - DocumentContextParameterType contextParameter = xmlFactory - .createDocumentContextParameterType(); - IDType idType = xmlFactory.createIDType(); - idType.setValue(DocumentContextParameterTypeConstants.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(DateTimeTypeConstants.DATE); - issueDateTimeString.setValue(zugferdDateFormat.format(trans - .getIssueDate())); - issueDateTime.setDateTimeString(issueDateTimeString); - document.setIssueDateTime(issueDateTime); - - DocumentCodeType documentCodeType = xmlFactory.createDocumentCodeType(); - documentCodeType.setValue(DocumentCodeTypeConstants.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(NoteTypeConstants.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); - } - - 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(TaxRegistrationTypeConstants.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(TaxRegistrationTypeConstants.TAXID); - sellerTaxRegistration.setID(sellerTaxId); - sellerTradeParty.getSpecifiedTaxRegistration().add( - sellerTaxRegistration); - - // Ust-ID - sellerTaxRegistration = xmlFactory.createTaxRegistrationType(); - IDType sellerUstId = xmlFactory.createIDType(); - sellerUstId.setValue(trans.getOwnVATID()); - sellerUstId.setSchemeID(TaxRegistrationTypeConstants.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(DateTimeTypeConstants.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(PaymentMeansCodeTypeConstants.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); - IDType kto = xmlFactory.createIDType(); - kto.setValue(trans.getOwnKto()); - bankAccount.setProprietaryID(kto); - 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); - IDType blz = xmlFactory.createIDType(); - blz.setValue(trans.getOwnBLZ()); - bankData.setGermanBankleitzahlID(blz); - - 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(TaxTypeCodeTypeConstants.SALESTAX); - tradeTax.setTypeCode(taxTypeCode); - - TaxCategoryCodeType taxCategoryCode = xmlFactory - .createTaxCategoryCodeType(); - taxCategoryCode.setValue(TaxCategoryCodeTypeConstants.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(TaxCategoryCodeTypeConstants.STANDARDRATE); - tradeTax.setCategoryCode(taxType); - - TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType(); - taxCode.setValue(TaxTypeCodeTypeConstants.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(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); - - /* - * Only in extended AmountType basisAmount = - * xmlFactory.createAmountType(); - * basisAmount.setCurrencyID(trans.getInvoiceCurrency()); - * basisAmount.setValue(amount.getBasis()); - * allowance.setBasisAmount(basisAmount); - */ - TaxCategoryCodeType taxType = xmlFactory - .createTaxCategoryCodeType(); - taxType.setValue(TaxCategoryCodeTypeConstants.STANDARDRATE); - tradeTax.setCategoryCode(taxType); - - TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType(); - taxCode.setValue(TaxTypeCodeTypeConstants.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(TaxCategoryCodeTypeConstants.STANDARDRATE); - tradeTax.setCategoryCode(taxType); - - TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType(); - taxCode.setValue(TaxTypeCodeTypeConstants.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(DateTimeTypeConstants.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(TaxCategoryCodeTypeConstants.STANDARDRATE); - tradeTax.setCategoryCode(taxCategoryCode); - - TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType(); - taxCode.setValue(TaxTypeCodeTypeConstants.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; - } - - private BigDecimal vatFormat(BigDecimal value) { - return nDigitFormat(value, 2); - } - - private BigDecimal currencyFormat(BigDecimal value) { - return nDigitFormat(value, 2); - } - - private BigDecimal priceFormat(BigDecimal value) { - return nDigitFormat(value, 4); - } - - private BigDecimal quantityFormat(BigDecimal value) { - return nDigitFormat(value, 4); - } - - 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'); - - DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(); - otherSymbols.setDecimalSeparator('.'); - DecimalFormat dec = new DecimalFormat("0." + new String(repeat), - otherSymbols); - return new BigDecimal(dec.format(value)); - - } - - /** - * 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 HashMap which taxes have been used with which amounts - * - */ - 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; - } - - ZUGFeRDTransactionModelConverter withTest(boolean isTest) { - this.isTest = isTest; - return this; - } - - private class LineCalc { - - 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 BigDecimal getItemTotalNetAmount() { - return itemTotalNetAmount; - } - - public BigDecimal getItemTotalVATAmount() { - return itemTotalVATAmount; - } - - public BigDecimal getItemNetAmount() { - return itemNetAmount; - } - - } - - 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; - - if (trans.getZFAllowances() != null) { - for (IZUGFeRDAllowanceCharge headerAllowance : trans - .getZFAllowances()) { - res = res.subtract(headerAllowance.getTotalAmount()); - } - } - - 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()); - } - } - - // Set total net amount - this.totalNetAmount = res; - - 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; - } - - } -} +/** ********************************************************************** + * + * Copyright 2018 Jochen Staerk + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +import org.mustangproject.ZUGFeRD.model.*; + +import javax.xml.bind.JAXBElement; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.SimpleDateFormat; +import java.util.*; + +class ZUGFeRDTransactionModelConverter { + private static final SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); + private static final ObjectFactory xmlFactory = new ObjectFactory(); + + private final IZUGFeRDExportableTransaction trans; + private final Totals totals; + private boolean isTest; + private String currency = "EUR"; + + ZUGFeRDTransactionModelConverter(IZUGFeRDExportableTransaction trans) { + this.trans = trans; + totals = new Totals(); + this.currency = trans.getCurrency() != null ? trans.getCurrency() : currency; + } + + + JAXBElement convertToModel() { + CrossIndustryDocumentType invoice = xmlFactory + .createCrossIndustryDocumentType(); + + invoice.setSpecifiedExchangedDocumentContext(this.getDocumentContext()); + invoice.setHeaderExchangedDocument(this.getDocument()); + invoice.setSpecifiedSupplyChainTradeTransaction(this + .getTradeTransaction()); + + return xmlFactory + .createCrossIndustryDocument(invoice); + } + + private ExchangedDocumentContextType getDocumentContext() { + + ExchangedDocumentContextType context = xmlFactory + .createExchangedDocumentContextType(); + DocumentContextParameterType contextParameter = xmlFactory + .createDocumentContextParameterType(); + IDType idType = xmlFactory.createIDType(); + idType.setValue(DocumentContextParameterTypeConstants.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(DateTimeTypeConstants.DATE); + issueDateTimeString.setValue(zugferdDateFormat.format(trans + .getIssueDate())); + issueDateTime.setDateTimeString(issueDateTimeString); + document.setIssueDateTime(issueDateTime); + + DocumentCodeType documentCodeType = xmlFactory.createDocumentCodeType(); + documentCodeType.setValue(DocumentCodeTypeConstants.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(NoteTypeConstants.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); + } + + 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(TaxRegistrationTypeConstants.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(TaxRegistrationTypeConstants.TAXID); + sellerTaxRegistration.setID(sellerTaxId); + sellerTradeParty.getSpecifiedTaxRegistration().add( + sellerTaxRegistration); + + // Ust-ID + sellerTaxRegistration = xmlFactory.createTaxRegistrationType(); + IDType sellerUstId = xmlFactory.createIDType(); + sellerUstId.setValue(trans.getOwnVATID()); + sellerUstId.setSchemeID(TaxRegistrationTypeConstants.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(DateTimeTypeConstants.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(PaymentMeansCodeTypeConstants.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); + IDType kto = xmlFactory.createIDType(); + kto.setValue(trans.getOwnKto()); + bankAccount.setProprietaryID(kto); + 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); + IDType blz = xmlFactory.createIDType(); + blz.setValue(trans.getOwnBLZ()); + bankData.setGermanBankleitzahlID(blz); + + 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(TaxTypeCodeTypeConstants.SALESTAX); + tradeTax.setTypeCode(taxTypeCode); + + TaxCategoryCodeType taxCategoryCode = xmlFactory + .createTaxCategoryCodeType(); + taxCategoryCode.setValue(TaxCategoryCodeTypeConstants.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(TaxCategoryCodeTypeConstants.STANDARDRATE); + tradeTax.setCategoryCode(taxType); + + TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType(); + taxCode.setValue(TaxTypeCodeTypeConstants.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(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); + + /* + * Only in extended AmountType basisAmount = + * xmlFactory.createAmountType(); + * basisAmount.setCurrencyID(trans.getInvoiceCurrency()); + * basisAmount.setValue(amount.getBasis()); + * allowance.setBasisAmount(basisAmount); + */ + TaxCategoryCodeType taxType = xmlFactory + .createTaxCategoryCodeType(); + taxType.setValue(TaxCategoryCodeTypeConstants.STANDARDRATE); + tradeTax.setCategoryCode(taxType); + + TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType(); + taxCode.setValue(TaxTypeCodeTypeConstants.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(TaxCategoryCodeTypeConstants.STANDARDRATE); + tradeTax.setCategoryCode(taxType); + + TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType(); + taxCode.setValue(TaxTypeCodeTypeConstants.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(DateTimeTypeConstants.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(TaxCategoryCodeTypeConstants.STANDARDRATE); + tradeTax.setCategoryCode(taxCategoryCode); + + TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType(); + taxCode.setValue(TaxTypeCodeTypeConstants.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; + } + + private BigDecimal vatFormat(BigDecimal value) { + return nDigitFormat(value, 2); + } + + private BigDecimal currencyFormat(BigDecimal value) { + return nDigitFormat(value, 2); + } + + private BigDecimal priceFormat(BigDecimal value) { + return nDigitFormat(value, 4); + } + + private BigDecimal quantityFormat(BigDecimal value) { + return nDigitFormat(value, 4); + } + + 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'); + + DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(); + otherSymbols.setDecimalSeparator('.'); + DecimalFormat dec = new DecimalFormat("0." + new String(repeat), + otherSymbols); + return new BigDecimal(dec.format(value)); + + } + + /** + * 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 HashMap which taxes have been used with which amounts + */ + 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; + } + + ZUGFeRDTransactionModelConverter withTest(boolean isTest) { + this.isTest = isTest; + return this; + } + + private class LineCalc { + + 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 BigDecimal getItemTotalNetAmount() { + return itemTotalNetAmount; + } + + public BigDecimal getItemTotalVATAmount() { + return itemTotalVATAmount; + } + + public BigDecimal getItemNetAmount() { + return itemNetAmount; + } + + } + + 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; + + if (trans.getZFAllowances() != null) { + for (IZUGFeRDAllowanceCharge headerAllowance : trans + .getZFAllowances()) { + res = res.subtract(headerAllowance.getTotalAmount()); + } + } + + 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()); + } + } + + // Set total net amount + this.totalNetAmount = res; + + 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; + } + + } +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/DateTimeTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/DateTimeTypeConstants.java index 7928a843..895aa899 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/DateTimeTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/DateTimeTypeConstants.java @@ -19,7 +19,7 @@ package org.mustangproject.ZUGFeRD.model; public class DateTimeTypeConstants { - public static final String DATE = "102"; - public static final String MONTH = "610"; - public static final String WEEK = "616"; + public static final String DATE = "102"; + public static final String MONTH = "610"; + public static final String WEEK = "616"; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentCodeTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentCodeTypeConstants.java index bf1077b8..028c7874 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentCodeTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentCodeTypeConstants.java @@ -19,7 +19,7 @@ package org.mustangproject.ZUGFeRD.model; public class DocumentCodeTypeConstants { - public static final String INVOICE = "380"; - public static final String DEBITNOTE = "84"; - public static final String CREDITNOTE = "389"; + public static final String INVOICE = "380"; + public static final String DEBITNOTE = "84"; + public static final String CREDITNOTE = "389"; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/NoteTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/NoteTypeConstants.java index dae6317c..6b868dc6 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/NoteTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/NoteTypeConstants.java @@ -19,9 +19,9 @@ package org.mustangproject.ZUGFeRD.model; public class NoteTypeConstants { - public static final String GENERAL = ""; - public static final String REGULARINFO = "REG"; - public static final String PRICECONDITION = "AAK"; - public static final String CONDITIONS = "AAJ"; - public static final String PAYMENTINFO = "PMT"; + public static final String GENERAL = ""; + public static final String REGULARINFO = "REG"; + public static final String PRICECONDITION = "AAK"; + public static final String CONDITIONS = "AAJ"; + public static final String PAYMENTINFO = "PMT"; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/PaymentMeansCodeTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/PaymentMeansCodeTypeConstants.java index c3d52cfa..fda92820 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/PaymentMeansCodeTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/PaymentMeansCodeTypeConstants.java @@ -19,13 +19,13 @@ package org.mustangproject.ZUGFeRD.model; public class PaymentMeansCodeTypeConstants { - public static final String BANKACCOUNT = "42"; - public static final String NOTSPECIFIED = "1"; - public static final String AUTOMATICCLEARING = "3"; - public static final String CASH = "10"; - public static final String CHECK = "20"; - public static final String DEBITADVICE = "31"; - public static final String CREDITCARD = "48"; - public static final String DEBIT = "49"; - public static final String COMPENSATION = "97"; + public static final String BANKACCOUNT = "42"; + public static final String NOTSPECIFIED = "1"; + public static final String AUTOMATICCLEARING = "3"; + public static final String CASH = "10"; + public static final String CHECK = "20"; + public static final String DEBITADVICE = "31"; + public static final String CREDITCARD = "48"; + public static final String DEBIT = "49"; + public static final String COMPENSATION = "97"; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/QuantityTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/QuantityTypeConstants.java index bc05313d..99bc7033 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/QuantityTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/QuantityTypeConstants.java @@ -19,25 +19,25 @@ package org.mustangproject.ZUGFeRD.model; public class QuantityTypeConstants { - public static final String PIECE = "C62"; - public static final String DAY = "DAY"; - public static final String HECTARE = "HAR"; - public static final String HOUR = "HUR"; - public static final String KILOGRAM = "KGM"; - public static final String KILOMETER = "KTM"; - public static final String KILOWATTHOUR = "KWH"; - public static final String FIXEDRATE = "LS"; - public static final String LITRE = "LTR"; - public static final String MINUTE = "MIN"; - public static final String SQUAREMILLIMETER = "MMK"; - public static final String MILLIMETER = "MMT"; - public static final String SQUAREMETER = "MTK"; - public static final String CUBICMETER = "MTQ"; - public static final String METER = "MTR"; - public static final String PRODUCTCOUNT = "NAR"; - public static final String PRODUCTPAIR = "NPR"; - public static final String PERCENT = "P1"; - public static final String SET = "SET"; - public static final String TON = "TNE"; - public static final String WEEK = "WEE"; + public static final String PIECE = "C62"; + public static final String DAY = "DAY"; + public static final String HECTARE = "HAR"; + public static final String HOUR = "HUR"; + public static final String KILOGRAM = "KGM"; + public static final String KILOMETER = "KTM"; + public static final String KILOWATTHOUR = "KWH"; + public static final String FIXEDRATE = "LS"; + public static final String LITRE = "LTR"; + public static final String MINUTE = "MIN"; + public static final String SQUAREMILLIMETER = "MMK"; + public static final String MILLIMETER = "MMT"; + public static final String SQUAREMETER = "MTK"; + public static final String CUBICMETER = "MTQ"; + public static final String METER = "MTR"; + public static final String PRODUCTCOUNT = "NAR"; + public static final String PRODUCTPAIR = "NPR"; + public static final String PERCENT = "P1"; + public static final String SET = "SET"; + public static final String TON = "TNE"; + public static final String WEEK = "WEE"; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java index 2fba730a..979207c8 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java @@ -19,10 +19,10 @@ package org.mustangproject.ZUGFeRD.model; public class TaxCategoryCodeTypeConstants { - public static final String STANDARDRATE = "S"; - public static final String REVERSECHARGE = "AE"; - public static final String TAXEXEMPT = "E"; - public static final String ZEROTAXPRODUCTS = "Z"; - public static final String UNTAXEDSERVICE = "O"; - public static final String INTRACOMMUNITY = "IC"; + public static final String STANDARDRATE = "S"; + public static final String REVERSECHARGE = "AE"; + public static final String TAXEXEMPT = "E"; + public static final String ZEROTAXPRODUCTS = "Z"; + public static final String UNTAXEDSERVICE = "O"; + public static final String INTRACOMMUNITY = "IC"; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/TaxRegistrationTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/TaxRegistrationTypeConstants.java index ad48e97b..ff5c03f5 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/TaxRegistrationTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/TaxRegistrationTypeConstants.java @@ -19,6 +19,6 @@ package org.mustangproject.ZUGFeRD.model; public class TaxRegistrationTypeConstants { - public static final String USTID = "VA"; - public static final String TAXID = "FC"; + public static final String USTID = "VA"; + public static final String TAXID = "FC"; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/TaxTypeCodeTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/TaxTypeCodeTypeConstants.java index 4bf81037..46bb3e75 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/TaxTypeCodeTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/TaxTypeCodeTypeConstants.java @@ -19,7 +19,7 @@ package org.mustangproject.ZUGFeRD.model; public class TaxTypeCodeTypeConstants { - public static final String SALESTAX = "VAT"; - public static final String INSURANCETAX = "ZF_INSURANCE_TAX"; - public static final String OLDPART = "AAJ"; + public static final String SALESTAX = "VAT"; + public static final String INSURANCETAX = "ZF_INSURANCE_TAX"; + public static final String OLDPART = "AAJ"; } diff --git a/src/main/java/org/mustangproject/toecount/FileChecker.java b/src/main/java/org/mustangproject/toecount/FileChecker.java index f7852cf5..26142289 100755 --- a/src/main/java/org/mustangproject/toecount/FileChecker.java +++ b/src/main/java/org/mustangproject/toecount/FileChecker.java @@ -23,18 +23,18 @@ import org.mustangproject.ZUGFeRD.ZUGFeRDImporter; public class FileChecker { String filename; StatRun thisRun; - boolean isPDF=false; + boolean isPDF = false; public FileChecker(String filename, StatRun statistics) { - this.filename=filename; - thisRun=statistics; + this.filename = filename; + thisRun = statistics; thisRun.incFileCount(); String extension = ""; if (!thisRun.shallIgnoreFileExt()) { int extIndex = filename.lastIndexOf("."); if (extIndex >= 0) { extension = filename.substring(extIndex).toLowerCase(); - isPDF=extension.equals(".pdf");// alternative check for PDF: File starts with %PDF- + isPDF = extension.equals(".pdf");// alternative check for PDF: File starts with %PDF- if (isPDF) { thisRun.incPDFCount(); } @@ -46,10 +46,10 @@ public class FileChecker { } public boolean checkForZUGFeRD() { - if ((!isPDF)&&(!thisRun.shallIgnoreFileExt())) { + if ((!isPDF) && (!thisRun.shallIgnoreFileExt())) { return false; } - ZUGFeRDImporter zi=new ZUGFeRDImporter(); + ZUGFeRDImporter zi = new ZUGFeRDImporter(); try { zi.extract(filename); if (zi.canParse()) { @@ -62,10 +62,10 @@ public class FileChecker { // 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) + 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 @@ -73,10 +73,10 @@ public class FileChecker { } 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 + 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/src/main/java/org/mustangproject/toecount/FileTraverser.java b/src/main/java/org/mustangproject/toecount/FileTraverser.java index b71887e3..da530782 100755 --- a/src/main/java/org/mustangproject/toecount/FileTraverser.java +++ b/src/main/java/org/mustangproject/toecount/FileTraverser.java @@ -30,11 +30,12 @@ public class FileTraverser extends SimpleFileVisitor { private StatRun thisRun; + public FileTraverser(StatRun statistics) { - this.thisRun=statistics; + this.thisRun = statistics; } - /*** + /** * check each file */ @Override @@ -51,7 +52,7 @@ public class FileTraverser extends SimpleFileVisitor { return CONTINUE; } - /*** + /** * for each directory */ @Override @@ -62,7 +63,7 @@ public class FileTraverser extends SimpleFileVisitor { } - /*** + /** * show errors like file permission stacktraces */ @Override diff --git a/src/main/java/org/mustangproject/toecount/StatRun.java b/src/main/java/org/mustangproject/toecount/StatRun.java index f2f2c4e0..e5f8771c 100755 --- a/src/main/java/org/mustangproject/toecount/StatRun.java +++ b/src/main/java/org/mustangproject/toecount/StatRun.java @@ -23,60 +23,64 @@ public class StatRun { private int horseCount = 0; private int fileCount = 0; private int dirCount = 0; - private boolean checkFileExt=true; + private boolean checkFileExt = true; public void ignoreFileExtension() { - checkFileExt=false; + checkFileExt = false; } public boolean shallIgnoreFileExt() { return !checkFileExt; } - public void incFileCount(){ + + public void incFileCount() { fileCount++; } - public void incPDFCount(){ + public void incPDFCount() { pdfCount++; } - public void incZUGFeRDCount(){ + public void incZUGFeRDCount() { horseCount++; } - public void incDirCount(){ + public void incDirCount() { dirCount++; } - public int getFileCount(){ + public int getFileCount() { return fileCount; } - public int getPDFCount(){ + public int getPDFCount() { return pdfCount; } - public int getZUGFeRDCount(){ + public int getZUGFeRDCount() { return horseCount; } - public int getDirCount(){ + public int getDirCount() { return dirCount; } - /*** + /** * returns final statistics + * * @return english string with linefeeds detailling number of files, directories, number of pdfs and of zugferd files */ public String getSummaryLine() { - return "\r\n===================================================================\r\n"+String.format( + return "\r\n===================================================================\r\n" + String.format( "Files:\t%d\tDirs:\t%d\tPDF:\t%d\tZUGFeRD:\t%d\r\n", getFileCount(), getDirCount(), getPDFCount(), getZUGFeRDCount()); } - /*** + + /** * show that something is happening + * * @return String, usually a dot */ public String getOutputLine() { diff --git a/src/main/java/org/mustangproject/toecount/Toecount.java b/src/main/java/org/mustangproject/toecount/Toecount.java index 6df7a3d8..6ae88e3d 100755 --- a/src/main/java/org/mustangproject/toecount/Toecount.java +++ b/src/main/java/org/mustangproject/toecount/Toecount.java @@ -108,19 +108,15 @@ public class Toecount { + "\t\t\tFor ZUGFeRD v2: INIMUM, BASIC L, ASIC, IUS, N16931, ETENDED\r\n"); } - /*** + /** * Asks the user (repeatedly, if neccessary) on the command line for a String * (offering a defaultValue) conforming to a Regex pattern * - * @param prompt - * the question to be asked to the user - * @param defaultValue - * the default return value if user hits enter - * @param pattern - * a regex of acceptable values + * @param prompt the question to be asked to the user + * @param defaultValue the default return value if user hits enter + * @param pattern a regex of acceptable values * @return the user answer conforming to pattern - * @throws Exception - * if pattern not compielable or IOexception on input + * @throws Exception if pattern not compielable or IOexception on input */ protected static String getStringFromUser(String prompt, String defaultValue, String pattern) throws Exception { String input = ""; @@ -156,24 +152,18 @@ public class Toecount { return input; } - /*** + /** * Prompts the user for a input or output filename - * - * @param the - * text the user is asked - * @param a - * default Filename - * @param expectedExtension - * will warn if filename does not match expected file extension - * @param ensureFileExists - * will warn if file does NOT exist (for input files) - * @param ensureFileNotExists - * will warn if file DOES exist (for output files) * + * @param the text the user is asked + * @param a default Filename + * @param expectedExtension will warn if filename does not match expected file extension + * @param ensureFileExists will warn if file does NOT exist (for input files) + * @param ensureFileNotExists will warn if file DOES exist (for output files) * @return String */ protected static String getFilenameFromUser(String prompt, String defaultFilename, String expectedExtension, - boolean ensureFileExists, boolean ensureFileNotExists) { + boolean ensureFileExists, boolean ensureFileNotExists) { boolean fileExistenceOK = false; String selectedName = ""; do { @@ -316,9 +306,7 @@ public class Toecount { if (helpRequested) { printHelp(); - } - - else if (((directoryName != null) && (directoryName.length() > 0)) || filesFromStdIn.booleanValue()) { + } else if (((directoryName != null) && (directoryName.length() > 0)) || filesFromStdIn.booleanValue()) { performMetrics(directoryName, filesFromStdIn, ignoreFileExt); } else if (combineRequested) { performCombine(sourceName, sourceXMLName, outName, zugferdVersion, zugferdProfile); @@ -431,7 +419,7 @@ public class Toecount { } private static void performCombine(String pdfName, String xmlName, String outName, String zfVersion, - String zfProfile) throws Exception { + String zfProfile) throws Exception { /* * ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory() * .setProducer("toecount") .setCreator(System.getProperty("user.name")) diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceChargeImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceChargeImpl.java index 8b028a04..fd2a107e 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceChargeImpl.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDAllowanceChargeImpl.java @@ -21,37 +21,37 @@ package org.mustangproject.ZUGFeRD; import java.math.BigDecimal; public class IZUGFeRDAllowanceChargeImpl implements IZUGFeRDAllowanceCharge { - private BigDecimal totalAmount; - private String reason; - private BigDecimal taxPercent; + private BigDecimal totalAmount; + private String reason; + private BigDecimal taxPercent; - @Override - public BigDecimal getTotalAmount() { - return totalAmount; - } + @Override + public BigDecimal getTotalAmount() { + return totalAmount; + } - @Override - public String getReason() { - return reason; - } + @Override + public String getReason() { + return reason; + } - @Override - public BigDecimal getTaxPercent() { - return taxPercent; - } + @Override + public BigDecimal getTaxPercent() { + return taxPercent; + } - public IZUGFeRDAllowanceChargeImpl setTotalAmount(BigDecimal totalAmount) { - this.totalAmount = totalAmount; - return this; - } + public IZUGFeRDAllowanceChargeImpl setTotalAmount(BigDecimal totalAmount) { + this.totalAmount = totalAmount; + return this; + } - public IZUGFeRDAllowanceChargeImpl setReason(String reason) { - this.reason = reason; - return this; - } + public IZUGFeRDAllowanceChargeImpl setReason(String reason) { + this.reason = reason; + return this; + } - public IZUGFeRDAllowanceChargeImpl setTaxPercent(BigDecimal taxPercent) { - this.taxPercent = taxPercent; - return this; - } + public IZUGFeRDAllowanceChargeImpl setTaxPercent(BigDecimal taxPercent) { + this.taxPercent = taxPercent; + return this; + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContactImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContactImpl.java index 84f896e6..38a17900 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContactImpl.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContactImpl.java @@ -19,70 +19,70 @@ package org.mustangproject.ZUGFeRD; public class IZUGFeRDExportableContactImpl implements IZUGFeRDExportableContact { - private String name; - private String zIP; - private String vATID; - private String country; - private String location; - private String street; + private String name; + private String zIP; + private String vATID; + private String country; + private String location; + private String street; - @Override - public String getName() { - return name; - } + @Override + public String getName() { + return name; + } - @Override - public String getZIP() { - return zIP; - } + @Override + public String getZIP() { + return zIP; + } - @Override - public String getVATID() { - return vATID; - } + @Override + public String getVATID() { + return vATID; + } - @Override - public String getCountry() { - return country; - } + @Override + public String getCountry() { + return country; + } - @Override - public String getLocation() { - return location; - } + @Override + public String getLocation() { + return location; + } - @Override - public String getStreet() { - return street; - } + @Override + public String getStreet() { + return street; + } - public IZUGFeRDExportableContactImpl setName(String name) { - this.name = name; - return this; - } + public IZUGFeRDExportableContactImpl setName(String name) { + this.name = name; + return this; + } - public IZUGFeRDExportableContactImpl setZIP(String zIP) { - this.zIP = zIP; - return this; - } + public IZUGFeRDExportableContactImpl setZIP(String zIP) { + this.zIP = zIP; + return this; + } - public IZUGFeRDExportableContactImpl setVATID(String vATID) { - this.vATID = vATID; - return this; - } + public IZUGFeRDExportableContactImpl setVATID(String vATID) { + this.vATID = vATID; + return this; + } - public IZUGFeRDExportableContactImpl setCountry(String country) { - this.country = country; - return this; - } + public IZUGFeRDExportableContactImpl setCountry(String country) { + this.country = country; + return this; + } - public IZUGFeRDExportableContactImpl setLocation(String location) { - this.location = location; - return this; - } + public IZUGFeRDExportableContactImpl setLocation(String location) { + this.location = location; + return this; + } - public IZUGFeRDExportableContactImpl setStreet(String street) { - this.street = street; - return this; - } + public IZUGFeRDExportableContactImpl setStreet(String street) { + this.street = street; + return this; + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItemImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItemImpl.java index c90e5908..e8733ffd 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItemImpl.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItemImpl.java @@ -21,59 +21,59 @@ package org.mustangproject.ZUGFeRD; import java.math.BigDecimal; public class IZUGFeRDExportableItemImpl implements IZUGFeRDExportableItem { - private IZUGFeRDExportableProduct product; - private IZUGFeRDAllowanceCharge[] itemAllowances; - private IZUGFeRDAllowanceCharge[] itemCharges; - private BigDecimal price; - private BigDecimal quantity; + private IZUGFeRDExportableProduct product; + private IZUGFeRDAllowanceCharge[] itemAllowances; + private IZUGFeRDAllowanceCharge[] itemCharges; + private BigDecimal price; + private BigDecimal quantity; - @Override - public IZUGFeRDExportableProduct getProduct() { - return product; - } + @Override + public IZUGFeRDExportableProduct getProduct() { + return product; + } - @Override - public IZUGFeRDAllowanceCharge[] getItemAllowances() { - return itemAllowances; - } + @Override + public IZUGFeRDAllowanceCharge[] getItemAllowances() { + return itemAllowances; + } - @Override - public IZUGFeRDAllowanceCharge[] getItemCharges() { - return itemCharges; - } + @Override + public IZUGFeRDAllowanceCharge[] getItemCharges() { + return itemCharges; + } - @Override - public BigDecimal getPrice() { - return price; - } + @Override + public BigDecimal getPrice() { + return price; + } - @Override - public BigDecimal getQuantity() { - return quantity; - } + @Override + public BigDecimal getQuantity() { + return quantity; + } - public IZUGFeRDExportableItemImpl setProduct(IZUGFeRDExportableProduct product) { - this.product = product; - return this; - } + public IZUGFeRDExportableItemImpl setProduct(IZUGFeRDExportableProduct product) { + this.product = product; + return this; + } - public IZUGFeRDExportableItemImpl setItemAllowances(IZUGFeRDAllowanceCharge[] itemAllowances) { - this.itemAllowances = itemAllowances; - return this; - } + public IZUGFeRDExportableItemImpl setItemAllowances(IZUGFeRDAllowanceCharge[] itemAllowances) { + this.itemAllowances = itemAllowances; + return this; + } - public IZUGFeRDExportableItemImpl setItemCharges(IZUGFeRDAllowanceCharge[] itemCharges) { - this.itemCharges = itemCharges; - return this; - } + public IZUGFeRDExportableItemImpl setItemCharges(IZUGFeRDAllowanceCharge[] itemCharges) { + this.itemCharges = itemCharges; + return this; + } - public IZUGFeRDExportableItemImpl setPrice(BigDecimal price) { - this.price = price; - return this; - } + public IZUGFeRDExportableItemImpl setPrice(BigDecimal price) { + this.price = price; + return this; + } - public IZUGFeRDExportableItemImpl setQuantity(BigDecimal quantity) { - this.quantity = quantity; - return this; - } + public IZUGFeRDExportableItemImpl setQuantity(BigDecimal quantity) { + this.quantity = quantity; + return this; + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProductImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProductImpl.java index a95ec27e..ebc3dad5 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProductImpl.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProductImpl.java @@ -21,48 +21,48 @@ package org.mustangproject.ZUGFeRD; import java.math.BigDecimal; public class IZUGFeRDExportableProductImpl implements IZUGFeRDExportableProduct { - private String unit; - private String name; - private String description; - private BigDecimal vatPercent; + private String unit; + private String name; + private String description; + private BigDecimal vatPercent; - @Override - public String getUnit() { - return unit; - } + @Override + public String getUnit() { + return unit; + } - @Override - public String getName() { - return name; - } + @Override + public String getName() { + return name; + } - @Override - public String getDescription() { - return description; - } + @Override + public String getDescription() { + return description; + } - @Override - public BigDecimal getVATPercent() { - return vatPercent; - } + @Override + public BigDecimal getVATPercent() { + return vatPercent; + } - public IZUGFeRDExportableProductImpl setUnit(String unit) { - this.unit = unit; - return this; - } + public IZUGFeRDExportableProductImpl setUnit(String unit) { + this.unit = unit; + return this; + } - public IZUGFeRDExportableProductImpl setName(String name) { - this.name = name; - return this; - } + public IZUGFeRDExportableProductImpl setName(String name) { + this.name = name; + return this; + } - public IZUGFeRDExportableProductImpl setDescription(String description) { - this.description = description; - return this; - } + public IZUGFeRDExportableProductImpl setDescription(String description) { + this.description = description; + return this; + } - public IZUGFeRDExportableProductImpl setVatPercent(BigDecimal vatPercent) { - this.vatPercent = vatPercent; - return this; - } + public IZUGFeRDExportableProductImpl setVatPercent(BigDecimal vatPercent) { + this.vatPercent = vatPercent; + return this; + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java index 2ac05c96..1aefd3a8 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java @@ -21,290 +21,290 @@ package org.mustangproject.ZUGFeRD; import java.util.Date; public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTransaction { - private String number; - private Date issueDate; - private String ownOrganisationFullPlaintextInfo; - private Date dueDate; - private IZUGFeRDAllowanceCharge[] zFAllowances; - private IZUGFeRDAllowanceCharge[] zFCharges; - private IZUGFeRDAllowanceCharge[] zFLogisticsServiceCharges; - private IZUGFeRDExportableItem[] zFItems; - private IZUGFeRDExportableContact recipient; - private String ownKto; - private String ownBLZ; - private String ownBIC; - private String ownBankName; - private String ownIBAN; - private String ownTaxID; - private String ownVATID; - private String ownOrganisationName; - private String ownStreet; - private String ownZIP; - private String ownLocation; - private String ownCountry; - private Date deliveryDate; - private String currency; - private String ownPaymentInfoText; - private String paymentTermDescription; - private String referenceNumber; + private String number; + private Date issueDate; + private String ownOrganisationFullPlaintextInfo; + private Date dueDate; + private IZUGFeRDAllowanceCharge[] zFAllowances; + private IZUGFeRDAllowanceCharge[] zFCharges; + private IZUGFeRDAllowanceCharge[] zFLogisticsServiceCharges; + private IZUGFeRDExportableItem[] zFItems; + private IZUGFeRDExportableContact recipient; + private String ownKto; + private String ownBLZ; + private String ownBIC; + private String ownBankName; + private String ownIBAN; + private String ownTaxID; + private String ownVATID; + private String ownOrganisationName; + private String ownStreet; + private String ownZIP; + private String ownLocation; + private String ownCountry; + private Date deliveryDate; + private String currency; + private String ownPaymentInfoText; + private String paymentTermDescription; + private String referenceNumber; - @Override - public String getNumber() { - return number; - } + @Override + public String getNumber() { + return number; + } - @Override - public Date getIssueDate() { - return issueDate; - } + @Override + public Date getIssueDate() { + return issueDate; + } - @Override - public String getOwnOrganisationFullPlaintextInfo() { - return ownOrganisationFullPlaintextInfo; - } + @Override + public String getOwnOrganisationFullPlaintextInfo() { + return ownOrganisationFullPlaintextInfo; + } - @Override - public Date getDueDate() { - return dueDate; - } + @Override + public Date getDueDate() { + return dueDate; + } - @Override - public IZUGFeRDAllowanceCharge[] getZFAllowances() { - return zFAllowances; - } + @Override + public IZUGFeRDAllowanceCharge[] getZFAllowances() { + return zFAllowances; + } - @Override - public IZUGFeRDAllowanceCharge[] getZFCharges() { - return zFCharges; - } + @Override + public IZUGFeRDAllowanceCharge[] getZFCharges() { + return zFCharges; + } - @Override - public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() { - return zFLogisticsServiceCharges; - } + @Override + public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() { + return zFLogisticsServiceCharges; + } - @Override - public IZUGFeRDExportableItem[] getZFItems() { - return zFItems; - } + @Override + public IZUGFeRDExportableItem[] getZFItems() { + return zFItems; + } - @Override - public IZUGFeRDExportableContact getRecipient() { - return recipient; - } + @Override + public IZUGFeRDExportableContact getRecipient() { + return recipient; + } - @Override - public String getOwnKto() { - return ownKto; - } + @Override + public String getOwnKto() { + return ownKto; + } - @Override - public String getOwnBLZ() { - return ownBLZ; - } + @Override + public String getOwnBLZ() { + return ownBLZ; + } - @Override - public String getOwnBIC() { - return ownBIC; - } + @Override + public String getOwnBIC() { + return ownBIC; + } - @Override - public String getOwnBankName() { - return ownBankName; - } + @Override + public String getOwnBankName() { + return ownBankName; + } - @Override - public String getOwnIBAN() { - return ownIBAN; - } + @Override + public String getOwnIBAN() { + return ownIBAN; + } - @Override - public String getOwnTaxID() { - return ownTaxID; - } + @Override + public String getOwnTaxID() { + return ownTaxID; + } - @Override - public String getOwnVATID() { - return ownVATID; - } + @Override + public String getOwnVATID() { + return ownVATID; + } - @Override - public String getOwnOrganisationName() { - return ownOrganisationName; - } + @Override + public String getOwnOrganisationName() { + return ownOrganisationName; + } - @Override - public String getOwnStreet() { - return ownStreet; - } + @Override + public String getOwnStreet() { + return ownStreet; + } - @Override - public String getOwnZIP() { - return ownZIP; - } + @Override + public String getOwnZIP() { + return ownZIP; + } - @Override - public String getOwnLocation() { - return ownLocation; - } + @Override + public String getOwnLocation() { + return ownLocation; + } - @Override - public String getOwnCountry() { - return ownCountry; - } + @Override + public String getOwnCountry() { + return ownCountry; + } - @Override - public Date getDeliveryDate() { - return deliveryDate; - } + @Override + public Date getDeliveryDate() { + return deliveryDate; + } - @Override - public String getCurrency() { - return currency; - } + @Override + public String getCurrency() { + return currency; + } - @Override - public String getOwnPaymentInfoText() { - return ownPaymentInfoText; - } + @Override + public String getOwnPaymentInfoText() { + return ownPaymentInfoText; + } - @Override - public String getPaymentTermDescription() { - return paymentTermDescription; - } + @Override + public String getPaymentTermDescription() { + return paymentTermDescription; + } - @Override - public String getReferenceNumber() { - return referenceNumber; - } + @Override + public String getReferenceNumber() { + return referenceNumber; + } - public IZUGFeRDExportableTransactionImpl setNumber(String number) { - this.number = number; - return this; - } + public IZUGFeRDExportableTransactionImpl setNumber(String number) { + this.number = number; + return this; + } - public IZUGFeRDExportableTransactionImpl setIssueDate(Date issueDate) { - this.issueDate = issueDate; - return this; - } + public IZUGFeRDExportableTransactionImpl setIssueDate(Date issueDate) { + this.issueDate = issueDate; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnOrganisationFullPlaintextInfo(String ownOrganisationFullPlaintextInfo) { - this.ownOrganisationFullPlaintextInfo = ownOrganisationFullPlaintextInfo; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnOrganisationFullPlaintextInfo(String ownOrganisationFullPlaintextInfo) { + this.ownOrganisationFullPlaintextInfo = ownOrganisationFullPlaintextInfo; + return this; + } - public IZUGFeRDExportableTransactionImpl setDueDate(Date dueDate) { - this.dueDate = dueDate; - return this; - } + public IZUGFeRDExportableTransactionImpl setDueDate(Date dueDate) { + this.dueDate = dueDate; + return this; + } - public IZUGFeRDExportableTransactionImpl setZFAllowances(IZUGFeRDAllowanceCharge... zFAllowances) { - this.zFAllowances = zFAllowances; - return this; - } + public IZUGFeRDExportableTransactionImpl setZFAllowances(IZUGFeRDAllowanceCharge... zFAllowances) { + this.zFAllowances = zFAllowances; + return this; + } - public IZUGFeRDExportableTransactionImpl setZFCharges(IZUGFeRDAllowanceCharge... zFCharges) { - this.zFCharges = zFCharges; - return this; - } + public IZUGFeRDExportableTransactionImpl setZFCharges(IZUGFeRDAllowanceCharge... zFCharges) { + this.zFCharges = zFCharges; + return this; + } - public IZUGFeRDExportableTransactionImpl setZFLogisticsServiceCharges(IZUGFeRDAllowanceCharge... zFLogisticsServiceCharges) { - this.zFLogisticsServiceCharges = zFLogisticsServiceCharges; - return this; - } + public IZUGFeRDExportableTransactionImpl setZFLogisticsServiceCharges(IZUGFeRDAllowanceCharge... zFLogisticsServiceCharges) { + this.zFLogisticsServiceCharges = zFLogisticsServiceCharges; + return this; + } - public IZUGFeRDExportableTransactionImpl setZFItems(IZUGFeRDExportableItem... zFItems) { - this.zFItems = zFItems; - return this; - } + public IZUGFeRDExportableTransactionImpl setZFItems(IZUGFeRDExportableItem... zFItems) { + this.zFItems = zFItems; + return this; + } - public IZUGFeRDExportableTransactionImpl setRecipient(IZUGFeRDExportableContact recipient) { - this.recipient = recipient; - return this; - } + public IZUGFeRDExportableTransactionImpl setRecipient(IZUGFeRDExportableContact recipient) { + this.recipient = recipient; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnBLZ(String ownBLZ) { - this.ownBLZ = ownBLZ; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnBLZ(String ownBLZ) { + this.ownBLZ = ownBLZ; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnBIC(String ownBIC) { - this.ownBIC = ownBIC; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnBIC(String ownBIC) { + this.ownBIC = ownBIC; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnBankName(String ownBankName) { - this.ownBankName = ownBankName; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnBankName(String ownBankName) { + this.ownBankName = ownBankName; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnKto(String ownKto) { - this.ownKto = ownKto; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnKto(String ownKto) { + this.ownKto = ownKto; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnIBAN(String ownIBAN) { - this.ownIBAN = ownIBAN; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnIBAN(String ownIBAN) { + this.ownIBAN = ownIBAN; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnTaxID(String ownTaxID) { - this.ownTaxID = ownTaxID; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnTaxID(String ownTaxID) { + this.ownTaxID = ownTaxID; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnVATID(String ownVATID) { - this.ownVATID = ownVATID; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnVATID(String ownVATID) { + this.ownVATID = ownVATID; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnOrganisationName(String ownOrganisationName) { - this.ownOrganisationName = ownOrganisationName; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnOrganisationName(String ownOrganisationName) { + this.ownOrganisationName = ownOrganisationName; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnStreet(String ownStreet) { - this.ownStreet = ownStreet; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnStreet(String ownStreet) { + this.ownStreet = ownStreet; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnZIP(String ownZIP) { - this.ownZIP = ownZIP; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnZIP(String ownZIP) { + this.ownZIP = ownZIP; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnLocation(String ownLocation) { - this.ownLocation = ownLocation; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnLocation(String ownLocation) { + this.ownLocation = ownLocation; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnCountry(String ownCountry) { - this.ownCountry = ownCountry; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnCountry(String ownCountry) { + this.ownCountry = ownCountry; + return this; + } - public IZUGFeRDExportableTransactionImpl setDeliveryDate(Date deliveryDate) { - this.deliveryDate = deliveryDate; - return this; - } + public IZUGFeRDExportableTransactionImpl setDeliveryDate(Date deliveryDate) { + this.deliveryDate = deliveryDate; + return this; + } - public IZUGFeRDExportableTransactionImpl setCurrency(String currency) { - this.currency = currency; - return this; - } + public IZUGFeRDExportableTransactionImpl setCurrency(String currency) { + this.currency = currency; + return this; + } - public IZUGFeRDExportableTransactionImpl setOwnPaymentInfoText(String ownPaymentInfoText) { - this.ownPaymentInfoText = ownPaymentInfoText; - return this; - } + public IZUGFeRDExportableTransactionImpl setOwnPaymentInfoText(String ownPaymentInfoText) { + this.ownPaymentInfoText = ownPaymentInfoText; + return this; + } - public IZUGFeRDExportableTransactionImpl setPaymentTermDescription(String paymentTermDescription) { - this.paymentTermDescription = paymentTermDescription; - return this; - } + public IZUGFeRDExportableTransactionImpl setPaymentTermDescription(String paymentTermDescription) { + this.paymentTermDescription = paymentTermDescription; + return this; + } - public IZUGFeRDExportableTransactionImpl setReferenceNumber(String referenceNumber) { - this.referenceNumber = referenceNumber; - return this; - } + public IZUGFeRDExportableTransactionImpl setReferenceNumber(String referenceNumber) { + this.referenceNumber = referenceNumber; + return this; + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java index 6f97d064..6a69321f 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java @@ -34,8 +34,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { /** * Create the test case * - * @param testName - * name of the test case + * @param testName name of the test case */ public MustangReaderWriterCustomXMLTest(String testName) { super(testName); @@ -50,7 +49,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { // //////// TESTS // ////////////////////////////////////////////////////////////////////////////////////////// - public void testCustomZF2Export() throws Exception { + public void testCustomZF2Export() throws Exception { final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506custom.pdf"; // the writing part @@ -61,210 +60,210 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { ZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1Factory().setProducer("My Application").setCreator("Test").setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931) .load(SOURCE_PDF); - - final byte[] UTF8ByteOrderMark = new byte[] { (byte)0xef, (byte)0xbb, - (byte)0xbf }; + + final byte[] UTF8ByteOrderMark = new byte[]{(byte) 0xef, (byte) 0xbb, + (byte) 0xbf}; /* we have much more information than just in the basic profile (comfort or extended) but it's perfectly valid to provide more information, just not less. */ - String ownZUGFeRDXML = new String(UTF8ByteOrderMark)+"\n" + - "\n" + - " \n" + - " false\n" + - " \n" + - " urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:extended\n" + - " \n" + - " \n" + - " \n" + - " RE-20171118/506\n" + - " RECHNUNG\n" + - " 380\n" + - " 20171118\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 1\n" + - " \n" + - " \n" + - " Künstlerische Gestaltung (Stunde): Einer Beispielrechnung\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 160.0000\n" + - " 1.0000\n" + - " \n" + - " \n" + - " 160.0000\n" + - " 1.0000\n" + - " \n" + - " \n" + - " \n" + - " 1.0000\n" + - " \n" + - " \n" + - " \n" + - " VAT\n" + - " S\n" + - " 7.00\n" + - " \n" + - " \n" + - " 160.00\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2\n" + - " \n" + - " \n" + - " Luftballon: Bunt, ca. 500ml\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 0.7900\n" + - " 1.0000\n" + - " \n" + - " \n" + - " 0.7900\n" + - " 1.0000\n" + - " \n" + - " \n" + - " \n" + - " 400.0000\n" + - " \n" + - " \n" + - " \n" + - " VAT\n" + - " S\n" + - " 19.00\n" + - " \n" + - " \n" + - " 316.00\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 3\n" + - " \n" + - " \n" + - " Heiße Luft pro Liter\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 0.1000\n" + - " 1.0000\n" + - " \n" + - " \n" + - " 0.1000\n" + - " 1.0000\n" + - " \n" + - " \n" + - " \n" + - " 200.0000\n" + - " \n" + - " \n" + - " \n" + - " VAT\n" + - " S\n" + - " 19.00\n" + - " \n" + - " \n" + - " 20.00\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " Bei Spiel GmbH\n" + - " \n" + - " 12345\n" + - " Ecke 12\n" + - " Stadthausen\n" + - " DE\n" + - " \n" + - " \n" + - " 22/815/0815/4\n" + - " \n" + - " \n" + - " DE136695976\n" + - " \n" + - " \n" + - " \n" + - " Theodor Est\n" + - " \n" + - " 88802\n" + - " Bahnstr. 42\n" + - " Spielkreis\n" + - " DE\n" + - " \n" + - " \n" + - " DE999999999\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 20171117\n" + - " \n" + - " \n" + - " \n" + - " RE-20171118/506\n" + - " EUR\n" + - " \n" + - " 42\n" + - " Überweisung\n" + - " \n" + + String ownZUGFeRDXML = new String(UTF8ByteOrderMark) + "\n" + + "\n" + + " \n" + + " false\n" + + " \n" + + " urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:extended\n" + + " \n" + + " \n" + + " \n" + + " RE-20171118/506\n" + + " RECHNUNG\n" + + " 380\n" + + " 20171118\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " Künstlerische Gestaltung (Stunde): Einer Beispielrechnung\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 160.0000\n" + + " 1.0000\n" + + " \n" + + " \n" + + " 160.0000\n" + + " 1.0000\n" + + " \n" + + " \n" + + " \n" + + " 1.0000\n" + + " \n" + + " \n" + + " \n" + + " VAT\n" + + " S\n" + + " 7.00\n" + + " \n" + + " \n" + + " 160.00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2\n" + + " \n" + + " \n" + + " Luftballon: Bunt, ca. 500ml\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 0.7900\n" + + " 1.0000\n" + + " \n" + + " \n" + + " 0.7900\n" + + " 1.0000\n" + + " \n" + + " \n" + + " \n" + + " 400.0000\n" + + " \n" + + " \n" + + " \n" + + " VAT\n" + + " S\n" + + " 19.00\n" + + " \n" + + " \n" + + " 316.00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 3\n" + + " \n" + + " \n" + + " Heiße Luft pro Liter\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 0.1000\n" + + " 1.0000\n" + + " \n" + + " \n" + + " 0.1000\n" + + " 1.0000\n" + + " \n" + + " \n" + + " \n" + + " 200.0000\n" + + " \n" + + " \n" + + " \n" + + " VAT\n" + + " S\n" + + " 19.00\n" + + " \n" + + " \n" + + " 20.00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Bei Spiel GmbH\n" + + " \n" + + " 12345\n" + + " Ecke 12\n" + + " Stadthausen\n" + + " DE\n" + + " \n" + + " \n" + + " 22/815/0815/4\n" + + " \n" + + " \n" + + " DE136695976\n" + + " \n" + + " \n" + + " \n" + + " Theodor Est\n" + + " \n" + + " 88802\n" + + " Bahnstr. 42\n" + + " Spielkreis\n" + + " DE\n" + + " \n" + + " \n" + + " DE999999999\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 20171117\n" + + " \n" + + " \n" + + " \n" + + " RE-20171118/506\n" + + " EUR\n" + + " \n" + + " 42\n" + + " Überweisung\n" + + " \n" + " DE88 2008 0000 0970 3757 00\n" + " 44421800\n" + " \n" + - " \n" + + " \n" + " COBADEFFXXX\n" + - " 41441604\n" + - " Commerzbank\n" + - " \n" + - " \n" + - " \n" + - " 11.20\n" + - " VAT\n" + - " 160.00\n" + - " S\n" + - " 7.00\n" + - " \n" + - " \n" + - " 63.84\n" + - " VAT\n" + - " 336.00\n" + - " S\n" + - " 19.00\n" + - " \n" + - " \n" + - " Zahlbar ohne Abzug bis 09.12.2017\n" + - " 20171209\n" + - " \n" + - " \n" + - " 496.00\n" + - " 0.00\n" + - " 0.00\n" + - " 496.00\n" + - " 75.04\n" + - " 571.04\n" + - " 571.04\n" + - " \n" + - " \n" + - " \n" + + " 41441604\n" + + " Commerzbank\n" + + " \n" + + " \n" + + " \n" + + " 11.20\n" + + " VAT\n" + + " 160.00\n" + + " S\n" + + " 7.00\n" + + " \n" + + " \n" + + " 63.84\n" + + " VAT\n" + + " 336.00\n" + + " S\n" + + " 19.00\n" + + " \n" + + " \n" + + " Zahlbar ohne Abzug bis 09.12.2017\n" + + " 20171209\n" + + " \n" + + " \n" + + " 496.00\n" + + " 0.00\n" + + " 0.00\n" + + " 496.00\n" + + " 75.04\n" + + " 571.04\n" + + " 571.04\n" + + " \n" + + " \n" + + " \n" + ""; - zea1.setZUGFeRDXMLData(ownZUGFeRDXML.getBytes("UTF-8")); + zea1.setZUGFeRDXMLData(ownZUGFeRDXML.getBytes("UTF-8")); - ByteArrayOutputStream baos=new ByteArrayOutputStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); zea1.disableAutoClose(true); zea1.export(TARGET_PDF); zea1.export(baos); zea1.close(); - String pdfContent=baos.toString("UTF-8"); - assertFalse(pdfContent.indexOf("(via mustangproject.org")==-1); + String pdfContent = baos.toString("UTF-8"); + assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); assertFalse(pdfContent.indexOf("EN 16931") == -1); } catch (IOException e) { @@ -279,31 +278,32 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { String amount = null; String bic = null; - String blz = null; + String blz = null; String iban = null; - String kto = null; + String kto = null; String holder = null; String ref = null; if (zi.canParse()) { zi.parse(); amount = zi.getAmount(); - blz = zi.getBLZ(); + blz = zi.getBLZ(); bic = zi.getBIC(); iban = zi.getIBAN(); - kto = zi.getKTO(); + kto = zi.getKTO(); holder = zi.getHolder(); ref = zi.getForeignReference(); } assertEquals(amount, "571.04"); - assertEquals(blz, "41441604"); + assertEquals(blz, "41441604"); assertEquals(bic, "COBADEFFXXX"); assertEquals(iban, "DE88 2008 0000 0970 3757 00"); assertEquals(kto, "44421800"); assertEquals(holder, "Bei Spiel GmbH"); assertEquals(ref, "RE-20171118/506"); } + /** * The exporter test bases on @{code * ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds @@ -362,10 +362,10 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { + "44421800\n" + "\n" + "\n" - + "COBADEFFXXX\n" - + "41441604\n" + + "COBADEFFXXX\n" + + "41441604\n" + "Commerzbank\n" - + "\n" + + "\n" + "\n" + "\n" + "11.20\n" + "VAT\n" @@ -459,13 +459,13 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { + "\n" + ""; zea1.setZUGFeRDXMLData(ownZUGFeRDXML.getBytes("UTF-8")); - ByteArrayOutputStream baos=new ByteArrayOutputStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); zea1.disableAutoClose(true); zea1.export(TARGET_PDF); zea1.export(baos); zea1.close(); - String pdfContent=baos.toString("UTF-8"); - assertFalse(pdfContent.indexOf("(via mustangproject.org")==-1); + String pdfContent = baos.toString("UTF-8"); + assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); assertFalse(pdfContent.indexOf("BASIC") == -1); } catch (IOException e) { @@ -480,7 +480,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { String amount = null; String bic = null; - String blz = null; + String blz = null; String iban = null; String kto = null; String holder = null; @@ -490,7 +490,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { zi.parse(); amount = zi.getAmount(); bic = zi.getBIC(); - blz = zi.getBLZ(); + blz = zi.getBLZ(); iban = zi.getIBAN(); kto = zi.getKTO(); holder = zi.getHolder(); @@ -499,7 +499,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { assertEquals(amount, "571.04"); assertEquals(bic, "COBADEFFXXX"); - assertEquals(blz, "41441604"); + assertEquals(blz, "41441604"); assertEquals(iban, "DE88 2008 0000 0970 3757 00"); assertEquals(kto, "44421800"); assertEquals(holder, "Bei Spiel GmbH"); diff --git a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java index bc5fb4d6..29c29d51 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java @@ -33,457 +33,405 @@ import java.util.Date; import java.util.GregorianCalendar; @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExportableTransaction -{ - - @Override - public Date getDeliveryDate() - { - return new GregorianCalendar(2017, Calendar.MAY, 7).getTime(); - } - - @Override - public Date getDueDate() - { - return new GregorianCalendar(2017, Calendar.MAY, 30).getTime(); - } - - @Override - public Date getIssueDate() - { - return new GregorianCalendar(2017, Calendar.MAY, 9).getTime(); - } - - @Override - public String getNumber() - { - return "RE-20170509/505"; - } - - @Override - public String getOwnKto() - { - return "44421800"; - } - - @Override - public String getOwnBLZ() - { - return "41441604"; - } - - @Override - public String getOwnBIC() - { - return "COBADEFFXXX"; - } - - @Override - public String getOwnBankName() - { - return "Commerzbank"; - } - - @Override - public String getOwnCountry() - { - return "DE"; - } - - @Override - public String getOwnIBAN() - { - return "DE88 2008 0000 0970 3757 00"; - } - - @Override - public String getOwnLocation() - { - return "Stadthausen"; - } - - @Override - public String getOwnOrganisationName() - { - return "Bei Spiel GmbH"; - } - - @Override - public String getOwnStreet() - { - return "Ecke 12"; - } - - @Override - public String getOwnTaxID() - { - return "22/815/0815/4"; - } - - @Override - public String getOwnVATID() - { - return "DE136695976"; - } - - @Override - public String getOwnZIP() - { - return "12345"; - } - - @Override - public IZUGFeRDExportableContact getRecipient() - { - return new Contact(); - } - - - @Override - public String getOwnOrganisationFullPlaintextInfo() - { - return null; - } - - @Override - public String getCurrency() - { - return "EUR"; - } - - @Override - public IZUGFeRDExportableItem[] getZFItems() - { - Item[] allItems = new Item[3]; - 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")); - - allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct); - allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct); - allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct); - return allItems; - } - - @Override - public String getOwnPaymentInfoText() { - return "Überweisung"; - } - - @Override - public String getPaymentTermDescription() { - SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); - return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate()); - } - - @Override - public IZUGFeRDAllowanceCharge[] getZFAllowances() { - return null; - } - - @Override - public IZUGFeRDAllowanceCharge[] getZFCharges() { - return null; - } - - @Override - public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() { - return null; - } - - @Override - public String getReferenceNumber() { - return null; - } - - class Contact implements IZUGFeRDExportableContact - { - - @Override - public String getCountry() - { - return "DE"; - } - - @Override - public String getLocation() - { - return "Spielkreis"; - } - - @Override - public String getName() - { - return "Theodor Est"; - } - - @Override - public String getStreet() - { - return "Bahnstr. 42"; - } - - @Override - public String getVATID() - { - return "DE999999999"; - } - - @Override - public String getZIP() - { - return "88802"; - } - } - - class Item implements IZUGFeRDExportableItem - { - - public Item(BigDecimal price, BigDecimal quantity, Product product) - { - super(); - this.price = price; - this.quantity = quantity; - this.product = product; - } - - private BigDecimal price,quantity; - private Product product; - - @Override - public BigDecimal getPrice() - { - return price; - } - - public void setPrice(BigDecimal price) - { - this.price = price; - } - - @Override - public BigDecimal getQuantity() - { - return quantity; - } - - public void setQuantity(BigDecimal quantity) - { - this.quantity = quantity; - } - - @Override - public Product getProduct() - { - return product; - } - - public void setProduct(Product product) - { - this.product = product; - } - - @Override - public IZUGFeRDAllowanceCharge[] getItemAllowances() { - return null; - } - - @Override - public IZUGFeRDAllowanceCharge[] getItemCharges() { - return null; - } - - } - - class Product implements IZUGFeRDExportableProduct - { - private String description, name, unit; - private BigDecimal VATPercent; - - public Product(String description, String name, String unit, BigDecimal VATPercent) - { - super(); - this.description = description; - this.name = name; - this.unit = unit; - this.VATPercent = VATPercent; - } - - @Override - public String getDescription() - { - return description; - } - - public void setDescription(String description) - { - this.description = description; - } - - @Override - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - @Override - public String getUnit() - { - return unit; - } - - public void setUnit(String unit) - { - this.unit = unit; - } - - @Override - public BigDecimal getVATPercent() - { - return VATPercent; - } - - public void setVATPercent(BigDecimal vATPercent) - { - VATPercent = vATPercent; - } - - } - - /** - * Create the test case - * - * @param testName - * name of the test case - */ - public MustangReaderWriterEdgeTest(String testName) - { - super(testName); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite(MustangReaderWriterEdgeTest.class); - } - - // //////// TESTS ////////////////////////////////////////////////////////////////////////////////////////// - - /** - * The importer test imports from ./src/test/MustangGnuaccountingBeispielRE-20170509_505.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 - */ - - public void testAImport() throws IOException - { - ZUGFeRDImporter zi = new ZUGFeRDImporter(); - zi.extractLowLevel(this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf")); - // Reading ZUGFeRD - - String amount = null; - String bic = null; - String blz = null; - String iban = null; - String kto = null; - String holder = null; - String ref = null; - String dueDate = null; - - if (zi.canParse()) - { - zi.parse(); - amount = zi.getAmount(); - bic = zi.getBIC(); - blz = zi.getBLZ(); - iban = zi.getIBAN(); - kto = zi.getKTO(); - holder = zi.getHolder(); - dueDate = zi.getDueDate(); - ref = zi.getForeignReference(); - } - - assertEquals(amount, "571.04"); - assertEquals(bic, getOwnBIC()); - assertEquals(blz, getOwnBLZ()); - assertEquals(iban, getOwnIBAN()); - assertEquals(kto, getOwnKto()); - assertEquals(holder, getOwnOrganisationName()); - - assertEquals(dueDate, "20170530"); - assertEquals(ref, getNumber()); - - } - - /** - * The exporter test bases on @{code ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds metadata, - * writes - * to @{code ./target/testout-*} and then imports to check the values. - * It would not make sense to have it run before the less complex importer test (which is probably redundant) - * --> as only Name Ascending is supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export - */ - public void testEdgeExport() throws Exception { - - final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505newEdge.pdf"; - // the writing part - - try(InputStream SOURCE_PDF = - this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); - - ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory() - .setProducer("My Application") - .setCreator(System.getProperty("user.name")) - .ignorePDFAErrors() - .load(SOURCE_PDF)) { - ze.setZUGFeRDVersion(1); - ze.PDFattachZugferdFile(this); - String theXML=new String(ze.getProvider().getXML()); - assertTrue(theXML.contains(" as only Name Ascending is supported for Test Unit sequence, I renamed the this test-A-Export to run before + * testZExport + * + * @throws IOException + */ + + public void testAImport() throws IOException { + ZUGFeRDImporter zi = new ZUGFeRDImporter(); + zi.extractLowLevel(this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf")); + // Reading ZUGFeRD + + String amount = null; + String bic = null; + String blz = null; + String iban = null; + String kto = null; + String holder = null; + String ref = null; + String dueDate = null; + + if (zi.canParse()) { + zi.parse(); + amount = zi.getAmount(); + bic = zi.getBIC(); + blz = zi.getBLZ(); + iban = zi.getIBAN(); + kto = zi.getKTO(); + holder = zi.getHolder(); + dueDate = zi.getDueDate(); + ref = zi.getForeignReference(); + } + + assertEquals(amount, "571.04"); + assertEquals(bic, getOwnBIC()); + assertEquals(blz, getOwnBLZ()); + assertEquals(iban, getOwnIBAN()); + assertEquals(kto, getOwnKto()); + assertEquals(holder, getOwnOrganisationName()); + + assertEquals(dueDate, "20170530"); + assertEquals(ref, getNumber()); + + } + + /** + * The exporter test bases on @{code ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds metadata, + * writes + * to @{code ./target/testout-*} and then imports to check the values. + * It would not make sense to have it run before the less complex importer test (which is probably redundant) + * --> as only Name Ascending is supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export + */ + public void testEdgeExport() throws Exception { + + final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505newEdge.pdf"; + // the writing part + + try (InputStream SOURCE_PDF = + this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); + + ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory() + .setProducer("My Application") + .setCreator(System.getProperty("user.name")) + .ignorePDFAErrors() + .load(SOURCE_PDF)) { + ze.setZUGFeRDVersion(1); + ze.PDFattachZugferdFile(this); + String theXML = new String(ze.getProvider().getXML()); + assertTrue(theXML.contains("\n" + - " \n" + - " \n" + - " \n" + - " uuid:6776DD95-DAF6-768E-DAE6-2697750D95C5\n" + - " uuid:47380404-5938-FE2C-8F0B-B505DCE43BF5\n" + - " \n" + - " \n" + - " BASIC\n" + - " ZUGFeRD-invoice.xml\n" + - " INVOICE\n" + - " 1.0\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " ZUGFeRD PDFA Extension Schema\n" + - " urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#\n" + - " zf\n" + - " \n" + - " \n" + - " \n" + - " DocumentFileName\n" + - " Text\n" + - " external\n" + - " name of the embedded XML invoice file\n" + - " \n" + - " \n" + - " DocumentType\n" + - " Text\n" + - " external\n" + - " INVOICE\n" + - " \n" + - " \n" + - " Version\n" + - " Text\n" + - " external\n" + - " The actual version of the ZUGFeRD XML schema\n" + - " \n" + - " \n" + - " ConformanceLevel\n" + - " Text\n" + - " external\n" + - " The conformance level of the embedded ZUGFeRD data\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 3\n" + - " B\n" + - " \n" + - " \n" + - " 2014-07-11T13:39:46+02:00\n" + - " 2014-07-11T13:39:46+02:00\n" + - " zugferd_invoice.java\n" + - " 2014-07-11T13:39:46+02:00\n" + - " \n" + - " \n" + - " PDFlib Personalization Server 9.0.3 (JDK 1.6/Mac OS X-10.6 64)\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " ZUGFeRD Rechnung $Revision: 1.13 $\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + + String amount = zi.getAmount(); + + assertEquals("\n" + + " \n" + + " \n" + + " \n" + + " uuid:6776DD95-DAF6-768E-DAE6-2697750D95C5\n" + + " uuid:47380404-5938-FE2C-8F0B-B505DCE43BF5\n" + + " \n" + + " \n" + + " BASIC\n" + + " ZUGFeRD-invoice.xml\n" + + " INVOICE\n" + + " 1.0\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ZUGFeRD PDFA Extension Schema\n" + + " urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#\n" + + " zf\n" + + " \n" + + " \n" + + " \n" + + " DocumentFileName\n" + + " Text\n" + + " external\n" + + " name of the embedded XML invoice file\n" + + " \n" + + " \n" + + " DocumentType\n" + + " Text\n" + + " external\n" + + " INVOICE\n" + + " \n" + + " \n" + + " Version\n" + + " Text\n" + + " external\n" + + " The actual version of the ZUGFeRD XML schema\n" + + " \n" + + " \n" + + " ConformanceLevel\n" + + " Text\n" + + " external\n" + + " The conformance level of the embedded ZUGFeRD data\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 3\n" + + " B\n" + + " \n" + + " \n" + + " 2014-07-11T13:39:46+02:00\n" + + " 2014-07-11T13:39:46+02:00\n" + + " zugferd_invoice.java\n" + + " 2014-07-11T13:39:46+02:00\n" + + " \n" + + " \n" + + " PDFlib Personalization Server 9.0.3 (JDK 1.6/Mac OS X-10.6 64)\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ZUGFeRD Rechnung $Revision: 1.13 $\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + "", zi.getXMP()); // this resembles the data written in MustangReaderWriterCustomXMLTest assertEquals(amount, "1005.55"); } - public void testMigratePDFA1ToA3() throws IOException { @@ -506,7 +504,7 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta try (InputStream SOURCE_PDF = this.getClass() .getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); - ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) { + ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) { ze.PDFattachZugferdFile(this); ze.disableAutoClose(true); @@ -554,8 +552,8 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta } /** - * @Test(expected = IndexOutOfBoundsException.class) * @throws Exception + * @Test(expected = IndexOutOfBoundsException.class) */ public void testExceptionOnPDF14() throws Exception { @@ -566,7 +564,7 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta try (InputStream SOURCE_PDF = this.getClass() .getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDF14.pdf"); - ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().load(SOURCE_PDF)) { + ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().load(SOURCE_PDF)) { ze.PDFattachZugferdFile(this); ze.export(TARGET_PDF); diff --git a/src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java b/src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java index b7e4bfc2..2a36e4ef 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java @@ -26,28 +26,35 @@ import java.util.logging.Level; import java.util.logging.Logger; - -/** This test utility class is providing usability functions for test file resources */ +/** + * This test utility class is providing usability functions for test file resources + */ public class ResourceUtilities { - private static final Logger LOG = Logger.getLogger(ResourceUtilities.class.getName()); + private static final Logger LOG = Logger.getLogger(ResourceUtilities.class.getName()); - /** Loading a File into a String using a certain encoding and file path */ - public static String readFile(Charset encoding, String path) throws IOException { - byte[] content = Files.readAllBytes(Paths.get(path)); - return new String(content, encoding); - } + /** + * Loading a File into a String using a certain encoding and file path + */ + public static String readFile(Charset encoding, String path) throws IOException { + byte[] content = Files.readAllBytes(Paths.get(path)); + return new String(content, encoding); + } - /** Saving a String as a file to a certain file path */ - public static void saveFile(Charset encoding, String path, String content) throws FileNotFoundException { + /** + * Saving a String as a file to a certain file path + */ + public static void saveFile(Charset encoding, String path, String content) throws FileNotFoundException { - // resources will be released automatically - try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(path)), encoding), true)) { - out.println(content); - } - } + // resources will be released automatically + try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(path)), encoding), true)) { + out.println(content); + } + } - /** The relative path of the test file will be resolved and the absolute will be returned + /** + * The relative path of the test file will be resolved and the absolute will be returned + * * @param relativeFilePath Path of the test resource relative to src/test/resource/. * @return the absolute path of the test file * @throws FileNotFoundException If the file could not be found @@ -66,7 +73,9 @@ public class ResourceUtilities { return uri.getPath(); } - /** The relative path of the test file will be resolved and the absolute will be returned + /** + * The relative path of the test file will be resolved and the absolute will be returned + * * @param relativeFilePath Path of the test resource relative to src/test/resource/. * @return the URI created based on the relativeFilePath * @throws URISyntaxException if no URI could be created from the given relative path @@ -77,19 +86,23 @@ public class ResourceUtilities { return new URI(filePath); } - /** The relative path of the test file will be used to determine an absolute - * path to a temporary directory in the output directory. + /** + * The relative path of the test file will be used to determine an absolute + * path to a temporary directory in the output directory. + * * @param relativeFilePath Path of the test resource relative to src/test/resource/. * @return absolute path to a test output * @throws IOException if no absolute Path could be created. */ public static String getTestOutput(String relativeFilePath) throws IOException { - File tempFile=File.createTempFile(relativeFilePath, null); + File tempFile = File.createTempFile(relativeFilePath, null); tempFile.deleteOnExit(); return tempFile.getAbsolutePath(); } - /** The Input of the test file will be resolved and the absolute will be returned + /** + * The Input of the test file will be resolved and the absolute will be returned + * * @param relativeFilePath Path of the test resource relative to src/test/resource/. * @return the absolute path of the test file */ @@ -97,7 +110,9 @@ public class ResourceUtilities { return ResourceUtilities.class.getClassLoader().getResourceAsStream(relativeFilePath); } - /** Relative to the test output directory a test file will be returned dependent on the relativeFilePath provided. + /** + * Relative to the test output directory a test file will be returned dependent on the relativeFilePath provided. + * * @param relativeFilePath Path of the test output resource relative to target/test-classes/. * @return the empty File of the test output (to be filled) */ @@ -127,17 +142,17 @@ public class ResourceUtilities { public static File getTempTestDirectory() { File tempDir = new File(ResourceUtilities.getTestOutputFolder() + "temp"); tempDir.mkdir(); //if it already exist no problem - return tempDir; + return tempDir; } -/** + /** * To fix the 3 slashes bug for File URI: For example: * file:/C:/work/test.txt -> file:///C:/work/test.txt * * @param u - the File URI * @return the String of the URI */ - public static String toExternalForm(URI u) { + public static String toExternalForm(URI u) { StringBuilder sb = new StringBuilder(); if (u.getScheme() != null) { sb.append(u.getScheme()); @@ -180,13 +195,14 @@ public class ResourceUtilities { sb.append(u.getFragment()); } String ret = null; - try { - ret = new URI(sb.toString()).toASCIIString(); - } catch (URISyntaxException ex) { - LOG.log(Level.SEVERE, null, ex); - } + try { + ret = new URI(sb.toString()).toASCIIString(); + } catch (URISyntaxException ex) { + LOG.log(Level.SEVERE, null, ex); + } return ret; } - private ResourceUtilities() { - } + + private ResourceUtilities() { + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/VersionMigrationTest.java b/src/test/java/org/mustangproject/ZUGFeRD/VersionMigrationTest.java index 52644375..1f2a0fde 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/VersionMigrationTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/VersionMigrationTest.java @@ -38,18 +38,18 @@ import java.util.logging.Logger; * will be migrated to src/test/resources/migration/output. * If there is a similar named file as test reference src/test/resources/migration/reference a test * will be triggered for every single file. - * + *

* Note: Any 'ZUGFeRD1' will be exchanged to 'ZUGFeRD2' during migration and adequate reference will be searched for. */ @RunWith(Parameterized.class) public class VersionMigrationTest { - private static final Logger LOG = Logger.getLogger(VersionMigrationTest.class.getName()); + private static final Logger LOG = Logger.getLogger(VersionMigrationTest.class.getName()); - private static final String INPUT_DIR = "src" + File.separator + "test" + File.separator + "resources" + File.separator + "migration" + File.separator + "input" + File.separator; - private static final String REFERENCE_DIR = "src" + File.separator + "test" + File.separator + "resources" + File.separator + "migration" + File.separator + "reference" + File.separator; - private static final String OUTPUT_DIR = "target" + File.separator + "test-classes" + File.separator + "migration" + File.separator + "output" + File.separator; - private File mTestFile = null; + private static final String INPUT_DIR = "src" + File.separator + "test" + File.separator + "resources" + File.separator + "migration" + File.separator + "input" + File.separator; + private static final String REFERENCE_DIR = "src" + File.separator + "test" + File.separator + "resources" + File.separator + "migration" + File.separator + "reference" + File.separator; + private static final String OUTPUT_DIR = "target" + File.separator + "test-classes" + File.separator + "migration" + File.separator + "output" + File.separator; + private File mTestFile = null; @BeforeClass public static void setUpBeforeClass() throws Exception { @@ -70,76 +70,75 @@ public class VersionMigrationTest { private static void addFilesFromFolder(final File folder, Collection testSuiteData) { String filePath = null; - for (final File fileEntry : folder.listFiles()) { + for (final File fileEntry : folder.listFiles()) { filePath = fileEntry.getAbsolutePath(); - if (fileEntry.isDirectory()) { + if (fileEntry.isDirectory()) { LOG.log(Level.INFO, "*** testDirectory:{0}", filePath); addFilesFromFolder(fileEntry, testSuiteData); } else { - LOG.log(Level.INFO, "*** testFile: {0}", filePath); - Object[] testData = new Object[]{fileEntry}; - testSuiteData.add(testData); + LOG.log(Level.INFO, "*** testFile: {0}", filePath); + Object[] testData = new Object[]{fileEntry}; + testSuiteData.add(testData); } } } @Test - /** - * ZUGFeRD 1.0 to 2.0 migration test. - * For more information see class description. */ + /** + * ZUGFeRD 1.0 to 2.0 migration test. + * For more information see class description. */ public void testFile() { - testMigration(mTestFile.getName()); + testMigration(mTestFile.getName()); } - private void testMigration(String fileName) { - try { - String tmp = new ZUGFeRDMigrator().migrateFromV1ToV2(INPUT_DIR + fileName); - String newName = fileName.replace("ZUGFeRD1", "ZUGFeRD2"); - ResourceUtilities.saveFile(StandardCharsets.UTF_8, OUTPUT_DIR + newName, tmp); - if(new File(REFERENCE_DIR + newName).exists()){ - // we need to save the string and reload it otherwise two bytes are missing (likely EOF related) - String outXML = ResourceUtilities.readFile(StandardCharsets.UTF_8, OUTPUT_DIR + newName); - String refXML = ResourceUtilities.readFile(StandardCharsets.UTF_8, REFERENCE_DIR + newName); - int t = outXML.length(); - int r = refXML.length(); - if (t != r || !(outXML.equals(refXML))) { - LOG.info("There are differences between:" - + "\nZUGFeRD 2.0 Test Output @ " + OUTPUT_DIR + newName - + "\nZUGFeRD 2.0 Test Reference @ " + REFERENCE_DIR + newName); - LOG.info("\n\nFile sizes:\n " - + "\nZUGFeRD 2.0 Test Output character count: " + t - + "\nZUGFeRD 2.0 Test Refer. character count: " + r); - findLineDiffs(outXML, refXML); - Assert.fail("Version update failed, as test result and reference are different!"); - }else{ - LOG.log(Level.INFO,"\n*** Tested successfull migration from ZUGFeRD 1.0 to 2.0: '" + newName + "'' ***\n", OUTPUT_DIR); - } - }else{ - LOG.log(Level.INFO,"\n*** Migrated from ZUGFeRD 1.0 to 2.0 invoice: '" + newName + "'' ***\n", OUTPUT_DIR); - } - } catch (IOException | TransformerException t) { - LOG.log(Level.SEVERE, t.getMessage(), t); - Assert.fail("Failed with " + t.getClass().getName() + ": '" + t.getMessage() + "'"); - } - } + private void testMigration(String fileName) { + try { + String tmp = new ZUGFeRDMigrator().migrateFromV1ToV2(INPUT_DIR + fileName); + String newName = fileName.replace("ZUGFeRD1", "ZUGFeRD2"); + ResourceUtilities.saveFile(StandardCharsets.UTF_8, OUTPUT_DIR + newName, tmp); + if (new File(REFERENCE_DIR + newName).exists()) { + // we need to save the string and reload it otherwise two bytes are missing (likely EOF related) + String outXML = ResourceUtilities.readFile(StandardCharsets.UTF_8, OUTPUT_DIR + newName); + String refXML = ResourceUtilities.readFile(StandardCharsets.UTF_8, REFERENCE_DIR + newName); + int t = outXML.length(); + int r = refXML.length(); + if (t != r || !(outXML.equals(refXML))) { + LOG.info("There are differences between:" + + "\nZUGFeRD 2.0 Test Output @ " + OUTPUT_DIR + newName + + "\nZUGFeRD 2.0 Test Reference @ " + REFERENCE_DIR + newName); + LOG.info("\n\nFile sizes:\n " + + "\nZUGFeRD 2.0 Test Output character count: " + t + + "\nZUGFeRD 2.0 Test Refer. character count: " + r); + findLineDiffs(outXML, refXML); + Assert.fail("Version update failed, as test result and reference are different!"); + } else { + LOG.log(Level.INFO, "\n*** Tested successfull migration from ZUGFeRD 1.0 to 2.0: '" + newName + "'' ***\n", OUTPUT_DIR); + } + } else { + LOG.log(Level.INFO, "\n*** Migrated from ZUGFeRD 1.0 to 2.0 invoice: '" + newName + "'' ***\n", OUTPUT_DIR); + } + } catch (IOException | TransformerException t) { + LOG.log(Level.SEVERE, t.getMessage(), t); + Assert.fail("Failed with " + t.getClass().getName() + ": '" + t.getMessage() + "'"); + } + } - - private static void findLineDiffs(String outXML, String refXML){ - Scanner outScanner = new Scanner(outXML); - Scanner refScanner = new Scanner(refXML); - String outLine = null; - String refLine = null; - while (outScanner.hasNextLine() && refScanner.hasNextLine()) { - outLine = outScanner.nextLine(); - refLine = refScanner.nextLine(); - if(!outLine.equals(refLine)){ - LOG.info("First line difference between reference and output file:" + - "\nRefLine: " + refLine + - "\nOutLine: " + outLine + "\n"); - } - } - refScanner.close(); - outScanner.close(); - } + private static void findLineDiffs(String outXML, String refXML) { + Scanner outScanner = new Scanner(outXML); + Scanner refScanner = new Scanner(refXML); + String outLine = null; + String refLine = null; + while (outScanner.hasNextLine() && refScanner.hasNextLine()) { + outLine = outScanner.nextLine(); + refLine = refScanner.nextLine(); + if (!outLine.equals(refLine)) { + LOG.info("First line difference between reference and output file:" + + "\nRefLine: " + refLine + + "\nOutLine: " + outLine + "\n"); + } + } + refScanner.close(); + outScanner.close(); + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java b/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java index 84e872eb..2e284fdd 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java @@ -27,48 +27,48 @@ import java.util.Date; import java.util.GregorianCalendar; public class ZUGFeRDTransactionModelConverterTest { - @Test - public void convertToModel_convertsMinimalTransactionToValidXml() throws Exception { - // setup - IZUGFeRDExportableTransaction transaction = new IZUGFeRDExportableTransactionImpl() - .setIssueDate(createDate(2000, 1, 1)) - .setDeliveryDate(createDate(2000, 1, 2)) - .setDueDate(createDate(2000, 1, 3)) - .setNumber("num") - .setRecipient(new IZUGFeRDExportableContactImpl() - .setName("recipient name") - .setStreet("recipient street") - .setLocation("recipient city") - .setCountry("recipient country") - ) - .setOwnOrganisationName("own org") - .setOwnStreet("own street") - .setOwnCountry("own country") - .setOwnLocation("own city") - .setOwnBankName("own bank") - .setZFItems( - new IZUGFeRDExportableItemImpl() - .setProduct(new IZUGFeRDExportableProductImpl() - .setVatPercent(new BigDecimal("1.19")) - .setName("product name") - .setDescription("product description") - .setUnit("product unit") - ) - .setQuantity(BigDecimal.ONE) - .setPrice(BigDecimal.TEN) - ); + @Test + public void convertToModel_convertsMinimalTransactionToValidXml() throws Exception { + // setup + IZUGFeRDExportableTransaction transaction = new IZUGFeRDExportableTransactionImpl() + .setIssueDate(createDate(2000, 1, 1)) + .setDeliveryDate(createDate(2000, 1, 2)) + .setDueDate(createDate(2000, 1, 3)) + .setNumber("num") + .setRecipient(new IZUGFeRDExportableContactImpl() + .setName("recipient name") + .setStreet("recipient street") + .setLocation("recipient city") + .setCountry("recipient country") + ) + .setOwnOrganisationName("own org") + .setOwnStreet("own street") + .setOwnCountry("own country") + .setOwnLocation("own city") + .setOwnBankName("own bank") + .setZFItems( + new IZUGFeRDExportableItemImpl() + .setProduct(new IZUGFeRDExportableProductImpl() + .setVatPercent(new BigDecimal("1.19")) + .setName("product name") + .setDescription("product description") + .setUnit("product unit") + ) + .setQuantity(BigDecimal.ONE) + .setPrice(BigDecimal.TEN) + ); - // execution - final JAXBElement actual = - new ZUGFeRDTransactionModelConverter(transaction).convertToModel(); + // execution + final JAXBElement actual = + new ZUGFeRDTransactionModelConverter(transaction).convertToModel(); - // evaluation - ZUGFeRDXMLAssert.assertValidZugferd(actual); - } + // evaluation + ZUGFeRDXMLAssert.assertValidZugferd(actual); + } - private static Date createDate(int year, int month, int day) { - final GregorianCalendar calendar = new GregorianCalendar(); - calendar.set(year, month-1, day); - return calendar.getTime(); - } + private static Date createDate(int year, int month, int day) { + final GregorianCalendar calendar = new GregorianCalendar(); + calendar.set(year, month - 1, day); + return calendar.getTime(); + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDXMLAssert.java b/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDXMLAssert.java index 62c2733b..55c3313e 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDXMLAssert.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDXMLAssert.java @@ -30,27 +30,27 @@ import javax.xml.bind.JAXBElement; import javax.xml.parsers.DocumentBuilderFactory; public class ZUGFeRDXMLAssert { - private static final ISchematronResource SCHEMATRON = loadSchematron(); + private static final ISchematronResource SCHEMATRON = loadSchematron(); - public static void assertValidZugferd(JAXBElement xml) throws Exception { - assertValidZugferd(toDocument(xml)); - } + public static void assertValidZugferd(JAXBElement xml) throws Exception { + assertValidZugferd(toDocument(xml)); + } - public static void assertValidZugferd(Node xml) throws Exception { - Assert.assertTrue("schema valid", SCHEMATRON.getSchematronValidity(xml, null).isValid()); - } + public static void assertValidZugferd(Node xml) throws Exception { + Assert.assertTrue("schema valid", SCHEMATRON.getSchematronValidity(xml, null).isValid()); + } - private static Document toDocument(Object jaxbElement) throws Exception { - final Document result = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); - JAXBContext.newInstance("org.mustangproject.ZUGFeRD.model").createMarshaller().marshal(jaxbElement, result); - return result; - } + private static Document toDocument(Object jaxbElement) throws Exception { + final Document result = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + JAXBContext.newInstance("org.mustangproject.ZUGFeRD.model").createMarshaller().marshal(jaxbElement, result); + return result; + } - private static SchematronResourcePure loadSchematron() { - final SchematronResourcePure result = SchematronResourcePure.fromClassPath("/ZUGFeRD_1p0.scmt"); - if (!result.isValidSchematron ()) { - throw new IllegalArgumentException("Invalid Schematron!"); - } - return result; - } + private static SchematronResourcePure loadSchematron() { + final SchematronResourcePure result = SchematronResourcePure.fromClassPath("/ZUGFeRD_1p0.scmt"); + if (!result.isValidSchematron()) { + throw new IllegalArgumentException("Invalid Schematron!"); + } + return result; + } }