Skip to content

Commit

Permalink
Make sure schxstl error messages are parsed into proper error objects
Browse files Browse the repository at this point in the history
This is to ensure validate_against_schema and validate_against_schematron return things that quack similarly.

Fixes #5
  • Loading branch information
halfbyte committed Nov 27, 2024
1 parent 785ab8a commit 952636f
Show file tree
Hide file tree
Showing 3 changed files with 284 additions and 2 deletions.
22 changes: 21 additions & 1 deletion lib/secretariat/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
require 'tmpdir'

module Secretariat

class ValidatorError < StandardError; end


class Validator
SCHEMATRON = [
'../../schemas/zugferd_1/ZUGFeRD1p0.sch',
Expand Down Expand Up @@ -59,8 +63,24 @@ def validate_against_schematron
jarpath = File.join(__dir__, '../..', 'bin', 'schxslt-cli.jar')
out = `java -jar #{jarpath} -v -d #{docpath} -s #{schematron_path}`
return [] if out.start_with?("[valid]")
out.lines
return process_schematron_errors(out)
end
end

private

def process_schematron_errors(output)
errors = []
error_lines = output.lines.clone
error_lines.shift # get rid of file notice

while(error_lines.length > 0) do
assert_error = error_lines.shift
_, ref = assert_error.split(" failed-assert ").map(&:strip)
error_description = error_lines.shift.strip
errors << ValidatorError.new("#{error_description} - Reference: #{ref}")
end
errors
end
end
end
252 changes: 252 additions & 0 deletions test/fixtures/factur-x_1.0.0.7/invalid.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!-- English disclaimer below.-->
<!--Nutzungsrechte
ZUGFeRD Datenformat Version 2.3.0, 18.09.2024
Beispiel Version 18.09.2024
Zweck des Forums elektronisch Rechnung Deutschland, welches am 31. März 2010 unter der Arbeitsgemeinschaft für
wirtschaftliche Verwaltung e. V. gegründet wurde, ist u. a. die Schaffung und Spezifizierung eines offenen Datenformats
für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht diskriminierender, standardisierter
Technologien („ZUGFeRD Datenformat“).
Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung
frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine
Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht
diskriminierenden Bedingungen an.
Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung
abrufbar unter www.ferd-net.de.
Im Einzelnen schließt die Nutzungsgewährung ein:
=====================================
FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils
geltenden und akzeptierten Fassung (www.ferd-net.de) ein.
Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung,
Weiterbearbeitung und Verbindung mit anderen Produkten.
Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder
anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige
Anwendungen und Dienste.
Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente
und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um
notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch
die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden.
Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares,
unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit
anderen Produkten einzuräumen.
Die Lizenz wird kostenfrei zur Verfügung gestellt.
Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen
Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten,
Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete,
beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der
Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können.-->

<!--Right of use
ZUGFeRD Data format version 2.3.0, September 18th, 2024
The purpose of the Forum elektronische Rechnung Deutschland (FeRD), which was founded on March 31, 2010 under the
umbrella of Arbeitsgemeinschaft für wirtschaftliche Verwaltung e. V., is, among other things, to create and specify an
open data format for structured electronic data exchange on the basis of open and non discriminatory, standardised
technologies ("ZUGFeRD data format").
The ZUGFeRD data format is used by both companies and public administration according to the FeRD
made freely accessible. For this purpose FeRD offers all companies and organisations of the public administration a
License to use the copyrighted ZUGFeRD data format in a fair, appropriate and non
discriminatory conditions.
The specification of the FeRD for the implementation of the ZUGFeRD data format is, in its currently valid version
available at www.ferd-net.de.
In detail, the grant of use includes
=====================================
FeRD grants a license for the use of the copyrighted ZUGFeRD data format in the respective
valid and accepted version (www.ferd-net.de).
The license includes an irrevocable right of use including the right of further development,
Further processing and connection with other products.
The license applies in particular to the development, design, production, sale, use or
other use of the ZUGFeRD data format for hardware and/or software products and other
applications and services.
This license does not include the essential patents of the members of FeRD. The essential patents are patents
and patent applications worldwide which contain one or more claims that are
necessary claims. Necessary claims are only those claims of the essential patents which are
the implementation of the ZUGFeRD data format would necessarily be violated.
The Licensee is entitled to provide its respective group companies with an unlimited, worldwide, non-transferable,
irrevocable right of use including the right of further development, further processing and connection with
other products.
The license is provided free of charge.
Except in the case of intentional fault or gross negligence, FeRD is not liable for loss of use, loss of
Profit, loss of data, loss of communication, loss of revenue, loss of contracts, loss of business or for costs
damages, losses or liabilities in connection with an interruption of business, nor for concrete,
incidental, indirect, punitive or consequential damages, even if the possibility of
costs, losses or damages could normally have been foreseen.-->

<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>471102</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20241115</udt:DateTimeString>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:Content>Rechnung gemäß Bestellung vom 01.11.2024.</ram:Content>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Lieferant GmbH
Lieferantenstraße 20
80333 München
Deutschland
Geschäftsführer: Hans Muster
Handelsregisternummer: H A 123
</ram:Content>
<ram:SubjectCode>REG</ram:SubjectCode>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0160">4012345001235</ram:GlobalID>
<ram:SellerAssignedID>TB100A4</ram:SellerAssignedID>
<ram:Name>Trennblätter A4</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>9.9000</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>9.9000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">20.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>198.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0160">4000050986428</ram:GlobalID>
<ram:SellerAssignedID>ARNR2</ram:SellerAssignedID>
<ram:Name>Joghurt Banane</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>5.5000</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>5.5000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">50.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>275.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:ID>549910</ram:ID>
<ram:GlobalID schemeID="0088">4000001123452</ram:GlobalID>
<ram:Name>Lieferant GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>80333</ram:PostcodeCode>
<ram:LineOne>Lieferantenstraße 20</ram:LineOne>
<ram:CityName>München</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">201/113/40209</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE123456789</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:ID>GE2020211</ram:ID>
<ram:Name>Kunden AG Mitte</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>69876</ram:PostcodeCode>
<ram:LineOne>Kundenstraße 15</ram:LineOne>
<ram:CityName>Frankfurt</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20241114</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>19.25</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>275.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>37.62</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>198.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Zahlbar innerhalb 30 Tagen netto bis 15.12.2024, 3% Skonto innerhalb 10 Tagen bis 25.11.2024</ram:Description>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>473.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>473.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">56.87</ram:TaxTotalAmount>
<ram:GrandTotalAmount>529.87</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>529.87</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format="102">20241216</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format="103">20241215</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
12 changes: 11 additions & 1 deletion test/validator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ def test_schematron_validator_2
assert_equal [], v.validate_against_schematron
end

def test_invalid_schematron_validator_2
xml = open(File.join(__dir__, 'fixtures/factur-x_1.0.0.7/invalid.xml'))
v = Validator.new(xml, version: 2)
errors = v.validate_against_schematron
assert_equal 2, errors.length
assert_match(/\[BR-29\]/, errors.first.message)
assert_match(/Value of '@format' is not allowed/, errors[1].message)
end

def test_schema_validator_1
xml = open(File.join(__dir__, 'fixtures/zugferd_1/einfach.xml'))
v = Validator.new(xml, version: 1)
Expand All @@ -31,7 +40,8 @@ def test_invalid_schematron_validator_1
xml = open(File.join(__dir__, 'fixtures/zugferd_1/invalid.xml'))
v = Validator.new(xml, version: 1)
errors = v.validate_against_schematron
assert_match(/^\[invalid\]/, errors.first)
assert_equal 1, errors.length
assert_match(/Element 'ram:BasisAmount' must occur exactly 1 times/, errors.first.message)
end
end
end
Expand Down

0 comments on commit 952636f

Please sign in to comment.