#814 upgrade CEN EN16931 Schematron from v1.3.12 to v1.3.15

Replace EN16931-CII-validation.xslt and EN16931-UBL-validation.xslt with
the v1.3.15 release. Fixes BR-DEC-23 XPath bug and aligns with KoSIT
XRechnung 3.0.2 validator (v2026-01-31). Adds regression test.

Made-with: Cursor
This commit is contained in:
Philipp
2026-04-14 15:43:35 +02:00
parent a366e6bb26
commit 18e0b1c691
4 changed files with 597 additions and 304 deletions

View File

@@ -405,6 +405,38 @@ public class XMLValidatorTest extends ResourceCase {
}
public void testBRDEC23Regression() {
// Regression test: BR-DEC-23 must fire for XRechnung CII invoices whose
// LineTotalAmount (BT-131) has more than 2 decimal places.
// The bug existed in CEN Schematron <=1.3.12 due to a wrong XPath context
// (SpecifiedTradeSettlement instead of SpecifiedLineTradeSettlement).
final ValidationContext ctx = new ValidationContext(null);
final XMLValidator xv = new XMLValidator(ctx);
final XPathEngine xpath = new JAXPXPathEngine();
File tempFile = getResourceAsFile("invalidXRV30_BR-DEC-23.xml");
boolean noExceptions = true;
try {
xv.setFilename(tempFile.getAbsolutePath());
xv.validate();
String s = "<validation>" + xv.getXMLResult() + "</validation>";
Source source = Input.fromString(s).build();
// must be invalid overall
String status = xpath.evaluate("/validation/summary/@status", source);
assertEquals("invalid", status);
// must contain the BR-DEC-23 rule ID in at least one error
assertThat(s).valueByXPath("count(//error[contains(text(),'BR-DEC-23')])")
.asInt()
.isGreaterThanOrEqualTo(1);
} catch (IrrecoverableValidationError e) {
noExceptions = false;
}
assertTrue(noExceptions);
}
public void testSubInvoiceLineHierarchy() {
final ValidationContext ctx = new ValidationContext(null);
final XMLValidator xv = new XMLValidator(ctx);

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Regression test fixture for BR-DEC-23.
LineTotalAmount on line item 1 intentionally has 4 decimal places (288.7934)
to trigger: [BR-DEC-23] The allowed maximum number of decimals for the Invoice
line net amount (BT-131) is 2.
Based on validXRV30.xml (XRechnung 3.0 / CII profile).
-->
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:ID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</ram:ID>
</ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>BR-DEC-23-REGRESSION</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20240101</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Test product</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>288.79</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="XPP">1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<!-- 4 decimal places: intentionally violates BR-DEC-23 -->
<ram:LineTotalAmount>288.7934</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>04011000-12345-03</ram:BuyerReference>
<ram:SellerTradeParty>
<ram:Name>Test Seller GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>12345</ram:PostcodeCode>
<ram:LineOne>Seller Street 1</ram:LineOne>
<ram:CityName>Berlin</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="EM">seller@test.de</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE123456789</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Test Buyer AG</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>10115</ram:PostcodeCode>
<ram:LineOne>Buyer Street 2</ram:LineOne>
<ram:CityName>Berlin</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="EM">buyer@test.de</ram:URIID>
</ram:URIUniversalCommunication>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>58</ram:TypeCode>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>DE75512108001245126199</ram:IBANID>
</ram:PayeePartyCreditorFinancialAccount>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>54.87</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>288.79</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Zahlbar sofort ohne Abzug.</ram:Description>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>288.79</ram:LineTotalAmount>
<ram:TaxBasisTotalAmount>288.79</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">54.87</ram:TaxTotalAmount>
<ram:GrandTotalAmount>343.66</ram:GrandTotalAmount>
<ram:DuePayableAmount>343.66</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>