Merge branch 'master' into issues/764

# Conflicts:
#	library/src/main/java/org/mustangproject/Charge.java
#	library/src/main/java/org/mustangproject/Item.java
#	library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java
This commit is contained in:
jstaerk
2025-05-20 08:29:53 +02:00
71 changed files with 26484 additions and 31011 deletions

View File

@@ -3,13 +3,13 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.16.4-SNAPSHOT</version>
<version>2.17.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.16.4-SNAPSHOT</version>
<version>2.17.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)</name>
<description>FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT
@@ -110,12 +110,12 @@
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
<version>3.0.2</version>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.2</version>
<version>3.0.5</version>
</dependency>
<!-- DOM4j -->
<dependency>

View File

@@ -56,7 +56,7 @@ public class Invoice implements IExportableTransaction {
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
protected IZUGFeRDPaymentTerms paymentTerms = null;
protected ArrayList<IZUGFeRDPaymentTerms> paymentTerms = new ArrayList<>();
protected String invoiceReferencedDocumentID = null;
protected Date invoiceReferencedIssueDate;
@@ -646,15 +646,43 @@ public class Invoice implements IExportableTransaction {
@Override
public IZUGFeRDPaymentTerms getPaymentTerms() {
return paymentTerms;
if (!paymentTerms.isEmpty()) {
return paymentTerms.get(0);
}
return null;
}
public Invoice setPaymentTerms(IZUGFeRDPaymentTerms paymentTerms) {
this.paymentTerms = paymentTerms;
public Invoice setPaymentTerms(IZUGFeRDPaymentTerms paymentTerm) {
if (paymentTerms.isEmpty()) {
paymentTerms.add(paymentTerm);
}
else {
paymentTerms.set(0, paymentTerm);
}
return this;
}
@Override
public IZUGFeRDPaymentTerms[] getExtendedPaymentTerms() {
return paymentTerms.toArray(new IZUGFeRDPaymentTerms[0]);
}
public Invoice setExtendedPaymentTerms(IZUGFeRDPaymentTerms[] paymentTerms) {
this.paymentTerms.clear();
this.paymentTerms.addAll(Arrays.asList(paymentTerms));
return this;
}
/**
* Set multiple payment terms when using the EXTENDED profile.
* @return
*/
public Invoice addPaymentTerms(IZUGFeRDPaymentTerms paymentTerm) {
paymentTerms.add(paymentTerm);
return this;
}
public String getPaymentReference() {
return paymentReference;
}

View File

@@ -173,6 +173,7 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAsNodeMap("ApplicableTradeTax")
.flatMap(cnm -> cnm.getAsString("ExemptionReason"))
.ifPresent(product::setTaxExemptionReason);
icnm.getAllNodes("SpecifiedTradeAllowanceCharge").map(NodeMap::new).forEach(stac -> {
stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> {
String isChargeString = ci.getAsString("Indicator").get();
@@ -210,7 +211,6 @@ public class Item implements IZUGFeRDExportableItem {
});
});
if (recalcPrice && !BigDecimal.ZERO.equals(quantity)) {
icnm.getAsNodeMap("SpecifiedTradeSettlementLineMonetarySummation")
.flatMap(cnm -> cnm.getAsBigDecimal("LineTotalAmount"))
@@ -228,6 +228,36 @@ public class Item implements IZUGFeRDExportableItem {
});
});
itemMap.getAllNodes("AllowanceCharge").map(NodeMap::new).forEach(stac -> { //UBL
String isChargeString = stac.getAsString("ChargeIndicator").get();
String percentString = stac.getAsStringOrNull("MultiplierFactorNumeric");
String amountString = stac.getAsStringOrNull("Amount");
String reason = stac.getAsStringOrNull("AllowanceChargeReason");
Charge izac = new Charge();
if (isChargeString.equalsIgnoreCase("false")) {
izac = new Allowance();
} else {
izac = new Charge();
}
if (amountString != null) {
izac.setTotalAmount(new BigDecimal(amountString));
}
if (percentString != null) {
izac.setPercent(new BigDecimal(percentString));
}
if (reason != null) {
izac.setReason(reason);
}
if (isChargeString.equalsIgnoreCase("false")) {
addAllowance(izac);
} else {
addCharge(izac);
}
});
itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(adld -> {
List<IncludedNote> includedNotes = new ArrayList<>();
adld.getAllNodes("IncludedNote").forEach(item -> {

View File

@@ -29,7 +29,7 @@ public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
public LegalOrganisation(SchemedID schemedID, String tradingBusinessName) {
this.schemedID = schemedID;
this.tradingBusinessName=tradingBusinessName;
this.tradingBusinessName = tradingBusinessName;
}
/***
@@ -54,8 +54,8 @@ public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
this.setSchemedID(gid);
}
}
if (currentItemNode.getLocalName().equals("TradingBusinessName")) {
setTradingBusinessName(currentItemNode.getFirstChild().getNodeValue());
if ((currentItemNode.getLocalName().equals("TradingBusinessName")) && (currentItemNode.getFirstChild() != null)) {
setTradingBusinessName(currentItemNode.getFirstChild().getNodeValue());
}
}
}

View File

@@ -305,8 +305,7 @@ public interface IExportableTransaction {
}
/**
* get payment terms. if set, getPaymentTermDescription() and getDueDate() are
* ignored
* get payment terms. if set, getPaymentTermDescription() and getDueDate() are ignored
*
* @return the IZUGFeRDPaymentTerms of the invoice
*/
@@ -318,6 +317,14 @@ public interface IExportableTransaction {
return null;
}
/**
* Get payment terms for the EXTENDED profile (multiple terms are allowed)
* @return
*/
default IZUGFeRDPaymentTerms[] getExtendedPaymentTerms() {
return new IZUGFeRDPaymentTerms[0];
}
/**
* returns if a rebate agreements exists
*

View File

@@ -56,7 +56,6 @@ public class LineCalculator {
}
BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100));
BigDecimal quantity=BigDecimal.ZERO;
if ((currentItem!=null)&&(currentItem.getQuantity()!=null)) {
quantity=currentItem.getQuantity();
@@ -72,8 +71,8 @@ public class LineCalculator {
BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0
? BigDecimal.ONE.setScale(4)
: currentItem.getBasisQuantity();
itemTotalNetAmount = quantity.multiply(currentItem.getPrice()).divide(basisQuantity, 18, RoundingMode.HALF_UP)
.subtract(allowanceItemTotal).subtract(allowance).add(charge).setScale(2, RoundingMode.HALF_UP);
itemTotalNetAmount = quantity.multiply(price).divide(basisQuantity, 18, RoundingMode.HALF_UP)
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
}

View File

@@ -506,36 +506,44 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
private String buildPaymentTermsXml() {
final IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
if (paymentTerms == null) {
final IZUGFeRDPaymentTerms[] paymentTerms = trans.getExtendedPaymentTerms();
String paymentTermsXml = "";
if (paymentTerms == null || paymentTerms.length == 0) {
return "";
}
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
final IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
if (discountTerms != null) {
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
final String currency = trans.getCurrency();
final String basisAmount = currencyFormat(calc.getGrandTotal());
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
for (IZUGFeRDPaymentTerms pt : paymentTerms)
{
paymentTermsXml += "<ram:SpecifiedTradePaymentTerms>";
final IZUGFeRDPaymentDiscountTerms discountTerms = pt.getDiscountTerms();
paymentTermsXml += "<ram:Description>" + pt.getDescription() + "</ram:Description>";
if (discountTerms != null)
{
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
final String currency = trans.getCurrency();
final String basisAmount = currencyFormat(calc.getGrandTotal());
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
+ "</ram:CalculationPercent>";
if (discountTerms.getBaseDate() != null) {
final Date baseDate = discountTerms.getBaseDate();
paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += DATE.udtFormat(baseDate);
paymentTermsXml += "</ram:BasisDateTime>";
if (discountTerms.getBaseDate() != null)
{
final Date baseDate = discountTerms.getBaseDate();
paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += DATE.udtFormat(baseDate);
paymentTermsXml += "</ram:BasisDateTime>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
}
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
}
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
}
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
return paymentTermsXml;
}

View File

@@ -7,6 +7,7 @@ import java.math.RoundingMode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -65,6 +66,24 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
return sumAllowanceCharge(percent, charges);
}
/**
* Returns information about every tax that is involved in the current transaction.
*
* @return transaction taxes.
*/
public Set<VATAmount> getTaxDetails() {
return getVATPercentAmountMap().entrySet().stream()
.map(entry ->
new VATAmount(
entry.getValue().getBasis(),
entry.getValue().getCalculated(),
entry.getValue().getCategoryCode()
).setCalculated(entry.getKey())
)
.collect(Collectors.toSet());
}
private BigDecimal sumAllowanceCharge(BigDecimal percent, IZUGFeRDAllowanceCharge[] charges) {
BigDecimal res = BigDecimal.ZERO;
if ((charges != null) && (charges.length > 0)) {

View File

@@ -433,44 +433,57 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider {
}
private String buildPaymentTermsXml() {
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
final IZUGFeRDPaymentTerms[] paymentTerms = trans.getExtendedPaymentTerms();
final IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
final IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
final Date dueDate = paymentTerms.getDueDate();
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
throw new IllegalStateException(
String paymentTermsXml = "";
if (paymentTerms == null || paymentTerms.length == 0) {
return paymentTermsXml;
}
for (IZUGFeRDPaymentTerms pt : paymentTerms)
{
paymentTermsXml += "<ram:SpecifiedTradePaymentTerms>";
final IZUGFeRDPaymentDiscountTerms discountTerms = pt.getDiscountTerms();
final Date dueDate = pt.getDueDate();
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null)
{
throw new IllegalStateException(
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
}
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
if (dueDate != null) {
paymentTermsXml += "<ram:DueDateDateTime>";
paymentTermsXml += DATE.udtFormat(dueDate);
paymentTermsXml += "</ram:DueDateDateTime>";
}
if (discountTerms != null) {
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
final String currency = trans.getCurrency();
final String basisAmount = currencyFormat(calc.getGrandTotal());
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
+ "</ram:CalculationPercent>";
if (discountTerms.getBaseDate() != null) {
final Date baseDate = discountTerms.getBaseDate();
paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += DATE.udtFormat(baseDate);
paymentTermsXml += "</ram:BasisDateTime>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
}
paymentTermsXml += "<ram:Description>" + pt.getDescription() + "</ram:Description>";
if (dueDate != null)
{
paymentTermsXml += "<ram:DueDateDateTime>";
paymentTermsXml += DATE.udtFormat(dueDate);
paymentTermsXml += "</ram:DueDateDateTime>";
}
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
}
if (discountTerms != null)
{
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
final String currency = trans.getCurrency();
final String basisAmount = currencyFormat(calc.getGrandTotal());
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
+ "</ram:CalculationPercent>";
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
if (discountTerms.getBaseDate() != null)
{
final Date baseDate = discountTerms.getBaseDate();
paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += DATE.udtFormat(baseDate);
paymentTermsXml += "</ram:BasisDateTime>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
}
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
}
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
}
return paymentTermsXml;
}

View File

@@ -969,56 +969,76 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
private String buildPaymentTermsXml() {
final IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
if (paymentTerms == null) {
ArrayList<IZUGFeRDPaymentTerms> paymentTerms = new ArrayList<IZUGFeRDPaymentTerms>(Arrays.asList(trans.getExtendedPaymentTerms()));
IZUGFeRDPaymentTerms izpt= trans.getPaymentTerms();
if (izpt!=null) {
paymentTerms.add(izpt);
}
String paymentTermsXml = "";
if (paymentTerms.size() == 0) {
return "";
}
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
final IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
final Date dueDate = paymentTerms.getDueDate();
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
throw new IllegalStateException(
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
}
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
for (IZUGFeRDPaymentTerms pt : paymentTerms)
{
if (dueDate != null) {
paymentTermsXml += "<ram:DueDateDateTime>";
paymentTermsXml += DATE.udtFormat(dueDate);
paymentTermsXml += "</ram:DueDateDateTime>";
}
paymentTermsXml += "<ram:SpecifiedTradePaymentTerms>";
if (trans.getTradeSettlement() != null) {
for (final IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
if ((payment != null) && (payment instanceof IZUGFeRDTradeSettlementDebit)) {
paymentTermsXml += payment.getPaymentXML();
final IZUGFeRDPaymentDiscountTerms discountTerms = pt.getDiscountTerms();
final Date dueDate = pt.getDueDate();
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null)
{
throw new IllegalStateException(
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
}
paymentTermsXml += "<ram:Description>" + pt.getDescription() + "</ram:Description>";
if (dueDate != null)
{
paymentTermsXml += "<ram:DueDateDateTime>";
paymentTermsXml += DATE.udtFormat(dueDate);
paymentTermsXml += "</ram:DueDateDateTime>";
}
if (trans.getTradeSettlement() != null)
{
for (final IZUGFeRDTradeSettlement payment : trans.getTradeSettlement())
{
if ((payment != null) && (payment instanceof IZUGFeRDTradeSettlementDebit))
{
paymentTermsXml += payment.getPaymentXML();
}
}
}
}
if (discountTerms != null) {
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
final String currency = trans.getCurrency();
final String basisAmount = currencyFormat(calc.getGrandTotal());
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
+ "</ram:CalculationPercent>";
if (discountTerms != null)
{
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
final String currency = trans.getCurrency();
final String basisAmount = currencyFormat(calc.getGrandTotal());
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
+ "</ram:CalculationPercent>";
if (discountTerms.getBaseDate() != null) {
final Date baseDate = discountTerms.getBaseDate();
paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += DATE.udtFormat(baseDate);
paymentTermsXml += "</ram:BasisDateTime>";
if (discountTerms.getBaseDate() != null)
{
final Date baseDate = discountTerms.getBaseDate();
paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += DATE.udtFormat(baseDate);
paymentTermsXml += "</ram:BasisDateTime>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
}
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
}
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
}
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
return paymentTermsXml;
}

View File

@@ -527,7 +527,7 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
try {
if (getVersion() == 1) {
nl = getNodeListByPath("//*[localname() = 'CrossIndustryDocument']//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']/*[local-name() = 'ApplicableSupplyChainTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']");
nl = getNodeListByPath("//*[local-name() = 'CrossIndustryDocument']//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']/*[local-name() = 'ApplicableSupplyChainTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']");
} else {
nl = getNodeListByPath("//*[local-name() = 'CrossIndustryInvoice']//*[local-name() = 'SupplyChainTradeTransaction']//*[local-name() = 'ApplicableHeaderTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']");
}

View File

@@ -449,8 +449,8 @@ public class ZUGFeRDInvoiceImporter {
xpr = xpath.compile("//*[local-name()=\"ExchangedDocument\"]|//*[local-name()=\"HeaderExchangedDocument\"]");
NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile("//*[local-name()=\"GrandTotalAmount\"]|//*[local-name()=\"PayableAmount\"]");
xpr = xpath.compile("//*[local-name()=\"GrandTotalAmount\"]|//*[local-name()=\"TaxInclusiveAmount\"]");
BigDecimal expectedGrandTotal = null;
NodeList totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (totalNodes.getLength() > 0) {

View File

@@ -82,8 +82,9 @@ public class CalculationTest extends ResourceCase {
@Test
public void testLineCalculatorForeignCurrencyExample() {
/*
File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml");
inputCII=new File("C:\\Users\\jstaerk\\workspace\\XMLExamples\\zfdiverses\\20250407\\fremdwaehrung.xml");
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter();
Invoice invoice=null;
zii.doIgnoreCalculationErrors();
@@ -103,9 +104,9 @@ public class CalculationTest extends ResourceCase {
final TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getDuePayable().stripTrailingZeros());
assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
*/
}

View File

@@ -240,13 +240,11 @@ public class ZF2EdgeTest extends MustangReaderTestCase {
e.printStackTrace();
}
return
new PaymentTerms(
"14 Tage 2% Skonto, 30 Tage rein netto",
due,// fälligkeitsdatum
paymentDiscountTerms //PaymentDiscountTerms
);
return new PaymentTerms(
"14 Tage 2% Skonto, 30 Tage rein netto",
due,// fälligkeitsdatum
paymentDiscountTerms //PaymentDiscountTerms
);
}
@Override

View File

@@ -431,7 +431,9 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
CalculatedInvoice i = new CalculatedInvoice();
zii.extractInto(i);
assertEquals("TOSL108", i.getNumber());
assertEquals("729", i.getGrandTotal().toString());
assertEquals("1729", i.getGrandTotal().toString());
assertEquals("729", i.getDuePayable().toString());
} catch (IOException e) {
fail("IOException not expected");
@@ -501,6 +503,24 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
@Test
public void testImportPrepaidUBL() throws XPathExpressionException, ParseException {
InputStream inputStream = this.getClass()
.getResourceAsStream("/ubl/XRECHNUNG_teilrechnung.ubl.xml");
ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter();
importer.doIgnoreCalculationErrors();
importer.setInputStream(inputStream);
CalculatedInvoice invoice = new CalculatedInvoice();
importer.extractInto(invoice);
assertEquals(0, invoice.getGrandTotal().compareTo(new BigDecimal("529.87")));
assertEquals(0, invoice.getLineTotalAmount().compareTo(new BigDecimal("473")));
assertEquals(0, invoice.getTotalPrepaidAmount().compareTo(new BigDecimal("500")));
assertEquals(0, invoice.getDuePayable().compareTo(new BigDecimal("29.87")));
}
@Test
public void testImportIncludedNotes() throws XPathExpressionException, ParseException {
InputStream inputStream = this.getClass()

View File

@@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cec="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>471102</cbc:ID>
<cbc:IssueDate>2024-11-15</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>Rechnung gemäß Bestellung vom 01.11.2024.</cbc:Note>
<cbc:Note>#REG#Lieferant GmbH
Lieferantenstraße 20
80333 München
Deutschland
Geschäftsführer: Hans Muster
Handelsregisternummer: H A 123
</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>04011000-12345-34</cbc:BuyerReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="EM">info@Mustermann.de</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID schemeID="0088">4000001123452</cbc:ID>
</cac:PartyIdentification>
<cac:PostalAddress>
<cbc:StreetName>Lieferantenstraße 20</cbc:StreetName>
<cbc:CityName>München</cbc:CityName>
<cbc:PostalZone>80333</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>201/113/40209</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>FC</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE123456789</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Lieferant GmbH</cbc:RegistrationName>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Max Mustermann</cbc:Name>
<cbc:Telephone>+49891234567</cbc:Telephone>
<cbc:ElectronicMail>Max@Mustermann.de</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="EM">info@kunde.de</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID>GE2020211</cbc:ID>
</cac:PartyIdentification>
<cac:PostalAddress>
<cbc:StreetName>Kundenstraße 15</cbc:StreetName>
<cbc:CityName>Frankfurt</cbc:CityName>
<cbc:PostalZone>69876</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Kunden AG Mitte</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2024-11-14</cbc:ActualDeliveryDate>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="Zahlung per SEPA Überweisung.">58</cbc:PaymentMeansCode>
<cac:PayeeFinancialAccount>
<cbc:ID>DE02120300000000202051</cbc:ID>
<cbc:Name>Kunden AG</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BYLADEM1001</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>Zahlbar innerhalb 30 Tagen netto bis 15.12.2024, 3% Skonto innerhalb 10 Tagen bis 25.11.2024</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">56.87</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">275</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">19.25</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">198</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">37.62</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">473</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">473</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">529.87</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">0</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">0</cbc:ChargeTotalAmount>
<cbc:PrepaidAmount currencyID="EUR">500</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="EUR">29.87</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="H87">20</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">198</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Trennblätter A4</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>TB100A4</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID schemeID="0160">4012345001235</cbc:ID>
</cac:StandardItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">9.9</cbc:PriceAmount>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">0</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">9.9</cbc:BaseAmount>
</cac:AllowanceCharge>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
<cbc:InvoicedQuantity unitCode="H87">50</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">275</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Joghurt Banane</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>ARNR2</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID schemeID="0160">4000050986428</cbc:ID>
</cac:StandardItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">5.5</cbc:PriceAmount>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">0</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">5.5</cbc:BaseAmount>
</cac:AllowanceCharge>
</cac:Price>
</cac:InvoiceLine>
</Invoice>