support document level charges/allowances in invoiceimporter

This commit is contained in:
jstaerk
2020-11-10 12:03:38 +01:00
parent b065a1beb1
commit 5b8d1c9c54
5 changed files with 117 additions and 10 deletions

View File

@@ -54,13 +54,11 @@ switch
### 2.0 still todo
- dont show empty tax number field
- new sample invoice
- *visualizer to work with Extended profile
- *visualizer tests
- fail when no bankverbindung?
- fail when xr attrs missing?
- build xr skonto???
- *validator not to XR error on ZF files (only notices)
- *from A3 does not seem tow ork see mustangreaderwriteredgetest:testedgeexport
- xmp errors may not show correctly in log
- finalize invoiceimporter
Alpha3 2020-10-24
Alpha2 2020-09-15
Alpha1 2020-08-06

View File

@@ -145,7 +145,7 @@ but there is also the new invoiceImporter
assertEquals("Spielkreis", invoice.getRecipient().getLocation());
TransactionCalculator tc=new TransactionCalculator(invoice);
assertEquals(new BigDecimal("571.040000"),tc.getTotalGross());
assertEquals(new BigDecimal("571.04"),tc.getTotalGross());
```

View File

@@ -1,6 +1,7 @@
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
/***
@@ -30,7 +31,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
res = res.add(amount.getCalculated());
}
return res;
return res.setScale(2, RoundingMode.HALF_UP);
}
/***

View File

@@ -40,6 +40,13 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
"//*[local-name()=\"ExchangedDocument\"]");
NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile(
"//*[local-name()=\"GrandTotalAmount\"]");
BigDecimal expectedGrandTotal = null;
NodeList totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (totalNodes.getLength() > 0) {
expectedGrandTotal = new BigDecimal(totalNodes.item(0).getTextContent());
}
Date issueDate = null;
Date dueDate = null;
@@ -192,6 +199,70 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
}
// item level charges+allowances are not yet handled but a lower item price will be read,
// so the invoice remains arithmetically correct
// -> parse document level charges+allowances
xpr = xpath.compile(
"//*[local-name()=\"SpecifiedTradeAllowanceCharge\"]");
NodeList chargeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < chargeNodes.getLength(); i++) {
NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes();
boolean isCharge = true;
String chargeAmount = null;
String reason = null;
String taxPercent = null;
for (int chargeChildIndex = 0; chargeChildIndex < chargeNodeChilds.getLength(); chargeChildIndex++) {
if (chargeNodeChilds.item(chargeChildIndex).getNodeName().equals("ram:ChargeIndicator")) {
NodeList indicatorChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
for (int indicatorChildIndex = 0; indicatorChildIndex < indicatorChilds.getLength(); indicatorChildIndex++) {
if (indicatorChilds.item(indicatorChildIndex).getNodeName().equals("udt:Indicator")) {
isCharge = indicatorChilds.item(indicatorChildIndex).getTextContent().equalsIgnoreCase("true");
}
}
} else if (chargeNodeChilds.item(chargeChildIndex).getNodeName().equals("ram:ActualAmount")) {
chargeAmount = chargeNodeChilds.item(chargeChildIndex).getTextContent();
} else if (chargeNodeChilds.item(chargeChildIndex).getNodeName().equals("ram:Reason")) {
reason = chargeNodeChilds.item(chargeChildIndex).getTextContent();
} else if (chargeNodeChilds.item(chargeChildIndex).getNodeName().equals("ram:CategoryTradeTax")) {
NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
if (taxChilds.item(taxChildIndex).getNodeName().equals("ram:RateApplicablePercent")) {
taxPercent = taxChilds.item(taxChildIndex).getTextContent();
}
}
}
}
if (isCharge) {
Charge c = new Charge(new BigDecimal(chargeAmount));
if (reason != null) {
c.setReason(reason);
}
if (taxPercent != null) {
c.setTaxPercent(new BigDecimal(taxPercent));
}
zpp.addCharge(c);
} else {
Allowance a = new Allowance(new BigDecimal(chargeAmount));
if (reason != null) {
a.setReason(reason);
}
if (taxPercent != null) {
a.setTaxPercent(new BigDecimal(taxPercent));
}
zpp.addAllowance(a);
}
}
TransactionCalculator tc = new TransactionCalculator(zpp);
String expectedStringTotalGross = tc.getTotalGross().toPlainString();
if (!expectedStringTotalGross.equals(XMLTools.nDigitFormat(expectedGrandTotal, 2))) {
throw new ParseException("Could not reproduce the invoice, this could mean that it could not be read properly", 0);
}
return zpp;
}

View File

@@ -41,11 +41,10 @@ import java.util.GregorianCalendar;
* used for this import, testout-ZF2New.pdf
*/
public class ZF2ZInvoiceImporterTest extends TestCase {
final String TARGET_PDF = "./target/testout-ZF2new.pdf";
public void testInvoiceImport() {
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter(TARGET_PDF);
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter("./target/testout-ZF2new.pdf");
boolean hasExceptions=false;
Invoice invoice=null;
@@ -82,7 +81,44 @@ public class ZF2ZInvoiceImporterTest extends TestCase {
assertEquals("Stadthausen", invoice.getSender().getLocation());
TransactionCalculator tc=new TransactionCalculator(invoice);
assertEquals(new BigDecimal("571.040000"),tc.getTotalGross());
assertEquals(new BigDecimal("571.04"),tc.getTotalGross());
// name street location zip country, contact name phone email, total amount
}
public void testItemAllowancesChargesImport() {
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushItemChargesAllowances.pdf");
boolean hasExceptions=false;
Invoice invoice=null;
try {
invoice=zii.extractInvoice();
} catch (XPathExpressionException | ParseException e) {
hasExceptions=true;
}
assertFalse(hasExceptions);
TransactionCalculator tc=new TransactionCalculator(invoice);
assertEquals(new BigDecimal("18.33"),tc.getTotalGross());
}
public void testAllowancesChargesImport() {
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushChargesAllowances.pdf");
boolean hasExceptions=false;
Invoice invoice=null;
try {
invoice=zii.extractInvoice();
} catch (XPathExpressionException | ParseException e) {
hasExceptions=true;
}
assertFalse(hasExceptions);
TransactionCalculator tc=new TransactionCalculator(invoice);
assertEquals(new BigDecimal("11.07"),tc.getTotalGross());
// name street location zip country, contact name phone email, total amount
@@ -91,4 +127,5 @@ public class ZF2ZInvoiceImporterTest extends TestCase {
}
}