From dd4feaa3347150a6d292a9d90deb946fe7592dce Mon Sep 17 00:00:00 2001 From: Kemal Taskin Date: Tue, 3 Dec 2024 14:13:55 +0100 Subject: [PATCH 01/67] Refactor and override toPDF method to accept xml string and return byte array --- .../ZUGFeRD/ZUGFeRDVisualizer.java | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index 64e14fc3..f9e456bf 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -35,6 +35,9 @@ import java.io.PipedOutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Supplier; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -312,16 +315,61 @@ public class ZUGFeRDVisualizer { // the writing part File XMLinputFile = new File(xmlFilename); - String result = null; + String fopInput = null; /* remove file endings so that tests can also pass after checking out from git with arbitrary options (which may include CSRF changes) */ try { - result = this.toFOP(XMLinputFile.getAbsolutePath()); + fopInput = this.toFOP(XMLinputFile.getAbsolutePath()); } catch (FileNotFoundException | TransformerException e) { LOGGER.error("Failed to apply FOP", e); } + + toPDFfromFOP(fopInput, () -> { + try { + return new FileOutputStream(pdfFilename); + } catch (FileNotFoundException e) { + LOGGER.error("Failed to create PDF", e); + } + return null; + }, (OutputStream out) -> {}); + } + + public byte[] toPDF(String xmlContent) { + + String fopInput = null; + + /* remove file endings so that tests can also pass after checking + out from git with arbitrary options (which may include CSRF changes) + */ + try { + ByteArrayInputStream fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8)); + EStandard theStandard = findOutStandardFromRootNode(fis); + fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));//rewind :-( + + fopInput = toFOP(fis, theStandard); + } catch (FileNotFoundException | TransformerException e) { + LOGGER.error("Failed to apply FOP", e); + } + + AtomicReference byteHolder = new AtomicReference<>(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + toPDFfromFOP(fopInput, () -> new BufferedOutputStream(os), (OutputStream out) -> { + + try { + out.flush(); + } catch (IOException e) { + LOGGER.error("Failed to create PDF", e); + } + byteHolder.set(os.toByteArray()); + }); + + return byteHolder.get(); + } + + private void toPDFfromFOP(String fopInput, Supplier outputStreamDelegate, Consumer consumerDelegate) { + DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); Configuration cfg = null; @@ -349,7 +397,7 @@ public class ZUGFeRDVisualizer { // Step 2: Set up output stream. // Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams). - try (OutputStream out = new BufferedOutputStream(new FileOutputStream(pdfFilename))) { + try (OutputStream out = new BufferedOutputStream(outputStreamDelegate.get())) { // Step 3: Construct fop with desired output format Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out); @@ -360,13 +408,15 @@ public class ZUGFeRDVisualizer { // Step 5: Setup input and output for XSLT transformation // Setup input stream - Source src = new StreamSource(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8))); + Source src = new StreamSource(new ByteArrayInputStream(fopInput.getBytes(StandardCharsets.UTF_8))); // Resulting SAX events (the generated FO) must be piped through to FOP Result res = new SAXResult(fop.getDefaultHandler()); // Step 6: Start XSLT transformation and FOP processing transformer.transform(src, res); + + consumerDelegate.accept(out); } catch (FOPException | IOException | TransformerException e) { LOGGER.error("Failed to create PDF", e); From 5732d23555ad0cd4e322960986f0fbfea406650a Mon Sep 17 00:00:00 2001 From: langfr Date: Sun, 8 Dec 2024 14:40:53 +0000 Subject: [PATCH 02/67] Enable flexible PaymentReference and a DocumentName. --- .../main/java/org/mustangproject/Invoice.java | 11 +++++++++++ .../ZUGFeRD/IExportableTransaction.java | 4 ++++ .../ZUGFeRD/ZUGFeRD2PullProvider.java | 17 ++++++++--------- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 12 +++++++++++- .../org/mustangproject/ZUGFeRD/ZF2PushTest.java | 5 ++++- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/library/src/main/java/org/mustangproject/Invoice.java b/library/src/main/java/org/mustangproject/Invoice.java index 10ba057f..667f8a6d 100644 --- a/library/src/main/java/org/mustangproject/Invoice.java +++ b/library/src/main/java/org/mustangproject/Invoice.java @@ -67,6 +67,7 @@ public class Invoice implements IExportableTransaction { protected String vatDueDateTypeCode = null; protected String creditorReferenceID; // required when direct debit is used. private BigDecimal roundingAmount=null; + private String paymentReference; // Remittance information / Verwendungszweck, BT-83 public Invoice() { ZFItems = new ArrayList<>(); @@ -617,6 +618,16 @@ public class Invoice implements IExportableTransaction { return this; } + @Override + public String getPaymentReference() { + return paymentReference; + } + + public Invoice setPaymentReference(String paymentReference) { + this.paymentReference = paymentReference; + return this; + } + @Override public TradeParty getDeliveryAddress() { return deliveryAddress; diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java index 0a67a6be..a06952ae 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java @@ -312,6 +312,10 @@ public interface IExportableTransaction { return null; } + default String getPaymentReference() { + return null; + } + /** * returns if a rebate agreements exists * diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index ff5aa321..6316c31a 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -388,14 +388,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + "" + "" + "" - + "" + XMLTools.encodeXML(trans.getNumber()) + "" - // + "RECHNUNG" - // + "380" - + "" + typecode + "" - + "" - + DATE.udtFormat(trans.getIssueDate()) + "" // date + + "" + XMLTools.encodeXML(trans.getNumber()) + ""; + if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) { + xml += "" + XMLTools.encodeXML(trans.getDocumentName()) + ""; + } + xml += "" + typecode + "" + + "" + DATE.udtFormat(trans.getIssueDate()) + "" // date + buildNotes(trans) - + "" + ""; int lineID = 0; @@ -662,8 +661,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { if ((trans.getCreditorReferenceID() != null) && (getProfile() != Profiles.getByName("Minimum"))) { xml += "" + XMLTools.encodeXML(trans.getCreditorReferenceID()) + ""; } - if ((trans.getNumber() != null) && (getProfile() != Profiles.getByName("Minimum"))) { - xml += "" + XMLTools.encodeXML(trans.getNumber()) + ""; + if ((trans.getPaymentReference() != null) && (getProfile() != Profiles.getByName("Minimum"))) { + xml += "" + XMLTools.encodeXML(trans.getPaymentReference()) + ""; } xml += "" + trans.getCurrency() + ""; if (this.trans.getPayee() != null) { diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index ffcfaac1..e83ffea1 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -288,6 +288,7 @@ public class ZUGFeRDInvoiceImporter { public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseException { String number = ""; + String documentName = null; String typeCode = null; String deliveryPeriodStart = null; String deliveryPeriodEnd = null; @@ -494,6 +495,9 @@ public class ZUGFeRDInvoiceImporter { if ((item.getLocalName() != null) && (item.getLocalName().equals("ID"))) { number = XMLTools.trimOrNull(item); } + if ((item.getLocalName() != null) && (item.getLocalName().equals("Name"))) { + documentName = XMLTools.trimOrNull(item); + } if ((item.getLocalName() != null) && (item.getLocalName().equals("TypeCode"))) { typeCode = XMLTools.trimOrNull(item); } @@ -659,6 +663,12 @@ public class ZUGFeRDInvoiceImporter { NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes(); for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) { + if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null) + && (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("PaymentReference"))) { + String paymentReference = headerTradeSettlementChilds.item(settlementChildIndex).getTextContent(); + zpp.setPaymentReference(paymentReference); + } + if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null) && (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("SpecifiedTradePaymentTerms"))) { NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes(); @@ -780,7 +790,7 @@ public class ZUGFeRDInvoiceImporter { } - zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode); + zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentName(documentName).setDocumentCode(typeCode); if ((directDebitMandateID != null) && (IBAN != null)) { DirectDebit d = new DirectDebit(IBAN, directDebitMandateID); diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java index d435e58e..84968add 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java @@ -526,7 +526,7 @@ public class ZF2PushTest extends TestCase { try { SchemedID gtin = new SchemedID("0160", "2001015001325"); SchemedID gln = new SchemedID("0088", "4304171000002"); - ze.setTransaction(new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()) + ze.setTransaction(new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setPaymentReference("Verwendungszweck").setDocumentName("Rechnung") .setSellerOrderReferencedDocumentID("9384").setBuyerOrderReferencedDocumentID("28934") .setDetailedDeliveryPeriod(new SimpleDateFormat("yyyyMMdd").parse(occurrenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurrenceTo)) .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).setEmail("sender@test.org").setID(orgID).addVATID("DE0815")) @@ -578,6 +578,7 @@ public class ZF2PushTest extends TestCase { assertTrue(zi.getUTF8().contains("++49555123456")); assertTrue(zi.getUTF8().contains("Cash Discount")); // default description for cash discounts assertThat(zi.getUTF8()).valueByXPath("//*[local-name()='ApplicableTradeTax']/*[local-name()='DueDateTypeCode']").asString().isEqualTo(EventTimeCodeTypeConstants.PAYMENT_DATE); + assertTrue(zi.getUTF8().contains("Rechnung")); ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_PUSHEDGE); try { @@ -587,6 +588,8 @@ public class ZF2PushTest extends TestCase { assertEquals("4304171000002", i.getRecipient().getGlobalID()); assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID()); assertEquals(orgID, i.getSender().getID()); + assertEquals("Verwendungszweck", i.getPaymentReference()); + assertEquals("Rechnung", i.getDocumentName()); } catch (XPathExpressionException e) { fail("XPathExpressionException should not be raised"); From 4edeab56ee849d7a6f07aaf1730ba50e80dd4ade Mon Sep 17 00:00:00 2001 From: Adrian-Devries Date: Tue, 7 Jan 2025 16:24:03 +0100 Subject: [PATCH 03/67] Add net.sf.offo:fop-hyph Add hyphenation patterns to avoid the following issue: "WARN org.apache.fop.apps.FOUserAgent - Hyphenation pattern not found." --- library/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/pom.xml b/library/pom.xml index 073661c1..8b5b3370 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -59,6 +59,12 @@ slf4j-api 2.0.9 + + net.sf.offo + fop-hyph + 2.0 + runtime + net.sf.saxon From d0d4346b71cdc4c0f1cd05f54c87f9a5ca698456 Mon Sep 17 00:00:00 2001 From: melo0187 <2528018+melo0187@users.noreply.github.com> Date: Mon, 13 Jan 2025 09:39:27 +0100 Subject: [PATCH 04/67] Fix #632: Return ubl_creditnote as Standard for CreditNotes This allows to distinguish between UBL's Invoice and UBL's CreditNote. I think this is usefule, since further processing with UBL libraries requires knowledge about the document type. --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index de66b35d..608a565e 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -1037,7 +1037,7 @@ public class ZUGFeRDInvoiceImporter { } else if (rootNode.equals("Invoice")) { return EStandard.ubl; } else if (rootNode.equals("CreditNote")) { - return EStandard.ubl; + return EStandard.ubl_creditnote; } else if (rootNode.equals("CrossIndustryInvoice")) { return EStandard.facturx; } else if (rootNode.equals("SCRDMCCBDACIDAMessageStructure")) { From b96a2c0438c3137993fe8bd904a7ec642a8b922e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20=C3=87atalkaya?= Date: Mon, 13 Jan 2025 14:17:09 +0100 Subject: [PATCH 05/67] Upgrades VeraPDF dependency to version 1.26.2 --- validator/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/pom.xml b/validator/pom.xml index 67d7ca94..739163cb 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -73,7 +73,7 @@ org.verapdf validation-model-jakarta - 1.26.1 + 1.26.2 From a55bc529670d8ddc1a124028a6f4da1d0ecf7263 Mon Sep 17 00:00:00 2001 From: "mr.mister123" Date: Wed, 15 Jan 2025 10:37:25 +0100 Subject: [PATCH 06/67] optimized validation-report to pdf functionality --- .../main/resources/stylesheets/result-pdf.xsl | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/library/src/main/resources/stylesheets/result-pdf.xsl b/library/src/main/resources/stylesheets/result-pdf.xsl index 0dfa7c95..f3e2e0d4 100644 --- a/library/src/main/resources/stylesheets/result-pdf.xsl +++ b/library/src/main/resources/stylesheets/result-pdf.xsl @@ -28,6 +28,14 @@ red + + + Das XML ist valide. + + + Das XML ist nicht valide. + + green @@ -37,18 +45,26 @@ - + Das ZUGFeRD-PDF ist valide. - + Das ZUGFeRD-PDF ist nicht valide. + + + green + + + red + + - + Es wird empfohlen, das Dokument anzunehmen und es weiterzuverarbeiten. - + Es wird empfohlen, das Dokument zurückzuweisen. @@ -118,6 +134,7 @@ + diff --git a/library/pom.xml b/library/pom.xml index 81a1716f..33154746 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.16.1-SNAPSHOT + 2.16.1 4.0.0 org.mustangproject library - 2.16.1-SNAPSHOT + 2.16.1 jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -20,7 +20,7 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git https://github.com/ZUGFeRD/mustangproject - core-2.3.2 + core-2.16.1 diff --git a/pom.xml b/pom.xml index 03f326a5..9d089f57 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.16.1-SNAPSHOT pom + 2.16.1 pom Mustang @@ -19,7 +19,7 @@ scm:git:git://github.com/dexecutor/dependent-tasks-executor.git scm:git:git@github.com:dexecutor/dexecutor.git https://github.com/dexecutor/dependent-tasks-executor - core-2.3.2 + core-2.16.1 diff --git a/validator/pom.xml b/validator/pom.xml index 6ceb0dd3..16498b6e 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.1-SNAPSHOT + 2.16.1 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.16.1-SNAPSHOT + 2.16.1 @@ -38,7 +38,7 @@ ${project.groupId} library - 2.16.1-SNAPSHOT + 2.16.1 org.dom4j From 331c05857b65b26efab44fb26afd2b7fdcd6a2e9 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 21 Jan 2025 13:12:43 +0100 Subject: [PATCH 12/67] [maven-release-plugin] prepare for next development iteration --- Mustang-CLI/pom.xml | 6 +++--- library/pom.xml | 6 +++--- pom.xml | 4 ++-- validator/pom.xml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml index 0504de84..d5b924e9 100644 --- a/Mustang-CLI/pom.xml +++ b/Mustang-CLI/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.1 + 2.16.2-SNAPSHOT 4.0.0 org.mustangproject @@ -12,7 +12,7 @@ should also work for XRechnung/CII. jar - 2.16.1 + 2.16.2-SNAPSHOT UTF-8 11 @@ -23,7 +23,7 @@ org.mustangproject validator - 2.16.1 + 2.16.2-SNAPSHOT diff --git a/library/pom.xml b/library/pom.xml index 33154746..6045292a 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.16.1 + 2.16.2-SNAPSHOT 4.0.0 org.mustangproject library - 2.16.1 + 2.16.2-SNAPSHOT jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -20,7 +20,7 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git https://github.com/ZUGFeRD/mustangproject - core-2.16.1 + core-2.3.2 diff --git a/pom.xml b/pom.xml index 9d089f57..7346b012 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.16.1 pom + 2.16.2-SNAPSHOT pom Mustang @@ -19,7 +19,7 @@ scm:git:git://github.com/dexecutor/dependent-tasks-executor.git scm:git:git@github.com:dexecutor/dexecutor.git https://github.com/dexecutor/dependent-tasks-executor - core-2.16.1 + core-2.3.2 diff --git a/validator/pom.xml b/validator/pom.xml index 16498b6e..6c94fd9e 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.1 + 2.16.2-SNAPSHOT 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.16.1 + 2.16.2-SNAPSHOT @@ -38,7 +38,7 @@ ${project.groupId} library - 2.16.1 + 2.16.2-SNAPSHOT org.dom4j From 1f1c0fc52a30773fbf95229ec5233f4456789146 Mon Sep 17 00:00:00 2001 From: Liam Costello Date: Wed, 22 Jan 2025 14:54:46 +0100 Subject: [PATCH 13/67] Ensure Base64 decoding can handle newlines when decoding a FileAttachment --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 9115feb4..7a17bd11 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -890,7 +890,7 @@ public class ZUGFeRDInvoiceImporter { xpr = xpath.compile("//*[local-name()=\"AttachmentBinaryObject\"]|//*[local-name()=\"EmbeddedDocumentBinaryObject\"]"); NodeList attachmentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); for (int i = 0; i < attachmentNodes.getLength(); i++) { - FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i)))); + FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getMimeDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i)))); zpp.embedFileInXML(fa); // filename = "Aufmass.png" mimeCode = "image/png" //EmbeddedDocumentBinaryObject cbc:EmbeddedDocumentBinaryObject mimeCode="image/png" filename="Aufmass.png" From 354756ed2466e94baaf7f8778f228ff584f25cff Mon Sep 17 00:00:00 2001 From: langfr Date: Wed, 22 Jan 2025 21:19:24 +0000 Subject: [PATCH 14/67] Fill TaxExemptionReason during InvoiceImport. --- library/src/main/java/org/mustangproject/Item.java | 3 +++ library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java | 2 +- .../org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index 8fefa87f..fc851930 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -172,6 +172,9 @@ public class Item implements IZUGFeRDExportableItem { icnm.getAsNodeMap("ApplicableTradeTax") .flatMap(cnm -> cnm.getAsBigDecimal("RateApplicablePercent", "ApplicablePercent")) .ifPresent(product::setVATPercent); + icnm.getAsNodeMap("ApplicableTradeTax") + .flatMap(cnm -> cnm.getAsString("ExemptionReason")) + .ifPresent(product::setTaxExemptionReason); icnm.getAsNodeMap("SpecifiedTradeAllowanceCharge").ifPresent(stac -> { stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> { String isChargeString=ci.getAsString("Indicator").get(); diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java index 3efa4ccf..e860c9a2 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java @@ -94,7 +94,7 @@ public class XRTest extends TestCase { .addCashDiscount(new CashDiscount(new BigDecimal(3), 14)) .setReferenceNumber("991-01484-64")//leitweg-id // not using any VAT, this is also a test of zero-rated goods: - .setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0))) + .setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO).setTaxExemptionReason("Kleinunternehmer"), amount, new BigDecimal(1.0))) .setPayee( new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199"))) .embedFileInXML(fe1); diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 6b50de4e..c3020e92 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -314,6 +314,9 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { LineCalculator lc = new LineCalculator(invoice.getZFItems()[0]); assertTrue(new BigDecimal("1").compareTo(lc.getItemTotalNetAmount()) == 0); + assertEquals("Z", invoice.getZFItems()[0].getProduct().getTaxCategoryCode()); + assertEquals("Kleinunternehmer", invoice.getZFItems()[0].getProduct().getTaxExemptionReason()); + assertTrue(invoice.getTradeSettlement().length == 1); assertTrue(invoice.getTradeSettlement()[0] instanceof IZUGFeRDTradeSettlementPayment); IZUGFeRDTradeSettlementPayment paym = (IZUGFeRDTradeSettlementPayment) invoice.getTradeSettlement()[0]; From aff57e5a511f6503c6d07ce6f1bd963db7074820 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Fri, 24 Jan 2025 12:29:55 +0100 Subject: [PATCH 15/67] closes #705 --- History.md | 2 + .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 47 +- .../ZUGFeRD/ZF2ZInvoiceImporterTest.java | 18 + .../resources/cii/extended_warenrechnung.xml | 567 ++++++++++++++++++ 4 files changed, 626 insertions(+), 8 deletions(-) create mode 100644 library/src/test/resources/cii/extended_warenrechnung.xml diff --git a/History.md b/History.md index c3afba03..be39ae49 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,5 @@ +#705 + 2.16.1 ======= 2025-01-21 diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 9115feb4..a1cd2d8d 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -556,13 +556,13 @@ public class ZUGFeRDInvoiceImporter { } zpp.addNotes(includedNotes); String rootNode = extractString("local-name(/*)"); - if (rootNode.equals("Invoice")||rootNode.equals("CreditNote")) { + if (rootNode.equals("Invoice") || rootNode.equals("CreditNote")) { // UBL... // //*[local-name()="Invoice" or local-name()="CreditNote"] number = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"ID\"]").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.length()>0) { + if (issueDateStr.length() > 0) { issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(issueDateStr); } String dueDt = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"DueDate\"]").trim(); @@ -651,7 +651,7 @@ public class ZUGFeRDInvoiceImporter { zpp.setCurrency(currency); String paymentTermsDescription = extractString("//*[local-name()=\"SpecifiedTradePaymentTerms\"]/*[local-name()=\"Description\"]|//*[local-name()=\"PaymentTerms\"]/*[local-name()=\"Note\"]"); - if ((paymentTermsDescription!=null)&&(!paymentTermsDescription.isEmpty())) { + if ((paymentTermsDescription != null) && (!paymentTermsDescription.isEmpty())) { zpp.setPaymentTermDescription(paymentTermsDescription); } @@ -848,15 +848,14 @@ public class ZUGFeRDInvoiceImporter { Node currentItemNode = nodes.item(i); ReferencedDocument doc = ReferencedDocument.fromNode(currentItemNode); - if (doc != null - && (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID()) - || !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime()))) - { + if (doc != null + && (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID()) + || !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime()))) { zpp.addInvoiceReferencedDocument(doc); } } } - + zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim()); String rounding = extractString("//*[local-name()=\"SpecifiedTradeSettlementHeaderMonetarySummation\"]/*[local-name()=\"RoundingAmount\"]|//*[local-name()=\"LegalMonetaryTotal\"]/*[local-name()=\"Party\"]/*[local-name()=\"PayableRoundingAmount\"]"); @@ -976,6 +975,38 @@ public class ZUGFeRDInvoiceImporter { } } + xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"SpecifiedLogisticsServiceCharge\"]");// UBL unknown + chargeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + for (int i = 0; i < chargeNodes.getLength(); i++) { + NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes(); + String chargeAmount = null; + String taxPercent = null; + for (int chargeChildIndex = 0; chargeChildIndex < chargeNodeChilds.getLength(); chargeChildIndex++) { + String chargeChildName = chargeNodeChilds.item(chargeChildIndex).getLocalName(); + if (chargeChildName != null) { + if (chargeChildName.equals("AppliedAmount")) { + chargeAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex)); + } else if (chargeChildName.equals("AppliedTradeTax")) { + NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes(); + for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { + String taxItemName = taxChilds.item(taxChildIndex).getLocalName(); + if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent"))) { + taxPercent = XMLTools.trimOrNull(taxChilds.item(taxChildIndex)); + } + } + } + } + //appliedAmount + //AppliedTradeTax + } + if (chargeAmount != null) { + Charge c = new Charge(new BigDecimal(chargeAmount)); + if (taxPercent != null) { + c.setTaxPercent(new BigDecimal(taxPercent)); + } + zpp.addCharge(c); + } + } TransactionCalculator tc = new TransactionCalculator(zpp); diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 6b50de4e..1e918395 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -232,6 +232,24 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { } + public void testSpecifiedLogisticsChargeImport() { + ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); + File expectedResult = getResourceAsFile("cii/extended_warenrechnung.xml"); + + + boolean hasExceptions = false; + CalculatedInvoice invoice = new CalculatedInvoice(); + try { + zii.setInputStream(new FileInputStream(expectedResult)); + zii.extractInto(invoice); + } catch (XPathExpressionException | ParseException | FileNotFoundException e) { + hasExceptions = true; + } + assertFalse(hasExceptions); + TransactionCalculator tc = new TransactionCalculator(invoice); + assertEquals(new BigDecimal("518.99"), tc.getGrandTotal()); + + } public void testItemAllowancesChargesImport() { ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushItemChargesAllowances.pdf"); diff --git a/library/src/test/resources/cii/extended_warenrechnung.xml b/library/src/test/resources/cii/extended_warenrechnung.xml new file mode 100644 index 00000000..46665e1a --- /dev/null +++ b/library/src/test/resources/cii/extended_warenrechnung.xml @@ -0,0 +1,567 @@ + + + + + + + + + + true + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + R87654321012345 + WARENRECHNUNG + 380 + + 20180806 + + + ST3 + Es bestehen Rabatt- oder Bonusvereinbarungen. + AAK + + + EEV + Der Verkäufer bleibt Eigentümer der Waren bis zu vollständigen Erfüllung der Kaufpreisforderung. + AAJ + + + MUSTERLIEFERANT GMBH +BAHNHOFSTRASSE 99 +99199 MUSTERHAUSEN +Geschäftsführung: +Max Mustermann +USt-IdNr: DE123456789 +Telefon: +49 932 431 0 +www.musterlieferant.de +HRB Nr. 372876 +Amtsgericht Musterstadt +GLN 4304171000002 +WEEE-Reg-Nr.: DE87654321 + + REG + + + Leergutwert: 46,50 + + + Wichtige Information: Bei Bestellungen bis zum 19.12. ist die Auslieferung bis spätestens 23.12. garantiert. + + + + + + 1 + + + 4123456000014 + ZS997 + Zitronensäure 100ml + + Verpackungsart + BO + + + + + 1.0000 + + + 1.0000 + + + + 100.0000 + 4.0000 + + + + VAT + S + 19.00 + + + 100.00 + + + + + + 2 + + + 4123456000021 + GZ250 + Gelierzucker Extra 250g + + + + 1.5000 + + + false + + 0.0300 + Artikelrabatt 1 + + + + false + + 0.0200 + Artikelrabatt 2 + + + + 1.4500 + + + + 50.0000 + 1.0000 + + + + VAT + S + 7.00 + + + 72.50 + + + + + + 3 + + + 4123456000021 + GZ250 + Gelierzucker Extra 250g + Artikel wie vereinbart ohne Berechnung + + + + 0.0000 + + + 0.0000 + + + + 10.0000 + 1.0000 + + + + VAT + S + 7.00 + + + 0.00 + + + + + + 4 + + + 4100130013294 + 2031 + + Bierbrau Pils 20/0500 + EAN-VKE: 4100130913297 + + Verpackung + Kiste + + + + + 12.0000 + + + 12.0000 + + + + 15.0000 + 20.0000 + + + + VAT + S + 19.00 + + + 180.00 + + + + + + 5 + + + 2001015001325 + 1805 + + Leergutpfand 20 x 0,5l + + Verpackung + unverpackt + + + + + 3.1000 + + + 3.1000 + + + + 15.0000 + 1.0000 + + + + VAT + S + 19.00 + + + 46.50 + + + + + + 6 + + + 4123456000038 + MP107 + Mischpalette Joghurt Karton 3 x 20 + + Verpackung + Karton + + + 4123456001035 + JOG103 + Erdbeer 20 x 150g Becher + 20.0000 + + + 4123456002032 + JOG203 + Banane 20 x 150g Becher + 20.0000 + + + 4123456003039 + JOG303 + Schoko 20 x 150g Becher + 20.0000 + + + + + 30.0000 + + + false + + 0.9000 + Artikelrabatt 1 + + + + 29.1000 + + + + 2.0000 + 1.0000 + + + + VAT + S + 7.00 + + + 58.20 + + + + + + 549910 + 4333741000005 + MUSTERLIEFERANT GMBH + + + +49 932 431 500 + + + max.mustermann@musterlieferant.de + + + + 99199 + BAHNHOFSTRASSE 99 + MUSTERHAUSEN + DE + + + DE123456789 + + + + 009420 + 4304171000002 + MUSTER-KUNDE GMBH + + 40235 + KUNDENWEG 88 + DUESSELDORF + DE + + + + B123456789 + + + A456123 + 130 + + + + + 4304171088093 + MUSTER-MARKT + + 8211 + + + 31157 + HAUPTSTRASSE 44 + SARSTEDT + DE + + + + + 20180805 + + + + L87654321012345 + + + + EUR + + 009420 + 4304171000002 + MUSTER-KUNDE GMBH + + 40235 + KUNDENWEG 88 + DUESSELDORF + DE + + + + 61.07 + VAT + 321.40 + 326.50 + -5.10 + S + 19.00 + + + 8.93 + VAT + 127.59 + 130.70 + -3.11 + S + 7.00 + + + + false + + 2.00 + 280.00 + 5.60 + Rechnungsrabatt 1 + + VAT + S + 19.00 + + + + + false + + 2.00 + 130.70 + 2.61 + Rechnungsrabatt 1 + + VAT + S + 7.00 + + + + + false + + 280.00 + 2.50 + Rechnungsrabatt 2 + + VAT + S + 19.00 + + + + + false + + 130.70 + 0.50 + Rechnungsrabatt 2 + + VAT + S + 7.00 + + + + Transportkosten + 3.00 + + VAT + S + 19.00 + + + + Bei Zahlung innerhalb 14 Tagen gewähren wir 2,0% Skonto. + + 14 + 2.00 + + + + 457.20 + 3.00 + 11.21 + 448.99 + 70.00 + 518.99 + 0.00 + 518.99 + + + + \ No newline at end of file From 796f5333acfab07e584577122afab1a75b6c0052 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sat, 25 Jan 2025 17:33:19 +0100 Subject: [PATCH 16/67] closes #707 --- library/src/main/java/org/mustangproject/Item.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index 8fefa87f..c73a7b7f 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -187,8 +187,12 @@ public class Item implements IZUGFeRDExportableItem { if (amountString!=null) { izac.setTotalAmount(new BigDecimal(amountString)); } - izac.setPercent(new BigDecimal(percentString)); - izac.setReason(reason); + if(percentString!=null) { + izac.setPercent(new BigDecimal(percentString)); + } + if(reason!=null) { + izac.setReason(reason); + } if (isChargeString.equalsIgnoreCase("false")) { addAllowance(izac); From 16c6f22566525f28bb92b91b37fefd07a965ad09 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 27 Jan 2025 11:54:23 +0100 Subject: [PATCH 17/67] closes #708 --- History.md | 2 ++ .../mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index be39ae49..e550bcbc 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,6 @@ #705 +#707 +-#708 2.16.1 ======= diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index a1cd2d8d..3f2231d1 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -1116,11 +1116,17 @@ public class ZUGFeRDInvoiceImporter { * * @return the file attachments embedded in XML (using base64) decoded as byte array, * for PDF embedded files in FX use getFileAttachmentsPDF() + * may return empty array * @deprecated use invoice.getAdditionalReferencedDocuments */ @Deprecated public List getFileAttachmentsXML() { - return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments())); + if (importedInvoice.getAdditionalReferencedDocuments()!=null) { + return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments())); + } else { + return new ArrayList<>(); + } + } /*** From f575cccfbeedfe4ea44e013c1ba902be101d9019 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 27 Jan 2025 12:18:28 +0100 Subject: [PATCH 18/67] closes #709 (just added a test the issue resolved itself with #708) --- History.md | 1 + .../org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index e550bcbc..7043484d 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,7 @@ #705 #707 -#708 +-#709 2.16.1 ======= diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 1e918395..55b8b605 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -351,6 +351,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { byte[] fileA = null; byte[] fileB = null; + boolean facturXFound=false; ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushAttachments.pdf"); for (FileAttachment fa : zii.getFileAttachmentsPDF()) { @@ -358,17 +359,19 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { fileA = fa.getData(); } else if (fa.getFilename().equals("two.pdf")) { fileB = fa.getData(); + } else if (fa.getFilename().equals("factur-x.xml")) { + facturXFound=true; } } byte[] b = {12, 13}; // the sample data that was used to write the files + assertTrue(facturXFound); assertTrue(Arrays.equals(fileA, b)); assertEquals(fileA.length, 2); assertTrue(Arrays.equals(fileB, b)); assertEquals(fileB.length, 2); } - public void testImportDebit() { File CIIinputFile = getResourceAsFile("cii/minimalDebit.xml"); try { From 5ec06bd74bf8ce19b46cb21cfc19e264bcc532af Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 27 Jan 2025 14:15:06 +0100 Subject: [PATCH 19/67] some merges --- History.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/History.md b/History.md index 7043484d..21dc49d3 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,18 @@ #707 -#708 -#709 +607 +649 +650 +665 +684 +703 +701 +691 + + + + 2.16.1 ======= From 325b841be19c7361aab60384d758089e68581ce3 Mon Sep 17 00:00:00 2001 From: langfr Date: Tue, 28 Jan 2025 18:51:53 +0000 Subject: [PATCH 20/67] Correct bracket setting on condition for output of allowance reason. --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 6958bb61..577412cd 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -277,7 +277,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } String reason = ""; - if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung")) || profile == Profiles.getByName("EN16931")) { + if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung") || profile == Profiles.getByName("EN16931"))) { reason = "" + XMLTools.encodeXML(allowance.getReason()) + ""; } String reasonCode = ""; From dc6a863a2d8d97bffe32125d6dab796d14b30b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timon=20F=C3=A4rber?= Date: Thu, 30 Jan 2025 11:07:04 +0100 Subject: [PATCH 21/67] extend ValidationLogVisualizer to not use only filesystem --- .../ZUGFeRD/ValidationLogVisualizer.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java index 686daa7c..d6397e22 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java @@ -1,5 +1,13 @@ package org.mustangproject.ZUGFeRD; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringReader; import org.apache.fop.apps.*; import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.configuration.Configuration; @@ -14,7 +22,7 @@ import javax.xml.transform.*; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import java.io.*; + import java.nio.charset.StandardCharsets; public class ValidationLogVisualizer { @@ -70,7 +78,7 @@ public class ValidationLogVisualizer { return baos.toString(StandardCharsets.UTF_8); } - public void toPDF(String xmlLogfileContent, String pdfFilename) { + public byte[] createPDFBytes(String xmlLogfileContent) { // the writing part @@ -111,7 +119,8 @@ public class ValidationLogVisualizer { // Step 2: Set up output stream. // Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams). - try (OutputStream out = new BufferedOutputStream(new FileOutputStream(pdfFilename))) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (OutputStream out = new BufferedOutputStream(baos)) { // Step 3: Construct fop with desired output format Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out); @@ -133,6 +142,20 @@ public class ValidationLogVisualizer { } catch (FOPException | IOException | TransformerException e) { LOGGER.error("Failed to create PDF", e); } + return baos.toByteArray(); + } + + public byte[] toPDF(String xmlLogfileContent) { + return createPDFBytes(xmlLogfileContent); + } + + public void toPDF(String xmlLogfileContent, String pdfFilename) { + byte[] pdfData = createPDFBytes(xmlLogfileContent); + try (FileOutputStream fos = new FileOutputStream(pdfFilename)) { + fos.write(pdfData); + } catch (IOException e) { + LOGGER.error("Failed to write PDF to file", e); + } } private static class ClasspathResourceURIResolver implements URIResolver { From 1b956e326b952e860bffd34cf9c401d4c3531973 Mon Sep 17 00:00:00 2001 From: "mr.mister123" Date: Fri, 31 Jan 2025 11:18:28 +0100 Subject: [PATCH 22/67] remove CIDSets from XObjects --- .../ZUGFeRD/ZUGFeRDExporterFromA3.java | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3.java index dea69a6f..87137411 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3.java @@ -58,6 +58,7 @@ import org.apache.pdfbox.pdmodel.font.PDCIDFontType2; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDFontDescriptor; import org.apache.pdfbox.pdmodel.font.PDType0Font; +import org.apache.pdfbox.pdmodel.graphics.PDXObject; import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.schema.AdobePDFSchema; @@ -559,6 +560,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte // https://github.com/ZUGFeRD/mustangproject/issues/249 COSName cidSet = COSName.getPDFName("CIDSet"); + COSName resources = COSName.getPDFName("Resources"); // iterate over all pdf pages @@ -567,29 +569,45 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte PDPage page = (PDPage) object; PDResources res = page.getResources(); - for (COSName fontName : res.getFontNames()) { - try { - PDFont pdFont = res.getFont(fontName); - if (pdFont instanceof PDType0Font) { - PDType0Font typedFont = (PDType0Font) pdFont; - if (typedFont.getDescendantFont() instanceof PDCIDFontType2) { - @SuppressWarnings("unused") - PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont(); - PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor(); - - fontDescriptor.getCOSObject().removeItem(cidSet); - } - } - } catch (IOException e) { - throw e; + // Check for fonts in PDXObjects: + for (COSName xObjectName : res.getXObjectNames()) { + PDXObject xObject = res.getXObject(xObjectName); + COSDictionary d = xObject.getCOSObject().getCOSDictionary(resources); + if (d != null) { + PDResources xr = new PDResources(d); + removeCIDSetFromPDResources(cidSet, xr); } - // do stuff with the font } + + // Check for fonts in document-resources: + removeCIDSetFromPDResources(cidSet, res); } } } + private void removeCIDSetFromPDResources(COSName cidSet, PDResources res) throws IOException { + for (COSName fontName : res.getFontNames()) { + try { + PDFont pdFont = res.getFont(fontName); + if (pdFont instanceof PDType0Font) { + PDType0Font typedFont = (PDType0Font) pdFont; + + if (typedFont.getDescendantFont() instanceof PDCIDFontType2) { + @SuppressWarnings("unused") + PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont(); + PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor(); + + fontDescriptor.getCOSObject().removeItem(cidSet); + } + } + } catch (IOException e) { + throw e; + } + // do stuff with the font + } + } + protected void prepareDocument() throws IOException { PDDocumentCatalog cat = doc.getDocumentCatalog(); From 327c6d8a3855b6e6715fb2c3198d1be74a7406aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timon=20F=C3=A4rber?= Date: Fri, 31 Jan 2025 18:58:31 +0100 Subject: [PATCH 23/67] feat: unable to perform XML-oriented attacks --- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 12 +++++++--- .../ZUGFeRD/ZUGFeRDVisualizer.java | 22 ++++++++++++++----- .../ZUGFeRD/VisualizationTest.java | 4 +++- .../validator/XMLValidator.java | 6 +++++ .../validator/ZUGFeRDValidator.java | 7 ++++++ 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 734f5f0c..7f38ddcc 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -1,5 +1,6 @@ package org.mustangproject.ZUGFeRD; +import javax.xml.XMLConstants; import org.apache.commons.io.IOUtils; import org.apache.pdfbox.Loader; import org.apache.pdfbox.pdmodel.PDDocument; @@ -258,9 +259,14 @@ public class ZUGFeRDInvoiceImporter { } private void setDocument() throws ParserConfigurationException, IOException, SAXException, ParseException { - final DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance(); - xmlFact.setNamespaceAware(true); - final DocumentBuilder builder = xmlFact.newDocumentBuilder(); + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setExpandEntityReferences(false); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + final DocumentBuilder builder = dbf.newDocumentBuilder(); final ByteArrayInputStream is = new ByteArrayInputStream(rawXML); /// is.skip(guessBOMSize(is)); document = builder.parse(is); diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index 8795b478..e133b028 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -21,6 +21,8 @@ package org.mustangproject.ZUGFeRD; import com.helger.commons.io.stream.StreamHelper; +import javax.xml.XMLConstants; +import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.io.IOUtils; import org.apache.fop.apps.*; import org.apache.fop.apps.io.ResourceResolverFactory; @@ -90,7 +92,8 @@ public class ZUGFeRDVisualizer { * @param fis inputstream (will be consumed) * @return (facturx = cii) */ - private EStandard findOutStandardFromRootNode(InputStream fis) { + private EStandard findOutStandardFromRootNode(InputStream fis) + throws ParserConfigurationException { String zf1Signature = "CrossIndustryDocument"; String zf2Signature = "CrossIndustryInvoice"; @@ -100,6 +103,11 @@ public class ZUGFeRDVisualizer { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); + dbf.setExpandEntityReferences(false); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); try { DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new InputSource(fis)); @@ -121,12 +129,14 @@ public class ZUGFeRDVisualizer { return null; } - public String visualize(String xmlFilename, Language lang) throws IOException, TransformerException { + public String visualize(String xmlFilename, Language lang) + throws IOException, TransformerException, ParserConfigurationException { FileInputStream fis = new FileInputStream(xmlFilename); return visualize(fis, lang); } - public String visualize(InputStream inputXml, Language lang) throws IOException, TransformerException { + public String visualize(InputStream inputXml, Language lang) + throws IOException, TransformerException, ParserConfigurationException { initTemplates(lang); String fileContent = new String(IOUtils.toByteArray(inputXml), StandardCharsets.UTF_8); @@ -211,7 +221,7 @@ public class ZUGFeRDVisualizer { } protected String toFOP(String xmlFilename) - throws IOException, TransformerException { + throws IOException, TransformerException, ParserConfigurationException { FileInputStream fis = new FileInputStream(xmlFilename); EStandard theStandard = findOutStandardFromRootNode(fis); @@ -264,7 +274,7 @@ public class ZUGFeRDVisualizer { */ try { fopInput = this.toFOP(XMLinputFile.getAbsolutePath()); - } catch (TransformerException | IOException e) { + } catch (TransformerException | IOException | ParserConfigurationException e) { LOGGER.error("Failed to apply FOP", e); } @@ -291,7 +301,7 @@ public class ZUGFeRDVisualizer { fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));//rewind :-( fopInput = toFOP(fis, theStandard); - } catch (TransformerException | IOException e) { + } catch (TransformerException | IOException | ParserConfigurationException e) { LOGGER.error("Failed to apply FOP", e); } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java index 88c4fccf..2b63a5da 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java @@ -20,6 +20,7 @@ */ package org.mustangproject.ZUGFeRD; +import javax.xml.parsers.ParserConfigurationException; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; import org.mustangproject.ZUGFeRD.ZUGFeRDVisualizer.Language; @@ -76,9 +77,10 @@ public class VisualizationTest extends ResourceCase { fail("TransformerException should not happen: " + e.getMessage()); } catch (IOException e) { fail("IOException should not happen: " + e.getMessage()); + } catch (ParserConfigurationException e) { + fail("ParserConfigurationException should not happen: " + e.getMessage()); } - assertNotNull(result); /* remove file endings so that tests can also pass after checking out from git with arbitrary options (which may include CSRF changes) diff --git a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java index c8bd3475..58dba911 100644 --- a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java @@ -10,6 +10,7 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Calendar; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.stream.StreamSource; @@ -151,6 +152,11 @@ public class XMLValidator extends Validator { final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); // otherwise we can not act namespace independently, i.e. use // document.getElementsByTagNameNS("*",... + dbf.setExpandEntityReferences(false); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); final DocumentBuilder db = dbf.newDocumentBuilder(); final InputSource is = new InputSource(new StringReader(zfXML)); diff --git a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java index d21317b1..cdab1874 100644 --- a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java @@ -17,6 +17,7 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -142,6 +143,12 @@ public class ZUGFeRDValidator { String xmlAsString = null; try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setExpandEntityReferences(false); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); DocumentBuilder db = dbf.newDocumentBuilder(); content = XMLTools.removeBOM(content); From 1b54d87e4093d549f00df5804de738a585db6552 Mon Sep 17 00:00:00 2001 From: cs Date: Tue, 4 Feb 2025 10:08:25 +0100 Subject: [PATCH 24/67] Fix the double assignment of invoices when using invoice setCorrection --- library/src/main/java/org/mustangproject/Invoice.java | 1 - 1 file changed, 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/Invoice.java b/library/src/main/java/org/mustangproject/Invoice.java index a03487ae..ce094c6a 100644 --- a/library/src/main/java/org/mustangproject/Invoice.java +++ b/library/src/main/java/org/mustangproject/Invoice.java @@ -154,7 +154,6 @@ public class Invoice implements IExportableTransaction { */ public Invoice setCorrection(String number) { setInvoiceReferencedDocumentID(number); - addInvoiceReferencedDocument(new ReferencedDocument(number)); documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE; return this; } From 5dd52580697e8516e4828f18efc6b5ce7bbb0a27 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 4 Feb 2025 14:10:52 +0100 Subject: [PATCH 25/67] updated history --- History.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/History.md b/History.md index 21dc49d3..4df8fdb6 100644 --- a/History.md +++ b/History.md @@ -1,19 +1,19 @@ -#705 -#707 --#708 --#709 -607 -649 -650 -665 -684 -703 -701 -691 - - - +2.16.2 +======= +2025-02-04 +-#705 specifiedLogisticsCharge is not imported +-#707 invoiceimporter may fail if certain values are not set +-#708 embedded files cannot be determined +-#709 ZUGFeRDInvoiceImporter ignored "first" embedded file in list of pdf attachments +-#607 Enable flexible PaymentReference and a DocumentName. +-#649 Reuse toPDF method to work without any dependencies to the file system +-#650 Add net.sf.offo:fop-hyph +-#665 Fix #632: Return ubl_creditnote as Standard for CreditNotes +-#684 Optimize validation-report to pdf functionality +-#703 Fill TaxExemptionReason during InvoiceImport. +-#701 Ensure Base64 decoding can handle newlines when decoding a FileAttachment +-#691 Fix current check failures. 2.16.1 ======= From 3bf9b0dca6a0ad499375eb5d850ee552db37e502 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 4 Feb 2025 14:15:19 +0100 Subject: [PATCH 26/67] [maven-release-plugin] prepare release core-2.16.2 --- Mustang-CLI/pom.xml | 6 +++--- library/pom.xml | 6 +++--- pom.xml | 4 ++-- validator/pom.xml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml index d5b924e9..729cf6bb 100644 --- a/Mustang-CLI/pom.xml +++ b/Mustang-CLI/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.2-SNAPSHOT + 2.16.2 4.0.0 org.mustangproject @@ -12,7 +12,7 @@ should also work for XRechnung/CII. jar - 2.16.2-SNAPSHOT + 2.16.2 UTF-8 11 @@ -23,7 +23,7 @@ org.mustangproject validator - 2.16.2-SNAPSHOT + 2.16.2 diff --git a/library/pom.xml b/library/pom.xml index 91695791..424a1fdb 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.16.2-SNAPSHOT + 2.16.2 4.0.0 org.mustangproject library - 2.16.2-SNAPSHOT + 2.16.2 jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -20,7 +20,7 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git https://github.com/ZUGFeRD/mustangproject - core-2.3.2 + core-2.16.2 diff --git a/pom.xml b/pom.xml index 7346b012..a39929b2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.16.2-SNAPSHOT pom + 2.16.2 pom Mustang @@ -19,7 +19,7 @@ scm:git:git://github.com/dexecutor/dependent-tasks-executor.git scm:git:git@github.com:dexecutor/dexecutor.git https://github.com/dexecutor/dependent-tasks-executor - core-2.3.2 + core-2.16.2 diff --git a/validator/pom.xml b/validator/pom.xml index 6c94fd9e..1227e0fd 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.2-SNAPSHOT + 2.16.2 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.16.2-SNAPSHOT + 2.16.2 @@ -38,7 +38,7 @@ ${project.groupId} library - 2.16.2-SNAPSHOT + 2.16.2 org.dom4j From 036de68d0ade14b34aa6f560a0c8232793cfa815 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 4 Feb 2025 14:15:22 +0100 Subject: [PATCH 27/67] [maven-release-plugin] prepare for next development iteration --- Mustang-CLI/pom.xml | 6 +++--- library/pom.xml | 6 +++--- pom.xml | 4 ++-- validator/pom.xml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml index 729cf6bb..d7c156e4 100644 --- a/Mustang-CLI/pom.xml +++ b/Mustang-CLI/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.2 + 2.16.3-SNAPSHOT 4.0.0 org.mustangproject @@ -12,7 +12,7 @@ should also work for XRechnung/CII. jar - 2.16.2 + 2.16.3-SNAPSHOT UTF-8 11 @@ -23,7 +23,7 @@ org.mustangproject validator - 2.16.2 + 2.16.3-SNAPSHOT diff --git a/library/pom.xml b/library/pom.xml index 424a1fdb..d3ed2ca7 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.16.2 + 2.16.3-SNAPSHOT 4.0.0 org.mustangproject library - 2.16.2 + 2.16.3-SNAPSHOT jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -20,7 +20,7 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git https://github.com/ZUGFeRD/mustangproject - core-2.16.2 + core-2.3.2 diff --git a/pom.xml b/pom.xml index a39929b2..45aa6c60 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.16.2 pom + 2.16.3-SNAPSHOT pom Mustang @@ -19,7 +19,7 @@ scm:git:git://github.com/dexecutor/dependent-tasks-executor.git scm:git:git@github.com:dexecutor/dexecutor.git https://github.com/dexecutor/dependent-tasks-executor - core-2.16.2 + core-2.3.2 diff --git a/validator/pom.xml b/validator/pom.xml index 1227e0fd..ab6398d7 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.2 + 2.16.3-SNAPSHOT 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.16.2 + 2.16.3-SNAPSHOT @@ -38,7 +38,7 @@ ${project.groupId} library - 2.16.2 + 2.16.3-SNAPSHOT org.dom4j From e30b4ba5b8adbfbc2a4076abce30942357e3c118 Mon Sep 17 00:00:00 2001 From: Andreas Reichmann Date: Wed, 5 Feb 2025 10:38:07 +0100 Subject: [PATCH 28/67] #562 OccurrenceDateTime Display OccurrenceDateTime (delivery address) in visualizations (HTML and PDF) when only the date is provided instead of the full delivery address. --- .../src/main/resources/stylesheets/cii-xr.xsl | 14 ++--- .../main/resources/stylesheets/xr-content.xsl | 2 +- .../src/test/resources/factur-x-vis.fr.html | 51 ++++++++++++++++++- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/library/src/main/resources/stylesheets/cii-xr.xsl b/library/src/main/resources/stylesheets/cii-xr.xsl index f741c903..cf03f74e 100644 --- a/library/src/main/resources/stylesheets/cii-xr.xsl +++ b/library/src/main/resources/stylesheets/cii-xr.xsl @@ -130,7 +130,7 @@ + select="./rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery"/> @@ -1146,18 +1146,18 @@ + match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery"> - + - + select="ram:ShipToTradeParty/ram:ID[empty(following-sibling::ram:GlobalID/@schemeID)]"/> + + select="ram:ActualDeliverySupplyChainEvent/ram:OccurrenceDateTime/udt:DateTimeString[@format='102']"/> - + diff --git a/library/src/main/resources/stylesheets/xr-content.xsl b/library/src/main/resources/stylesheets/xr-content.xsl index 4b8adb6f..cbc50ec2 100644 --- a/library/src/main/resources/stylesheets/xr-content.xsl +++ b/library/src/main/resources/stylesheets/xr-content.xsl @@ -789,7 +789,7 @@ - + diff --git a/library/src/test/resources/factur-x-vis.fr.html b/library/src/test/resources/factur-x-vis.fr.html index e22b12ef..5de16ae2 100644 --- a/library/src/test/resources/factur-x-vis.fr.html +++ b/library/src/test/resources/factur-x-vis.fr.html @@ -1905,6 +1905,55 @@
+
+
Informations de livraison
+
+
+
Identification du lieu de livraison:
+
+
+
+
Schéma de l'Identifiant:
+
+
+
+
Date de livraison:
+
10.11.2020
+
+
+
Nom du destinataire:
+
+
+
+
Rue / Numéro de maison:
+
+
+
+
Boîte postale:
+
+
+
+
Supplément d'adresse:
+
+
+
+
Code postal:
+
+
+
+
Lieu:
+
+
+
+
Région:
+
+
+
+
Pays:
+
+
+
+
@@ -2120,4 +2169,4 @@ function downloadData (element_id) { }); // - + \ No newline at end of file From e2290e36cd204455f8f2323d5ccd69cd68ca9d90 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 10 Feb 2025 07:50:57 +0100 Subject: [PATCH 29/67] closes #558 --- History.md | 1 + library/src/main/java/org/mustangproject/Charge.java | 5 ++++- .../org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java | 7 +++++++ .../src/test/java/org/mustangproject/ZUGFeRD/XRTest.java | 2 +- .../mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 4df8fdb6..b2b4ab64 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,4 @@ +#558 2.16.2 ======= diff --git a/library/src/main/java/org/mustangproject/Charge.java b/library/src/main/java/org/mustangproject/Charge.java index 6232611d..1b3320bf 100644 --- a/library/src/main/java/org/mustangproject/Charge.java +++ b/library/src/main/java/org/mustangproject/Charge.java @@ -134,7 +134,10 @@ public class Charge implements IZUGFeRDAllowanceCharge { if (totalAmount!=null) { return totalAmount; } else { - throw new RuntimeException("totalAmount must be set"); + if (percent==null) { + throw new RuntimeException("totalAmount must be set"); + } + return null; } } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 734f5f0c..4ce5ae56 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -704,6 +704,7 @@ public class ZUGFeRDInvoiceImporter { NodeList paymentMeansChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes(); IBAN = null; BIC = null; + String accountName = null; paymentMeansCode = null; paymentMeansInformation = null; for (int paymentMeansChildIndex = 0; paymentMeansChildIndex < paymentMeansChilds.getLength(); paymentMeansChildIndex++) { @@ -722,6 +723,9 @@ public class ZUGFeRDInvoiceImporter { if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds.item(accountChildIndex).getLocalName().equals("IBANID"))) {//CII IBAN = XMLTools.trimOrNull(accountChilds.item(accountChildIndex)); } + if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds.item(accountChildIndex).getLocalName().equals("AccountName"))) {//CII + accountName = XMLTools.trimOrNull(accountChilds.item(accountChildIndex)); + } } } if ((paymentMeansChilds.item(paymentMeansChildIndex).getLocalName() != null) && (paymentMeansChilds.item(paymentMeansChildIndex).getLocalName().equals("PayeeSpecifiedCreditorFinancialInstitution"))) { @@ -739,6 +743,9 @@ public class ZUGFeRDInvoiceImporter { if (BIC != null) { bd.setBIC(BIC); } + if (accountName!=null) { + bd.setAccountName(accountName); + } bankDetails.add(bd); } } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java index e860c9a2..5fc304ec 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java @@ -88,7 +88,7 @@ public class XRTest extends TestCase { FileAttachment fe1 = new FileAttachment("one.pdf", "application/pdf", "Alternative", b); Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()) - .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX"))) + .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX").setAccountName("kontoInhaber"))) .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setEmail("recipient@sample.org")) .addCashDiscount(new CashDiscount(new BigDecimal(2), 7)) .addCashDiscount(new CashDiscount(new BigDecimal(3), 14)) diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 8ad04529..6cef6ab2 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -340,6 +340,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { IZUGFeRDTradeSettlementPayment paym = (IZUGFeRDTradeSettlementPayment) invoice.getTradeSettlement()[0]; assertEquals("DE12500105170648489890", paym.getOwnIBAN()); assertEquals("COBADEFXXX", paym.getOwnBIC()); + assertEquals("kontoInhaber",paym.getAccountName()); assertTrue(invoice.getPayee() != null); From 6f19c3996a8f450db0cf789e8e06f61eea09348e Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 10 Feb 2025 08:06:46 +0100 Subject: [PATCH 30/67] #588 ubl --- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 4ce5ae56..6e5eb051 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -665,6 +665,7 @@ public class ZUGFeRDInvoiceImporter { List bankDetails = new ArrayList<>(); String directDebitMandateID = null; String IBAN = null, BIC = null, paymentMeansCode = null, paymentMeansInformation = null; + String accountName = null; for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) { // XMLTools.trimOrNull(nodes.item(i)))) { @@ -704,7 +705,6 @@ public class ZUGFeRDInvoiceImporter { NodeList paymentMeansChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes(); IBAN = null; BIC = null; - String accountName = null; paymentMeansCode = null; paymentMeansInformation = null; for (int paymentMeansChildIndex = 0; paymentMeansChildIndex < paymentMeansChilds.getLength(); paymentMeansChildIndex++) { @@ -793,12 +793,12 @@ public class ZUGFeRDInvoiceImporter { && (paymentMeansChilds.item(meansChildIndex).getLocalName().equals("PayeeFinancialAccount"))) { NodeList paymentTermChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes(); for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) { + + if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("Name"))) { + accountName = XMLTools.trimOrNull(paymentTermChilds.item(paymentTermChildIndex)); + } if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("ID"))) { IBAN = XMLTools.trimOrNull(paymentTermChilds.item(paymentTermChildIndex)); - if (IBAN != null) { - BankDetails bd = new BankDetails(IBAN); - bankDetails.add(bd); - } } } } @@ -816,6 +816,14 @@ public class ZUGFeRDInvoiceImporter { } } + if (IBAN != null) { + BankDetails bd = new BankDetails(IBAN); + if (accountName!=null) { + bd.setAccountName(accountName); + } + bankDetails.add(bd); + } + } From e76c5226399c53996407a1cf3033fc90e4c62e77 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 11 Feb 2025 13:36:24 +0100 Subject: [PATCH 31/67] closes #739 --- History.md | 2 + .../java/org/mustangproject/XMLTools.java | 8 +- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 15 ++ .../mustangproject/ZUGFeRD/ZF2PushTest.java | 11 +- .../ZUGFeRD/ZF2ZInvoiceImporterTest.java | 28 +++ .../src/test/resources/ubl/periods.ubl.xml | 197 ++++++++++++++++++ 6 files changed, 257 insertions(+), 4 deletions(-) create mode 100644 library/src/test/resources/ubl/periods.ubl.xml diff --git a/History.md b/History.md index b2b4ab64..e8f81cdd 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,6 @@ #558 +#686 +#739 2.16.2 ======= diff --git a/library/src/main/java/org/mustangproject/XMLTools.java b/library/src/main/java/org/mustangproject/XMLTools.java index d890c3d1..3fd71c63 100644 --- a/library/src/main/java/org/mustangproject/XMLTools.java +++ b/library/src/main/java/org/mustangproject/XMLTools.java @@ -129,7 +129,13 @@ public class XMLTools extends XMLWriter { * @return a util.Date, or null, if not parseable */ public static Date tryDate(String toParse) { - final SimpleDateFormat formatter = ZUGFeRDDateFormat.DATE.getFormatter(); + SimpleDateFormat formatter = null; + if (toParse.contains("-")) { + // from ubl + formatter = new SimpleDateFormat("yyyy-MM-dd"); + } else { + formatter = ZUGFeRDDateFormat.DATE.getFormatter(); + } try { return formatter.parse(toParse); } catch (final Exception e) { diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 6e5eb051..dc261749 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -775,6 +775,21 @@ public class ZUGFeRDInvoiceImporter { } } + xpr = xpath.compile("/*[local-name()=\"Invoice\"]/*[local-name()=\"InvoicePeriod\"]/*"); //UBL only + NodeList periodNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + + for (int periodChildIndex = 0; periodChildIndex < periodNodes.getLength(); periodChildIndex++) { + String localName=periodNodes.item(periodChildIndex).getLocalName(); + if ((localName != null) && (periodNodes.item(periodChildIndex).getLocalName().equals("StartDate"))) { + deliveryPeriodStart = XMLTools.trimOrNull(periodNodes.item(periodChildIndex)); + } + if ((localName != null) && (periodNodes.item(periodChildIndex).getLocalName().equals("EndDate"))) { + deliveryPeriodEnd = XMLTools.trimOrNull(periodNodes.item(periodChildIndex)); + } + + } + + if ((deliveryPeriodStart != null) && (deliveryPeriodEnd != null)) { zpp.setDetailedDeliveryPeriod(XMLTools.tryDate(deliveryPeriodStart), XMLTools.tryDate(deliveryPeriodEnd)); } else if (deliveryPeriodStart != null) { diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java index b1b61257..10f28a3a 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java @@ -32,6 +32,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; +import com.fasterxml.jackson.databind.ObjectMapper; import org.mustangproject.*; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; @@ -254,7 +255,7 @@ public class ZF2PushTest extends TestCase { // ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr", "55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number) // .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50))))); - ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()) + Invoice i=new Invoice().setDueDate(new Date()).setIssueDate(new Date()) .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815")) .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE") .setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562"))) @@ -263,8 +264,9 @@ public class ZF2PushTest extends TestCase { .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1")))) .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))) .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AnotherReason"))) - .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1))).addAllowance(new Allowance(new BigDecimal("1")))) - ); + .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1))).addAllowance(new Allowance(new BigDecimal("1")))); + ze.setTransaction(i); + String theXML = new String(ze.getProvider().getXML()); assertTrue(theXML.contains(" + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + 123 + 2025-02-10 + 2025-02-10 + 380 + document level 1/2 + document level 2/2 + CHF + + 2020-10-01 + 2020-10-05 + 432 + + + 28934 + 9384 + + + + abc123 + + + + 376zreurzu0983 + + + + sender@test.org + + 0009845 + + + teststr + teststadt + 55232 + + DE + + + + DE0815 + + VAT + + + + 9990815 + + NOVAT + + + + Test company + + + + + + recipient@test.org + + 0088:4304171000002 + + + teststr.12 + Hinterhaus 3 + Entenhausen + 55232 + + DE + + + + DE4711 + + VAT + + + + Franz Müller + + + 01779999999 + franz@mueller.de + + + + + 2020-11-02 + + + teststr.12a + Entenhausen + 55232 + + DE + + + + + + just the other side of the street + + + + + Verwendungszweck + + + Please remit until 10.02.2025 + + + false + discount + 0.20 + + S + 16.00 + + VAT + + + + + true + quick delivery charge + 0.50 + + S + 16.00 + + VAT + + + + + 0.20 + + 1.28 + 0.20 + + S + 16.00 + + VAT + + + + + + 0.98 + 1.28 + 1.48 + 0.20 + 0.50 + 1.48 + + + a123 + item level 1/1 + 1.00000000 + 0.98 + + 2020-01-13 + 2020-01-15 + + + xxx + + + Testprodukt + + 4711 + + + 2001015001325 + + + S + 16.00 + + VAT + + + + + 0.98 + 1.00 + + false + 0.0200 + 1.0000 + + + + From 9e9e0cf44402664f581aae8bf0b1e76ace85b4d2 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 11 Feb 2025 16:38:14 +0100 Subject: [PATCH 32/67] closes #740 --- .../main/java/org/mustangproject/Invoice.java | 6 +- .../ZUGFeRD/DeSerializationTest.java | 78 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/Invoice.java b/library/src/main/java/org/mustangproject/Invoice.java index a03487ae..7e011986 100644 --- a/library/src/main/java/org/mustangproject/Invoice.java +++ b/library/src/main/java/org/mustangproject/Invoice.java @@ -125,7 +125,11 @@ public class Invoice implements IExportableTransaction { * @return fluent setter */ public Invoice setAdditionalReferencedDocuments(FileAttachment[] fileArr) { - xmlEmbeddedFiles = new ArrayList<>(Arrays.asList(fileArr)); + if (fileArr!=null) { + xmlEmbeddedFiles = new ArrayList<>(Arrays.asList(fileArr)); + } else { + xmlEmbeddedFiles = new ArrayList<>(); + } return this; } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java index 2b18655f..bb41fb5a 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/DeSerializationTest.java @@ -34,6 +34,7 @@ import java.util.TimeZone; import javax.xml.xpath.XPathExpressionException; import org.junit.FixMethodOrder; +import org.junit.experimental.theories.FromDataPoints; import org.junit.runners.MethodSorters; import org.mustangproject.Allowance; import org.mustangproject.BankDetails; @@ -324,6 +325,83 @@ public class DeSerializationTest extends ResourceCase { assertNull(exText); + } + public void testNulledAttachments() { + + String json="{\n" + + " \"number\": \"471102\",\n" + + " \"currency\": \"EUR\",\n" + + " \"issueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" + + " \"dueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" + + " \"deliveryDate\": \"2018-03-04T00:00:00.000+01:00\",\n" + + " \"sender\": {\n" + + " \"name\": \"Lieferant GmbH\",\n" + + " \"zip\": \"80333\",\n" + + " \"street\": \"Lieferantenstraße 20\",\n" + + " \"location\": \"München\",\n" + + " \"country\": \"DE\",\n" + + " \"taxID\": \"201/113/40209\",\n" + + " \"vatID\": \"DE123456789\",\n" + + " \"globalID\": \"4000001123452\",\n" + + " \"globalIDScheme\": \"0088\"\n" + + " },\n" + + " \"recipient\": {\n" + + " \"name\": \"Kunden AG Mitte\",\n" + + " \"zip\": \"69876\",\n" + + " \"street\": \"Kundenstraße 15\",\n" + + " \"location\": \"Frankfurt\",\n" + + " \"country\": \"DE\"\n" + + " },\n" + + "\"additionalReferencedDocuments\":null,"+ + " \"zfitems\": [\n" + + " {\n" + + " \"price\": 9.9,\n" + + " \"quantity\": 20,\n" + + " \"product\": {\n" + + " \"unit\": \"H87\",\n" + + " \"name\": \"Trennblätter A4\",\n" + + " \"description\": \"\",\n" + + " \"vatpercent\": 19,\n" + + " \"taxCategoryCode\": \"S\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"price\": 5.5,\n" + + " \"quantity\": 50,\n" + + " \"product\": {\n" + + " \"unit\": \"H87\",\n" + + " \"name\": \"Joghurt Banane\",\n" + + " \"description\": \"\",\n" + + " \"vatpercent\": 7,\n" + + " \"taxCategoryCode\": \"S\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}\n"; + ObjectMapper mapper = new ObjectMapper(); + boolean exceptions=false; + try { + Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class); + } catch (JsonProcessingException e) { + exceptions=true; + } + assertFalse(exceptions); + } + + public void testItemAllowances() { + + String json="{\"number\":\"123\",\"currency\":\"EUR\",\"issueDate\":1738935176399,\"dueDate\":1738935176399,\"sender\":{\"name\":\"Test company\",\"zip\":\"55232\",\"street\":\"teststr\",\"location\":\"teststadt\",\"country\":\"DE\",\"taxID\":\"4711\",\"vatID\":\"DE0815\",\"vatid\":\"DE0815\"},\"recipient\":{\"name\":\"Franz Müller\",\"zip\":\"55232\",\"street\":\"teststr.12\",\"location\":\"Entenhausen\",\"country\":\"DE\",\"contact\":{\"name\":\"contact testname\",\"phone\":\"123456\",\"email\":\"contact.testemail@example.org\",\"fax\":\"0911623562\"}},\"zfitems\":[{\"price\":3.00,\"quantity\":1,\"basisQuantity\":1,\"product\":{\"unit\":\"C62\",\"name\":\"Testprodukt\",\"taxCategoryCode\":\"S\",\"vatpercent\":19,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"itemAllowances\":[{\"totalAmount\":0.1,\"categoryCode\":\"S\"}],\"value\":3.00},{\"price\":3.00,\"quantity\":1,\"basisQuantity\":1,\"product\":{\"unit\":\"C62\",\"name\":\"Testprodukt\",\"taxCategoryCode\":\"S\",\"vatpercent\":19,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"itemAllowances\":[{\"percent\":50,\"taxPercent\":0,\"categoryCode\":\"S\"}],\"value\":3.00},{\"price\":3.00,\"quantity\":2,\"basisQuantity\":1,\"product\":{\"unit\":\"C62\",\"name\":\"Testprodukt\",\"taxCategoryCode\":\"S\",\"vatpercent\":19,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"itemCharges\":[{\"totalAmount\":1,\"reason\":\"AnotherReason\",\"reasonCode\":\"ABK\",\"categoryCode\":\"S\"}],\"value\":3.00},{\"price\":3.00,\"quantity\":1,\"basisQuantity\":1,\"product\":{\"unit\":\"C62\",\"name\":\"Testprodukt\",\"taxCategoryCode\":\"S\",\"vatpercent\":19,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"itemAllowances\":[{\"totalAmount\":1,\"categoryCode\":\"S\"}],\"itemCharges\":[{\"totalAmount\":1,\"categoryCode\":\"S\"}],\"value\":3.00}],\"ownStreet\":\"teststr\",\"ownCountry\":\"DE\",\"zfcharges\":[{\"totalAmount\":1,\"taxPercent\":19,\"reason\":\"AReason\",\"reasonCode\":\"ABK\",\"categoryCode\":\"S\"}],\"ownLocation\":\"teststadt\",\"ownTaxID\":\"4711\",\"ownZIP\":\"55232\",\"ownVATID\":\"DE0815\",\"valid\":true}"; + ObjectMapper mapper = new ObjectMapper(); + try { + Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class); + TransactionCalculator tc=new TransactionCalculator(newInvoiceFromJSON); + assertEquals(new BigDecimal("19.52"),tc.getGrandTotal()); + + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + } public void testIssuerAssignedIDRoundtrip() { From 51ebbd8fb1a1b539440d61034b5a20d9529b3640 Mon Sep 17 00:00:00 2001 From: ean Date: Wed, 12 Feb 2025 08:30:47 +0100 Subject: [PATCH 33/67] read position accountingReference To new field ReceivableSpecifiedTradeAccountingAccount --- library/src/main/java/org/mustangproject/Item.java | 8 ++++++++ .../ZUGFeRD/IZUGFeRDExportableItem.java | 4 ++++ .../ZUGFeRD/ZF2ZInvoiceImporterTest.java | 12 ++++++++++++ 3 files changed, 24 insertions(+) diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index 0688530a..456e465a 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -42,6 +42,7 @@ public class Item implements IZUGFeRDExportableItem { protected ArrayList Allowances = new ArrayList<>(); protected ArrayList Charges = new ArrayList<>(); protected List includedNotes = null; + protected String accountingReference; //protected HashMap attributes = new HashMap<>(); /*** @@ -214,6 +215,8 @@ public class Item implements IZUGFeRDExportableItem { icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference); + icnm.getAsString("ReceivableSpecifiedTradeAccountingAccount").ifPresent(s -> this.accountingReference = s == null ? null : s.trim()); + icnm.getAsNodeMap("BillingSpecifiedPeriod").ifPresent(periodNode -> { Date start = periodNode.getAsNodeMap("StartDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(dts -> XMLTools.tryDate(dts)).orElse(null); Date end = periodNode.getAsNodeMap("EndDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(dts -> XMLTools.tryDate(dts)).orElse(null); @@ -538,4 +541,9 @@ public class Item implements IZUGFeRDExportableItem { public List getNotesWithSubjectCode() { return includedNotes; } + + @Override + public String getAccountingReference() { + return accountingReference; + } } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java index 45c210ea..6d68cdff 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java @@ -172,4 +172,8 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{ default List getNotesWithSubjectCode() { return null; } + + default String getAccountingReference() { + return null; + } } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index b0454510..f5ecb15a 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -585,4 +585,16 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { assertEquals("0", zii.importedInvoice.getDuePayable().toPlainString()); } + + @Test + public void test() throws FileNotFoundException, XPathExpressionException, ParseException { + File inputFile = getResourceAsFile("ORDER-X_EX01_ORDER_FULL_DATA-COMFORTorder-x.xml"); + ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); + zii.doIgnoreCalculationErrors(); + zii.setInputStream(new FileInputStream(inputFile)); + + Invoice invoice = zii.extractInvoice(); + assertEquals(3, invoice.getZFItems().length); + assertEquals("BUYER_ACCOUNTING_REF", invoice.getZFItems()[0].getAccountingReference()); + } } From 248f854d2a2ea5ffcdbd1465b534a6041f019b80 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 18 Feb 2025 09:56:42 +0100 Subject: [PATCH 34/67] closes #745 --- History.md | 1 + .../main/java/org/mustangproject/LegalOrganisation.java | 4 ++++ .../org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java | 7 ++++++- .../src/test/java/org/mustangproject/ZUGFeRD/XRTest.java | 7 ++++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index e8f81cdd..a33526a1 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,7 @@ #558 #686 #739 +#745 2.16.2 ======= diff --git a/library/src/main/java/org/mustangproject/LegalOrganisation.java b/library/src/main/java/org/mustangproject/LegalOrganisation.java index 705420c2..d5b6d42f 100644 --- a/library/src/main/java/org/mustangproject/LegalOrganisation.java +++ b/library/src/main/java/org/mustangproject/LegalOrganisation.java @@ -23,6 +23,10 @@ public class LegalOrganisation implements IZUGFeRDLegalOrganisation { this.schemedID = new SchemedID(scheme, ID); } + public LegalOrganisation(String ID) { + this.schemedID = new SchemedID(null, ID); + } + public LegalOrganisation(SchemedID schemedID, String tradingBusinessName) { this.schemedID = schemedID; this.tradingBusinessName=tradingBusinessName; diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 6958bb61..2b6ae8ec 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -149,7 +149,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { if (profile == Profiles.getByName("Minimum")) { xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + ""; } else { - xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + ""; + String schemeAttribute=""; + if ((party.getLegalOrganisation().getSchemedID().getScheme()!=null)&&(party.getLegalOrganisation().getSchemedID().getScheme().length()>0)) { + schemeAttribute="schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme())+"\""; + + } + xml += "" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + ""; } } if (party.getLegalOrganisation().getTradingBusinessName() != null) { diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java index 5fc304ec..ace63df4 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java @@ -52,12 +52,17 @@ public class XRTest extends TestCase { TradeParty recipient = new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"); recipient.setEmail("quack@ducktown.org"); Invoice i = createInvoice(recipient); - + String legalOrgID="aCustomSellerLegalOrgId"; + String sellerID="aSellerTradePartyID"; + i.getSender().setLegalOrganisation(new LegalOrganisation(legalOrgID)); + i.getSender().setID(sellerID); ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider(); zf2p.setProfile(Profiles.getByName("XRechnung")); zf2p.generateXML(i); String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8); assertTrue(theXML.contains(""+sellerID+""));// must be possible without scheme # + assertTrue(theXML.contains(""+legalOrgID+""));// must be possible without scheme # assertThat(theXML).valueByXPath("count(//*[local-name()='IncludedSupplyChainTradeLineItem'])") .asInt() .isEqualTo(1); //2 errors are OK because there is a known bug From adc9665b7ba402f2e43111bd2ce780ccbb61563f Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 18 Feb 2025 11:25:31 +0100 Subject: [PATCH 35/67] closes #747 --- History.md | 1 + .../main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java | 1 + 2 files changed, 2 insertions(+) diff --git a/History.md b/History.md index a33526a1..228c5679 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,7 @@ #686 #739 #745 +#747 2.16.2 ======= diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index 76abd748..d138bf15 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -86,6 +86,7 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter { case "urn:factur-x.eu:1p0:minimum": return "MINIMUM"; case "urn:ferd:CrossIndustryDocument:invoice:1p0:extended": + case "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended": case "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended": return "EXTENDED"; default: From b446d92b131dbfef0b1468ea069f9499ffc7864e Mon Sep 17 00:00:00 2001 From: langfr Date: Thu, 20 Feb 2025 20:48:22 +0000 Subject: [PATCH 36/67] Do not output Adresszusatz 1 as Postfach. --- library/src/main/resources/stylesheets/xr-mapping.xsl | 4 ++-- .../main/resources/stylesheets/xrechnung-html.de.ids.xsl | 8 ++++---- .../src/main/resources/stylesheets/xrechnung-html.de.xsl | 8 ++++---- library/src/main/resources/stylesheets/xrechnung-html.xsl | 8 ++++---- library/src/test/resources/factur-x-vis-extended.de.html | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/library/src/main/resources/stylesheets/xr-mapping.xsl b/library/src/main/resources/stylesheets/xr-mapping.xsl index be261921..064e4e43 100644 --- a/library/src/main/resources/stylesheets/xr-mapping.xsl +++ b/library/src/main/resources/stylesheets/xr-mapping.xsl @@ -398,7 +398,7 @@ BT-64 - + BT-65 @@ -486,7 +486,7 @@ BT-75 - + BT-76 diff --git a/library/src/main/resources/stylesheets/xrechnung-html.de.ids.xsl b/library/src/main/resources/stylesheets/xrechnung-html.de.ids.xsl index ab453b51..1c02ca63 100644 --- a/library/src/main/resources/stylesheets/xrechnung-html.de.ids.xsl +++ b/library/src/main/resources/stylesheets/xrechnung-html.de.ids.xsl @@ -1193,7 +1193,7 @@ function downloadData (element_id) {
-
Postfach (BT-51):
+
Adresszusatz (BT-51):
@@ -1258,7 +1258,7 @@ function downloadData (element_id) {
-
Postfach (BT-36):
+
Adresszusatz (BT-36):
@@ -1998,7 +1998,7 @@ function downloadData (element_id) {
-
Postfach (BT-65):
+
Adresszusatz (BT-65):
@@ -2111,7 +2111,7 @@ function downloadData (element_id) {
-
Postfach (BT-76):
+
Adresszusatz (BT-76):
diff --git a/library/src/main/resources/stylesheets/xrechnung-html.de.xsl b/library/src/main/resources/stylesheets/xrechnung-html.de.xsl index e2a2e930..052cb544 100644 --- a/library/src/main/resources/stylesheets/xrechnung-html.de.xsl +++ b/library/src/main/resources/stylesheets/xrechnung-html.de.xsl @@ -13,7 +13,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -166,7 +166,7 @@ - + @@ -189,7 +189,7 @@ - + diff --git a/library/src/main/resources/stylesheets/xrechnung-html.xsl b/library/src/main/resources/stylesheets/xrechnung-html.xsl index 54a0de84..6309f380 100644 --- a/library/src/main/resources/stylesheets/xrechnung-html.xsl +++ b/library/src/main/resources/stylesheets/xrechnung-html.xsl @@ -122,7 +122,7 @@
-
Postfach:
+
Adresszusatz:
@@ -179,7 +179,7 @@
-
Postfach:
+
Adresszusatz:
@@ -892,7 +892,7 @@
-
Postfach:
+
Adresszusatz:
@@ -998,7 +998,7 @@
-
Postfach:
+
Adresszusatz:
diff --git a/library/src/test/resources/factur-x-vis-extended.de.html b/library/src/test/resources/factur-x-vis-extended.de.html index ed5a147d..4ef990b5 100644 --- a/library/src/test/resources/factur-x-vis-extended.de.html +++ b/library/src/test/resources/factur-x-vis-extended.de.html @@ -762,7 +762,7 @@
KUNDENWEG 88
-
Postfach:
+
Adresszusatz:
@@ -826,7 +826,7 @@
BAHNHOFSTRASSE 99
-
Postfach:
+
Adresszusatz:
@@ -2203,7 +2203,7 @@
HAUPTSTRASSE 44
-
Postfach:
+
Adresszusatz:
From 64913c2ac805f819a92a81af98c2e55ce8176fa9 Mon Sep 17 00:00:00 2001 From: langfr Date: Fri, 28 Feb 2025 10:54:10 +0000 Subject: [PATCH 37/67] Use the dedicated class instead of var type. --- .../main/java/org/mustangproject/ZUGFeRD/OXPullProvider.java | 3 ++- .../java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/OXPullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/OXPullProvider.java index 7347d422..eb3ff49c 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/OXPullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/OXPullProvider.java @@ -32,6 +32,7 @@ import java.util.Map; import org.mustangproject.EStandard; import org.mustangproject.FileAttachment; +import org.mustangproject.ReferencedDocument; import org.mustangproject.XMLTools; public class OXPullProvider extends ZUGFeRD2PullProvider { @@ -460,7 +461,7 @@ public class OXPullProvider extends ZUGFeRD2PullProvider { xml += ""; } if (trans.getInvoiceReferencedDocuments() != null) { - for (var doc : trans.getInvoiceReferencedDocuments()) { + for (ReferencedDocument doc : trans.getInvoiceReferencedDocuments()) { xml += "" + "" + XMLTools.encodeXML(doc.getIssuerAssignedID()) + ""; diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 79ea800e..9cbf6afa 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -45,6 +45,7 @@ import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import org.mustangproject.FileAttachment; import org.mustangproject.IncludedNote; +import org.mustangproject.ReferencedDocument; import org.mustangproject.XMLTools; import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants; import org.slf4j.Logger; @@ -898,7 +899,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { xml += ""; } if (trans.getInvoiceReferencedDocuments() != null) { - for (var doc : trans.getInvoiceReferencedDocuments()) { + for (ReferencedDocument doc : trans.getInvoiceReferencedDocuments()) { xml += "" + "" + XMLTools.encodeXML(doc.getIssuerAssignedID()) + ""; From 20a995af38805eb9af92f1a991e84e290599f01c Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 3 Mar 2025 08:02:42 +0100 Subject: [PATCH 38/67] closes #761 --- History.md | 4 ++++ .../main/java/org/mustangproject/Item.java | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/History.md b/History.md index 228c5679..31120eb7 100644 --- a/History.md +++ b/History.md @@ -3,6 +3,10 @@ #739 #745 #747 +#710 +#712 +#725 +#761 2.16.2 ======= diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index 0688530a..4052eaf9 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -366,6 +366,29 @@ public class Item implements IZUGFeRDExportableItem { return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]); } + /*** + * jackson convenience method + */ + public void setItemAllowances(ArrayList theAllowances) { + if (theAllowances!=null) { + Allowances.clear(); + for (Allowance theAllowance : theAllowances) { + Allowances.add(theAllowance); + } + } + } + /*** + * jackson convenience method + */ + public void setItemCharges(ArrayList theCharges) { + if (theCharges!=null) { + Charges.clear(); + for (Charge theCharge : theCharges) { + Charges.add(theCharge); + } + } + } + @Override public IZUGFeRDAllowanceCharge[] getItemCharges() { if (Charges.isEmpty()) { From 8da541656ad7c5e0bad7b8dd8cd163c98851fc26 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 3 Mar 2025 08:06:42 +0100 Subject: [PATCH 39/67] beautified history --- History.md | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/History.md b/History.md index 31120eb7..6a355875 100644 --- a/History.md +++ b/History.md @@ -1,28 +1,31 @@ -#558 -#686 -#739 -#745 -#747 -#710 -#712 -#725 -#761 +2.16.3 +======= +2025-03-03 +- #558 ZUGFeRDInvoiceImporter does not read BankDetails.accountName +- #686 Item: add BillingSpecifiedPeriod +- #739 also parse invoiceperiod from ubl +- #745 be able to specify legalorganisation id without schema +- #747 correct profile detection +- #710 Validation Error due to empty elements +- #712 Correct bracket setting on condition for output of allowance reason. +- #725 Unable to perform XML-oriented attacks +- #761 Allow to set item allowance/charges from JSON 2.16.2 ======= 2025-02-04 --#705 specifiedLogisticsCharge is not imported --#707 invoiceimporter may fail if certain values are not set --#708 embedded files cannot be determined --#709 ZUGFeRDInvoiceImporter ignored "first" embedded file in list of pdf attachments --#607 Enable flexible PaymentReference and a DocumentName. --#649 Reuse toPDF method to work without any dependencies to the file system --#650 Add net.sf.offo:fop-hyph --#665 Fix #632: Return ubl_creditnote as Standard for CreditNotes --#684 Optimize validation-report to pdf functionality --#703 Fill TaxExemptionReason during InvoiceImport. --#701 Ensure Base64 decoding can handle newlines when decoding a FileAttachment --#691 Fix current check failures. +- #705 specifiedLogisticsCharge is not imported +- #707 invoiceimporter may fail if certain values are not set +- #708 embedded files cannot be determined +- #709 ZUGFeRDInvoiceImporter ignored "first" embedded file in list of pdf attachments +- #607 Enable flexible PaymentReference and a DocumentName. +- #649 Reuse toPDF method to work without any dependencies to the file system +- #650 Add net.sf.offo:fop-hyph +- #665 Fix #632: Return ubl_creditnote as Standard for CreditNotes +- #684 Optimize validation-report to pdf functionality +- #703 Fill TaxExemptionReason during InvoiceImport. +- #701 Ensure Base64 decoding can handle newlines when decoding a FileAttachment +- #691 Fix current check failures. 2.16.1 ======= From f870e2a476c875389f2a37417e07fb3bd97947dc Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 3 Mar 2025 11:21:09 +0100 Subject: [PATCH 40/67] fixed failing tests --- library/src/main/java/org/mustangproject/XMLTools.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/src/main/java/org/mustangproject/XMLTools.java b/library/src/main/java/org/mustangproject/XMLTools.java index 3fd71c63..e5e297f1 100644 --- a/library/src/main/java/org/mustangproject/XMLTools.java +++ b/library/src/main/java/org/mustangproject/XMLTools.java @@ -130,6 +130,9 @@ public class XMLTools extends XMLWriter { */ public static Date tryDate(String toParse) { SimpleDateFormat formatter = null; + if (toParse==null) { + return null; + } if (toParse.contains("-")) { // from ubl formatter = new SimpleDateFormat("yyyy-MM-dd"); From f3f3e7919d2df1710322c459e745a65f63c25e38 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 3 Mar 2025 11:30:04 +0100 Subject: [PATCH 41/67] updated history --- History.md | 1 + 1 file changed, 1 insertion(+) diff --git a/History.md b/History.md index 6a355875..d91af9a5 100644 --- a/History.md +++ b/History.md @@ -9,6 +9,7 @@ - #710 Validation Error due to empty elements - #712 Correct bracket setting on condition for output of allowance reason. - #725 Unable to perform XML-oriented attacks +- #685 Security Issue: XXE Vulnerability in ZUGFeRDInvoiceImporter (PR #725) - #761 Allow to set item allowance/charges from JSON 2.16.2 From 96a7115de1fdc89c7ecb8aad37cd8d42810b34d6 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 3 Mar 2025 11:33:55 +0100 Subject: [PATCH 42/67] [maven-release-plugin] prepare release core-2.16.3 --- Mustang-CLI/pom.xml | 6 +++--- library/pom.xml | 6 +++--- pom.xml | 4 ++-- validator/pom.xml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml index d7c156e4..0ff29730 100644 --- a/Mustang-CLI/pom.xml +++ b/Mustang-CLI/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.3-SNAPSHOT + 2.16.3 4.0.0 org.mustangproject @@ -12,7 +12,7 @@ should also work for XRechnung/CII. jar - 2.16.3-SNAPSHOT + 2.16.3 UTF-8 11 @@ -23,7 +23,7 @@ org.mustangproject validator - 2.16.3-SNAPSHOT + 2.16.3 diff --git a/library/pom.xml b/library/pom.xml index d3ed2ca7..b2007cca 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.16.3-SNAPSHOT + 2.16.3 4.0.0 org.mustangproject library - 2.16.3-SNAPSHOT + 2.16.3 jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -20,7 +20,7 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git https://github.com/ZUGFeRD/mustangproject - core-2.3.2 + core-2.16.3 diff --git a/pom.xml b/pom.xml index 45aa6c60..8df6c940 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.16.3-SNAPSHOT pom + 2.16.3 pom Mustang @@ -19,7 +19,7 @@ scm:git:git://github.com/dexecutor/dependent-tasks-executor.git scm:git:git@github.com:dexecutor/dexecutor.git https://github.com/dexecutor/dependent-tasks-executor - core-2.3.2 + core-2.16.3 diff --git a/validator/pom.xml b/validator/pom.xml index ab6398d7..db907b65 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.3-SNAPSHOT + 2.16.3 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.16.3-SNAPSHOT + 2.16.3 @@ -38,7 +38,7 @@ ${project.groupId} library - 2.16.3-SNAPSHOT + 2.16.3 org.dom4j From c3332c3329748534a6ee8d2aed174bd1da62d9b4 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 3 Mar 2025 11:33:56 +0100 Subject: [PATCH 43/67] [maven-release-plugin] prepare for next development iteration --- Mustang-CLI/pom.xml | 6 +++--- library/pom.xml | 6 +++--- pom.xml | 4 ++-- validator/pom.xml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml index 0ff29730..e040777d 100644 --- a/Mustang-CLI/pom.xml +++ b/Mustang-CLI/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.3 + 2.16.4-SNAPSHOT 4.0.0 org.mustangproject @@ -12,7 +12,7 @@ should also work for XRechnung/CII. jar - 2.16.3 + 2.16.4-SNAPSHOT UTF-8 11 @@ -23,7 +23,7 @@ org.mustangproject validator - 2.16.3 + 2.16.4-SNAPSHOT diff --git a/library/pom.xml b/library/pom.xml index b2007cca..9862a1d5 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.16.3 + 2.16.4-SNAPSHOT 4.0.0 org.mustangproject library - 2.16.3 + 2.16.4-SNAPSHOT jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -20,7 +20,7 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git https://github.com/ZUGFeRD/mustangproject - core-2.16.3 + core-2.3.2 diff --git a/pom.xml b/pom.xml index 8df6c940..5cc3f0ac 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.16.3 pom + 2.16.4-SNAPSHOT pom Mustang @@ -19,7 +19,7 @@ scm:git:git://github.com/dexecutor/dependent-tasks-executor.git scm:git:git@github.com:dexecutor/dexecutor.git https://github.com/dexecutor/dependent-tasks-executor - core-2.16.3 + core-2.3.2 diff --git a/validator/pom.xml b/validator/pom.xml index db907b65..8d8b7ff0 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.3 + 2.16.4-SNAPSHOT 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.16.3 + 2.16.4-SNAPSHOT @@ -38,7 +38,7 @@ ${project.groupId} library - 2.16.3 + 2.16.4-SNAPSHOT org.dom4j From d66761b017f3a22c76cc09ba207543d1b7bbc98b Mon Sep 17 00:00:00 2001 From: Jochen Staerk Date: Wed, 5 Mar 2025 11:23:50 +0100 Subject: [PATCH 44/67] Create SECURITY.md upon request :-) --- SECURITY.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..38dd608d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,29 @@ +# Security Policy + +## Supported Versions + +The following versions are currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 2.x.x | :white_check_mark: | +| < 2.0 | :x: | + +## Reporting a Vulnerability + +Feel free to submit issues to info at mustangproject.org with [security] indicated in the subject. +We may ask back questions but we usually open (or communicate about) an issue (potentially in a private location you would be provided with access to) and decide on the severity within two working days. + +Please indicate +* a proof of concept, if possible +* If any of the information you submit, e.g. an invoice which can not be [anonymized](https://github.com/ZUGFeRD/einvoice-anonymizer), is confidential +* A quick justification why you require a fix in a older version than he most up to date one, if you can not update to the most recent version +* If you require encrypted communication (our GPG fingerprint will likely be 68F4 2269 8165 F0F5 63CA A13B 7CB7 1548 B596 66A3) + + +## After your Report + +We try to fix critical issues in less than a week, and release a fixed version in less than two weeks. + +Thank you for keeping our software safe! + From 31861373f05b4591cc005e3697ded7378437c7b0 Mon Sep 17 00:00:00 2001 From: Peter Hermsdorf Date: Mon, 10 Mar 2025 16:37:59 +0100 Subject: [PATCH 45/67] ExemptionReason is repeated once used Closes Issue #614 --- .../ZUGFeRD/ZUGFeRD2PullProvider.java | 15 +++++----- .../org/mustangproject/ZUGFeRD/XRTest.java | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 79ea800e..f594a56c 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -342,8 +342,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { boolean hasDueDate = trans.getDueDate() != null; final SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); - String exemptionReason = ""; - if (trans.getPaymentTermDescription() != null) { paymentTermsDescription = XMLTools.encodeXML(trans.getPaymentTermDescription()); } @@ -409,9 +407,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { if (currentItem.getId()!=null) { lineIDStr=currentItem.getId(); } - if (currentItem.getProduct().getTaxExemptionReason() != null) { - exemptionReason = "" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + ""; - } final LineCalculator lc = new LineCalculator(currentItem); if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BasicWL"))) { xml += "" + @@ -532,9 +527,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + "" + "" + "" - + "VAT" - + exemptionReason - + "" + currentItem.getProduct().getTaxCategoryCode() + "" + + "VAT"; + + if (currentItem.getProduct().getTaxExemptionReason() != null) { + xml += "" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + ""; + } + + xml += "" + currentItem.getProduct().getTaxCategoryCode() + "" + "" + vatFormat(currentItem.getProduct().getVATPercent()) + "" + ""; diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java index ace63df4..6d0a2664 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java @@ -178,6 +178,36 @@ public class XRTest extends TestCase { } } + + public void testTaxExemptionReasonIssue() { + String orgname = "Test company"; + String number = "123"; + String amountStr = "1.00"; + BigDecimal amount = new BigDecimal(amountStr); + byte[] b = {12, 13}; + + Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()) + .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX").setAccountName("kontoInhaber"))) + .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setEmail("recipient@sample.org")) + .setReferenceNumber("991-01484-64")//leitweg-id + // not using any VAT, this is also a test of zero-rated goods: + .setNumber(number) + .addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO).setTaxCategoryCode("E").setTaxExemptionReason("Kleinunternehmer"), amount, new BigDecimal(1.0))) + .addItem(new Item(new Product("Testprodukt2", "", "C62", BigDecimal.ZERO).setTaxCategoryCode("S"), amount, new BigDecimal(1.0))) + .setPayee( new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199"))); + + + + ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider(); + + zf2p.setProfile(Profiles.getByName("XRechnung")); + zf2p.generateXML(i); + String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8); + assertThat(theXML).valueByXPath("count(//*[local-name()='ExemptionReason'])") + .asInt() + .isEqualTo(1); + } + private org.mustangproject.Invoice createInvoice(TradeParty recipient) { String orgname = "Test company"; From 2bcedad471da77a40b70c9cb3cec5f58daafa9c4 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Wed, 12 Mar 2025 13:43:12 +0100 Subject: [PATCH 46/67] working on #774 --- History.md | 3 +++ .../org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java | 6 ++++++ .../java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java | 4 ++++ .../main/java/org/mustangproject/validator/Validator.java | 4 ++++ 4 files changed, 17 insertions(+) diff --git a/History.md b/History.md index d91af9a5..f11df7d0 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,6 @@ +- #722 +- #774 + 2.16.3 ======= 2025-03-03 diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java index 686daa7c..db68ccb2 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java @@ -10,6 +10,7 @@ import org.mustangproject.ClasspathResolverURIAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.xml.XMLConstants; import javax.xml.transform.*; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; @@ -118,6 +119,11 @@ public class ValidationLogVisualizer { // Step 4: Setup JAXP using identity transformer TransformerFactory factory = TransformerFactory.newInstance(); + + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); Transformer transformer = factory.newTransformer(); // identity transformer // Step 5: Setup input and output for XSLT transformation diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index e133b028..6e42b632 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -356,6 +356,10 @@ public class ZUGFeRDVisualizer { // Step 4: Setup JAXP using identity transformer TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); Transformer transformer = factory.newTransformer(); // identity transformer // Step 5: Setup input and output for XSLT transformation diff --git a/validator/src/main/java/org/mustangproject/validator/Validator.java b/validator/src/main/java/org/mustangproject/validator/Validator.java index 545ee574..92e38228 100644 --- a/validator/src/main/java/org/mustangproject/validator/Validator.java +++ b/validator/src/main/java/org/mustangproject/validator/Validator.java @@ -61,6 +61,10 @@ public abstract class Validator { Source xmlData = new StreamSource(new ByteArrayInputStream(xmlRawData)); SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); try { + schemaFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + schemaFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + schemaFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); + schemaFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); Schema schema = schemaFactory.newSchema(schemaFile); javax.xml.validation.Validator validator = schema.newValidator(); validator.validate(xmlData); From 7fa2d7012868979a614828cfc80efefa8e1dd77f Mon Sep 17 00:00:00 2001 From: Ivan Pereverziev Date: Thu, 13 Mar 2025 11:26:35 +0100 Subject: [PATCH 47/67] Fix resource leaks in core file processing classes - Add try-with-resources for FileInputStream in ZUGFeRDVisualizer - Fix unclosed InputStream in ZUGFeRDInvoiceImporter with try-with-resources - Add explicit close() call for XMLWriter in ZUGFeRDValidator - Properly close DataInputStream in ZUGFeRDExporterFromPDFA - Fix resource management in Main.convertInputStreamToString --- .../org/mustangproject/commandline/Main.java | 20 +++++++++---------- .../java/org/mustangproject/XMLTools.java | 3 ++- .../ZUGFeRD/ZUGFeRDExporterFromPDFA.java | 7 ++++--- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 6 +++--- .../ZUGFeRD/ZUGFeRDVisualizer.java | 19 ++++++++++-------- .../validator/ZUGFeRDValidator.java | 1 + 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java index 275da445..5ab757fe 100755 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java @@ -307,12 +307,13 @@ public class Main { // Plain Java // based on https://mkyong.com/java/how-to-convert-inputstream-to-string-in-java/ private static String convertInputStreamToString(InputStream is) { - int DEFAULT_BUFFER_SIZE = 8192; - ByteArrayOutputStream result = new ByteArrayOutputStream(); - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - int length; - try { - while ((length = is.read(buffer)) != -1) { + try (InputStream inputStream = is) { + int DEFAULT_BUFFER_SIZE = 8192; + ByteArrayOutputStream result = new ByteArrayOutputStream(); + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + int length; + + while ((length = inputStream.read(buffer)) != -1) { result.write(buffer, 0, length); } @@ -320,11 +321,10 @@ public class Main { return result.toString(StandardCharsets.UTF_8.name()); } catch (IOException e) { e.printStackTrace(); + return null; + // Java 10 + // return result.toString(StandardCharsets.UTF_8); } - return null; - // Java 10 - // return result.toString(StandardCharsets.UTF_8); - } /*** diff --git a/library/src/main/java/org/mustangproject/XMLTools.java b/library/src/main/java/org/mustangproject/XMLTools.java index e5e297f1..5905fdae 100644 --- a/library/src/main/java/org/mustangproject/XMLTools.java +++ b/library/src/main/java/org/mustangproject/XMLTools.java @@ -220,7 +220,8 @@ public class XMLTools extends XMLWriter { } public static byte[] getBytesFromStream(InputStream fileinput) throws IOException { - return IOUtils.toByteArray (fileinput); + // Stream closing responsibility is with the caller + return IOUtils.toByteArray(fileinput); } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromPDFA.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromPDFA.java index c3b9299b..e128f0a6 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromPDFA.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromPDFA.java @@ -90,9 +90,10 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter { protected byte[] inputstreamToByteArray(InputStream fileInputStream) throws IOException { byte[] bytes = new byte[fileInputStream.available()]; - DataInputStream dataInputStream = new DataInputStream(fileInputStream); - dataInputStream.readFully(bytes); - return bytes; + try (DataInputStream dataInputStream = new DataInputStream(fileInputStream)) { + dataInputStream.readFully(bytes); + return bytes; + } } /*** diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index eb063440..d9c48c95 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -138,9 +138,9 @@ public class ZUGFeRDInvoiceImporter { return; } - final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata(); - - xmpString = new String(XMLTools.getBytesFromStream(XMP), StandardCharsets.UTF_8); + try (final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata()) { + xmpString = new String(XMLTools.getBytesFromStream(XMP), StandardCharsets.UTF_8); + } final PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles(); if (etn == null) { diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index 6e42b632..e9197e9f 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -131,8 +131,9 @@ public class ZUGFeRDVisualizer { public String visualize(String xmlFilename, Language lang) throws IOException, TransformerException, ParserConfigurationException { - FileInputStream fis = new FileInputStream(xmlFilename); - return visualize(fis, lang); + try (FileInputStream fis = new FileInputStream(xmlFilename)) { + return visualize(fis, lang); + } } public String visualize(InputStream inputXml, Language lang) @@ -222,12 +223,14 @@ public class ZUGFeRDVisualizer { protected String toFOP(String xmlFilename) throws IOException, TransformerException, ParserConfigurationException { - - FileInputStream fis = new FileInputStream(xmlFilename); - EStandard theStandard = findOutStandardFromRootNode(fis); - fis = new FileInputStream(xmlFilename);//rewind :-( - - return toFOP(fis, theStandard); + EStandard theStandard; + try (FileInputStream fis = new FileInputStream(xmlFilename)) { + theStandard = findOutStandardFromRootNode(fis); + } + + try (FileInputStream fis = new FileInputStream(xmlFilename)) { + return toFOP(fis, theStandard); + } } protected String toFOP(InputStream is, EStandard theStandard) diff --git a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java index cdab1874..c0aa0433 100644 --- a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java @@ -301,6 +301,7 @@ public class ZUGFeRDValidator { XMLWriter writer = new XMLWriter(sw, format); try { writer.write(document); + writer.close(); } catch (Exception e) { LOGGER.error(e.getMessage()); } From 8127b177fbef7183d8ac8c8dfbba8fc3951e9960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20R=C3=B6schke?= Date: Tue, 18 Mar 2025 08:43:00 +0100 Subject: [PATCH 48/67] Added XEE Protection features (that were missing according to Stackoverflow) --- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 17 ++++++++++++++--- .../ZUGFeRD/ZUGFeRDVisualizer.java | 17 ++++++++++++++--- .../mustangproject/validator/XMLValidator.java | 18 ++++++++++++++---- .../validator/ZUGFeRDValidator.java | 17 ++++++++++++++--- 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index eb063440..a1327c0d 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -260,12 +260,23 @@ public class ZUGFeRDInvoiceImporter { private void setDocument() throws ParserConfigurationException, IOException, SAXException, ParseException { final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setExpandEntityReferences(false); - dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //REDHAT + //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf + dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + + //OWASP + //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + // Disable external DTDs as well + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" + dbf.setXIncludeAware(false); + dbf.setExpandEntityReferences(false); + dbf.setNamespaceAware(true); final DocumentBuilder builder = dbf.newDocumentBuilder(); final ByteArrayInputStream is = new ByteArrayInputStream(rawXML); /// is.skip(guessBOMSize(is)); diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index 6e42b632..c4ab3051 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -102,12 +102,23 @@ public class ZUGFeRDVisualizer { String cioSignature = "SCRDMCCBDACIOMessageStructure"; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setExpandEntityReferences(false); - dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //REDHAT + //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf + dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + + //OWASP + //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + // Disable external DTDs as well + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" + dbf.setXIncludeAware(false); + dbf.setExpandEntityReferences(false); + dbf.setNamespaceAware(true); try { DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new InputSource(fis)); diff --git a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java index 58dba911..cf911dc6 100644 --- a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java @@ -150,13 +150,23 @@ public class XMLValidator extends Validator { */ final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); // otherwise we can not act namespace independently, i.e. use - // document.getElementsByTagNameNS("*",... - dbf.setExpandEntityReferences(false); - dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //REDHAT + //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf + dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + + //OWASP + //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + // Disable external DTDs as well + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" + dbf.setXIncludeAware(false); + dbf.setExpandEntityReferences(false); + dbf.setNamespaceAware(true); final DocumentBuilder db = dbf.newDocumentBuilder(); final InputSource is = new InputSource(new StringReader(zfXML)); diff --git a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java index cdab1874..214c5517 100644 --- a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java @@ -143,12 +143,23 @@ public class ZUGFeRDValidator { String xmlAsString = null; try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setExpandEntityReferences(false); - dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //REDHAT + //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf + dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + + //OWASP + //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + // Disable external DTDs as well + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" + dbf.setXIncludeAware(false); + dbf.setExpandEntityReferences(false); + dbf.setNamespaceAware(true); DocumentBuilder db = dbf.newDocumentBuilder(); content = XMLTools.removeBOM(content); From b2917ed742a55384219b4dc3c8b0ae937e948e11 Mon Sep 17 00:00:00 2001 From: itomic Date: Wed, 26 Mar 2025 13:46:25 +0100 Subject: [PATCH 49/67] #771: Added null check to prevent NullPointerException on Product Description --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 6e23e7f2..af0e2f4c 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -450,7 +450,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } xml += "" + XMLTools.encodeXML(currentItem.getProduct().getName()) + ""; - if (currentItem.getProduct().getDescription().length() > 0) { + if (currentItem.getProduct().getDescription() != null && currentItem.getProduct().getDescription().length() > 0) { xml += "" + XMLTools.encodeXML(currentItem.getProduct().getDescription()) + ""; From 732c9c94a1c9b72c9cec0b3e98251309e8104c2e Mon Sep 17 00:00:00 2001 From: itomic Date: Wed, 26 Mar 2025 13:52:12 +0100 Subject: [PATCH 50/67] #772: Made Deliver to party name (BT-70) optional to align with specification --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 6e23e7f2..3a838902 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -140,7 +140,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { xml += "" + XMLTools.encodeXML(party.getGlobalID()) + ""; } - xml += "" + XMLTools.encodeXML(party.getName()) + ""; + if (party.getName() != null && !party.getName().isEmpty()) { + xml += "" + XMLTools.encodeXML(party.getName()) + ""; + } if (party.getDescription() != null) { xml += "" + XMLTools.encodeXML(party.getDescription()) + ""; } From 76d54cfb28a6eda3585f28dbb518044769952ea6 Mon Sep 17 00:00:00 2001 From: rechtsanwalt-fortbildung <95717047+rechtsanwalt-fortbildung@users.noreply.github.com> Date: Tue, 1 Apr 2025 18:24:24 +0200 Subject: [PATCH 51/67] fix: capitial letter for ID in listID --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 6e23e7f2..761dda72 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -458,7 +458,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { if (currentItem.getProduct().getClassifications() != null && currentItem.getProduct().getClassifications().length > 0) { for (IDesignatedProductClassification classification : currentItem.getProduct().getClassifications()) { xml += "" - + " Date: Thu, 3 Apr 2025 13:22:58 +0200 Subject: [PATCH 52/67] added a forgotten file which is not really neccessary because it's XSLT equivalent is used --- .../XR_30/XRechnung-CII-validation.sch | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 validator/src/main/resources/schematron/XR_30/XRechnung-CII-validation.sch diff --git a/validator/src/main/resources/schematron/XR_30/XRechnung-CII-validation.sch b/validator/src/main/resources/schematron/XR_30/XRechnung-CII-validation.sch new file mode 100644 index 00000000..b38a931a --- /dev/null +++ b/validator/src/main/resources/schematron/XR_30/XRechnung-CII-validation.sch @@ -0,0 +1,305 @@ + + + Schematron Version @xr-schematron.version.full@ - XRechnung @xrechnung.version@ compatible - CII + + + + + + + + + + + + + + + + + + + + + + + + + + + + [BR-DE-30] Wenn "DIRECT DEBIT" BG-19 vorhanden ist, dann muss "Bank assigned creditor identifier" BT-90 übermittelt werden. + [BR-DE-31] Wenn "DIRECT DEBIT" BG-19 vorhanden ist, dann muss "Debited account identifier" BT-91 übermittelt werden. +[BR-DE-1] Eine Rechnung (INVOICE) muss Angaben zu "PAYMENT INSTRUCTIONS" (BG-16) enthalten. + [BR-DE-15] Das Element "Buyer reference" (BT-10) muss übermittelt werden. + [BR-DE-16] Wenn in einer Rechnung die Steuercodes S, Z, E, AE, K, G, L oder M verwendet werden, muss mindestens eines der Elemente "Seller VAT identifier" (BT-31), "Seller tax registration identifier" (BT-32) + oder "SELLER TAX REPRESENTATIVE PARTY" (BG-11) übermittelt werden. + + [BR-DE-17] Mit dem Element "Invoice type code" (BT-3) sollen ausschließlich folgende Codes aus der Codeliste UNTDID 1001 übermittelt werden: 326 (Partial invoice), 380 (Commercial invoice), 384 (Corrected invoice), 389 (Self-billed invoice) und 381 (Credit note),875 (Partial construction invoice), 876 (Partial final construction invoice), 877 (Final construction invoice). + [BR-DE-18] Skonto Zeilen in muessen diesem regulärem Ausdruck entsprechen: . Die Informationen zur Gewährung von Skonto müssen wie folgt im Element "Payment terms" (BT-20) übermittelt werden: Anzugeben ist im ersten Segment "SKONTO", im zweiten "TAGE=n", im dritten "PROZENT=n". Prozentzahlen sind ohne Vorzeichen sowie mit Punkt getrennt von zwei Nachkommastellen anzugeben. Liegt dem zu berechnenden Betrag nicht BT-115, "fälliger Betrag" zugrunde, sondern nur ein Teil des fälligen Betrags der Rechnung, ist der Grundwert zur Berechnung von Skonto als viertes Segment "BASISBETRAG=n" gemäß dem semantischen Datentypen Amount anzugeben. Jeder Eintrag beginnt mit einer #, die Segmente sind mit einer # getrennt und eine Zeile schließt mit einer # ab. Am Ende einer vollständigen Skontoangabe muss ein XML-konformer Zeilenumbruch folgen. Alle Angaben zur Gewährung von Skonto müssen in Großbuchstaben gemacht werden. Zusätzliches Whitespace (Leerzeichen, Tabulatoren oder Zeilenumbrüche) ist nicht zulässig. Andere Zeichen oder Texte als in den oberen Vorgaben genannt sind nicht zulässig. + + [BR-DE-22] Not all filename attributes of the embeddedDocumentBinaryObject elements are unique + [BR-DE-26] Wenn im Element Invoice type code (BT-3) der Code 384 (Corrected invoice) übergeben wird, soll PRECEDING INVOICE REFERENCE BG-3 mind. einmal vorhanden sein. + + + + [BR-DE-21] Das Element "Specification identifier" (BT-24) soll syntaktisch der Kennung des Standards XRechnung entsprechen. + + + + [BR-DE-2] Die Gruppe "SELLER CONTACT" (BG-6) muss übermittelt werden. + + + + [BR-DE-3] Das Element "Seller city" (BT-37) muss übermittelt werden. + [BR-DE-4] Das Element "Seller post code" (BT-38) muss übermittelt werden. + + + + [BR-DE-5] Das Element "Seller contact point" (BT-41) muss übermittelt werden. + [BR-DE-6] Das Element "Seller contact telephone number" (BT-42) muss übermittelt werden. + [BR-DE-7] Das Element "Seller contact email address" (BT-43) muss übermittelt werden. + [BR-DE-27] In BT-42 sollen mindestens drei Ziffern enthalten sein. + [BR-DE-28] In BT-43 soll genau ein @-Zeichen enthalten sein, welches nicht von einem Leerzeichen, einem Punkt, aber mindestens zwei Zeichen auf beiden Seiten flankiert werden soll. Ein Punkt sollte nicht am Anfang oder am Ende stehen. + + + + [BR-DE-8] Das Element "Buyer city" (BT-52) muss übermittelt werden. + [BR-DE-9] Das Element "Buyer post code" (BT-53) muss übermittelt werden. + + + [BR-TMP-2] BT-124 "External document location" muss eine absolute URL mit gültigem Schema enthalten. + + + + [BR-DE-10] Das Element "Deliver to city" (BT-77) muss übermittelt werden, wenn die Gruppe "DELIVER TO ADDRESS" (BG-15) übermittelt wird. + [BR-DE-11] Das Element "Deliver to post code" (BT-78) muss übermittelt werden, wenn die Gruppe "DELIVER TO ADDRESS" (BG-15) übermittelt wird. + + + + [BR-DE-19] "Payment account identifier" (BT-84) soll eine korrekte IBAN enthalten, wenn in "Payment means type code" (BT-81) mit dem Code 58 SEPA als Zahlungsmittel gefordert wird. + [BR-DE-23-a] Wenn BT-81 "Payment means type code" einen Schlüssel für Überweisungen enthält (30, 58), muss BG-17 "CREDIT TRANSFER" übermittelt werden. + [BR-DE-23-b] Wenn BT-81 "Payment means type code" einen Schlüssel für Überweisungen enthält (30, 58), dürfen BG-18 und BG-19 nicht übermittelt werden. + + + + [BR-DE-24-a] Wenn BT-81 "Payment means type code" einen Schlüssel für Kartenzahlungen enthält (48, 54, 55), muss genau BG-18 "PAYMENT CARD INFORMATION" übermittelt werden. + [BR-DE-24-b] Wenn BT-81 "Payment means type code" einen Schlüssel für Kartenzahlungen enthält (48, 54, 55), dürfen BG-17 und BG-19 nicht übermittelt werden. + + + + [BR-DE-20] "Debited account identifier" (BT-91) soll eine korrekte IBAN enthalten, wenn in "Payment means type code" (BT-81) mit dem Code 59 SEPA als Zahlungsmittel gefordert wird. + [BR-DE-25-a] Wenn BT-81 "Payment means type code" einen Schlüssel für Lastschriften enthält (59), muss genau BG-19 "DIRECT DEBIT" übermittelt werden. + [BR-DE-25-b] Wenn BT-81 "Payment means type code" einen Schlüssel für Lastschriften enthält (59), dürfen BG-17 und BG-18 nicht übermittelt werden. + + + + [BR-DE-14] Das Element "VAT category rate" (BT-119) muss übermittelt werden. + + + + + + + + + [BR-DEX-15] This CII file might use the concept of Sub Invoice Lines. However XRechnung does not support this. + + + + + [BR-DEX-04] Any scheme identifier in MUST be coded using one of the ISO 6523 ICD list. + + + + [BR-DEX-05] Any scheme identifier in MUST be coded using one of the ISO 6523 ICD list. + + + + [BR-DEX-06] Any scheme identifier in MUST be coded using one of the ISO 6523 ICD list. + + + + [BR-DEX-07] Any scheme identifier for an Endpoint Identifier in MUST belong to the CEF EAS code list. + + + + [BR-DEX-08] Any scheme identifier for a Delivery location identifier in MUST be coded using one of the ISO 6523 ICD list. + + + + + [BR-DEX-01] Das Element "Attached Document" (BT-125) benutzt einen nicht zulässigen MIME-Code: . Im Falle einer Extension darf zusätzlich zu der Liste der mime codes (definiert in Abschnitt 8.2, "Binary Object") der MIME-Code application/xml genutzt werden. + + + From 1074590f785140e8dd51a5f45910e7f30f2eb497 Mon Sep 17 00:00:00 2001 From: Philip Helger Date: Thu, 3 Apr 2025 18:22:30 +0200 Subject: [PATCH 53/67] Delete temp file on exit; #775 --- .../ZUGFeRD/PDFBoxUpdateMitigation.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/PDFBoxUpdateMitigation.java b/library/src/main/java/org/mustangproject/ZUGFeRD/PDFBoxUpdateMitigation.java index 652051b6..252cd7ba 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/PDFBoxUpdateMitigation.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/PDFBoxUpdateMitigation.java @@ -13,14 +13,14 @@ import org.apache.pdfbox.preflight.parser.PreflightParser; import jakarta.activation.DataSource; -// Copied from PDFBox preflight 2.0.x +// Copied from PDFBox preflight 2.0.x final class ByteArrayDataSource implements DataSource { private ByteArrayOutputStream data; private String type = null; private String name = null; - public ByteArrayDataSource (InputStream is) throws IOException + public ByteArrayDataSource (final InputStream is) throws IOException { data = new ByteArrayOutputStream (); IOUtils.copy (is, data); @@ -36,7 +36,7 @@ final class ByteArrayDataSource implements DataSource * @param type * the type to set */ - public void setType (String type) + public void setType (final String type) { this.type = type; } @@ -45,7 +45,7 @@ final class ByteArrayDataSource implements DataSource * @param name * the name to set */ - public void setName (String name) + public void setName (final String name) { this.name = name; } @@ -70,12 +70,13 @@ final class ByteArrayDataSource implements DataSource // Try to create an API similar to the 2.x one final class PreflightParserHelper { - private static File createTmpFile (InputStream input) throws IOException + private static File createTmpFile (final InputStream input) throws IOException { FileOutputStream fos = null; try { - File tmpFile = File.createTempFile ("mustang-pdf", ".pdf"); + final File tmpFile = File.createTempFile ("mustang-pdf", ".pdf"); + tmpFile.deleteOnExit (); fos = new FileOutputStream (tmpFile); IOUtils.copy (input, fos); return tmpFile; @@ -87,7 +88,7 @@ final class PreflightParserHelper } } - public static PreflightParser createPreflightParser (DataSource dataSource) throws IOException + public static PreflightParser createPreflightParser (final DataSource dataSource) throws IOException { return new PreflightParser (createTmpFile (dataSource.getInputStream ())); } From 12dd49a54e7450b28b73aab0defeb88e2a85b24f Mon Sep 17 00:00:00 2001 From: jstaerk Date: Tue, 8 Apr 2025 08:41:55 +0200 Subject: [PATCH 54/67] closes #809 --- History.md | 13 + .../main/java/org/mustangproject/Item.java | 2 +- .../ZUGFeRD/CalculationTest.java | 37 +- .../test/resources/Extended_fremdwaehrung.xml | 345 ++++++++++++++++++ 4 files changed, 395 insertions(+), 2 deletions(-) create mode 100644 library/src/test/resources/Extended_fremdwaehrung.xml diff --git a/History.md b/History.md index f11df7d0..718e3b1c 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,18 @@ - #722 - #774 +- #742/#753 +- #778 +- #759 +- #614, #770 +- #728 +- #776 +- #741 +- #782 +- #772 +- #775 +- #802 +- #809 + 2.16.3 ======= diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index 4052eaf9..552084d6 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -175,7 +175,7 @@ public class Item implements IZUGFeRDExportableItem { icnm.getAsNodeMap("ApplicableTradeTax") .flatMap(cnm -> cnm.getAsString("ExemptionReason")) .ifPresent(product::setTaxExemptionReason); - icnm.getAsNodeMap("SpecifiedTradeAllowanceCharge").ifPresent(stac -> { + icnm.getAllNodes("SpecifiedTradeAllowanceCharge").map(NodeMap::new).forEach(stac -> { stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> { String isChargeString=ci.getAsString("Indicator").get(); String percentString=stac.getAsStringOrNull("CalculationPercent"); diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java index 6d84a0f6..1e993dc9 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java @@ -3,20 +3,27 @@ package org.mustangproject.ZUGFeRD; import static java.math.BigDecimal.TEN; import static java.math.BigDecimal.valueOf; import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import org.junit.Test; import org.mustangproject.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.xml.xpath.XPathExpressionException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.math.BigDecimal; +import java.text.ParseException; import java.text.SimpleDateFormat; /*** * tests the linecalculator and transactioncalculator classes * */ -public class CalculationTest { +public class CalculationTest extends ResourceCase { private static final Logger LOGGER = LoggerFactory.getLogger(CalculationTest.class); @Test @@ -72,6 +79,34 @@ public class CalculationTest { assertEquals(valueOf(314.1184).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros()); } + @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(); + boolean hasExceptions=false; + try { + zii.setInputStream(new FileInputStream(inputCII)); + + invoice=zii.extractInvoice(); + } catch (XPathExpressionException | ParseException e) { +// handle Exceptions + hasExceptions=true; + } catch (FileNotFoundException e) { + hasExceptions=true; + } + assertFalse(hasExceptions); + // Reading ZUGFeRD + + final TransactionCalculator calculator = new TransactionCalculator(invoice); + + assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros()); + } + @Test public void testTotalCalculatorGrandTotalRounding() { diff --git a/library/src/test/resources/Extended_fremdwaehrung.xml b/library/src/test/resources/Extended_fremdwaehrung.xml new file mode 100644 index 00000000..4d10dea8 --- /dev/null +++ b/library/src/test/resources/Extended_fremdwaehrung.xml @@ -0,0 +1,345 @@ + + + + + + + + + + Beispielgeschäftsprozess + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + 47110815 + RECHNUNG + 380 + + 20241115 + + + Mitglieder der Geschäftsleitung + H. Meier Geschäftsführer + T. Müller Prokurist + HRB Braunschweig 12345 + REG + + + Vom 17. Dezember 2024 bis 6. Januar 2025 haben wir Betriebsferien. + AAI + + + Aus konzern-internen Gründen wird der Steuerbetrag sowohl in der Rechungswährung (EUR) als auch in der Buchwährung (GBP) ausgegeben. + TXD + + + + + + 1 + + Materialzertifikat X-234 gem ISO XYZ. + Ware bleibt bis zur vollständigen Bezahlung unser Eigentum. + + + + + CO-123/V2A + Toolbox 0815 + Stahlcoil + + DE + + + + + ORDER84359 + 1 + + + 100.00 + 1 + + + 100 + 1 + + + + 10 + + + + VAT + S + 19 + + + + false + + 10 + 1000 + 100 + 64 + Lagerware + + + + false + + 1000 + 50 + 70 + Direktbelieferung + + + 850 + + + + + + 12345676 + Rohstoff AG Salzgitter + + 38226 + Marktstr. 153 + Salzgitter + DE + + + DE123456789 + + + + 75969813 + Metallbau Leipzig GmbH & Co. KG + + 12345 + Pappelallee 15 + Hof 3 + Leipzig + DE + + + 04 0 11 000 - 12345 12345 - 35 + + + + Global Supplies Financial Services + + 12345 + Friedrichstraße 165 + Berlin + DE + + + DE1334567 + + + + + + 75969815 + Metallbau Leipzig GmbH & Co. KG + + 12347 + Eichenpromenade 37 + Tor 1 + Metallstadt + DE + + + 999999999 + + + + + 20241111 + + + + + EUR + GBP + + 432156789 + Global Supplies Financial Services + + 12345 + Friedrichstraße 165 + Berlin + DE + + + + GBP + EUR + 1.12244 + + 20181031 + + + + 58 + + DE77 3707 0060 0321 9870 00 + Global Supplies Financial Services + + + + 163.16 + VAT + 858.75 + 850 + 8.75 + S + 19 + + + + 20181001 + + + 20181031 + + + + + true + + 30 + ABK + Einwegverpackung + + VAT + S + 19 + + + + + false + + 2.5 + 850 + 21.25 + 102 + Stammkundenrabatt + + VAT + S + 19 + + + + Zahlbar ohne Abschlag bis + + 20241201 + + + + Zahlbar mit 2% Skonto bis + + 20241120 + + + + 850 + 30 + 21.25 + 858.75 + 163.16 + 183.14 + 1021.91 + 500 + 521.91 + + + + From c30ceb9cf484f5d15b332cfa1b4ce7ae0469306d Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 14 Apr 2025 09:46:34 +0200 Subject: [PATCH 55/67] closes #812 --- History.md | 1 + .../org/mustangproject/FileAttachment.java | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 718e3b1c..8d09ce9f 100644 --- a/History.md +++ b/History.md @@ -12,6 +12,7 @@ - #775 - #802 - #809 +- #812 2.16.3 diff --git a/library/src/main/java/org/mustangproject/FileAttachment.java b/library/src/main/java/org/mustangproject/FileAttachment.java index ed1fe39f..99a60419 100644 --- a/library/src/main/java/org/mustangproject/FileAttachment.java +++ b/library/src/main/java/org/mustangproject/FileAttachment.java @@ -9,7 +9,7 @@ public class FileAttachment { protected String filename; protected String mimetype; - protected String relation; + protected String relation = "Unspecified"; protected String description; protected byte[] data; @@ -29,6 +29,13 @@ public class FileAttachment { this.description = "Additional file attachment"; } + public FileAttachment(String filename, String mimetype, byte[] data) { + this.filename = filename; + this.mimetype = mimetype; + this.data = data; + this.description = "Additional file attachment"; + } + public String getDescription() { return description; } @@ -60,6 +67,28 @@ public class FileAttachment { return relation; } + /*** + * only needed when embedded in PDF described + * + * values + * - Source shall be used if this file specification is the original + * source material for the associated content. + * - Data shall be used if this file specification represents information + * used to derive a visual presentation, such as for a table or a + * graph. + * - Alternative shall be used if this file specification is an alternative + * representation of content, for example audio. + * - Supplement shall be used if this file specification represents a + * supplemental representation of the original source or data that + * may be more easily consumable (e.g. A MathML version of an + * equation). + * - Unspecified shall be used when the relationship is not known + * or cannot be described using one of the other values. + * @param relation String: either : Source, Data or Alternative. Usually Data, except source if the file attachment + * is the basis for the pdf (xrechnung2fx) or Alternative if it contains the same content (e.g. the + * factur-x.xml file in a factur-x PDF) + * @return fluent setter + */ public FileAttachment setRelation(String relation) { this.relation = relation; return this; From 5a39e50bcf0c229fe6a341c1ad45c8d496aef506 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 14 Apr 2025 09:58:07 +0200 Subject: [PATCH 56/67] remving disabling unsupported features --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java | 3 --- .../test/java/org/mustangproject/ZUGFeRD/CalculationTest.java | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index da340ad1..d4f280a9 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -371,9 +371,6 @@ public class ZUGFeRDVisualizer { // Step 4: Setup JAXP using identity transformer TransformerFactory factory = TransformerFactory.newInstance(); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - factory.setFeature("http://xml.org/sax/features/external-general-entities", false); - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); Transformer transformer = factory.newTransformer(); // identity transformer // Step 5: Setup input and output for XSLT transformation diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java index 1e993dc9..9f3f3ea2 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java @@ -82,7 +82,7 @@ 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(); @@ -105,6 +105,8 @@ inputCII=new File("C:\\Users\\jstaerk\\workspace\\XMLExamples\\zfdiverses\\20250 final TransactionCalculator calculator = new TransactionCalculator(invoice); assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros()); + + */ } From 060aca216a82934cd8d89bae253e8289341c7300 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 14 Apr 2025 10:13:32 +0200 Subject: [PATCH 57/67] removed disabling of required features --- .../src/main/java/org/mustangproject/validator/Validator.java | 4 +--- .../java/org/mustangproject/validator/ZUGFeRDValidator.java | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/validator/src/main/java/org/mustangproject/validator/Validator.java b/validator/src/main/java/org/mustangproject/validator/Validator.java index 92e38228..539bf4c9 100644 --- a/validator/src/main/java/org/mustangproject/validator/Validator.java +++ b/validator/src/main/java/org/mustangproject/validator/Validator.java @@ -61,10 +61,8 @@ public abstract class Validator { Source xmlData = new StreamSource(new ByteArrayInputStream(xmlRawData)); SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); try { - schemaFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); +// schemaFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); schemaFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - schemaFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); - schemaFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); Schema schema = schemaFactory.newSchema(schemaFile); javax.xml.validation.Validator validator = schema.newValidator(); validator.validate(xmlData); diff --git a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java index 1b328cd0..a64efdce 100644 --- a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java @@ -152,7 +152,6 @@ public class ZUGFeRDValidator { //OWASP //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); // Disable external DTDs as well dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); From f635f355bef7abcf83b2ac0d6dcd4d5b1df3dcc9 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 14 Apr 2025 10:28:41 +0200 Subject: [PATCH 58/67] further removal disabling of required features --- .../src/main/java/org/mustangproject/validator/Validator.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/validator/src/main/java/org/mustangproject/validator/Validator.java b/validator/src/main/java/org/mustangproject/validator/Validator.java index 539bf4c9..545ee574 100644 --- a/validator/src/main/java/org/mustangproject/validator/Validator.java +++ b/validator/src/main/java/org/mustangproject/validator/Validator.java @@ -61,8 +61,6 @@ public abstract class Validator { Source xmlData = new StreamSource(new ByteArrayInputStream(xmlRawData)); SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); try { -// schemaFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - schemaFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); Schema schema = schemaFactory.newSchema(schemaFile); javax.xml.validation.Validator validator = schema.newValidator(); validator.validate(xmlData); From 17bc5c483f83b83e8ecf18f2109bf4e3fdc4881c Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 14 Apr 2025 11:10:43 +0200 Subject: [PATCH 59/67] =?UTF-8?q?Correcting=20calculation=20for=20extended?= =?UTF-8?q?=5Ffremdwaehrung=20(issue=20#764),=20now=20the=20following=20er?= =?UTF-8?q?rors=20arise:=20[ERROR]=20=20=20CalculationTest.testTotalCalcul?= =?UTF-8?q?atorGrandTotalRounding:223=20expected:<101.86>=20but=20was:<104?= =?UTF-8?q?.04>=20[ERROR]=20=20=20DeSerializationTest.testItemAllowances:3?= =?UTF-8?q?98=20expected:<19.52>=20but=20was:<18.33>=20[ERROR]=20=20=20ZF2?= =?UTF-8?q?PushTest.testAllowancesExport:648=20expected:<[4046].00>=20but?= =?UTF-8?q?=20was:<[10829].00>=20[ERROR]=20=20=20ZF2PushTest.testItemCharg?= =?UTF-8?q?esAllowancesExport:286=20expected:<1[9.52]>=20but=20was:<1[8.33?= =?UTF-8?q?]>=20[ERROR]=20=20=20ZF2PushTest.testPushEdge:609=20ParseExcept?= =?UTF-8?q?ion=20should=20not=20be=20raised=20[ERROR]=20=20=20ZF2ZInvoiceI?= =?UTF-8?q?mporterTest.testEdgeInvoiceImport:179=20[ERROR]=20=20=20ZF2ZInv?= =?UTF-8?q?oiceImporterTest.testItemAllowancesChargesImport:265=20[ERROR]?= =?UTF-8?q?=20=20=20CalculationTest.testLineCalculatorInclusiveAllowance:5?= =?UTF-8?q?5=20=C2=BB=20Arithmetic=20Non-terminating=20decimal=20expansion?= =?UTF-8?q?;=20no=20exact=20representable=20decimal=20result.=20[ERROR]=20?= =?UTF-8?q?=20=20CalculationTest.testLineCalculatorInclusiveAllowanceAndCh?= =?UTF-8?q?arge:75=20=C2=BB=20Arithmetic=20Non-terminating=20decimal=20exp?= =?UTF-8?q?ansion;=20no=20exact=20representable=20decimal=20result.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/src/main/java/org/mustangproject/Charge.java | 6 +++--- .../org/mustangproject/ZUGFeRD/LineCalculator.java | 11 +++++++---- .../org/mustangproject/ZUGFeRD/CalculationTest.java | 7 +++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/library/src/main/java/org/mustangproject/Charge.java b/library/src/main/java/org/mustangproject/Charge.java index 1b3320bf..aaa14ba2 100644 --- a/library/src/main/java/org/mustangproject/Charge.java +++ b/library/src/main/java/org/mustangproject/Charge.java @@ -121,10 +121,10 @@ public class Charge implements IZUGFeRDAllowanceCharge { @Override public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) { - if (percent!=null) { - return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100))); - } else if(totalAmount != null) { + if(totalAmount != null) { return totalAmount; + } else if (percent!=null) { + return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100))); } else { throw new RuntimeException("percent must be set"); } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java index d17ccfec..67d4ab35 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java @@ -42,21 +42,24 @@ public class LineCalculator { vatPercent = BigDecimal.ZERO; } BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100)); - priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159 - price = priceGross.subtract(allowance).add(charge); + BigDecimal quantity=BigDecimal.ZERO; if ((currentItem!=null)&&(currentItem.getQuantity()!=null)) { quantity=currentItem.getQuantity(); } + price=currentItem.getPrice(); + BigDecimal delta=charge.subtract(allowanceItemTotal).subtract(allowance); + delta=delta.divide(currentItem.getQuantity()); + priceGross=currentItem.getPrice().add(delta); // Division/Zero occurred here. // Used the setScale only because that's also done in getBasisQuantity BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ONE.setScale(4) : currentItem.getBasisQuantity(); - itemTotalNetAmount = quantity.multiply(price).divide(basisQuantity, 18, RoundingMode.HALF_UP) - .subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP); + itemTotalNetAmount = quantity.multiply(currentItem.getPrice()).divide(basisQuantity, 18, RoundingMode.HALF_UP) + .subtract(allowanceItemTotal).subtract(allowance).add(charge).setScale(2, RoundingMode.HALF_UP); itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator); } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java index 9f3f3ea2..73499123 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java @@ -82,9 +82,8 @@ 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(); @@ -104,9 +103,9 @@ inputCII=new File("C:\\Users\\jstaerk\\workspace\\XMLExamples\\zfdiverses\\20250 final TransactionCalculator calculator = new TransactionCalculator(invoice); - assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros()); + assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getDuePayable().stripTrailingZeros()); + - */ } From 9e77433a13ed41709471d225526f95cfae41e44c Mon Sep 17 00:00:00 2001 From: jstaerk Date: Thu, 17 Apr 2025 09:42:45 +0200 Subject: [PATCH 60/67] fixing an exception --- .../main/java/org/mustangproject/ZUGFeRD/LineCalculator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java index 67d4ab35..d7e010cb 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java @@ -51,7 +51,7 @@ public class LineCalculator { price=currentItem.getPrice(); BigDecimal delta=charge.subtract(allowanceItemTotal).subtract(allowance); - delta=delta.divide(currentItem.getQuantity()); + delta=delta.divide(currentItem.getQuantity(), 18, RoundingMode.HALF_UP); priceGross=currentItem.getPrice().add(delta); // Division/Zero occurred here. // Used the setScale only because that's also done in getBasisQuantity From 31c5d0461efb590959aeb8bc6c6dc8206634db5f Mon Sep 17 00:00:00 2001 From: jstaerk Date: Fri, 18 Apr 2025 13:42:29 +0200 Subject: [PATCH 61/67] outsourcing calc correction to issues/764 --- library/src/main/java/org/mustangproject/Charge.java | 6 +++--- .../org/mustangproject/ZUGFeRD/LineCalculator.java | 11 ++++------- .../org/mustangproject/ZUGFeRD/CalculationTest.java | 7 ++++--- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/library/src/main/java/org/mustangproject/Charge.java b/library/src/main/java/org/mustangproject/Charge.java index aaa14ba2..1b3320bf 100644 --- a/library/src/main/java/org/mustangproject/Charge.java +++ b/library/src/main/java/org/mustangproject/Charge.java @@ -121,10 +121,10 @@ public class Charge implements IZUGFeRDAllowanceCharge { @Override public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) { - if(totalAmount != null) { - return totalAmount; - } else if (percent!=null) { + if (percent!=null) { return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100))); + } else if(totalAmount != null) { + return totalAmount; } else { throw new RuntimeException("percent must be set"); } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java index d7e010cb..d17ccfec 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java @@ -42,24 +42,21 @@ public class LineCalculator { vatPercent = BigDecimal.ZERO; } BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100)); - + priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159 + price = priceGross.subtract(allowance).add(charge); BigDecimal quantity=BigDecimal.ZERO; if ((currentItem!=null)&&(currentItem.getQuantity()!=null)) { quantity=currentItem.getQuantity(); } - price=currentItem.getPrice(); - BigDecimal delta=charge.subtract(allowanceItemTotal).subtract(allowance); - delta=delta.divide(currentItem.getQuantity(), 18, RoundingMode.HALF_UP); - priceGross=currentItem.getPrice().add(delta); // Division/Zero occurred here. // Used the setScale only because that's also done in getBasisQuantity 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); } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java index 73499123..9f3f3ea2 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/CalculationTest.java @@ -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()); + */ } From f1adde1abadb55e0134ccccbc72edad2a4dcefff Mon Sep 17 00:00:00 2001 From: jstaerk Date: Fri, 18 Apr 2025 16:09:26 +0200 Subject: [PATCH 62/67] closes #818 --- History.md | 1 + .../org/mustangproject/commandline/Main.java | 14 ++- .../commandline/ValidatorFileWalker.java | 119 +++++++++--------- 3 files changed, 73 insertions(+), 61 deletions(-) diff --git a/History.md b/History.md index 8d09ce9f..03373820 100644 --- a/History.md +++ b/History.md @@ -13,6 +13,7 @@ - #802 - #809 - #812 +- #818 2.16.3 diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java index 5ab757fe..5d7806ab 100755 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java @@ -347,8 +347,11 @@ public class Main { Option attachmentOpt = new Option("attachments", "attachments", true, "File attachments"); attachmentOpt.setValueSeparator(','); attachmentOpt.setArgs(Option.UNLIMITED_VALUES); - options.addOption(attachmentOpt); + Option excludeOpt = new Option("exclude", "exclude", true, "Files to exclude from recursive directory traversal"); + excludeOpt.setValueSeparator(','); + excludeOpt.setArgs(Option.UNLIMITED_VALUES); + options.addOption(excludeOpt); options.addOption(new Option("source", "source", true, "which source file to use")); options.addOption(new Option("source-xml", "source-xml", true, "which source file to use")); options.addOption(new Option("language", "language", true, "output language (en, de or fr)")); @@ -389,6 +392,7 @@ public class Main { String zugferdProfile = cmd.getOptionValue("profile"); String[] attachmentFilenames = cmd.hasOption("attachments") ? cmd.getOptionValues("attachments") : null; + String[] excludedFilenames = cmd.hasOption("exclude") ? cmd.getOptionValues("exclude") : null; ArrayList attachments = new ArrayList<>(); @@ -433,9 +437,9 @@ public class Main { } else if ((action != null) && (action.equals("validate"))) { optionsRecognized = performValidate(sourceName, noNotices, cmd.getOptionValue("logAppend"), LogAsPDF); } else if ((action != null) && (action.equals("validateExpectValid"))) { - optionsRecognized = performValidateExpect(true, directoryName); + optionsRecognized = performValidateExpect(true, directoryName, excludedFilenames); } else if ((action != null) && (action.equals("validateExpectInvalid"))) { - optionsRecognized = performValidateExpect(false, directoryName); + optionsRecognized = performValidateExpect(false, directoryName, excludedFilenames); } } catch (UnrecognizedOptionException ex) { @@ -487,8 +491,8 @@ public class Main { return optionsRecognized; } - private static boolean performValidateExpect(boolean valid, String dirName) { - ValidatorFileWalker zfWalk = new ValidatorFileWalker(valid); + private static boolean performValidateExpect(boolean valid, String dirName, String[] excludedFiles) { + ValidatorFileWalker zfWalk = new ValidatorFileWalker(valid, excludedFiles); Path startingDir = Paths.get(dirName); try { Files.walkFileTree(startingDir, zfWalk); diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/ValidatorFileWalker.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/ValidatorFileWalker.java index 5b5d8340..4fa12361 100644 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/ValidatorFileWalker.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/ValidatorFileWalker.java @@ -1,7 +1,6 @@ package org.mustangproject.commandline; - import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; @@ -11,25 +10,29 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.mustangproject.validator.ZUGFeRDValidator; import static org.xmlunit.assertj.XmlAssert.assertThat; -public class ValidatorFileWalker - extends SimpleFileVisitor { +public class ValidatorFileWalker + extends SimpleFileVisitor { private static final Logger LOGGER = LoggerFactory.getLogger(ValidatorFileWalker.class.getCanonicalName()); // log protected PathMatcher matcher; protected ZUGFeRDValidator zul; - protected int fileCount=1; - protected boolean expectValid=true; - protected boolean allValid=true; + protected int fileCount = 1; + protected boolean expectValid = true; + protected boolean allValid = true; + protected String[] excludedFiles = {}; - public ValidatorFileWalker(boolean expectValid) { + public ValidatorFileWalker(boolean expectValid, String[] excludedFiles) { this.zul = new ZUGFeRDValidator(); - this.expectValid=expectValid; + this.expectValid = expectValid; + this.excludedFiles = excludedFiles; matcher = FileSystems.getDefault().getPathMatcher("glob:*.{pdf,xml}"); } @@ -37,54 +40,58 @@ public class ValidatorFileWalker public boolean getResult() { return allValid; } - // Print information about - // each type of file. - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attr) { - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - //get current date time with Date() - Date date = new Date(); - String expectedString="valid"; - if (!expectValid) { - expectedString="invalid"; - } - if ((attr!=null)&&(attr.isRegularFile())) { - if (matcher.matches(file.getFileName())) { - String thisResultString=" valid"; - try { - assertThat(zul.validate(file.toAbsolutePath().toString())).valueByXPath("/validation/summary/@status") - .asString() - .isEqualTo(expectedString); - - } catch (AssertionError ae) { - thisResultString="invalid"; - allValid=false; - } - LOGGER.info(String.format("\n@%s Testing file %d: %s (%s)", dateFormat.format(date), fileCount++, thisResultString, file)); - - } - } - return FileVisitResult.CONTINUE; - } - // Print each directory visited. - @Override - public FileVisitResult postVisitDirectory(Path dir, - IOException exc) { - LOGGER.info("\nDirectory: %s%n", dir); - return FileVisitResult.CONTINUE; - } + // Print information about + // each type of file. + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attr) { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //get current date time with Date() + Date date = new Date(); + String expectedString = "valid"; + if (!expectValid) { + expectedString = "invalid"; + } + if ((attr != null) && (attr.isRegularFile())) { + if (matcher.matches(file.getFileName())) { + // I could have extended the path matcher but an exclusion list is quite simple + if ((excludedFiles == null) || (!Arrays.asList(excludedFiles).contains(file.getFileName().toString()))) { - // If there is some error accessing - // the file, let the user know. - // If you don't override this method - // and an error occurs, an IOException - // is thrown. - @Override - public FileVisitResult visitFileFailed(Path file, - IOException exc) { - LOGGER.error(exc.getMessage(),exc); - return FileVisitResult.CONTINUE; - } + String thisResultString = " valid"; + try { + assertThat(zul.validate(file.toAbsolutePath().toString())).valueByXPath("/validation/summary/@status") + .asString() + .isEqualTo(expectedString); + + } catch (AssertionError ae) { + thisResultString = "invalid"; + allValid = false; + } + LOGGER.info(String.format("\n@%s Testing file %d: %s (%s) ", dateFormat.format(date), fileCount++, thisResultString, file)); + } + } + } + return FileVisitResult.CONTINUE; + } + + // Print each directory visited. + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException exc) { + LOGGER.info("\nDirectory: %s%n", dir); + return FileVisitResult.CONTINUE; + } + + // If there is some error accessing + // the file, let the user know. + // If you don't override this method + // and an error occurs, an IOException + // is thrown. + @Override + public FileVisitResult visitFileFailed(Path file, + IOException exc) { + LOGGER.error(exc.getMessage(), exc); + return FileVisitResult.CONTINUE; + } } From b82e7a2b18cb12f881a184de81d70cf0f8845b1f Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sat, 19 Apr 2025 08:13:47 +0200 Subject: [PATCH 63/67] updated history --- History.md | 36 ++++++++++--------- .../commandline/ValidatorFileWalker.java | 2 +- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/History.md b/History.md index 03373820..ffa807db 100644 --- a/History.md +++ b/History.md @@ -1,19 +1,23 @@ -- #722 -- #774 -- #742/#753 -- #778 -- #759 -- #614, #770 -- #728 -- #776 -- #741 -- #782 -- #772 -- #775 -- #802 -- #809 -- #812 -- #818 + +2.16.4 +======= +2025-04-19 +- #722 extend ValidationLogVisualizer to not use only file system +- #774 disable XML parsing entities +- #742/#753 "Adresszusatz 1" (LineTwo) showing up as "Postfach" in HTML visualization +- #778 Added XEE Protection features (that were missing according to Stackoverflow) +- #759 Use the dedicated class instead of var type +- #614, #770 Exemption reason text should not be reused +- #728 Invoice setCorrection causes duplicate XML output +- #776 Fix potential resource leaks in core file processing classes +- #741 read position accountingReference +- #782/771 prevent NullPointerException on Product Description +- #772 TradeParty Name should be optional for ShipToTradeParty +- #775 not deleted tmp files +- #802 fix: capital letter for ID in listID +- #809 invoice reader to support multiple charges per item +- #812 fileattachment relation should have a default +- #818 need exceptions from files validated with validateExpectValid 2.16.3 diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/ValidatorFileWalker.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/ValidatorFileWalker.java index 4fa12361..a368baaa 100644 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/ValidatorFileWalker.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/ValidatorFileWalker.java @@ -79,7 +79,7 @@ public class ValidatorFileWalker @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { - LOGGER.info("\nDirectory: %s%n", dir); + LOGGER.info(String.format("\nDirectory: %s \n", dir)); return FileVisitResult.CONTINUE; } From 68dc92c53a6c0e9a2a1571ff1523aa515f3bcbb5 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sat, 19 Apr 2025 08:20:15 +0200 Subject: [PATCH 64/67] updated CLI documentation --- .../org/mustangproject/commandline/Main.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java index 5d7806ab..9cdb54e2 100755 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java @@ -73,10 +73,10 @@ public class Main { + " For ZUGFeRD v2: INIMUM, BASIC L, ASIC, IUS, N16931, Rechnung, EXENDED\n" + " [--attachments ]: list of file attachments (passing a single empty file name prevents prompting)\n" + " [--no-additional-attachments]: prevent prompting for attachments\n" - + " --action ubl convert UN/CEFACT 2016b CII XML to UBL XML\n" + + " --action ubl convert UN/CEFACT 2016b CII XML to UBL XML\n" + " [--source ]: set input XML file\n" + " [--out ]: set output XML file\n" - + " --action upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n" + + " --action upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n" + " Additional parameters (optional - user will be prompted if not defined)\n" + " [--source ]: set input XML ZUGFeRD 1 file\n" + " [--out ]: set output XML ZUGFeRD 2 file\n" @@ -86,14 +86,18 @@ public class Main { + " Additional parameters (optional - user will be prompted if not defined)\n" + " [--source ]: input PDF or XML file\n" + " [--log-as-pdf]: save log output as pdf\n" - + " --action validateExpectInvalid validate directory expecting negative results \n" + + " --action validateExpectInvalid validate directory recursively expecting negative results \n" + " [--no-notices]: refrain from reporting notices\n" - + " Additional parameters (optional - user will be prompted if not defined)\n" + + " Additional parameters (user will be prompted if not defined)\n" + " -d, --directory to check recursively\n" - + " --action validateExpectValid validate directory expecting positive results \n" + + " Additional parameters (optional)\n" + + " --exclude: comma-separated list of filenames to ignore\n" + + " --action validateExpectValid validate directory recursively expecting positive results \n" + " [--no-notices]: refrain from reporting notices\n" - + " Additional parameters (optional - user will be prompted if not defined)\n" + + " Additional parameters (user will be prompted if not defined)\n" + " -d, --directory to check recursively \n" + + " Additional parameters (user will be prompted if not defined)\n" + + " --exclude: comma-separated list of filenames to ignore\n" + " --action visualize convert XML to HTML \n" + " [--language ]: set output lang (en, fr or de)\n" + " [--source ]: set input XML file\n" From af7e0e8fc63c5b9cbb8c5bba9044574c0879163e Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sat, 19 Apr 2025 08:27:39 +0200 Subject: [PATCH 65/67] [maven-release-plugin] prepare release core-2.16.4 --- Mustang-CLI/pom.xml | 6 +++--- library/pom.xml | 6 +++--- pom.xml | 4 ++-- validator/pom.xml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml index e040777d..7f062940 100644 --- a/Mustang-CLI/pom.xml +++ b/Mustang-CLI/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.4-SNAPSHOT + 2.16.4 4.0.0 org.mustangproject @@ -12,7 +12,7 @@ should also work for XRechnung/CII. jar - 2.16.4-SNAPSHOT + 2.16.4 UTF-8 11 @@ -23,7 +23,7 @@ org.mustangproject validator - 2.16.4-SNAPSHOT + 2.16.4 diff --git a/library/pom.xml b/library/pom.xml index 9862a1d5..42f55289 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.16.4-SNAPSHOT + 2.16.4 4.0.0 org.mustangproject library - 2.16.4-SNAPSHOT + 2.16.4 jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -20,7 +20,7 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git https://github.com/ZUGFeRD/mustangproject - core-2.3.2 + core-2.16.4 diff --git a/pom.xml b/pom.xml index 5cc3f0ac..45d9ae98 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.16.4-SNAPSHOT pom + 2.16.4 pom Mustang @@ -19,7 +19,7 @@ scm:git:git://github.com/dexecutor/dependent-tasks-executor.git scm:git:git@github.com:dexecutor/dexecutor.git https://github.com/dexecutor/dependent-tasks-executor - core-2.3.2 + core-2.16.4 diff --git a/validator/pom.xml b/validator/pom.xml index 8d8b7ff0..792da85d 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.4-SNAPSHOT + 2.16.4 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.16.4-SNAPSHOT + 2.16.4 @@ -38,7 +38,7 @@ ${project.groupId} library - 2.16.4-SNAPSHOT + 2.16.4 org.dom4j From dc7f17b7f45036e8a377bb695843a021a3bd0203 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sat, 19 Apr 2025 08:27:42 +0200 Subject: [PATCH 66/67] [maven-release-plugin] prepare for next development iteration --- Mustang-CLI/pom.xml | 6 +++--- library/pom.xml | 6 +++--- pom.xml | 4 ++-- validator/pom.xml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml index 7f062940..77b79394 100644 --- a/Mustang-CLI/pom.xml +++ b/Mustang-CLI/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.4 + 2.17.0-SNAPSHOT 4.0.0 org.mustangproject @@ -12,7 +12,7 @@ should also work for XRechnung/CII. jar - 2.16.4 + 2.17.0-SNAPSHOT UTF-8 11 @@ -23,7 +23,7 @@ org.mustangproject validator - 2.16.4 + 2.17.0-SNAPSHOT diff --git a/library/pom.xml b/library/pom.xml index 42f55289..e84707f9 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -3,13 +3,13 @@ org.mustangproject core - 2.16.4 + 2.17.0-SNAPSHOT 4.0.0 org.mustangproject library - 2.16.4 + 2.17.0-SNAPSHOT jar Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII) FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT @@ -20,7 +20,7 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git https://github.com/ZUGFeRD/mustangproject - core-2.16.4 + core-2.3.2 diff --git a/pom.xml b/pom.xml index 45d9ae98..c3dbca52 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.mustangproject core - 2.16.4 pom + 2.17.0-SNAPSHOT pom Mustang @@ -19,7 +19,7 @@ scm:git:git://github.com/dexecutor/dependent-tasks-executor.git scm:git:git@github.com:dexecutor/dexecutor.git https://github.com/dexecutor/dependent-tasks-executor - core-2.16.4 + core-2.3.2 diff --git a/validator/pom.xml b/validator/pom.xml index 792da85d..47f731a9 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -3,7 +3,7 @@ org.mustangproject core - 2.16.4 + 2.17.0-SNAPSHOT 4.0.0 org.mustangproject @@ -11,7 +11,7 @@ Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung) jar - 2.16.4 + 2.17.0-SNAPSHOT @@ -38,7 +38,7 @@ ${project.groupId} library - 2.16.4 + 2.17.0-SNAPSHOT org.dom4j From 1d502d9a9474c55e6536405f8e86c68d749cbefa Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sat, 19 Apr 2025 16:00:34 +0200 Subject: [PATCH 67/67] closes #819 --- History.md | 1 + .../XR_30/XRechnung-CII-validation.sch | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index ffa807db..edf47c76 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,4 @@ +- #819 2.16.4 ======= diff --git a/validator/src/main/resources/schematron/XR_30/XRechnung-CII-validation.sch b/validator/src/main/resources/schematron/XR_30/XRechnung-CII-validation.sch index b38a931a..07b760ef 100644 --- a/validator/src/main/resources/schematron/XR_30/XRechnung-CII-validation.sch +++ b/validator/src/main/resources/schematron/XR_30/XRechnung-CII-validation.sch @@ -26,8 +26,29 @@ - + + + + + + + + + + + + + + + + + + + + + +