This commit is contained in:
jstaerk
2025-10-07 08:18:09 +02:00
parent 63d21f8703
commit 55b89bed54
5 changed files with 92 additions and 115 deletions

View File

@@ -8,6 +8,9 @@
- #932
- #933, #413, #557, #765
- make Line Calculation, e.g. total line net amount, accessible via JSON using getCalculation
- #940
- #939
- #692
2.19.0
=======

View File

@@ -8,21 +8,8 @@ import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.mustangproject.Allowance;
import org.mustangproject.BankDetails;
import org.mustangproject.CalculatedInvoice;
import org.mustangproject.Charge;
import org.mustangproject.DirectDebit;
import org.mustangproject.EStandard;
import org.mustangproject.*;
import org.mustangproject.Exceptions.StructureException;
import org.mustangproject.FileAttachment;
import org.mustangproject.IncludedNote;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.ReferencedDocument;
import org.mustangproject.SchemedID;
import org.mustangproject.TradeParty;
import org.mustangproject.XMLTools;
import org.mustangproject.util.NodeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,6 +48,8 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -606,10 +595,12 @@ public class ZUGFeRDInvoiceImporter {
}
zpp.addNotes(includedNotes);
String rootNode = extractString("local-name(/*)");
String potentialCashDiscountTerms=null;
if (rootNode != null && Set.of("Invoice", "CreditNote").contains(rootNode)) {
// UBL...
// //*[local-name()="Invoice" or local-name()="CreditNote"]
number = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"ID\"]").trim();
potentialCashDiscountTerms = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"PaymentTerms\"]/*[local-name()=\"Note\"]").trim();
typeCode = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"InvoiceTypeCode\"]").trim();
String issueDateStr = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"IssueDate\"]").trim();
if (!issueDateStr.isEmpty()) {
@@ -623,6 +614,10 @@ public class ZUGFeRDInvoiceImporter {
if (!deliveryDt.isEmpty()) {
deliveryDate = parseDate(deliveryDt, "yyyy-MM-dd");
}
} else {
//CII
potentialCashDiscountTerms = extractString("//*[local-name()=\"SpecifiedTradePaymentTerms\"]/*[local-name()=\"Description\"]").trim();
}
String creditorReferenceID = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"CreditorReferenceID\"]").trim();//BT-90
@@ -1127,6 +1122,63 @@ public class ZUGFeRDInvoiceImporter {
}
}
xpr = xpath.compile("//*[local-name()=\"SpecifiedTradePaymentTerms\"]/*[local-name()=\"ApplicableTradePaymentDiscountTerms\"]");// cash discounts, UBL unknown
NodeList cashdiscountNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < cashdiscountNodes.getLength(); i++) {
NodeList cashDiscountNodeChilds = cashdiscountNodes.item(i).getChildNodes();
String chargeAmount = null;
String taxPercent = null;
CashDiscount cd=new CashDiscount();
for (int cashDiscountChildIndex = 0; cashDiscountChildIndex < cashDiscountNodeChilds.getLength(); cashDiscountChildIndex++) {
Node currentNode=cashDiscountNodeChilds.item(cashDiscountChildIndex);
String chargeChildName = currentNode.getLocalName();
if (chargeChildName != null) {
if (chargeChildName.equals("BasisPeriodMeasure")) {
if (currentNode.getAttributes().getNamedItem("unitCode").getNodeValue().equals("DAY")) {
cd.setDays(Integer.valueOf(XMLTools.trimOrNull(currentNode)));
}
} else if (chargeChildName.equals("CalculationPercent")) {
cd.setPercent(new BigDecimal(XMLTools.trimOrNull(currentNode)));
}
}
//appliedAmount
//AppliedTradeTax
}
if ((cd.getPercent() != null)&&(cd.getDays() != null)) {
zpp.addCashDiscount(cd);
}
}
if ((potentialCashDiscountTerms!=null&&potentialCashDiscountTerms.length()>3)) {
for (String currentLine:potentialCashDiscountTerms.split("\\n")) {
if (currentLine.startsWith("#SKONTO#")) {
CashDiscount cd=new CashDiscount();
Pattern pattern = Pattern.compile("#TAGE=(.*?)#", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(currentLine);
boolean daysFound = matcher.find();
String days=matcher.group(1);
pattern = Pattern.compile("#PROZENT=(.*?)#", Pattern.CASE_INSENSITIVE);
matcher = pattern.matcher(currentLine);
boolean percentFound = matcher.find();
String percent=matcher.group(1);
if (daysFound&&percentFound) {
cd.setDays(Integer.valueOf(days));
cd.setPercent(new BigDecimal(percent));
zpp.addCashDiscount(cd);
} //else : could not parse skonto
/*
String percent=;
cd.setDays()
cd.setPercent()*/
}
}
}
TransactionCalculator tc = new TransactionCalculator(zpp);
String calculatedPayableTotal = tc.getDuePayable().toPlainString();

View File

@@ -165,13 +165,13 @@ public class CalculationTest extends ResourceCase {
}
@Test
/* @Test
public void testRounding() {
/*** xml of official fx sample with allowances and charges
* 10x100 with 10% and 50€ item discount =850€
* +8,75 charges on document level=858,75, +19%VAT=1021,91
* prepaid 500->due payable=521,91
*/
*
File inputCII = getResourceAsFile("EN16931_1_Teilrechnung_corrected.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
@@ -197,7 +197,7 @@ public class CalculationTest extends ResourceCase {
}
*/
@Test
public void testTotalCalculatorGrandTotalRounding() {

View File

@@ -35,7 +35,6 @@ import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -235,9 +234,9 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
public void testSpecifiedLogisticsChargeImport() {
public void testSpecifiedLogisticsChargeCashDiscountImport() {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
File expectedResult = getResourceAsFile("cii/extended_warenrechnung.xml");
File expectedResult = getResourceAsFile("cii/extended_warenrechnung_based_doublecashdiscount.xml");
boolean hasExceptions = false;
@@ -249,9 +248,11 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
hasExceptions = true;
}
assertFalse(hasExceptions);
assertEquals(invoice.getCashDiscounts().length,2);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("518.99"), tc.getGrandTotal());
}
public void testItemAllowancesChargesImport() {
@@ -347,7 +348,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("1.00"), tc.getGrandTotal());
assertEquals(invoice.getCashDiscounts().length,2);
assertEquals(version,2);
assertTrue(new BigDecimal("1").compareTo(invoice.getZFItems()[0].getQuantity()) == 0);
LineCalculator lc=invoice.getZFItems()[0].getCalculation();

View File

@@ -1,90 +1,4 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!-- English disclaimer below.-->
<!--Nutzungsrechte
ZUGFeRD Datenformat Version 2.2.0, 14.02.2022
Beispiel Version 14.02.2022
Zweck des Forums elektronisch Rechnung Deutschland, welches am 31. März 2010 unter der Arbeitsgemeinschaft für
wirtschaftliche Verwaltung e. V. gegründet wurde, ist u. a. die Schaffung und Spezifizierung eines offenen Datenformats
für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht diskriminierender, standardisierter
Technologien („ZUGFeRD Datenformat“).
Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung
frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine
Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht
diskriminierenden Bedingungen an.
Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung
abrufbar unter www.ferd-net.de.
Im Einzelnen schließt die Nutzungsgewährung ein:
=====================================
FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils
geltenden und akzeptierten Fassung (www.ferd-net.de) ein.
Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung,
Weiterbearbeitung und Verbindung mit anderen Produkten.
Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder
anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige
Anwendungen und Dienste.
Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente
und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um
notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch
die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden.
Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares,
unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit
anderen Produkten einzuräumen.
Die Lizenz wird kostenfrei zur Verfügung gestellt.
Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen
Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten,
Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete,
beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der
Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können.-->
<!--Right of use
ZUGFeRD Data format version 2.2.0, February 14th, 2022
The purpose of the Forum elektronische Rechnung Deutschland (FeRD), which was founded on March 31, 2010 under the
umbrella of Arbeitsgemeinschaft für wirtschaftliche Verwaltung e. V., is, among other things, to create and specify an
open data format for structured electronic data exchange on the basis of open and non discriminatory, standardised
technologies ("ZUGFeRD data format").
The ZUGFeRD data format is used by both companies and public administration according to the FeRD
made freely accessible. For this purpose FeRD offers all companies and organisations of the public administration a
License to use the copyrighted ZUGFeRD data format in a fair, appropriate and non
discriminatory conditions.
The specification of the FeRD for the implementation of the ZUGFeRD data format is, in its currently valid version
available at www.ferd-net.de.
In detail, the grant of use includes
=====================================
FeRD grants a license for the use of the copyrighted ZUGFeRD data format in the respective
valid and accepted version (www.ferd-net.de).
The license includes an irrevocable right of use including the right of further development,
Further processing and connection with other products.
The license applies in particular to the development, design, production, sale, use or
other use of the ZUGFeRD data format for hardware and/or software products and other
applications and services.
This license does not include the essential patents of the members of FeRD. The essential patents are patents
and patent applications worldwide which contain one or more claims that are
necessary claims. Necessary claims are only those claims of the essential patents which are
the implementation of the ZUGFeRD data format would necessarily be violated.
The Licensee is entitled to provide its respective group companies with an unlimited, worldwide, non-transferable,
irrevocable right of use including the right of further development, further processing and connection with
other products.
The license is provided free of charge.
Except in the case of intentional fault or gross negligence, FeRD is not liable for loss of use, loss of
Profit, loss of data, loss of communication, loss of revenue, loss of contracts, loss of business or for costs
damages, losses or liabilities in connection with an interruption of business, nor for concrete,
incidental, indirect, punitive or consequential damages, even if the possibility of
costs, losses or damages could normally have been foreseen.-->
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:TestIndicator>
@@ -552,6 +466,13 @@ WEEE-Reg-Nr.: DE87654321
<ram:CalculationPercent>2.00</ram:CalculationPercent>
</ram:ApplicableTradePaymentDiscountTerms>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Bei Zahlung innerhalb 7 Tagen gewähren wir 1,0% Skonto.</ram:Description>
<ram:ApplicableTradePaymentDiscountTerms>
<ram:BasisPeriodMeasure unitCode="DAY">7</ram:BasisPeriodMeasure>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
</ram:ApplicableTradePaymentDiscountTerms>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>457.20</ram:LineTotalAmount>
<ram:ChargeTotalAmount>3.00</ram:ChargeTotalAmount>