Merge remote-tracking branch 'remotes/origin/master'
This commit is contained in:
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,3 +1,3 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: [jstaerk]
|
custom: ["https://www.mustangproject.org/support/"]
|
||||||
|
|||||||
@@ -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
|
2.0.3
|
||||||
=======
|
=======
|
||||||
2020-12-06
|
2020-12-06
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.mustangproject</groupId>
|
<groupId>org.mustangproject</groupId>
|
||||||
<artifactId>Mustang-CLI</artifactId>
|
<artifactId>Mustang-CLI</artifactId>
|
||||||
<name>Mustang commandline tool</name>
|
<name>e-invoices commandline tool, allowing to create(embed), split and validate Factur-X/ZUGFeRD files. Validation should also work for XRechnung/CII. </name>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<version>2.0.4-SNAPSHOT</version>
|
<version>2.0.4-SNAPSHOT</version>
|
||||||
<repositories>
|
<repositories>
|
||||||
@@ -53,7 +53,6 @@
|
|||||||
<version>4.13.1</version>
|
<version>4.13.1</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- for directory validation: -->
|
<!-- for directory validation: -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.xmlunit</groupId>
|
<groupId>org.xmlunit</groupId>
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
<artifactId>library</artifactId>
|
<artifactId>library</artifactId>
|
||||||
<version>2.0.4-SNAPSHOT</version>
|
<version>2.0.4-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>Library to write and read FacturX and ZUGFeRD e-invoices. </name>
|
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD and to a limited extend XRechnung/CII). </name>
|
||||||
<description>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.
|
<description>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.
|
||||||
</description>
|
</description>
|
||||||
<url>http://www.mustangproject.org/</url>
|
<url>http://www.mustangproject.org/</url>
|
||||||
<scm>
|
<scm>
|
||||||
@@ -83,6 +83,14 @@
|
|||||||
<version>4.13.1</version>
|
<version>4.13.1</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- CII to UBL conversion -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.helger</groupId>
|
||||||
|
<artifactId>en16931-cii2ubl</artifactId>
|
||||||
|
<version>1.2.5</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.helger</groupId>
|
<groupId>com.helger</groupId>
|
||||||
<artifactId>ph-schematron</artifactId>
|
<artifactId>ph-schematron</artifactId>
|
||||||
@@ -101,6 +109,12 @@
|
|||||||
<artifactId>xmlunit-assertj</artifactId>
|
<artifactId>xmlunit-assertj</artifactId>
|
||||||
<version>2.6.3</version>
|
<version>2.6.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.helger</groupId>
|
||||||
|
<artifactId>ph-commons</artifactId>
|
||||||
|
<version>9.1.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
50
library/src/main/java/org/mustangproject/CII/CIIToUBL.java
Normal file
50
library/src/main/java/org/mustangproject/CII/CIIToUBL.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -126,13 +126,19 @@ public interface IExportableTransaction {
|
|||||||
return null;
|
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();
|
IZUGFeRDExportableItem[] getZFItems();
|
||||||
@@ -290,7 +296,7 @@ public interface IExportableTransaction {
|
|||||||
* @return three character currency of this invoice
|
* @return three character currency of this invoice
|
||||||
*/
|
*/
|
||||||
default String getCurrency() {
|
default String getCurrency() {
|
||||||
return null;
|
return "EUR";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,13 +37,17 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
|||||||
* item level discounts
|
* item level discounts
|
||||||
* @return array of the discounts on a single item
|
* @return array of the discounts on a single item
|
||||||
*/
|
*/
|
||||||
IZUGFeRDAllowanceCharge[] getItemAllowances();
|
default IZUGFeRDAllowanceCharge[] getItemAllowances() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* item level price additions
|
* item level price additions
|
||||||
* @return array of the additional charges on the item
|
* @return array of the additional charges on the item
|
||||||
*/
|
*/
|
||||||
IZUGFeRDAllowanceCharge[] getItemCharges();
|
default IZUGFeRDAllowanceCharge[] getItemCharges() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -68,17 +68,13 @@ public interface IZUGFeRDExportableTradeParty {
|
|||||||
*
|
*
|
||||||
* @return First and last name of the recipient
|
* @return First and last name of the recipient
|
||||||
*/
|
*/
|
||||||
default String getName() {
|
String getName();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Postal code of the recipient
|
* Postal code of the recipient
|
||||||
*
|
*
|
||||||
* @return Postal code of the recipient
|
* @return Postal code of the recipient
|
||||||
*/
|
*/
|
||||||
default String getZIP() {
|
String getZIP();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,9 +92,7 @@ public interface IZUGFeRDExportableTradeParty {
|
|||||||
*
|
*
|
||||||
* @return two-letter iso country code of the contact
|
* @return two-letter iso country code of the contact
|
||||||
*/
|
*/
|
||||||
default String getCountry() {
|
String getCountry();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,9 +100,7 @@ public interface IZUGFeRDExportableTradeParty {
|
|||||||
*
|
*
|
||||||
* @return Returns the city of the recipient
|
* @return Returns the city of the recipient
|
||||||
*/
|
*/
|
||||||
default String getLocation() {
|
String getLocation();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,9 +108,7 @@ public interface IZUGFeRDExportableTradeParty {
|
|||||||
*
|
*
|
||||||
* @return street address (street+number) of the contact
|
* @return street address (street+number) of the contact
|
||||||
*/
|
*/
|
||||||
default String getStreet() {
|
String getStreet();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns additional address information which is display in xml tag "LineTwo"
|
* returns additional address information which is display in xml tag "LineTwo"
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import java.time.Year;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
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")},
|
{"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")},
|
{"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")},
|
{"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]));
|
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Profile) data[1]));
|
||||||
static Map<String, Profile> zf1Map = Stream.of(new Object[][]{
|
static Map<String, Profile> zf1Map = Stream.of(new Object[][]{
|
||||||
|
|||||||
@@ -127,10 +127,11 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
|||||||
* @return item sum
|
* @return item sum
|
||||||
*/
|
*/
|
||||||
protected BigDecimal getTotal() {
|
protected BigDecimal getTotal() {
|
||||||
return Stream.of(trans.getZFItems())
|
BigDecimal dec = Stream.of(trans.getZFItems())
|
||||||
.map(LineCalculator::new)
|
.map(LineCalculator::new)
|
||||||
.map(LineCalculator::getItemTotalNetAmount)
|
.map(LineCalculator::getItemTotalNetAmount)
|
||||||
.reduce(ZERO, BigDecimal::add);
|
.reduce(ZERO, BigDecimal::add);
|
||||||
|
return dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@@ -139,8 +140,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
|||||||
* @return item sum +- charges/allowances
|
* @return item sum +- charges/allowances
|
||||||
*/
|
*/
|
||||||
protected BigDecimal getTaxBasis() {
|
protected BigDecimal getTaxBasis() {
|
||||||
BigDecimal res = getTotal().add(getChargesForPercent(null)).subtract(getAllowancesForPercent(null));
|
return getTotal().add(getChargesForPercent(null).setScale(2, RoundingMode.HALF_UP)).subtract(getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP)).setScale(2, RoundingMode.HALF_UP);
|
||||||
return res.setScale(2, RoundingMode.HALF_UP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mustangproject's ZUGFeRD implementation
|
* Mustangproject's ZUGFeRD implementation
|
||||||
@@ -55,7 +56,7 @@ public class VATAmount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setBasis(BigDecimal basis) {
|
public void setBasis(BigDecimal basis) {
|
||||||
this.basis = basis;
|
this.basis = basis.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,5 +24,5 @@ public class TaxCategoryCodeTypeConstants {
|
|||||||
public static final String TAXEXEMPT = "E";
|
public static final String TAXEXEMPT = "E";
|
||||||
public static final String ZEROTAXPRODUCTS = "Z";
|
public static final String ZEROTAXPRODUCTS = "Z";
|
||||||
public static final String UNTAXEDSERVICE = "O";
|
public static final String UNTAXEDSERVICE = "O";
|
||||||
public static final String INTRACOMMUNITY = "IC";
|
public static final String INTRACOMMUNITY = "K";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user