diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index bafab84d..8fee7481 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,3 +1,3 @@
# These are supported funding model platforms
-github: [jstaerk]
+custom: ["https://www.mustangproject.org/support/"]
diff --git a/History.md b/History.md
index 97088002..9227afca 100644
--- a/History.md
+++ b/History.md
@@ -1,3 +1,9 @@
+2.1.0
+=======
+
+- fixed a charge/allowance rounding error #212
+- Corrected intra community supply tax exemption category code
+
2.0.3
=======
2020-12-06
diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml
index 274d1f1c..c7f94c3d 100644
--- a/Mustang-CLI/pom.xml
+++ b/Mustang-CLI/pom.xml
@@ -8,7 +8,7 @@
4.0.0
org.mustangproject
Mustang-CLI
- Mustang commandline tool
+ e-invoices commandline tool, allowing to create(embed), split and validate Factur-X/ZUGFeRD files. Validation should also work for XRechnung/CII.
jar
2.0.4-SNAPSHOT
@@ -53,7 +53,6 @@
4.13.1
test
-
org.xmlunit
diff --git a/library/pom.xml b/library/pom.xml
index d1c0b4bf..6686b648 100644
--- a/library/pom.xml
+++ b/library/pom.xml
@@ -11,8 +11,8 @@
library
2.0.4-SNAPSHOT
jar
- Library to write and read FacturX and ZUGFeRD e-invoices.
- The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs. To write files, a provided PDF/A will be combined with generated or provided XML.
+ Library to write, read and validate e-invoices (Factur-X, ZUGFeRD and to a limited extend XRechnung/CII).
+ The Mustang project is a java library to read, write and validate Factur-X/ZUGFeRD meta data inside your invoice PDFs. To write files, a provided PDF/A will be combined with generated or provided XML.
http://www.mustangproject.org/
@@ -83,6 +83,14 @@
4.13.1
test
+
+
+
+ com.helger
+ en16931-cii2ubl
+ 1.2.5
+
+
com.helger
ph-schematron
@@ -101,6 +109,12 @@
xmlunit-assertj
2.6.3
+
+ com.helger
+ ph-commons
+ 9.1.1
+ compile
+
diff --git a/library/src/main/java/org/mustangproject/CII/CIIToUBL.java b/library/src/main/java/org/mustangproject/CII/CIIToUBL.java
new file mode 100644
index 00000000..8b2a28e3
--- /dev/null
+++ b/library/src/main/java/org/mustangproject/CII/CIIToUBL.java
@@ -0,0 +1,50 @@
+package org.mustangproject.CII;
+import com.helger.commons.error.list.ErrorList;
+import com.helger.en16931.cii2ubl.CIIToUBL22Converter;
+import com.helger.ubl21.UBL21Writer;
+import com.helger.ubl22.UBL22Writer;
+
+import java.io.File;
+import java.io.Serializable;
+
+public class CIIToUBL {
+ /***
+ * converts a CII XML file to a UBL XML file
+ * thanks to Philip Helger for his library
+ * @param input
+ * @param output
+ */
+ public void convert(File input, File output) {
+ ErrorList occurred=new ErrorList();
+ CIIToUBL22Converter cc=new CIIToUBL22Converter();
+ Serializable aUBL = cc.convertCIItoUBL(input, occurred);
+ if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_21.InvoiceType)
+ {
+ UBL21Writer.invoice ()
+ .setFormattedOutput (true)
+ .write ((oasis.names.specification.ubl.schema.xsd.invoice_21.InvoiceType) aUBL, output);
+ }
+ else
+ if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_21.CreditNoteType)
+ {
+ UBL21Writer.creditNote ()
+ .setFormattedOutput (true)
+ .write ((oasis.names.specification.ubl.schema.xsd.creditnote_21.CreditNoteType) aUBL, output);
+ }
+ else
+ if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_22.InvoiceType)
+ {
+ UBL22Writer.invoice ()
+ .setFormattedOutput (true)
+ .write ((oasis.names.specification.ubl.schema.xsd.invoice_22.InvoiceType) aUBL, output);
+ }
+ else
+ if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_22.CreditNoteType)
+ {
+ UBL22Writer.creditNote ()
+ .setFormattedOutput (true)
+ .write ((oasis.names.specification.ubl.schema.xsd.creditnote_22.CreditNoteType) aUBL, output);
+ }
+ }
+
+}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
index e7ef193c..70fa9e50 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
@@ -126,13 +126,19 @@ public interface IExportableTransaction {
return null;
}
- IZUGFeRDAllowanceCharge[] getZFAllowances();
+ default IZUGFeRDAllowanceCharge[] getZFAllowances() {
+ return null;
+ }
- IZUGFeRDAllowanceCharge[] getZFCharges();
+ default IZUGFeRDAllowanceCharge[] getZFCharges() {
+ return null;
+ }
- IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges();
+ default IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
+ return null;
+ }
IZUGFeRDExportableItem[] getZFItems();
@@ -290,7 +296,7 @@ public interface IExportableTransaction {
* @return three character currency of this invoice
*/
default String getCurrency() {
- return null;
+ return "EUR";
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
index 80ead5ed..a584c718 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
@@ -37,13 +37,17 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
* item level discounts
* @return array of the discounts on a single item
*/
- IZUGFeRDAllowanceCharge[] getItemAllowances();
+ default IZUGFeRDAllowanceCharge[] getItemAllowances() {
+ return null;
+ }
/**
* item level price additions
* @return array of the additional charges on the item
*/
- IZUGFeRDAllowanceCharge[] getItemCharges();
+ default IZUGFeRDAllowanceCharge[] getItemCharges() {
+ return null;
+ }
/**
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTradeParty.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTradeParty.java
index 66f25163..315de277 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTradeParty.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTradeParty.java
@@ -68,17 +68,13 @@ public interface IZUGFeRDExportableTradeParty {
*
* @return First and last name of the recipient
*/
- default String getName() {
- return null;
- }
+ String getName();
/**
* Postal code of the recipient
*
* @return Postal code of the recipient
*/
- default String getZIP() {
- return null;
- }
+ String getZIP();
/**
@@ -96,9 +92,7 @@ public interface IZUGFeRDExportableTradeParty {
*
* @return two-letter iso country code of the contact
*/
- default String getCountry() {
- return null;
- }
+ String getCountry();
/**
@@ -106,9 +100,7 @@ public interface IZUGFeRDExportableTradeParty {
*
* @return Returns the city of the recipient
*/
- default String getLocation() {
- return null;
- }
+ String getLocation();
/**
@@ -116,9 +108,7 @@ public interface IZUGFeRDExportableTradeParty {
*
* @return street address (street+number) of the contact
*/
- default String getStreet() {
- return null;
- }
+ String getStreet();
/**
* returns additional address information which is display in xml tag "LineTwo"
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/Profiles.java b/library/src/main/java/org/mustangproject/ZUGFeRD/Profiles.java
index 515e9505..dc0d6e4f 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/Profiles.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/Profiles.java
@@ -20,7 +20,6 @@
*/
package org.mustangproject.ZUGFeRD;
-import java.time.Year;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -32,7 +31,7 @@ public class Profiles {
{"BASIC", new Profile("BASIC", "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic")},
{"EN16931", new Profile("EN16931", "urn:cen.eu:en16931:2017")},
{"EXTENDED", new Profile("EXTENDED", "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended")},
- {"XRECHNUNG", new Profile("XRECHNUNG", "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_"+((Year.now().getValue()<=2020)?"1.2":"2.0"))} //intentionally switch to XRechnung 2.0 on 01.01.2021
+ {"XRECHNUNG", new Profile("XRECHNUNG", "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0")} //switched to XRechnung 2.0 in 2021
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Profile) data[1]));
static Map zf1Map = Stream.of(new Object[][]{
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java
index 8352cf7c..dc126ab4 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java
@@ -19,7 +19,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
* @param trans the invoice (or IExportableTransaction) to be calculated
*/
public TransactionCalculator(IExportableTransaction trans) {
- this.trans=trans;
+ this.trans = trans;
}
/***
@@ -30,7 +30,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
if (trans.getTotalPrepaidAmount() == null) {
return BigDecimal.ZERO;
} else {
- return trans.getTotalPrepaidAmount().setScale(2, RoundingMode.HALF_UP);
+ return trans.getTotalPrepaidAmount().setScale(2, RoundingMode.HALF_UP);
}
}
@@ -42,9 +42,9 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
final BigDecimal res = getTaxBasis();
return getVATPercentAmountMap().values().stream()
- .map(VATAmount::getCalculated)
- .map(p -> p.setScale(2, RoundingMode.HALF_UP))
- .reduce(BigDecimal.ZERO, BigDecimal::add).add(res);
+ .map(VATAmount::getCalculated)
+ .map(p -> p.setScale(2, RoundingMode.HALF_UP))
+ .reduce(BigDecimal.ZERO, BigDecimal::add).add(res);
}
/***
@@ -58,15 +58,15 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
private BigDecimal sumAllowanceCharge(BigDecimal percent, IZUGFeRDAllowanceCharge[] charges) {
- BigDecimal res = BigDecimal.ZERO;
- if ((charges != null) && (charges.length > 0)) {
- for (IZUGFeRDAllowanceCharge currentCharge : charges) {
- if ((percent==null)||(currentCharge.getTaxPercent().compareTo(percent)==0)) {
- res = res.add(currentCharge.getTotalAmount(this));
- }
- }
- }
- return res;
+ BigDecimal res = BigDecimal.ZERO;
+ if ((charges != null) && (charges.length > 0)) {
+ for (IZUGFeRDAllowanceCharge currentCharge : charges) {
+ if ((percent == null) || (currentCharge.getTaxPercent().compareTo(percent) == 0)) {
+ res = res.add(currentCharge.getTotalAmount(this));
+ }
+ }
+ }
+ return res;
}
/***
@@ -78,23 +78,23 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges();
String res = getAllowanceChargeReasonForPercent(percent, charges);
if ("".equals(res)) {
- res="Charges";
+ res = "Charges";
}
return res;
}
private String getAllowanceChargeReasonForPercent(BigDecimal percent, IZUGFeRDAllowanceCharge[] charges) {
- String res = " ";
- if ((charges != null) && (charges.length > 0)) {
- for (IZUGFeRDAllowanceCharge currentCharge : charges) {
- if ((percent==null)||(currentCharge.getTaxPercent().compareTo(percent)==0)
- && currentCharge.getReason()!=null) {
- res += currentCharge.getReason()+" ";
- }
- }
- }
- res=res.substring(0,res.length()-1);
- return res;
+ String res = " ";
+ if ((charges != null) && (charges.length > 0)) {
+ for (IZUGFeRDAllowanceCharge currentCharge : charges) {
+ if ((percent == null) || (currentCharge.getTaxPercent().compareTo(percent) == 0)
+ && currentCharge.getReason() != null) {
+ res += currentCharge.getReason() + " ";
+ }
+ }
+ }
+ res = res.substring(0, res.length() - 1);
+ return res;
}
/***
@@ -106,7 +106,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances();
String res = getAllowanceChargeReasonForPercent(percent, allowances);
if ("".equals(res)) {
- res="Allowances";
+ res = "Allowances";
}
return res;
}
@@ -127,10 +127,11 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
* @return item sum
*/
protected BigDecimal getTotal() {
- return Stream.of(trans.getZFItems())
- .map(LineCalculator::new)
- .map(LineCalculator::getItemTotalNetAmount)
- .reduce(ZERO, BigDecimal::add);
+ BigDecimal dec = Stream.of(trans.getZFItems())
+ .map(LineCalculator::new)
+ .map(LineCalculator::getItemTotalNetAmount)
+ .reduce(ZERO, BigDecimal::add);
+ return dec;
}
/***
@@ -139,8 +140,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
* @return item sum +- charges/allowances
*/
protected BigDecimal getTaxBasis() {
- BigDecimal res = getTotal().add(getChargesForPercent(null)).subtract(getAllowancesForPercent(null));
- return res.setScale(2, RoundingMode.HALF_UP);
+ return getTotal().add(getChargesForPercent(null).setScale(2, RoundingMode.HALF_UP)).subtract(getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP)).setScale(2, RoundingMode.HALF_UP);
}
/**
@@ -172,8 +172,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
VATAmount theAmount = hm.get(currentCharge.getTaxPercent().stripTrailingZeros());
if (theAmount == null) {
- theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO,
- currentCharge.getCategoryCode()!=null?currentCharge.getCategoryCode():"S");
+ theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO,
+ currentCharge.getCategoryCode() != null ? currentCharge.getCategoryCode() : "S");
}
theAmount.setBasis(theAmount.getBasis().add(currentCharge.getTotalAmount(this)));
BigDecimal factor = currentCharge.getTaxPercent().divide(new BigDecimal(100));
@@ -186,8 +186,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
for (IZUGFeRDAllowanceCharge currentAllowance : allowances) {
VATAmount theAmount = hm.get(currentAllowance.getTaxPercent().stripTrailingZeros());
if (theAmount == null) {
- theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO,
- currentAllowance.getCategoryCode()!=null?currentAllowance.getCategoryCode():"S");
+ theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO,
+ currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S");
}
theAmount.setBasis(theAmount.getBasis().subtract(currentAllowance.getTotalAmount(this)));
BigDecimal factor = currentAllowance.getTaxPercent().divide(new BigDecimal(100));
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java b/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
index f08b406f..6644d97e 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java
@@ -19,6 +19,7 @@
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
+import java.math.RoundingMode;
/**
* Mustangproject's ZUGFeRD implementation
@@ -55,7 +56,7 @@ public class VATAmount {
}
public void setBasis(BigDecimal basis) {
- this.basis = basis;
+ this.basis = basis.setScale(2, RoundingMode.HALF_UP);
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java b/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
index 979207c8..b7669ba0 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
@@ -24,5 +24,5 @@ public class TaxCategoryCodeTypeConstants {
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 INTRACOMMUNITY = "K";
}
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java
new file mode 100644
index 00000000..88d398f8
--- /dev/null
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java
@@ -0,0 +1,202 @@
+package org.mustangproject.ZUGFeRD;
+
+import static java.math.BigDecimal.TEN;
+import static java.math.BigDecimal.valueOf;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.mustangproject.*;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/***
+ * tests the linecalculator and transactioncalculator classes
+ *
+ */
+public class CalculationTest {
+
+ @Test
+ public void testLineCalculator_simpleAmounts_resultInValidVATAmount() {
+ final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
+ final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(100))
+ .setQuantity(TEN)
+ .setProduct(product);
+
+ final LineCalculator calculator = new LineCalculator(currentItem);
+
+ assertEquals(valueOf(100).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
+ assertEquals(valueOf(1000).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
+ assertEquals(valueOf(160).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
+ }
+
+ @Test
+ public void testLineCalculatorInclusiveAllowance() {
+ //This test failed with previous implementation. By rounding the totalVATAmount to 2 decimal places the result became wrong
+ final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
+ // 10 % discount on each item
+ final IZUGFeRDAllowanceCharge allowance = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(14.8730));
+
+ final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
+ .setQuantity(valueOf(12))
+ .setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
+ .setProduct(product);
+
+ final LineCalculator calculator = new LineCalculator(currentItem);
+
+ assertEquals(valueOf(133.857).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
+ assertEquals(valueOf(1606.28).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
+ assertEquals(valueOf(257.0048).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
+ }
+
+ @Test
+ public void testLineCalculatorInclusiveAllowanceAndCharge() {
+ final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
+ // 10 % discount on each item
+ final IZUGFeRDAllowanceCharge allowance = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(14.873));
+ // 20 % charge
+ final IZUGFeRDAllowanceCharge charge = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(29.746));
+ final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
+ .setQuantity(valueOf(12))
+ .setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
+ .setItemCharges(new IZUGFeRDAllowanceCharge[]{charge})
+ .setProduct(product);
+
+ final LineCalculator calculator = new LineCalculator(currentItem);
+
+ assertEquals(valueOf(163.603).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
+ assertEquals(valueOf(1963.24).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
+ assertEquals(valueOf(314.1184).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
+ }
+
+
+ @Test
+ public void testTotalCalculatorGrandTotalRounding() {
+ SimpleDateFormat sqlDate = new SimpleDateFormat("yyyy-MM-dd");
+
+ BigDecimal sales_tax_percent1 = new BigDecimal(16);
+ BigDecimal total_increase_percent = new BigDecimal(0.80);
+ BigDecimal total_discount_percent = new BigDecimal(2.00);
+
+
+ /* invoice (1st part) */
+
+ Invoice invoice = new Invoice();
+ invoice.setDocumentName("Rechnung");
+ invoice.setNumber("777777");
+ try {
+ invoice.setIssueDate(sqlDate.parse("2020-12-31"));
+ invoice.setDetailedDeliveryPeriod(sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[0]), sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[1]));
+ invoice.setDeliveryDate(sqlDate.parse("2020-12-31"));
+ invoice.setDueDate(sqlDate.parse("2021-01-15"));
+ } catch (Exception e) {
+ Logger.getLogger(CalculationTest.class.getName()).log(Level.SEVERE, null, e);
+
+ }
+
+ /* trade party (sender) */
+
+ TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE");
+ sender.addVATID("DE2222222222");
+ invoice.setSender(sender);
+ /* trade party (recipient) */
+
+ TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE");
+ recipient.setID("111111");
+ recipient.addVATID("DE111111111");
+ invoice.setRecipient(recipient);
+ /* item */
+
+ Product product;
+ Item item;
+ BigDecimal item_increase = BigDecimal.ZERO;
+ BigDecimal item_discount = BigDecimal.ZERO;
+
+ product = new Product("AAA", "", "H84", sales_tax_percent1).setSellerAssignedID("1AAA");
+ item = new Item(product, new BigDecimal("4.750"), new BigDecimal(5.00));
+
+ item_discount = new BigDecimal("10.00");
+
+
+ if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
+ item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
+ }
+
+ if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
+ item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
+ }
+
+ invoice.addItem(item);
+ product = new Product("BBB", "", "H84", sales_tax_percent1).setSellerAssignedID("2BBB");
+ item = new Item(product, new BigDecimal("5.750"), new BigDecimal(4.00));
+ item_discount = BigDecimal.ZERO;
+ if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
+ item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
+ }
+ if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
+ item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
+ }
+
+ invoice.addItem(item);
+ product = new Product("CCC", "", "H84", sales_tax_percent1).setSellerAssignedID("3CCC");
+ item = new Item(product, new BigDecimal("6.750"), new BigDecimal(3.00));
+ item_discount = new BigDecimal("10.00");
+ if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
+ item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
+ }
+
+ if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
+ item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
+ }
+
+ invoice.addItem(item);
+
+
+ product = new Product("DDD", "", "H84", sales_tax_percent1).setSellerAssignedID("4DDD");
+ item = new Item(product, new BigDecimal("7.750"), new BigDecimal(2.00));
+
+ item_discount = BigDecimal.ZERO;
+
+
+ if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
+ item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
+ }
+
+ if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
+ item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
+ }
+
+ invoice.addItem(item);
+
+
+ product = new Product("EEE", "", "H84", sales_tax_percent1).setSellerAssignedID("5EEE");
+ item = new Item(product, new BigDecimal("8.750"), new BigDecimal(1.00));
+
+ item_discount = BigDecimal.ZERO;
+
+
+ if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
+ item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
+ }
+
+ if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
+ item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
+
+ }
+ invoice.addItem(item);
+
+ if (total_increase_percent.compareTo(BigDecimal.ZERO) > 0) {
+ invoice.addCharge(new Charge().setPercent(total_increase_percent).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschläge"));
+ }
+
+ if (total_discount_percent.compareTo(BigDecimal.ZERO) > 0) {
+ invoice.addAllowance(new Allowance().setPercent(total_discount_percent).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatte"));
+ }
+ TransactionCalculator calculator = new TransactionCalculator(invoice);
+ assertEquals(valueOf(99.54).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
+ }
+
+
+}
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/LineCalculatorTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/LineCalculatorTest.java
deleted file mode 100644
index 438470aa..00000000
--- a/library/src/test/java/org/mustangproject/ZUGFeRD/LineCalculatorTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.mustangproject.ZUGFeRD;
-
-import static java.math.BigDecimal.TEN;
-import static java.math.BigDecimal.valueOf;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-public class LineCalculatorTest {
-
- @Test
- public void testLineCalculator_simpleAmounts_resultInValidVATAmount() {
- final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
- final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(100))
- .setQuantity(TEN)
- .setProduct(product);
-
- final LineCalculator calculator = new LineCalculator(currentItem);
-
- assertEquals(valueOf(100).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
- assertEquals(valueOf(1000).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
- assertEquals(valueOf(160).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
- }
-
- @Test
- public void testLineCalculatorInclusiveAllowance() {
- //This test failed with previous implementation. By rounding the totalVATAmount to 2 decimal places the result became wrong
- final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
- // 10 % discount on each item
- final IZUGFeRDAllowanceCharge allowance = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(14.8730));
-
- final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
- .setQuantity(valueOf(12))
- .setItemAllowances(new IZUGFeRDAllowanceCharge[] { allowance })
- .setProduct(product);
-
- final LineCalculator calculator = new LineCalculator(currentItem);
-
- assertEquals(valueOf(133.857).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
- assertEquals(valueOf(1606.28).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
- assertEquals(valueOf(257.0048).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
- }
-
- @Test
- public void testLineCalculatorInclusiveAllowanceAndCharge() {
- final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
- // 10 % discount on each item
- final IZUGFeRDAllowanceCharge allowance = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(14.873));
- // 20 % charge
- final IZUGFeRDAllowanceCharge charge = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(29.746));
- final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
- .setQuantity(valueOf(12))
- .setItemAllowances(new IZUGFeRDAllowanceCharge[] { allowance })
- .setItemCharges(new IZUGFeRDAllowanceCharge[] { charge })
- .setProduct(product);
-
- final LineCalculator calculator = new LineCalculator(currentItem);
-
- assertEquals(valueOf(163.603).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
- assertEquals(valueOf(1963.24).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
- assertEquals(valueOf(314.1184).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
- }
-}