From ede19a6b74b7e34c1fae50bce0cf641954556986 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sat, 31 Oct 2020 18:16:10 +0100 Subject: [PATCH] refactoring Transactioncalculator --- History.md | 7 +- .../{LineCalc.java => LineCalculator.java} | 8 +- .../ZUGFeRD/TransactionCalculator.java | 134 ++++++++ .../ZUGFeRD/ZUGFeRD1PullProvider.java | 19 +- .../ZUGFeRD/ZUGFeRD2PullProvider.java | 147 +------- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 317 +++++++++--------- .../ZUGFeRD/ZF2ZInvoiceImporterTest.java | 16 +- 7 files changed, 340 insertions(+), 308 deletions(-) rename library/src/main/java/org/mustangproject/ZUGFeRD/{LineCalc.java => LineCalculator.java} (89%) create mode 100644 library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java diff --git a/History.md b/History.md index 05ce9552..8571a94b 100644 --- a/History.md +++ b/History.md @@ -3,16 +3,17 @@ - support for ZF 2.1.1, i.e. "Reference profile" Xrechnung - ZF 2.1.1 now default (up to 1.7.8 ZF2 could be set but ZF1 was default) +- integrates validator - removed jaxb #87 - fluent setter api/pushprovider #40 -- new xrechnung profile -- visualization? zugferdvisualizer? +- new xrechnung reference profile +- visualization zugferdvisualizer - migration feature (XSLT upgrade of ZF1 to ZF2) has been improved and moved from the commandline into the library - german bank account numbers can no longer be specified (dropped in favor of IBAN and BIC) - factory for xrechnung #86 - moved to Maven central - complete or discard read into push provider -- integrates validator +- now TransactionCalculator is a dedicated class and no longer mixed up with pullprovider - validator now additionally supports xrechnung - modular project setup - getSellerTradePartyAddress (PR #157 ) thanks to aberndt-hub diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalc.java b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java similarity index 89% rename from library/src/main/java/org/mustangproject/ZUGFeRD/LineCalc.java rename to library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java index 39511cb0..5912ff3f 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalc.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java @@ -2,7 +2,11 @@ package org.mustangproject.ZUGFeRD; import java.math.BigDecimal; -public class LineCalc { +/*** + * the linecalculator does the math within an item line, and e.g. calculates quantity*price. + * @see TransactionCalculator + */ +public class LineCalculator { private BigDecimal totalGross; private BigDecimal price; private BigDecimal priceGross; @@ -11,7 +15,7 @@ public class LineCalc { private BigDecimal allowance = new BigDecimal(0); private BigDecimal charge = new BigDecimal(0); - public LineCalc(IZUGFeRDExportableItem currentItem) { + public LineCalculator(IZUGFeRDExportableItem currentItem) { if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) { for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) { diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java new file mode 100644 index 00000000..909a619a --- /dev/null +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java @@ -0,0 +1,134 @@ +package org.mustangproject.ZUGFeRD; + +import java.math.BigDecimal; +import java.util.HashMap; + +/*** + * The Transactioncalculator e.g. adds the line totals and applies VAT on whole invoices + * @see LineCalculator + */ +public class TransactionCalculator implements IAbsoluteValueProvider { + protected IExportableTransaction trans; + + public TransactionCalculator(IExportableTransaction trans) { + this.trans=trans; + } + + protected BigDecimal getTotalPrepaid() { + if (trans.getTotalPrepaidAmount() == null) { + return new BigDecimal(0); + } else { + return trans.getTotalPrepaidAmount(); + } + } + + protected BigDecimal getTotalGross() { + + BigDecimal res = getTaxBasis(); + HashMap VATPercentAmountMap = getVATPercentAmountMap(); + for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { + VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); + res = res.add(amount.getCalculated()); + } + return res; + } + + protected BigDecimal getCharges() { + BigDecimal res = new BigDecimal(0); + IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges(); + if ((charges != null) && (charges.length > 0)) { + for (IZUGFeRDAllowanceCharge currentCharge : charges) { + res = res.add(currentCharge.getTotalAmount(this)); + } + } + return res; + } + + protected BigDecimal getAllowances() { + BigDecimal res = new BigDecimal(0); + IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances(); + if ((allowances != null) && (allowances.length > 0)) { + for (IZUGFeRDAllowanceCharge currentAllowance : allowances) { + res = res.add(currentAllowance.getTotalAmount(this)); + } + } + return res; + } + + protected BigDecimal getTotal() { + BigDecimal res = new BigDecimal(0); + for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { + LineCalculator lc = new LineCalculator(currentItem); + res = res.add(lc.getItemTotalGrossAmount()); + } + return res; + } + + protected BigDecimal getTaxBasis() { + BigDecimal res = getTotal().add(getCharges()).subtract(getAllowances()); + return res; + } + + /** + * 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 which taxes have been used with which amounts in this invoice + */ + protected HashMap getVATPercentAmountMap() { + HashMap hm = new HashMap<>(); + + for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { + BigDecimal percent = currentItem.getProduct().getVATPercent(); + LineCalculator lc = new LineCalculator(currentItem); + VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), + trans.getDocumentCode()); + VATAmount current = hm.get(percent); + if (current == null) { + hm.put(percent, itemVATAmount); + } else { + hm.put(percent, current.add(itemVATAmount)); + } + } + + + IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges(); + if ((charges != null) && (charges.length > 0)) { + for (IZUGFeRDAllowanceCharge currentCharge : charges) { + VATAmount theAmount = hm.get(currentCharge.getTaxPercent()); + if (theAmount == null) { + theAmount = new VATAmount(new BigDecimal(0), new BigDecimal(0), "S"); + } + theAmount.setBasis(theAmount.getBasis().add(currentCharge.getTotalAmount(this))); + BigDecimal factor = currentCharge.getTaxPercent().divide(new BigDecimal(100)); + theAmount.setCalculated(theAmount.getBasis().multiply(factor)); + hm.put(currentCharge.getTaxPercent(), theAmount); + } + } + IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances(); + if ((allowances != null) && (allowances.length > 0)) { + for (IZUGFeRDAllowanceCharge currentAllowance : allowances) { + VATAmount theAmount = hm.get(currentAllowance.getTaxPercent()); + if (theAmount == null) { + theAmount = new VATAmount(new BigDecimal(0), new BigDecimal(0), "S"); + } + theAmount.setBasis(theAmount.getBasis().subtract(currentAllowance.getTotalAmount(this))); + BigDecimal factor = currentAllowance.getTaxPercent().divide(new BigDecimal(100)); + theAmount.setCalculated(theAmount.getBasis().multiply(factor)); + + hm.put(currentAllowance.getTaxPercent(), theAmount); + } + } + + + return hm; + } + + + @Override + public BigDecimal getValue() { + return getTotal(); + } + +} diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java index deca7fcf..032b6bfc 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java @@ -104,6 +104,7 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr @Override public void generateXML(IExportableTransaction trans) { this.trans = trans; + this.calc=new TransactionCalculator(trans); boolean hasDueDate=false; String taxCategoryCode=""; @@ -288,7 +289,7 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr } } - HashMap VATPercentAmountMap = getVATPercentAmountMap(); + HashMap VATPercentAmountMap = calc.getVATPercentAmountMap(); for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); if (amount != null) { @@ -329,23 +330,23 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr } xml = xml + " \n" - + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-2$ + + " " + currencyFormat(calc.getTotal()) + "\n" //$NON-NLS-2$ // currencyID=\"EUR\" + " 0.00\n" // currencyID=\"EUR\" + " 0.00\n" // // currencyID=\"EUR\" // + " 5.80\n" // + " 14.73\n" - + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-2$ + + " " + currencyFormat(calc.getTotal()) + "\n" //$NON-NLS-2$ // // // currencyID=\"EUR\" + " " - + currencyFormat(getTotalGross().subtract(getTotal())) + "\n" - + " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-2$ + + currencyFormat(calc.getTotalGross().subtract(calc.getTotal())) + "\n" + + " " + currencyFormat(calc.getTotalGross()) + "\n" //$NON-NLS-2$ // // // currencyID=\"EUR\" - + " " + currencyFormat(getTotalPrepaid()) + "\n" - + " " + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "\n" //$NON-NLS-2$ + + " " + currencyFormat(calc.getTotalPrepaid()) + "\n" + + " " + currencyFormat(calc.getTotalGross().subtract(calc.getTotalPrepaid())) + "\n" //$NON-NLS-2$ // // // currencyID=\"EUR\" + " \n" @@ -361,7 +362,7 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr } - LineCalc lc = new LineCalc(currentItem); + LineCalculator lc = new LineCalculator(currentItem); xml = xml + " \n" + " \n" + " " + lineID + "\n" //$NON-NLS-2$ @@ -482,7 +483,7 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr if (discountTerms != null) { paymentTermsXml += ""; String currency = trans.getCurrency(); - String basisAmount = currencyFormat(getTotalGross()); + String basisAmount = currencyFormat(calc.getTotalGross()); paymentTermsXml += "" + basisAmount + ""; paymentTermsXml += "" + discountTerms.getCalculationPercentage().toString() + ""; diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 75fda7af..9dc9b68d 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -31,22 +31,21 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.Base64; -import net.sf.saxon.value.Base64BinaryValue; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import org.mustangproject.FileAttachment; -import org.mustangproject.Invoice; import org.mustangproject.XMLTools; -public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvider { +public class ZUGFeRD2PullProvider implements IXMLProvider { //// MAIN CLASS protected SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); protected byte[] zugferdData; protected IExportableTransaction trans; + protected TransactionCalculator calc; private String paymentTermsDescription; protected Profile profile = Profiles.getByName("EN16931"); @@ -100,117 +99,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide } - //move - protected BigDecimal getTotalPrepaid() { - if (trans.getTotalPrepaidAmount() == null) { - return new BigDecimal(0); - } else { - return trans.getTotalPrepaidAmount(); - } - } - - protected BigDecimal getTotalGross() { - - BigDecimal res = getTaxBasis(); - HashMap VATPercentAmountMap = getVATPercentAmountMap(); - for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { - VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); - res = res.add(amount.getCalculated()); - } - return res; - } - - protected BigDecimal getCharges() { - BigDecimal res = new BigDecimal(0); - IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges(); - if ((charges != null) && (charges.length > 0)) { - for (IZUGFeRDAllowanceCharge currentCharge : charges) { - res = res.add(currentCharge.getTotalAmount(this)); - } - } - return res; - } - - protected BigDecimal getAllowances() { - BigDecimal res = new BigDecimal(0); - IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances(); - if ((allowances != null) && (allowances.length > 0)) { - for (IZUGFeRDAllowanceCharge currentAllowance : allowances) { - res = res.add(currentAllowance.getTotalAmount(this)); - } - } - return res; - } - - protected BigDecimal getTotal() { - BigDecimal res = new BigDecimal(0); - for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { - LineCalc lc = new LineCalc(currentItem); - res = res.add(lc.getItemTotalGrossAmount()); - } - return res; - } - - protected BigDecimal getTaxBasis() { - BigDecimal res = getTotal().add(getCharges()).subtract(getAllowances()); - return res; - } - - /** - * 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 which taxes have been used with which amounts in this invoice - */ - protected HashMap getVATPercentAmountMap() { - 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(), - trans.getDocumentCode()); - VATAmount current = hm.get(percent); - if (current == null) { - hm.put(percent, itemVATAmount); - } else { - hm.put(percent, current.add(itemVATAmount)); - } - } - - - IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges(); - if ((charges != null) && (charges.length > 0)) { - for (IZUGFeRDAllowanceCharge currentCharge : charges) { - VATAmount theAmount = hm.get(currentCharge.getTaxPercent()); - if (theAmount == null) { - theAmount = new VATAmount(new BigDecimal(0), new BigDecimal(0), "S"); - } - theAmount.setBasis(theAmount.getBasis().add(currentCharge.getTotalAmount(this))); - BigDecimal factor = currentCharge.getTaxPercent().divide(new BigDecimal(100)); - theAmount.setCalculated(theAmount.getBasis().multiply(factor)); - hm.put(currentCharge.getTaxPercent(), theAmount); - } - } - IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances(); - if ((allowances != null) && (allowances.length > 0)) { - for (IZUGFeRDAllowanceCharge currentAllowance : allowances) { - VATAmount theAmount = hm.get(currentAllowance.getTaxPercent()); - if (theAmount == null) { - theAmount = new VATAmount(new BigDecimal(0), new BigDecimal(0), "S"); - } - theAmount.setBasis(theAmount.getBasis().subtract(currentAllowance.getTotalAmount(this))); - BigDecimal factor = currentAllowance.getTaxPercent().divide(new BigDecimal(100)); - theAmount.setCalculated(theAmount.getBasis().multiply(factor)); - - hm.put(currentAllowance.getTaxPercent(), theAmount); - } - } - - - return hm; - } @Override public Profile getProfile() { @@ -305,6 +193,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide @Override public void generateXML(IExportableTransaction trans) { this.trans = trans; + this.calc=new TransactionCalculator(trans); boolean hasDueDate = false; String taxCategoryCode = ""; @@ -387,7 +276,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide exemptionReason = "" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + ""; } - LineCalc lc = new LineCalc(currentItem); + LineCalculator lc = new LineCalculator(currentItem); xml = xml + " \n" + " \n" + " " + lineID + "\n" //$NON-NLS-2$ @@ -558,7 +447,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide } } - HashMap VATPercentAmountMap = getVATPercentAmountMap(); + HashMap VATPercentAmountMap = calc.getVATPercentAmountMap(); for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); if (amount != null) { @@ -592,7 +481,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide " \n" + " true\n" + " \n" + - " " + currencyFormat(getCharges()) + "\n" + + " " + currencyFormat(calc.getCharges()) + "\n" + " Charge\n" + " \n" + " VAT\n" + @@ -609,7 +498,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide " \n" + " false\n" + " \n" + - " " + currencyFormat(getAllowances()) + "\n" + + " " + currencyFormat(calc.getAllowances()) + "\n" + " Allowance\n" + " \n" + " VAT\n" + @@ -645,24 +534,24 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide } - String allowanceTotalLine = "" + currencyFormat(getAllowances()) + ""; + String allowanceTotalLine = "" + currencyFormat(calc.getAllowances()) + ""; - String chargesTotalLine = "" + currencyFormat(getCharges()) + ""; + String chargesTotalLine = "" + currencyFormat(calc.getCharges()) + ""; xml = xml + " \n" - + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-2$ + + " " + currencyFormat(calc.getTotal()) + "\n" //$NON-NLS-2$ + chargesTotalLine + allowanceTotalLine - + " " + currencyFormat(getTaxBasis()) + "\n" //$NON-NLS-2$ + + " " + currencyFormat(calc.getTaxBasis()) + "\n" //$NON-NLS-2$ // // // currencyID=\"EUR\" + " " - + currencyFormat(getTotalGross().subtract(getTaxBasis())) + "\n" - + " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-2$ + + currencyFormat(calc.getTotalGross().subtract(calc.getTaxBasis())) + "\n" + + " " + currencyFormat(calc.getTotalGross()) + "\n" //$NON-NLS-2$ // // // currencyID=\"EUR\" - + " " + currencyFormat(getTotalPrepaid()) + "\n" - + " " + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "\n" //$NON-NLS-2$ + + " " + currencyFormat(calc.getTotalPrepaid()) + "\n" + + " " + currencyFormat(calc.getTotalGross().subtract(calc.getTotalPrepaid())) + "\n" //$NON-NLS-2$ // // // currencyID=\"EUR\" + " \n" @@ -721,7 +610,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide if (discountTerms != null) { paymentTermsXml += ""; String currency = trans.getCurrency(); - String basisAmount = currencyFormat(getTotalGross()); + String basisAmount = currencyFormat(calc.getTotalGross()); paymentTermsXml += "" + basisAmount + ""; paymentTermsXml += "" + discountTerms.getCalculationPercentage().toString() + ""; @@ -743,8 +632,4 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide return paymentTermsXml; } - @Override - public BigDecimal getValue() { - return getTotal(); - } } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index c219caec..042398f9 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -19,7 +19,7 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { * This will parse a XML into a invoice object * @return the parsed invoice object */ - public Invoice extractInvoice() { + public Invoice extractInvoice() throws XPathExpressionException, ParseException { String number = ""; /* @@ -29,177 +29,170 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { XPathFactory xpathFact = XPathFactory.newInstance(); XPath xpath = xpathFact.newXPath(); Invoice zpp = null; - try { - XPathExpression xpr = xpath.compile( - "//*[local-name()=\"SellerTradeParty\"]"); - NodeList SellerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + XPathExpression xpr = xpath.compile( + "//*[local-name()=\"SellerTradeParty\"]"); + NodeList SellerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); - xpr = xpath.compile( - "//*[local-name()=\"BuyerTradeParty\"]"); - NodeList BuyerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); - xpr = xpath.compile( - "//*[local-name()=\"ExchangedDocument\"]"); - NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + xpr = xpath.compile( + "//*[local-name()=\"BuyerTradeParty\"]"); + NodeList BuyerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + xpr = xpath.compile( + "//*[local-name()=\"ExchangedDocument\"]"); + NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); - Date issueDate = null; - Date dueDate = null; - Date deliveryDate = null; - for (int i = 0; i < ExchangedDocumentNodes.getLength(); i++) { + Date issueDate = null; + Date dueDate = null; + Date deliveryDate = null; + for (int i = 0; i < ExchangedDocumentNodes.getLength(); i++) { - //nodes.item(i).getTextContent())) { - Node exchangedDocumentNode = ExchangedDocumentNodes.item(i); - NodeList exchangedDocumentChilds = exchangedDocumentNode.getChildNodes(); - for (int documentChildIndex = 0; documentChildIndex < exchangedDocumentChilds.getLength(); documentChildIndex++) { - if (exchangedDocumentChilds.item(documentChildIndex).getNodeName().equals("ram:ID")) { - number = exchangedDocumentChilds.item(documentChildIndex).getTextContent(); - } - if (exchangedDocumentChilds.item(documentChildIndex).getNodeName().equals("ram:IssueDateTime")) { - NodeList issueDateTimeChilds = exchangedDocumentChilds.item(documentChildIndex).getChildNodes(); - for (int issueDateChildIndex = 0; issueDateChildIndex < issueDateTimeChilds.getLength(); issueDateChildIndex++) { - if (issueDateTimeChilds.item(issueDateChildIndex).getNodeName().equals("udt:DateTimeString")) { - issueDate = new SimpleDateFormat("yyyyMMdd").parse(issueDateTimeChilds.item(issueDateChildIndex).getTextContent()); - } + //nodes.item(i).getTextContent())) { + Node exchangedDocumentNode = ExchangedDocumentNodes.item(i); + NodeList exchangedDocumentChilds = exchangedDocumentNode.getChildNodes(); + for (int documentChildIndex = 0; documentChildIndex < exchangedDocumentChilds.getLength(); documentChildIndex++) { + if (exchangedDocumentChilds.item(documentChildIndex).getNodeName().equals("ram:ID")) { + number = exchangedDocumentChilds.item(documentChildIndex).getTextContent(); + } + if (exchangedDocumentChilds.item(documentChildIndex).getNodeName().equals("ram:IssueDateTime")) { + NodeList issueDateTimeChilds = exchangedDocumentChilds.item(documentChildIndex).getChildNodes(); + for (int issueDateChildIndex = 0; issueDateChildIndex < issueDateTimeChilds.getLength(); issueDateChildIndex++) { + if (issueDateTimeChilds.item(issueDateChildIndex).getNodeName().equals("udt:DateTimeString")) { + issueDate = new SimpleDateFormat("yyyyMMdd").parse(issueDateTimeChilds.item(issueDateChildIndex).getTextContent()); } } } } - - - xpr = xpath.compile( - "//*[local-name()=\"ApplicableHeaderTradeDelivery\"]"); - NodeList headerTradeDeliveryNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); - - for (int i = 0; i < headerTradeDeliveryNodes.getLength(); i++) { - //nodes.item(i).getTextContent())) { - Node headerTradeDeliveryNode = headerTradeDeliveryNodes.item(i); - NodeList headerTradeDeliveryChilds = headerTradeDeliveryNode.getChildNodes(); - for (int deliveryChildIndex = 0; deliveryChildIndex < headerTradeDeliveryChilds.getLength(); deliveryChildIndex++) { - if (headerTradeDeliveryChilds.item(deliveryChildIndex).getNodeName().equals("ram:ActualDeliverySupplyChainEvent")) { - NodeList actualDeliveryChilds = headerTradeDeliveryChilds.item(deliveryChildIndex).getChildNodes(); - for (int actualDeliveryChildIndex = 0; actualDeliveryChildIndex < actualDeliveryChilds.getLength(); actualDeliveryChildIndex++) { - if (actualDeliveryChilds.item(actualDeliveryChildIndex).getNodeName().equals("ram:OccurrenceDateTime")) { - NodeList occurenceChilds = actualDeliveryChilds.item(actualDeliveryChildIndex).getChildNodes(); - for (int occurenceChildIndex = 0; occurenceChildIndex < occurenceChilds.getLength(); occurenceChildIndex++) { - if (occurenceChilds.item(occurenceChildIndex).getNodeName().equals("udt:DateTimeString")) { - deliveryDate = new SimpleDateFormat("yyyyMMdd").parse(occurenceChilds.item(occurenceChildIndex).getTextContent()); - - } - } - } - } - } - } - } - - - xpr = xpath.compile( - "//*[local-name()=\"ApplicableHeaderTradeSettlement\"]"); - NodeList headerTradeSettlementNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); - - for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) { - //nodes.item(i).getTextContent())) { - Node headerTradeSettlementNode = headerTradeSettlementNodes.item(i); - NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes(); - for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) { - if (headerTradeSettlementChilds.item(settlementChildIndex).getNodeName().equals("ram:SpecifiedTradePaymentTerms")) { - NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes(); - for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) { - if (paymentTermChilds.item(paymentTermChildIndex).getNodeName().equals("ram:DueDateDateTime")) { - NodeList dueDateChilds = paymentTermChilds.item(paymentTermChildIndex).getChildNodes(); - for (int dueDateChildIndex = 0; dueDateChildIndex < dueDateChilds.getLength(); dueDateChildIndex++) { - if (dueDateChilds.item(dueDateChildIndex).getNodeName().equals("udt:DateTimeString")) { - dueDate = new SimpleDateFormat("yyyyMMdd").parse(dueDateChilds.item(dueDateChildIndex).getTextContent()); - - } - } - } - } - } - } - } - - zpp = new Invoice().setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number); -//.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),amount,new BigDecimal(1.0))) - zpp.setOwnOrganisationName(extractString("//SellerTradeParty/Name")); - xpr = xpath.compile( - "//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]"); - NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); - - if (nodes.getLength() == 0) { - } else { - for (int i = 0; i < nodes.getLength(); i++) { - - String price = "0"; - String name = ""; - String description = ""; - String quantity = "0"; - String vatPercent = "0"; - String unitCode = "0"; - - //nodes.item(i).getTextContent())) { - Node currentItemNode = nodes.item(i); - NodeList itemChilds = currentItemNode.getChildNodes(); - for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) { - if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeAgreement")) { - NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes(); - for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) { - if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram:NetPriceProductTradePrice")) { - NodeList netChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes(); - for (int netIndex = 0; netIndex < netChilds.getLength(); netIndex++) { - if (netChilds.item(netIndex).getNodeName().equals("ram:ChargeAmount")) { - price = netChilds.item(netIndex).getTextContent();//ram:ChargeAmount - - } - } - } - } - } - if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeDelivery")) { - NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes(); - for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) { - if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram:BilledQuantity")) { - quantity = tradeLineChilds.item(tradeLineChildIndex).getTextContent(); - unitCode = tradeLineChilds.item(tradeLineChildIndex).getAttributes().getNamedItem("unitCode").getNodeValue(); - } - } - } - if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedTradeProduct")) { - NodeList tradeProductChilds = itemChilds.item(itemChildIndex).getChildNodes(); - for (int tradeProductChildIndex = 0; tradeProductChildIndex < tradeProductChilds.getLength(); tradeProductChildIndex++) { - if (tradeProductChilds.item(tradeProductChildIndex).getNodeName().equals("ram:Name")) { - name = tradeProductChilds.item(tradeProductChildIndex).getTextContent(); - } - } - } - if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeSettlement")) { - NodeList tradeSettlementChilds = itemChilds.item(itemChildIndex).getChildNodes(); - for (int tradeSettlementChildIndex = 0; tradeSettlementChildIndex < tradeSettlementChilds.getLength(); tradeSettlementChildIndex++) { - if (tradeSettlementChilds.item(tradeSettlementChildIndex).getNodeName().equals("ram:ApplicableTradeTax")) { - NodeList taxChilds = tradeSettlementChilds.item(tradeSettlementChildIndex).getChildNodes(); - for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { - if (taxChilds.item(taxChildIndex).getNodeName().equals("ram:RateApplicablePercent")) { - vatPercent = taxChilds.item(taxChildIndex).getTextContent(); - } - } - } - } - } - - - } - zpp.addItem(new Item(new Product(name, description, unitCode, new BigDecimal(vatPercent)), new BigDecimal(price), new BigDecimal(quantity))); - } - - } - - - } catch (XPathExpressionException e) { - e.printStackTrace(); - } catch (ParseException ex) { - ex.printStackTrace(); } + + xpr = xpath.compile( + "//*[local-name()=\"ApplicableHeaderTradeDelivery\"]"); + NodeList headerTradeDeliveryNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + + for (int i = 0; i < headerTradeDeliveryNodes.getLength(); i++) { + //nodes.item(i).getTextContent())) { + Node headerTradeDeliveryNode = headerTradeDeliveryNodes.item(i); + NodeList headerTradeDeliveryChilds = headerTradeDeliveryNode.getChildNodes(); + for (int deliveryChildIndex = 0; deliveryChildIndex < headerTradeDeliveryChilds.getLength(); deliveryChildIndex++) { + if (headerTradeDeliveryChilds.item(deliveryChildIndex).getNodeName().equals("ram:ActualDeliverySupplyChainEvent")) { + NodeList actualDeliveryChilds = headerTradeDeliveryChilds.item(deliveryChildIndex).getChildNodes(); + for (int actualDeliveryChildIndex = 0; actualDeliveryChildIndex < actualDeliveryChilds.getLength(); actualDeliveryChildIndex++) { + if (actualDeliveryChilds.item(actualDeliveryChildIndex).getNodeName().equals("ram:OccurrenceDateTime")) { + NodeList occurenceChilds = actualDeliveryChilds.item(actualDeliveryChildIndex).getChildNodes(); + for (int occurenceChildIndex = 0; occurenceChildIndex < occurenceChilds.getLength(); occurenceChildIndex++) { + if (occurenceChilds.item(occurenceChildIndex).getNodeName().equals("udt:DateTimeString")) { + deliveryDate = new SimpleDateFormat("yyyyMMdd").parse(occurenceChilds.item(occurenceChildIndex).getTextContent()); + + } + } + } + } + } + } + } + + + xpr = xpath.compile( + "//*[local-name()=\"ApplicableHeaderTradeSettlement\"]"); + NodeList headerTradeSettlementNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + + for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) { + //nodes.item(i).getTextContent())) { + Node headerTradeSettlementNode = headerTradeSettlementNodes.item(i); + NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes(); + for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) { + if (headerTradeSettlementChilds.item(settlementChildIndex).getNodeName().equals("ram:SpecifiedTradePaymentTerms")) { + NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes(); + for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) { + if (paymentTermChilds.item(paymentTermChildIndex).getNodeName().equals("ram:DueDateDateTime")) { + NodeList dueDateChilds = paymentTermChilds.item(paymentTermChildIndex).getChildNodes(); + for (int dueDateChildIndex = 0; dueDateChildIndex < dueDateChilds.getLength(); dueDateChildIndex++) { + if (dueDateChilds.item(dueDateChildIndex).getNodeName().equals("udt:DateTimeString")) { + dueDate = new SimpleDateFormat("yyyyMMdd").parse(dueDateChilds.item(dueDateChildIndex).getTextContent()); + + } + } + } + } + } + } + } + + zpp = new Invoice().setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number); +//.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),amount,new BigDecimal(1.0))) + zpp.setOwnOrganisationName(extractString("//SellerTradeParty/Name")); + xpr = xpath.compile( + "//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]"); + NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + + if (nodes.getLength() == 0) { + } else { + for (int i = 0; i < nodes.getLength(); i++) { + + String price = "0"; + String name = ""; + String description = ""; + String quantity = "0"; + String vatPercent = "0"; + String unitCode = "0"; + + //nodes.item(i).getTextContent())) { + Node currentItemNode = nodes.item(i); + NodeList itemChilds = currentItemNode.getChildNodes(); + for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) { + if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeAgreement")) { + NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes(); + for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) { + if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram:NetPriceProductTradePrice")) { + NodeList netChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes(); + for (int netIndex = 0; netIndex < netChilds.getLength(); netIndex++) { + if (netChilds.item(netIndex).getNodeName().equals("ram:ChargeAmount")) { + price = netChilds.item(netIndex).getTextContent();//ram:ChargeAmount + + } + } + } + } + } + if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeDelivery")) { + NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes(); + for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) { + if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram:BilledQuantity")) { + quantity = tradeLineChilds.item(tradeLineChildIndex).getTextContent(); + unitCode = tradeLineChilds.item(tradeLineChildIndex).getAttributes().getNamedItem("unitCode").getNodeValue(); + } + } + } + if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedTradeProduct")) { + NodeList tradeProductChilds = itemChilds.item(itemChildIndex).getChildNodes(); + for (int tradeProductChildIndex = 0; tradeProductChildIndex < tradeProductChilds.getLength(); tradeProductChildIndex++) { + if (tradeProductChilds.item(tradeProductChildIndex).getNodeName().equals("ram:Name")) { + name = tradeProductChilds.item(tradeProductChildIndex).getTextContent(); + } + } + } + if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeSettlement")) { + NodeList tradeSettlementChilds = itemChilds.item(itemChildIndex).getChildNodes(); + for (int tradeSettlementChildIndex = 0; tradeSettlementChildIndex < tradeSettlementChilds.getLength(); tradeSettlementChildIndex++) { + if (tradeSettlementChilds.item(tradeSettlementChildIndex).getNodeName().equals("ram:ApplicableTradeTax")) { + NodeList taxChilds = tradeSettlementChilds.item(tradeSettlementChildIndex).getChildNodes(); + for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { + if (taxChilds.item(taxChildIndex).getNodeName().equals("ram:RateApplicablePercent")) { + vatPercent = taxChilds.item(taxChildIndex).getTextContent(); + } + } + } + } + } + + + } + zpp.addItem(new Item(new Product(name, description, unitCode, new BigDecimal(vatPercent)), new BigDecimal(price), new BigDecimal(quantity))); + } + + } + + return zpp; } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 3ebad073..01adc049 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -27,6 +27,9 @@ import junit.framework.TestCase; import junit.framework.Test; import junit.framework.TestSuite; +import javax.xml.xpath.XPathExpressionException; +import java.math.BigDecimal; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; @@ -44,7 +47,14 @@ public class ZF2ZInvoiceImporterTest extends TestCase { ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter(TARGET_PDF); - Invoice invoice=zii.extractInvoice(); + boolean hasExceptions=false; + Invoice invoice=null; + try { + invoice=zii.extractInvoice(); + } catch (XPathExpressionException | ParseException e) { + hasExceptions=true; + } + assertFalse(hasExceptions); // Reading ZUGFeRD assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName()); assertEquals(3, invoice.getZFItems().length); @@ -71,6 +81,10 @@ public class ZF2ZInvoiceImporterTest extends TestCase { assertEquals("DE", invoice.getSender().getCountry()); assertEquals("Stadthausen", invoice.getSender().getLocation()); + TransactionCalculator tc=new TransactionCalculator(invoice); + assertEquals(new BigDecimal("571.040000"),tc.getTotalGross()); + + // name street location zip country, contact name phone email, total amount