From c4c4216bbe1d8b73772daf878c7c67caf1417067 Mon Sep 17 00:00:00 2001 From: langfr Date: Mon, 13 Oct 2025 19:05:16 +0100 Subject: [PATCH 1/4] Replace fixed version number with variable from root pom.xml. --- library/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/pom.xml b/library/pom.xml index e83cbbd4..390797b5 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -250,7 +250,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.3 + ${version.org.apache.maven.plugins.maven-shade-plugin} true false From 401b568353fac9c01d6e640cc3e36ba9cdc6115e Mon Sep 17 00:00:00 2001 From: Frank Langelage <833507+langfr@users.noreply.github.com> Date: Sun, 19 Oct 2025 12:25:49 +0200 Subject: [PATCH 2/4] Add optional Invoicer and Invoicee for Extended profile. --- .../main/java/org/mustangproject/Invoice.java | 32 ++++++++++++++++++- .../ZUGFeRD/IExportableTransaction.java | 21 +++++++++++- .../ZUGFeRD/ZUGFeRD2PullProvider.java | 11 +++++++ .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 16 +++++++++- .../mustangproject/ZUGFeRD/ZF2PushTest.java | 4 +++ 5 files changed, 81 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/org/mustangproject/Invoice.java b/library/src/main/java/org/mustangproject/Invoice.java index d1a31537..3bc1f4b6 100644 --- a/library/src/main/java/org/mustangproject/Invoice.java +++ b/library/src/main/java/org/mustangproject/Invoice.java @@ -41,7 +41,7 @@ public class Invoice implements IExportableTransaction { protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null; protected Date issueDate = null, dueDate = null, deliveryDate = null; - protected TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null; + protected TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null, invoicer = null, invoicee = null; protected ArrayList cashDiscounts = null; @JsonDeserialize(contentAs = Item.class) protected ArrayList ZFItems = null; @@ -722,6 +722,36 @@ public class Invoice implements IExportableTransaction { return this; } + @Override + public TradeParty getInvoicer() { + return this.invoicer; + } + + /*** + * if the invoicer is not the seller, it can be specified here + * @param invoicer the invoice issuing organisation + * @return fluent setter + */ + public Invoice setInvoicer(TradeParty invoicer) { + this.invoicer = invoicer; + return this; + } + + @Override + public TradeParty getInvoicee() { + return this.invoicee; + } + + /*** + * if the invoicee is not the buyer, it can be specified here + * @param invoicee the invoice receiving organisation + * @return fluent setter + */ + public Invoice setInvoicee(TradeParty invoicee) { + this.invoicee = invoicee; + return this; + } + /*** * Adds a cash discount (skonto) * @param c the CashDiscount percent/period combination diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java index c7a6d903..5d72a517 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java @@ -38,6 +38,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.mustangproject.FileAttachment; import org.mustangproject.IncludedNote; import org.mustangproject.ReferencedDocument; +import org.mustangproject.TradeParty; import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants; /*** @@ -493,12 +494,30 @@ public interface IExportableTransaction { /*** * payee / payment receiver, if different from seller, ram:Payee (only supported for zf2) * - * @return the IZUGFeRDExportableTradeParty payment receiver, if different from sellver + * @return the IZUGFeRDExportableTradeParty payment receiver, if different from seller */ default IZUGFeRDExportableTradeParty getPayee() { return null; } + /*** + * invoicer / invoice sender, if different from seller, ram:InvoicerTradeParty + * + * @return the IZUGFeRDExportableTradeParty invoice sender, if different from seller + */ + default IZUGFeRDExportableTradeParty getInvoicer() { + return null; + } + + /*** + * invoicee / invoice receiver, if different from buyer, ram:InvoiceeTradeParty + * + * @return the IZUGFeRDExportableTradeParty invoice receiver, if different from buyer + */ + default IZUGFeRDExportableTradeParty getInvoicee() { + return null; + } + /*** * specifies the document level delivery period, will be included in a * BillingSpecifiedPeriod element diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index ddd841d7..b303c353 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -677,6 +677,17 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { xml += "" + XMLTools.encodeXML(trans.getPaymentReference()) + ""; } xml += "" + trans.getCurrency() + ""; + + if (this.trans.getInvoicer() != null && getProfile() == Profiles.getByName("Extended")) { + xml += "" + + getTradePartyAsXML(this.trans.getInvoicer(), false, false) + + ""; + } + if (this.trans.getInvoicee() != null && getProfile() == Profiles.getByName("Extended")) { + xml += "" + + getTradePartyAsXML(this.trans.getInvoicee(), false, false) + + ""; + } if (this.trans.getPayee() != null) { xml += "" + getTradePartyPayeeAsXML(this.trans.getPayee()) + diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 8de6319a..2f7cc2f4 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -315,7 +315,7 @@ public class ZUGFeRDInvoiceImporter { final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //REDHAT //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf - dbf.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); @@ -436,6 +436,12 @@ public class ZUGFeRDInvoiceImporter { xpr = xpath.compile("//*[local-name()=\"BuyerTradeParty\"]|//*[local-name()=\"AccountingCustomerParty\"]/*"); NodeList BuyerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + xpr = xpath.compile("//*[local-name()=\"InvoicerTradeParty\"]"); + NodeList invoicerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + + xpr = xpath.compile("//*[local-name()=\"InvoiceeTradeParty\"]"); + NodeList invoiceeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); + xpr = xpath.compile("//*[local-name()=\"PayeeTradeParty\"]"); NodeList payeeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); @@ -908,6 +914,14 @@ public class ZUGFeRDInvoiceImporter { } + if (invoicerNodes.getLength() > 0) { + zpp.setInvoicer(new TradeParty(invoicerNodes)); + } + + if (invoiceeNodes.getLength() > 0) { + zpp.setInvoicee(new TradeParty(invoiceeNodes)); + } + if (payeeNodes.getLength() > 0) { zpp.setPayee(new TradeParty(payeeNodes)); } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java index 1defb4b3..32d77d49 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java @@ -604,6 +604,8 @@ public class ZF2PushTest extends TestCase { .setContractReferencedDocument(contractID) .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addGlobalID(gln).setEmail("recipient@test.org").addVATID("DE4711") .setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")).setAdditionalAddress("Hinterhaus 3")) + .setInvoicer( new TradeParty("Abweichender Rechnungssteller", "Teststr.12", "04711", "Entenhausen", "DE") ) + .setInvoicee( new TradeParty("Abweichender Rechnungsempfänger", "Teststr.42", "00815", "Entenhausen", "DE") ) .addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).setId("a123").addBuyerOrderReferencedDocumentID("orderId").addBuyerOrderReferencedDocumentLineID("xxx").addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15"))) .addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16))) .addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16))) @@ -669,6 +671,8 @@ public class ZF2PushTest extends TestCase { assertEquals("++49555123456",i.getRecipient().getContact().getFax()); + assertNotNull(i.getInvoicer()); + assertNotNull(i.getInvoicee()); } catch (XPathExpressionException e) { fail("XPathExpressionException should not be raised"); } catch (ParseException e) { From c01c3660164854afe2a6a6453a1b4115f4fd31a9 Mon Sep 17 00:00:00 2001 From: Detlef Sander Date: Wed, 22 Oct 2025 10:49:55 +0200 Subject: [PATCH 3/4] fixes feature secure processing not working --- .../ZUGFeRD/ZUGFeRDVisualizer.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index fda79d55..ec699252 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -107,9 +107,23 @@ public class ZUGFeRDVisualizer { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //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, ""); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + try + { + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + } + catch (IllegalArgumentException e) + { + LOGGER.warn("Property: \"Access external DTD\" not supported."); + } + try + { + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + } + catch (IllegalArgumentException e) + { + LOGGER.warn("Property: \"Access external schema\" not supported."); + } //OWASP //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html From 0e8941c4356b2cf349a6d7d56e4a27acb25451c2 Mon Sep 17 00:00:00 2001 From: Frank Langelage <833507+langfr@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:36:48 +0100 Subject: [PATCH 4/4] Add invoicer and invoicee to ZF2PushTest --- .../src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java index 428d8f89..55a93e6a 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java @@ -607,6 +607,8 @@ public class ZF2PushTest extends TestCase { .setContractReferencedDocument(contractID) .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addGlobalID(gln).setEmail("recipient@test.org").addVATID("DE4711") .setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")).setAdditionalAddress("Hinterhaus 3")) + .setInvoicer( new TradeParty("Abweichender Rechnungssteller", "Teststr.12", "04711", "Entenhausen", "DE") ) + .setInvoicee( new TradeParty("Abweichender Rechnungsempfänger", "Teststr.42", "00815", "Entenhausen", "DE") ) .addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).setId("a123"). addAdditionalReference(dr2).addBuyerOrderReferencedDocumentID("orderId").addBuyerOrderReferencedDocumentLineID("xxx").addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15"))) .addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16)))