Skip to content

fix for #1014#1016

Open
ThomasChr wants to merge 1 commit intoZUGFeRD:masterfrom
ThomasChr:issue1014
Open

fix for #1014#1016
ThomasChr wants to merge 1 commit intoZUGFeRD:masterfrom
ThomasChr:issue1014

Conversation

@ThomasChr
Copy link
Copy Markdown
Contributor

@ThomasChr ThomasChr commented Jan 21, 2026

Possible problem:
I'm not quite sure if the top-level Node is always called <Invoice>. It's called <CrossIndustryInvoice> in ZUGFeRD and the xPath would fail in this case. But leaving the root element out of the xpath would make it find the item level AllowanceCharge also, which is also wrong.

@ThomasChr
Copy link
Copy Markdown
Contributor Author

Testfile src/test/java/org/mustangproject/validator/DocumentDiscountTest.java:

package org.mustangproject.validator;

import junit.framework.TestCase;

public class DocumentDiscountTest  extends TestCase {
	String XMLString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
		"<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\" xmlns:cac=\"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\" xmlns:cec=\"urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2\" xmlns:cbc=\"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\">\n" +
		"  <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>\n" +
		"  <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>\n" +
		"  <cbc:ID>UBL_2Items_with_CD_and_DocumentCD_fa</cbc:ID>\n" +
		"  <cbc:IssueDate>2025-01-29</cbc:IssueDate>\n" +
		"  <cbc:DueDate>2025-02-05</cbc:DueDate>\n" +
		"  <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>\n" +
		"  <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>\n" +
		"  <cbc:BuyerReference>0</cbc:BuyerReference>\n" +
		"  <cac:OrderReference>\n" +
		"    <cbc:ID>BE00000050</cbc:ID>\n" +
		"  </cac:OrderReference>\n" +
		"  <cac:AccountingSupplierParty>\n" +
		"    <cac:Party>\n" +
		"      <cbc:EndpointID schemeID=\"EM\">info@hamburgerdelikat.zz</cbc:EndpointID>\n" +
		"      <cac:PartyName>\n" +
		"        <cbc:Name>Klaus Hamburger GmbH</cbc:Name>\n" +
		"      </cac:PartyName>\n" +
		"      <cac:PostalAddress>\n" +
		"        <cbc:StreetName>Wachtelweg 13</cbc:StreetName>\n" +
		"        <cbc:CityName>Braunschweig</cbc:CityName>\n" +
		"        <cbc:PostalZone>38104</cbc:PostalZone>\n" +
		"        <cac:Country>\n" +
		"          <cbc:IdentificationCode>DE</cbc:IdentificationCode>\n" +
		"        </cac:Country>\n" +
		"      </cac:PostalAddress>\n" +
		"      <cac:PartyTaxScheme>\n" +
		"        <cbc:CompanyID>DE151077100</cbc:CompanyID>\n" +
		"        <cac:TaxScheme>\n" +
		"          <cbc:ID>VAT</cbc:ID>\n" +
		"        </cac:TaxScheme>\n" +
		"      </cac:PartyTaxScheme>\n" +
		"      <cac:PartyTaxScheme>\n" +
		"        <cbc:CompanyID>123546891</cbc:CompanyID>\n" +
		"        <cac:TaxScheme>\n" +
		"          <cbc:ID>FC</cbc:ID>\n" +
		"        </cac:TaxScheme>\n" +
		"      </cac:PartyTaxScheme>\n" +
		"      <cac:PartyLegalEntity>\n" +
		"        <cbc:RegistrationName>Klaus Hamburger GmbH</cbc:RegistrationName>\n" +
		"      </cac:PartyLegalEntity>\n" +
		"      <cac:Contact>\n" +
		"        <cbc:Name>Meier Ralf</cbc:Name>\n" +
		"        <cbc:Telephone>+4953177889910</cbc:Telephone>\n" +
		"        <cbc:ElectronicMail>info@hamburgerdelikat.zz</cbc:ElectronicMail>\n" +
		"      </cac:Contact>\n" +
		"    </cac:Party>\n" +
		"  </cac:AccountingSupplierParty>\n" +
		"  <cac:AccountingCustomerParty>\n" +
		"    <cac:Party>\n" +
		"      <cbc:EndpointID schemeID=\"EM\">max.mustermann@demo.de</cbc:EndpointID>\n" +
		"      <cac:PartyName>\n" +
		"        <cbc:Name>Feinkoste GmbH</cbc:Name>\n" +
		"      </cac:PartyName>\n" +
		"      <cac:PostalAddress>\n" +
		"        <cbc:StreetName>Landsberger Straße 45</cbc:StreetName>\n" +
		"        <cbc:CityName>Freiburg</cbc:CityName>\n" +
		"        <cbc:PostalZone>80687</cbc:PostalZone>\n" +
		"        <cac:Country>\n" +
		"          <cbc:IdentificationCode>DE</cbc:IdentificationCode>\n" +
		"        </cac:Country>\n" +
		"      </cac:PostalAddress>\n" +
		"      <cac:PartyLegalEntity>\n" +
		"        <cbc:RegistrationName>Feinkoste GmbH</cbc:RegistrationName>\n" +
		"      </cac:PartyLegalEntity>\n" +
		"    </cac:Party>\n" +
		"  </cac:AccountingCustomerParty>\n" +
		"  <cac:Delivery>\n" +
		"    <cbc:ActualDeliveryDate>2025-01-31</cbc:ActualDeliveryDate>\n" +
		"  </cac:Delivery>\n" +
		"  <cac:PaymentMeans>\n" +
		"    <cbc:PaymentMeansCode>58</cbc:PaymentMeansCode>\n" +
		"    <cac:PayeeFinancialAccount>\n" +
		"      <cbc:ID>DE12500105170648489890</cbc:ID>\n" +
		"      <cbc:Name>Bank</cbc:Name>\n" +
		"    </cac:PayeeFinancialAccount>\n" +
		"  </cac:PaymentMeans>\n" +
		"  <cac:AllowanceCharge>\n" +
		"    <cbc:ChargeIndicator>false</cbc:ChargeIndicator>\n" +
		"    <cbc:AllowanceChargeReason>Document Discount</cbc:AllowanceChargeReason>\n" +
		"    <cbc:MultiplierFactorNumeric>10</cbc:MultiplierFactorNumeric>\n" +
		"    <cbc:Amount currencyID=\"EUR\">6.00</cbc:Amount>\n" +
		"    <cbc:BaseAmount currencyID=\"EUR\">59.99</cbc:BaseAmount>\n" +
		"    <cac:TaxCategory>\n" +
		"      <cbc:ID>S</cbc:ID>\n" +
		"      <cbc:Percent>19</cbc:Percent>\n" +
		"      <cac:TaxScheme>\n" +
		"        <cbc:ID>VAT</cbc:ID>\n" +
		"      </cac:TaxScheme>\n" +
		"    </cac:TaxCategory>\n" +
		"  </cac:AllowanceCharge>\n" +
		"  <cac:AllowanceCharge>\n" +
		"    <cbc:ChargeIndicator>true</cbc:ChargeIndicator>\n" +
		"    <cbc:AllowanceChargeReason>Document Charge</cbc:AllowanceChargeReason>\n" +
		"    <cbc:MultiplierFactorNumeric>12</cbc:MultiplierFactorNumeric>\n" +
		"    <cbc:Amount currencyID=\"EUR\">7.20</cbc:Amount>\n" +
		"    <cbc:BaseAmount currencyID=\"EUR\">59.99</cbc:BaseAmount>\n" +
		"    <cac:TaxCategory>\n" +
		"      <cbc:ID>S</cbc:ID>\n" +
		"      <cbc:Percent>19</cbc:Percent>\n" +
		"      <cac:TaxScheme>\n" +
		"        <cbc:ID>VAT</cbc:ID>\n" +
		"      </cac:TaxScheme>\n" +
		"    </cac:TaxCategory>\n" +
		"  </cac:AllowanceCharge>\n" +
		"  <cac:TaxTotal>\n" +
		"    <cbc:TaxAmount currencyID=\"EUR\">11.63</cbc:TaxAmount>\n" +
		"    <cac:TaxSubtotal>\n" +
		"      <cbc:TaxableAmount currencyID=\"EUR\">61.19</cbc:TaxableAmount>\n" +
		"      <cbc:TaxAmount currencyID=\"EUR\">11.63</cbc:TaxAmount>\n" +
		"      <cac:TaxCategory>\n" +
		"        <cbc:ID>S</cbc:ID>\n" +
		"        <cbc:Percent>19</cbc:Percent>\n" +
		"        <cac:TaxScheme>\n" +
		"          <cbc:ID>VAT</cbc:ID>\n" +
		"        </cac:TaxScheme>\n" +
		"      </cac:TaxCategory>\n" +
		"    </cac:TaxSubtotal>\n" +
		"  </cac:TaxTotal>\n" +
		"<cac:LegalMonetaryTotal>\n" +
		"    <cbc:LineExtensionAmount currencyID=\"EUR\">59.99</cbc:LineExtensionAmount>\n" +
		"    <cbc:TaxExclusiveAmount currencyID=\"EUR\">61.19</cbc:TaxExclusiveAmount>\n" +
		"    <cbc:TaxInclusiveAmount currencyID=\"EUR\">72.82</cbc:TaxInclusiveAmount>\n" +
		"    <cbc:AllowanceTotalAmount currencyID=\"EUR\">6.00</cbc:AllowanceTotalAmount>\n" +
		"    <cbc:ChargeTotalAmount currencyID=\"EUR\">7.20</cbc:ChargeTotalAmount>\n" +
		"    <cbc:PrepaidAmount currencyID=\"EUR\">0.00</cbc:PrepaidAmount>\n" +
		"    <cbc:PayableAmount currencyID=\"EUR\">72.82</cbc:PayableAmount>\n" +
		"</cac:LegalMonetaryTotal>\n" +
		"  <cac:InvoiceLine>\n" +
		"    <cbc:ID>1</cbc:ID>\n" +
		"    <cbc:InvoicedQuantity unitCode=\"KGM\">1</cbc:InvoicedQuantity>\n" +
		"    <cbc:LineExtensionAmount currencyID=\"EUR\">54.49</cbc:LineExtensionAmount>\n" +
		"    <cac:AllowanceCharge>\n" +
		"      <cbc:ChargeIndicator>false</cbc:ChargeIndicator>\n" +
		"      <cbc:AllowanceChargeReason>Catch Weight Item Discount</cbc:AllowanceChargeReason>\n" +
		"      <cbc:MultiplierFactorNumeric>3</cbc:MultiplierFactorNumeric>\n" +
		"      <cbc:Amount currencyID=\"EUR\">1.50</cbc:Amount>\n" +
		"      <cbc:BaseAmount currencyID=\"EUR\">49.99</cbc:BaseAmount>\n" +
		"    </cac:AllowanceCharge>\n" +
		"    <cac:AllowanceCharge>\n" +
		"      <cbc:ChargeIndicator>true</cbc:ChargeIndicator>\n" +
		"      <cbc:AllowanceChargeReason>Catch Weight Item Charge</cbc:AllowanceChargeReason>\n" +
		"      <cbc:MultiplierFactorNumeric>12</cbc:MultiplierFactorNumeric>\n" +
		"      <cbc:Amount currencyID=\"EUR\">6.00</cbc:Amount>\n" +
		"      <cbc:BaseAmount currencyID=\"EUR\">49.99</cbc:BaseAmount>\n" +
		"    </cac:AllowanceCharge>\n" +
		"    <cac:Item>\n" +
		"\t <cbc:Description>Catch Weight Stock Item description</cbc:Description>\n" +
		"      <cbc:Name>Catch Weight Stock Item</cbc:Name>\n" +
		"      <cac:SellersItemIdentification>\n" +
		"        <cbc:ID>000000000000014</cbc:ID>\n" +
		"      </cac:SellersItemIdentification>\n" +
		"      <cac:ClassifiedTaxCategory>\n" +
		"        <cbc:ID>S</cbc:ID>\n" +
		"        <cbc:Percent>19</cbc:Percent>\n" +
		"        <cac:TaxScheme>\n" +
		"          <cbc:ID>VAT</cbc:ID>\n" +
		"        </cac:TaxScheme>\n" +
		"      </cac:ClassifiedTaxCategory>\n" +
		"    </cac:Item>\n" +
		"    <cac:Price>\n" +
		"      <cbc:PriceAmount currencyID=\"EUR\">49.99</cbc:PriceAmount>\n" +
		"    </cac:Price>\n" +
		"  </cac:InvoiceLine>\n" +
		"  <cac:InvoiceLine>\n" +
		"    <cbc:ID>2</cbc:ID>\n" +
		"    <cbc:InvoicedQuantity unitCode=\"C62\">1</cbc:InvoicedQuantity>\n" +
		"    <cbc:LineExtensionAmount currencyID=\"EUR\">5.50</cbc:LineExtensionAmount>\n" +
		"    <cac:AllowanceCharge>\n" +
		"      <cbc:ChargeIndicator>false</cbc:ChargeIndicator>\n" +
		"      <cbc:AllowanceChargeReason>Live domestic turkeys Discount</cbc:AllowanceChargeReason>\n" +
		"      <cbc:MultiplierFactorNumeric>5</cbc:MultiplierFactorNumeric>\n" +
		"      <cbc:Amount currencyID=\"EUR\">0.25</cbc:Amount>\n" +
		"      <cbc:BaseAmount currencyID=\"EUR\">5.00</cbc:BaseAmount>\n" +
		"    </cac:AllowanceCharge>\n" +
		"    <cac:AllowanceCharge>\n" +
		"      <cbc:ChargeIndicator>true</cbc:ChargeIndicator>\n" +
		"      <cbc:AllowanceChargeReason>Live domestic turkeys Charge</cbc:AllowanceChargeReason>\n" +
		"      <cbc:MultiplierFactorNumeric>15</cbc:MultiplierFactorNumeric>\n" +
		"      <cbc:Amount currencyID=\"EUR\">0.75</cbc:Amount>\n" +
		"      <cbc:BaseAmount currencyID=\"EUR\">5.00</cbc:BaseAmount>\n" +
		"    </cac:AllowanceCharge>\n" +
		"    <cac:Item>\n" +
		"\t  <cbc:Description>Live domestic turkeys description</cbc:Description>\n" +
		"      <cbc:Name>Live domestic turkeys, weighing &lt;= 185 g [intrastat]</cbc:Name>\n" +
		"      <cac:SellersItemIdentification>\n" +
		"        <cbc:ID>000000000000022</cbc:ID>\n" +
		"      </cac:SellersItemIdentification>\n" +
		"      <cac:ClassifiedTaxCategory>\n" +
		"        <cbc:ID>S</cbc:ID>\n" +
		"        <cbc:Percent>19</cbc:Percent>\n" +
		"        <cac:TaxScheme>\n" +
		"          <cbc:ID>VAT</cbc:ID>\n" +
		"        </cac:TaxScheme>\n" +
		"      </cac:ClassifiedTaxCategory>\n" +
		"    </cac:Item>\n" +
		"    <cac:Price>\n" +
		"      <cbc:PriceAmount currencyID=\"EUR\">5</cbc:PriceAmount>\n" +
		"    </cac:Price>\n" +
		"  </cac:InvoiceLine>\n" +
		"</Invoice>\n";

	public void testValidateXML() {
		ZUGFeRDValidator validator = new ZUGFeRDValidator();
		System.out.println(validator.validate(XMLString.getBytes(), "test.xml"));
		assertEquals(true, true);
	}
}

(as this is no real test I did not add it to the PR)

@taskinkemal
Copy link
Copy Markdown
Contributor

Hello, are there any updates on this? The fix seems to work and we are waiting for this PR to be evaluated. Would you like to take it out of the draft status or does @jstaerk evaluate it in the draft state as well? Thank you!

@ThomasChr
Copy link
Copy Markdown
Contributor Author

I‘ll take a look at it tomorrow to see if it needs to be changed for ZUGFeRD and will disable Draft afterwards!

@ThomasChr
Copy link
Copy Markdown
Contributor Author

Carefully searched through the documentation.
This AllowanceCharge will only be in UBL, so there is no danger of breaking something with this xpath.
Deactivating draft status.

@ThomasChr ThomasChr marked this pull request as ready for review February 18, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants