[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs:validation":3},{"versions":4,"version":26,"nav":28,"path":49,"kind":106,"page":107},[5,10,13,16,18,20,22,24],{"name":6,"label":7,"prefix":8,"channel":9},"0.7","0.7 (latest)","","latest",{"name":11,"label":12,"prefix":11,"channel":11},"next","next (unreleased)",{"name":14,"label":14,"prefix":14,"channel":15},"0.6","old",{"name":17,"label":17,"prefix":17,"channel":15},"0.5",{"name":19,"label":19,"prefix":19,"channel":15},"0.4",{"name":21,"label":21,"prefix":21,"channel":15},"0.3",{"name":23,"label":23,"prefix":23,"channel":15},"0.2",{"name":25,"label":25,"prefix":25,"channel":15},"0.1",{"name":6,"label":7,"prefix":8,"channel":9,"base":27},"\u002Fdocs",[29,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,91,94,97,100,103],{"slug":30,"title":31,"preview":32},"index","Home",false,{"slug":34,"title":35,"preview":32},"getting-started","Getting started",{"slug":37,"title":38,"preview":32},"concepts","E-invoicing basics",{"slug":40,"title":41,"preview":32},"examples","Examples",{"slug":43,"title":44,"preview":32},"building-invoices","Building invoices",{"slug":46,"title":47,"preview":32},"formats","Formats and profiles",{"slug":49,"title":50,"preview":32},"validation","Validation",{"slug":52,"title":53,"preview":32},"templates","Templates and design",{"slug":55,"title":56,"preview":32},"documents","Quotes and other documents",{"slug":58,"title":59,"preview":32},"reading","Reading incoming invoices",{"slug":61,"title":62,"preview":32},"laravel","Laravel integration",{"slug":64,"title":65,"preview":32},"configuration","Configuration",{"slug":67,"title":68,"preview":32},"commands","Artisan commands",{"slug":70,"title":71,"preview":32},"testing","Testing",{"slug":73,"title":74,"preview":32},"country-packs","Country packs",{"slug":76,"title":77,"parent":74,"preview":32},"country-at","Austria",{"slug":79,"title":80,"parent":74,"preview":32},"country-be","Belgium",{"slug":82,"title":83,"parent":74,"preview":32},"country-ch","Switzerland",{"slug":85,"title":86,"parent":74,"preview":32},"country-fr","France",{"slug":88,"title":89,"preview":90},"managed","Managed layer (preview)",true,{"slug":92,"title":93,"preview":32},"troubleshooting","Troubleshooting",{"slug":95,"title":96,"preview":32},"faq","FAQ",{"slug":98,"title":99,"preview":32},"compatibility","Versioning and compatibility",{"slug":101,"title":102,"preview":32},"field-reference","Field reference",{"slug":104,"title":105,"preview":32},"ai","AI assistants","page",{"title":50,"description":108,"html":109,"headings":110,"editUrl":204,"markdownUrl":205,"prev":206,"next":207},"Quittio checks every invoice before it issues it: against the rules of EN 16931, of the profile (for example XRechnung or Peppol, see Formats) and of the country (for example the German VAT Act).","\u003Ch1 id=\"validation\">Validation\u003C\u002Fh1>\n\u003Cp>Quittio checks every invoice before it issues it: against the rules of EN 16931, of the profile (for example XRechnung or Peppol, see \u003Ca href=\"\u002Fdocs\u002Fconcepts#formats\">Formats\u003C\u002Fa>) and of the country (for example the German VAT Act). This page explains what happens when an invoice is invalid, how to read and handle the messages and how to configure the checks. It then describes the validation levels, the installation of the official external validators, all built-in rules and how to add your own.\u003C\u002Fp>\n\u003Cp>Rule codes such as \u003Ccode>BR-CO-25\u003C\u002Fcode> are explained in \u003Ca href=\"\u002Fdocs\u002Fconcepts#rules-and-validation\">Rules and validation\u003C\u002Fa>, field numbers such as BT-10 in \u003Ca href=\"\u002Fdocs\u002Fconcepts#en-16931-and-business-terms\">EN 16931 and business terms\u003C\u002Fa>. Common errors and their fixes are listed in \u003Ca href=\"\u002Fdocs\u002Ftroubleshooting\">Troubleshooting\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"errors-while-rendering\">Errors while rendering\u003Ca class=\"q-doc-anchor\" href=\"#errors-while-rendering\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>By default (validation mode \u003Ccode>error\u003C\u002Fcode>), an invoice with errors is not rendered: \u003Ccode>render()\u003C\u002Fcode> throws a \u003Ccode>Quittio\\Core\\Validation\\ValidationException\u003C\u002Fcode>. Its message lists the first five errors, each with rule code, field and message, and the hint on the next line. For example, an XRechnung without buyer reference:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>text\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan>The invoice is not valid (2 errors):\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan>[QUITTIO-PROFILE-REQUIRED] BT-10: The field buyerReference (BT-10) is mandatory in profile XRechnung 3.0.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan>    Provide the field or choose a profile that does not require it.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan>[BR-DE-15] BT-10: The buyer reference (BT-10) must be provided.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan>    Set the Leitweg-ID with ->buyerReference('04011000-12345-03').\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>More than five errors end with &quot;… and N more.&quot;; the full result is in \u003Ccode>$e-&gt;result\u003C\u002Fcode>. When only warnings block (with \u003Ccode>block_on_warnings\u003C\u002Fcode>), the message lists the blocking warnings instead.\u003C\u002Fp>\n\u003Ch3 id=\"reading-a-message\">Reading a message\u003Ca class=\"q-doc-anchor\" href=\"#reading-a-message\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Each finding starts with its rule code in brackets:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>[BR-DE-15]\u003C\u002Fcode> is the rule code. Its prefix tells where the rule comes from: \u003Ccode>BR-\u003C\u002Fcode> EN 16931, \u003Ccode>BR-DE-\u003C\u002Fcode> XRechnung, \u003Ccode>PEPPOL-\u003C\u002Fcode> Peppol, \u003Ccode>DE-USTG-\u003C\u002Fcode> the German VAT Act (UStG), \u003Ccode>QUITTIO-\u003C\u002Fcode> Quittio itself. All built-in rules are listed in \u003Ca href=\"#rule-sets\">Rule sets\u003C\u002Fa>.\u003C\u002Fli>\n\u003Cli>\u003Ccode>BT-10\u003C\u002Fcode> is the field, here the buyer reference. The \u003Ca href=\"\u002Fdocs\u002Ffield-reference\">Field reference\u003C\u002Fa> shows where each field is in the data model.\u003C\u002Fli>\n\u003Cli>The text is the message. The indented line below is the hint, usually the builder method that fixes the error. The hint of \u003Ccode>BR-DE-15\u003C\u002Fcode> sets the Leitweg-ID, the routing ID of a German public buyer (\u003Ca href=\"\u002Fdocs\u002Fconcepts#german-terms\">German terms\u003C\u002Fa>).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>One missing value can be reported by more than one rule. In the example, the field check of the profile (level L2, \u003Ccode>QUITTIO-PROFILE-REQUIRED\u003C\u002Fcode>) and the XRechnung rule \u003Ccode>BR-DE-15\u003C\u002Fcode> (level L3) both report the buyer reference. Setting it fixes both.\u003C\u002Fp>\n\u003Ch3 id=\"handling-the-exception\">Handling the exception\u003Ca class=\"q-doc-anchor\" href=\"#handling-the-exception\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\ValidationException\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Laravel\\Facades\\Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">try\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    $rendered \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($invoice)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">format\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xrechnung-cii'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">render\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">} \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">catch\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">ValidationException\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $e) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FF7B72\">    foreach\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($e\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">result\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">errors\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">() \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">as\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $message) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#D2A8FF\">        report\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($message\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">code\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">.\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">' '\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">.\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">$message\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">message);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>\u003Ccode>$e-&gt;result\u003C\u002Fcode> is a \u003Ca href=\"#the-result\">\u003Ccode>ValidationResult\u003C\u002Fcode>\u003C\u002Fa> with all findings.\u003C\u002Fp>\n\u003Cp>The Laravel integration dispatches two events (\u003Ca href=\"\u002Fdocs\u002Flaravel#events\">Events\u003C\u002Fa>):\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>InvoiceValidationFailed($invoice, $result)\u003C\u002Fcode> before the exception is thrown,\u003C\u002Fli>\n\u003Cli>\u003Ccode>InvoiceValidated($invoice, $result)\u003C\u002Fcode> after a successful run. This includes mode \u003Ccode>warn\u003C\u002Fcode>, with warnings or errors, but not mode \u003Ccode>off\u003C\u002Fcode>, where nothing is validated.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Other exceptions of a render run:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>ConfigurationException\u003C\u002Fcode>: unknown format, profile not supported by the format, watermark with e-invoice XML, invalid design values,\u003C\u002Fli>\n\u003Cli>\u003Ccode>Quittio\\Core\\View\\MandatoryFieldMissing\u003C\u002Fcode> from the \u003Ca href=\"#mandatory-field-guard\">mandatory field guard\u003C\u002Fa>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>All exceptions of the package implement \u003Ccode>Quittio\\Core\\Exceptions\\QuittioException\u003C\u002Fcode>, so \u003Ccode>catch (QuittioException $e)\u003C\u002Fcode> catches every error of Quittio. Invalid arguments and runtime errors without a class of their own are \u003Ccode>InvalidArgumentException\u003C\u002Fcode>, \u003Ccode>RuntimeException\u003C\u002Fcode> or \u003Ccode>LogicException\u003C\u002Fcode> from \u003Ccode>Quittio\\Core\\Exceptions\u003C\u002Fcode>; they extend the PHP classes of the same name.\u003C\u002Fp>\n\u003Ch3 id=\"warnings\">Warnings\u003Ca class=\"q-doc-anchor\" href=\"#warnings\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Every finding has a severity: error, warning or info. Only errors stop the rendering. Warnings, for example a BIC with an invalid format (\u003Ccode>QUITTIO-BIC\u003C\u002Fcode>), are attached to the result: \u003Ccode>$rendered-&gt;validation()-&gt;warnings()\u003C\u002Fcode>. With \u003Ccode>block_on_warnings\u003C\u002Fcode> set to \u003Ccode>true\u003C\u002Fcode>, warnings block like errors (\u003Ca href=\"#configuration\">Configuration\u003C\u002Fa>).\u003C\u002Fp>\n\u003Ch3 id=\"checking-without-rendering\">Checking without rendering\u003Ca class=\"q-doc-anchor\" href=\"#checking-without-rendering\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>While you build an invoice, \u003Ccode>check()\u003C\u002Fcode> instead of \u003Ccode>render()\u003C\u002Fcode> shows all findings at once. It validates like \u003Ccode>render()\u003C\u002Fcode>, renders no PDF, returns the \u003Ccode>ValidationResult\u003C\u002Fcode> and never throws for invalid data:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Laravel\\Facades\\Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$report \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">invoice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">buyer\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($customer)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">line\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'Consulting'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FFA657\">netPrice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'120.00'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">check\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xrechnung-cii'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$report \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($invoice)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">format\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xrechnung-cii'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">check\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$report\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">isValid\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$report\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">errors\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Details are in \u003Ca href=\"#when-validation-runs\">When validation runs\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"configuration\">Configuration\u003Ca class=\"q-doc-anchor\" href=\"#configuration\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The validation mode decides what happens with errors:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Mode\u003C\u002Fth>\n\u003Cth>Behaviour\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>error\u003C\u002Fcode> (default)\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour\">Errors throw a \u003Ccode>ValidationException\u003C\u002Fcode>; nothing is rendered.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>warn\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour\">The run continues. \u003Ccode>$rendered-&gt;validation()\u003C\u002Fcode> holds all findings, errors included.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>off\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour\">Nothing is validated while rendering; the result is empty. \u003Ccode>check()\u003C\u002Fcode> and \u003Ccode>prepare()\u003C\u002Fcode> still validate.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Set it for the application with \u003Ccode>validation.mode\u003C\u002Fcode> (environment variable \u003Ccode>QUITTIO_VALIDATION_MODE\u003C\u002Fcode>), or for one call.\u003C\u002Fp>\n\u003Ch3 id=\"per-call\">Per call\u003Ca class=\"q-doc-anchor\" href=\"#per-call\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($invoice)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">validate\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">render\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();               \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F mode error\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($invoice)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">validate\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">false\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">render\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();          \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F mode warn: errors are attached, nothing is thrown\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($invoice)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">withoutValidation\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">render\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();      \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F mode off: empty result (check() and prepare() still validate)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($invoice)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">option\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'max_decimals'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">6\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">render\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(); \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F option for the rules\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch3 id=\"settings\">Settings\u003Ca class=\"q-doc-anchor\" href=\"#settings\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>In Laravel (keys of \u003Ccode>config\u002Fquittio.php\u003C\u002Fcode>, see \u003Ca href=\"\u002Fdocs\u002Fconfiguration#validation\">Configuration\u003C\u002Fa>). The levels L1 to L7 are described in \u003Ca href=\"#validation-levels\">Validation levels\u003C\u002Fa> below.\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Key\u003C\u002Fth>\n\u003Cth>Values\u003C\u002Fth>\n\u003Cth>Default\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.mode\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">\u003Ccode>error\u003C\u002Fcode> (throw), \u003Ccode>warn\u003C\u002Fcode> (attach the result only), \u003Ccode>off\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>error\u003C\u002Fcode> (\u003Ccode>QUITTIO_VALIDATION_MODE\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.levels\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">\u003Ccode>php\u003C\u002Fcode> (L1, L2, L3, L7), \u003Ccode>xsd\u003C\u002Fcode> (L4), \u003Ccode>kosit\u003C\u002Fcode> (L5), \u003Ccode>verapdf\u003C\u002Fcode> (L6), or the name of a driver registered with \u003Ccode>Quittio::extend('validator', …)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>['php', 'xsd']\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.block_on_warnings\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">\u003Ccode>true\u003C\u002Fcode>: warnings block like errors\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>false\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.locale\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">language of the messages: \u003Ccode>null\u003C\u002Fcode> = the language of the application, \u003Ccode>'invoice'\u003C\u002Fcode> = the language of the invoice, or a locale\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>null\u003C\u002Fcode> (\u003Ccode>QUITTIO_VALIDATION_LOCALE\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.mandatory_field_guard\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">\u003Ccode>exception\u003C\u002Fcode>, \u003Ccode>log\u003C\u002Fcode>, \u003Ccode>off\u003C\u002Fcode>; \u003Ccode>null\u003C\u002Fcode> = \u003Ccode>exception\u003C\u002Fcode> outside production, \u003Ccode>log\u003C\u002Fcode> in production\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>null\u003C\u002Fcode> (\u003Ccode>QUITTIO_MANDATORY_FIELD_GUARD\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.rules\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">single PHP rules switched off or re-rated by code, see \u003Ca href=\"#switching-rules-off-and-changing-their-severity\">Switching rules off\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">nothing changed\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.drivers.kosit\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">see \u003Ca href=\"#kosit-validator-l5\">KoSIT validator\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.drivers.verapdf\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">see \u003Ca href=\"#verapdf-l6\">veraPDF\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>validation.drivers.vies\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Values\">see \u003Ca href=\"#vat-identifiers-and-vies\">VIES\u003C\u002Fa>\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Without Laravel, \u003Ccode>Quittio::create()\u003C\u002Fcode> takes the same settings. It uses the level names of the enum and separate switches for the external validators:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Country\\DE\\CountryDE\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$quittio \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">create\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">([\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#A5D6FF\">    'validation'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'mode'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'error'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">,                              \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F error, warn, off\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'levels'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'L1'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'L2'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'L3'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'L4'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'L7'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">],     \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F default; L5 and L6 are switched on below\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'block_on_warnings'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> false\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'kosit'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'enabled'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> true\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'mode'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'daemon'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'url'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'http:\u002F\u002F127.0.0.1:8081'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'verapdf'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'enabled'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> true\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'mode'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'docker'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    ],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#A5D6FF\">    'mandatory_fields'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'exception'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">,                  \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F exception, log, off\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#A5D6FF\">    'options'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'max_decimals'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> 4\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">],                 \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F options for rules, see below\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">], [\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> CountryDE\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">]);\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>In \u003Ccode>Quittio::create()\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>The PHP driver runs only the listed levels of L1, L2, L3 and L7, so L7 can be left out.\u003C\u002Fli>\n\u003Cli>\u003Ccode>L4\u003C\u002Fcode> adds the XSD driver.\u003C\u002Fli>\n\u003Cli>The KoSIT and veraPDF drivers are added only with \u003Ccode>enabled =&gt; true\u003C\u002Fcode>. Listing \u003Ccode>L5\u003C\u002Fcode> or \u003Ccode>L6\u003C\u002Fcode> alone has no effect.\u003C\u002Fli>\n\u003Cli>An unknown mode throws a \u003Ccode>ConfigurationException\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"options-for-rules\">Options for rules\u003Ca class=\"q-doc-anchor\" href=\"#options-for-rules\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Some rules read options. Set them per call with \u003Ccode>-&gt;option()\u003C\u002Fcode>, without Laravel also in \u003Ccode>options\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Option\u003C\u002Fth>\n\u003Cth>Used by\u003C\u002Fth>\n\u003Cth>Default\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>max_decimals\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Used by\">\u003Ccode>QUITTIO-PRECISION\u003C\u002Fcode>: more decimals in quantity or net price are a warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>4\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>attachment_max_bytes\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Used by\">\u003Ccode>QUITTIO-ATTACHMENT-SIZE\u003C\u002Fcode>: limit per attached document\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">10 MB\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>attachments_max_total_bytes\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Used by\">\u003Ccode>QUITTIO-ATTACHMENT-SIZE\u003C\u002Fcode>: limit of all attachments\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">15 MB\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>syntax\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Used by\">Syntax of the XML that will be written (\u003Ccode>Quittio\\Core\\Profiles\\Syntax\u003C\u002Fcode>); set by the run for every format with XML, used by \u003Ccode>QUITTIO-THIRD-PARTY-PAYMENTS\u003C\u002Fcode>, \u003Ccode>QUITTIO-CREDIT-NOTE-DUE-DATE\u003C\u002Fcode>, the \u003Ccode>BR-DEX-…\u003C\u002Fcode> rules, \u003Ccode>DE-XRECHNUNG-EXT-01\u003C\u002Fcode> and the rules a profile replaces (\u003Ccode>ReplacesRules\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">from the format\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch2 id=\"validation-levels\">Validation levels\u003Ca class=\"q-doc-anchor\" href=\"#validation-levels\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The checks are split into seven levels. Each level is checked by a driver. The default configuration runs L1 to L4 and L7 in PHP. L5 and L6 use the official external validators, which you install separately.\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Level\u003C\u002Fth>\n\u003Cth>What is checked\u003C\u002Fth>\n\u003Cth>Driver\u003C\u002Fth>\n\u003Cth>Stage\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>L1\u003C\u002Ftd>\n\u003Ctd data-label=\"What is checked\">Structure and data formats of the data model (calculated, country and currency codes, decimals)\u003C\u002Ftd>\n\u003Ctd data-label=\"Driver\">\u003Ccode>php\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Stage\">data\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>L2\u003C\u002Ftd>\n\u003Ctd data-label=\"What is checked\">Mandatory and allowed fields of the profile (field matrix)\u003C\u002Ftd>\n\u003Ctd data-label=\"Driver\">\u003Ccode>php\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Stage\">data\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>L3\u003C\u002Ftd>\n\u003Ctd data-label=\"What is checked\">Business rules: EN 16931 (\u003Ccode>BR-…\u003C\u002Fcode>, \u003Ccode>BR-CO-…\u003C\u002Fcode>, \u003Ccode>BR-CL-…\u003C\u002Fcode>, VAT categories), package rules (\u003Ccode>QUITTIO-…\u003C\u002Fcode>), profile rules (Peppol, XRechnung) and country pack rules (\u003Ccode>DE-USTG-…\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd data-label=\"Driver\">\u003Ccode>php\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Stage\">data\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>L4\u003C\u002Ftd>\n\u003Ctd data-label=\"What is checked\">XML against the XSD (CII D16B, UBL 2.1)\u003C\u002Ftd>\n\u003Ctd data-label=\"Driver\">\u003Ccode>xsd\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Stage\">xml\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>L5\u003C\u002Ftd>\n\u003Ctd data-label=\"What is checked\">XML against the official Schematron (KoSIT validator: EN 16931, XRechnung, Peppol)\u003C\u002Ftd>\n\u003Ctd data-label=\"Driver\">\u003Ccode>kosit\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Stage\">xml\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>L6\u003C\u002Ftd>\n\u003Ctd data-label=\"What is checked\">PDF\u002FA-3b conformance\u003C\u002Ftd>\n\u003Ctd data-label=\"Driver\">\u003Ccode>verapdf\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Stage\">pdf\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>L7\u003C\u002Ftd>\n\u003Ctd data-label=\"What is checked\">Plausibility: IBAN, BIC, VAT identifier formats, e-mail addresses, dates, VAT category against the destination, Leitweg-ID, optional VIES check\u003C\u002Ftd>\n\u003Ctd data-label=\"Driver\">\u003Ccode>php\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Stage\">data\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Some terms of the table:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>The XSD (XML Schema Definition) describes which elements an XML file of a syntax may contain.\u003C\u002Fli>\n\u003Cli>The Schematron files are the official rules of EN 16931, XRechnung and Peppol, published as executable checks. The \u003Ca href=\"#kosit-validator-l5\">KoSIT validator\u003C\u002Fa> runs them.\u003C\u002Fli>\n\u003Cli>PDF\u002FA-3b is the archiving variant of PDF that may carry embedded files. \u003Ca href=\"#verapdf-l6\">veraPDF\u003C\u002Fa> checks it.\u003C\u002Fli>\n\u003Cli>VIES is the EU service that confirms VAT identification numbers online (\u003Ca href=\"#vat-identifiers-and-vies\">VAT identifiers and VIES\u003C\u002Fa>).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>L1 to L3 and L7 run in PHP. L4 needs only \u003Ccode>ext-dom\u003C\u002Fcode>. L5 needs Java (or Docker), L6 needs veraPDF (or Docker). No other external validator (for example Mustang) is integrated; add one as \u003Ca href=\"#own-rules-and-drivers\">own driver\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"when-validation-runs\">When validation runs\u003Ca class=\"q-doc-anchor\" href=\"#when-validation-runs\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>A render run validates in three stages, per requested format:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>data\u003C\u002Fstrong> (L1, L2, L3, L7) on the calculated invoice, before any XML is written;\u003C\u002Fli>\n\u003Cli>\u003Cstrong>xml\u003C\u002Fstrong> (L4, L5) on the generated XML, for formats with XML (and for \u003Ccode>pdf\u003C\u002Fcode> with embedded XML for consumers, \u003Ccode>b2c_embed_xml\u003C\u002Fcode>);\u003C\u002Fli>\n\u003Cli>\u003Cstrong>pdf\u003C\u002Fstrong> (L6) on the rendered PDF.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>In mode \u003Ccode>error\u003C\u002Fcode>, the run stops after the first stage that has errors (or warnings with \u003Ccode>block_on_warnings\u003C\u002Fcode>). Data errors throw before XML is written, XML errors before the PDF is rendered. A driver runs only if it supports the subject: XML drivers need XML, veraPDF needs a PDF.\u003C\u002Fp>\n\u003Cp>The validation context holds:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>the profile of the format,\u003C\u002Fli>\n\u003Cli>the country packs: the seller's pack first, the buyer's pack for cross-border invoices,\u003C\u002Fli>\n\u003Cli>the locale of the run: the language of the invoice, which rules use for its texts,\u003C\u002Fli>\n\u003Cli>the language of the messages (\u003Ca href=\"#messages-and-translations\">Messages and translations\u003C\u002Fa>),\u003C\u002Fli>\n\u003Cli>the options.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Formats without XML (\u003Ccode>pdf\u003C\u002Fcode>, \u003Ccode>html\u003C\u002Fcode>, \u003Ccode>json\u003C\u002Fcode>) are no e-invoices: L2 (profile field matrix) is skipped for them. With several formats (\u003Ccode>-&gt;formats([...])\u003C\u002Fcode>), every format is validated with its own profile and syntax.\u003C\u002Fp>\n\u003Cp>\u003Ccode>check()\u003C\u002Fcode> and \u003Ccode>prepare()\u003C\u002Fcode> validate like a render run without template and PDF:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$result \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($invoice)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">format\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xrechnung-cii'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">check\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();      \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F ValidationResult\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$prepared \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($invoice)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">formats\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">([\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'zugferd'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">])\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">prepare\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();     \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F PreparedInvoice: data, formats, country, buyerCountry, locale, validation\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>They are explicit validation requests:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>They run the data and xml stages of every requested format with all configured drivers, whatever the validation mode (also \u003Ccode>off\u003C\u002Fcode> and \u003Ccode>withoutValidation()\u003C\u002Fcode>). The \u003Ca href=\"\u002Fdocs\u002Fmanaged\">Managed layer\u003C\u002Fa> freezes invoices with \u003Ccode>prepare()\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>They never throw a \u003Ccode>ValidationException\u003C\u002Fcode>. Configuration errors, such as an unsupported profile or an XML format for watermarked data, still throw.\u003C\u002Fli>\n\u003Cli>They take the same decisions as \u003Ccode>render()\u003C\u002Fcode>. For \u003Ccode>pdf\u003C\u002Fcode> with \u003Ccode>b2c_embed_xml\u003C\u002Fcode> (and no watermark), the embedded CII XML is generated and validated in the same profile, so what is checked is what is rendered.\u003C\u002Fli>\n\u003Cli>L6 does not run, because it needs the rendered PDF.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"the-result\">The result\u003Ca class=\"q-doc-anchor\" href=\"#the-result\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Ccode>Quittio\\Core\\Validation\\ValidationResult\u003C\u002Fcode> (immutable, \u003Ccode>JsonSerializable\u003C\u002Fcode>):\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Member\u003C\u002Fth>\n\u003Cth>Returns\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>messages\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">\u003Ccode>list&lt;ValidationMessage&gt;\u003C\u002Fcode> – all findings\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>levels\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">\u003Ccode>list&lt;ValidationLevel&gt;\u003C\u002Fcode> – the levels that were checked\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>isValid()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">\u003Ccode>true\u003C\u002Fcode> if there is no finding with severity \u003Ccode>error\u003C\u002Fcode>; warnings never make a result invalid\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hasWarnings()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">whether there are warnings\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>errors()\u003C\u002Fcode>, \u003Ccode>warnings()\u003C\u002Fcode>, \u003Ccode>infos()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">findings of one severity\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>byLevel(ValidationLevel $level)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">findings of one level\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>has(string $code)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">whether a finding with this code exists\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>merge(ValidationResult $other)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">new result with the messages of both and the union of the levels\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>toArray()\u003C\u002Fcode>, \u003Ccode>jsonSerialize()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">\u003Ccode>['valid' =&gt; bool, 'levels' =&gt; ['L1', …], 'messages' =&gt; [ … ]]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>toHtml()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">self-contained HTML fragment: status (&quot;Valid&quot;, &quot;Valid with warnings&quot;, &quot;Invalid&quot;) and a table with severity, level, code, BT and message (with the hint); CSS classes \u003Ccode>quittio-report\u003C\u002Fcode>, \u003Ccode>quittio-report-status\u003C\u002Fcode>, \u003Ccode>quittio-valid\u003C\u002Fcode>, \u003Ccode>quittio-invalid\u003C\u002Fcode>, \u003Ccode>quittio-{severity}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Ccode>Quittio\\Core\\Validation\\ValidationMessage\u003C\u002Fcode> (readonly):\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Property\u003C\u002Fth>\n\u003Cth>Content\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>severity\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">\u003Ccode>Severity::Error\u003C\u002Fcode>, \u003Ccode>Severity::Warning\u003C\u002Fcode> or \u003Ccode>Severity::Info\u003C\u002Fcode> (\u003Ccode>error\u003C\u002Fcode>, \u003Ccode>warning\u003C\u002Fcode>, \u003Ccode>info\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>code\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">rule identifier, e.g. \u003Ccode>BR-CO-25\u003C\u002Fcode>, \u003Ccode>BR-DE-15\u003C\u002Fcode>, \u003Ccode>DE-USTG-03\u003C\u002Fcode>, \u003Ccode>PEPPOL-EN16931-R010\u003C\u002Fcode>, \u003Ccode>QUITTIO-IBAN\u003C\u002Fcode>, \u003Ccode>XSD\u003C\u002Fcode>, \u003Ccode>PDFA-6.2.2-1\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>message\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">text in the language of the messages (\u003Ccode>validation.locale\u003C\u002Fcode>, see \u003Ca href=\"#messages-and-translations\">Messages and translations\u003C\u002Fa>), where a translation exists\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>level\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">\u003Ccode>ValidationLevel::L1\u003C\u002Fcode> … \u003Ccode>L7\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>bt\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">business term or group, e.g. \u003Ccode>BT-10\u003C\u002Fcode>, \u003Ccode>BG-23\u003C\u002Fcode> (nullable)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>path\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">path in the data model, e.g. \u003Ccode>buyer.vatId\u003C\u002Fcode>, \u003Ccode>line 2.price.netPrice\u003C\u002Fcode>, \u003Ccode>vatBreakdown[0].taxAmount\u003C\u002Fcode>; for XSD \u003Ccode>line 12\u003C\u002Fcode> (nullable)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hint\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">solution hint from the message catalog (nullable)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>xpath\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">location in the XML (KoSIT findings, nullable)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Ccode>isError()\u003C\u002Fcode> and \u003Ccode>toArray()\u003C\u002Fcode> are available on every message.\u003C\u002Fp>\n\u003Cp>Results of several drivers are merged by concatenation. A rule that is checked both in PHP (L3) and by the official Schematron (L5) can therefore appear twice, with the two levels. Within the PHP driver, identical findings (same code, path and message) are reported once.\u003C\u002Fp>\n\u003Ch2 id=\"messages-and-translations\">Messages and translations\u003Ca class=\"q-doc-anchor\" href=\"#messages-and-translations\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>In Laravel, messages and hints are written in the language of the application (\u003Ccode>app()-&gt;getLocale()\u003C\u002Fcode>). A developer of an English application therefore reads English messages, also for German invoices. \u003Ccode>validation.locale\u003C\u002Fcode> sets \u003Ccode>'invoice'\u003C\u002Fcode> (the language of the invoice, as in the PDF) or a fixed locale.\u003C\u002Fp>\n\u003Cp>Without Laravel, the default is the language of the invoice. \u003Ccode>Quittio::create(['validation' =&gt; ['locale' =&gt; 'en']])\u003C\u002Fcode> sets a fixed locale, \u003Ccode>'app'\u003C\u002Fcode> the locale of the translator.\u003C\u002Fp>\n\u003Cp>Rules that check texts of the invoice, e.g. the reverse charge statement of \u003Ccode>DE-USTG-06\u003C\u002Fcode> (the note that the buyer owes the VAT), still use the language of the invoice.\u003C\u002Fp>\n\u003Cp>Messages come from the catalog \u003Ccode>quittio::rules.{CODE}\u003C\u002Fcode> with the entries \u003Ccode>message\u003C\u002Fcode> and \u003Ccode>hint\u003C\u002Fcode>; placeholders such as \u003Ccode>:value\u003C\u002Fcode> are replaced. The core ships the catalog in German and English (\u003Ccode>packages\u002Fcore\u002Fresources\u002Flang\u002F{de,en}\u002Frules.php\u003C\u002Fcode>). Other locales fall back to English, and rules without an entry use their English fallback text. Country packs bring their own namespace (\u003Ccode>quittio-de::rules.DE-USTG-01\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Cp>To override messages in Laravel, publish the language files with \u003Ccode>php artisan vendor:publish --tag=quittio-lang\u003C\u002Fcode> and edit \u003Ccode>lang\u002Fvendor\u002Fquittio\u002F{locale}\u002Frules.php\u003C\u002Fcode>. Without Laravel, register a directory with \u003Ccode>{locale}\u002Frules.php\u003C\u002Fcode> files; later paths override earlier ones:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\I18n\\Translations\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">Translations\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">translator\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">addPath\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">__DIR__\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">.\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'\u002Flang'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'quittio'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Findings of the XSD validation, the KoSIT validator, veraPDF and the invoice reader are not translated: they carry the text of the tool or an English text.\u003C\u002Fp>\n\u003Ch2 id=\"xml-schema-l4\">XML schema (L4)\u003Ca class=\"q-doc-anchor\" href=\"#xml-schema-l4\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Ccode>Quittio\\Core\\Validation\\Drivers\\XsdValidator\u003C\u002Fcode> validates against the bundled schemas (\u003Ccode>packages\u002Fcore\u002Fresources\u002Fxsd\u003C\u002Fcode>): CII D16B for \u003Ccode>CrossIndustryInvoice\u003C\u002Fcode>, UBL 2.1 for \u003Ccode>Invoice\u003C\u002Fcode> and \u003Ccode>CreditNote\u003C\u002Fcode>. It needs no installation. All its findings are errors:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Code\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>XSD\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">The XML does not match the schema; the path is \u003Ccode>line N\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>XSD-NOT-WELL-FORMED\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Unsafe or broken XML, see \u003Ca href=\"\u002Fdocs\u002Freading#limits-and-security\">reading\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>XSD-UNKNOWN-ROOT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">No schema for the root element\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Use it on its own with \u003Ccode>(new XsdValidator)-&gt;validateXml($xml)\u003C\u002Fcode> (returns \u003Ccode>list&lt;ValidationMessage&gt;\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Ch2 id=\"kosit-validator-l5\">KoSIT validator (L5)\u003Ca class=\"q-doc-anchor\" href=\"#kosit-validator-l5\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>KoSIT, the German agency that publishes XRechnung, provides the official validator. The official Schematron rules are XSLT 2.0, which PHP cannot execute, so L5 uses the KoSIT validator (Java). It checks EN 16931 and XRechnung (CII and UBL) with the XRechnung validator configuration, and Peppol BIS Billing 3.0 with a second configuration.\u003C\u002Fp>\n\u003Cp>To use it:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Download the validator and its configurations (\u003Ca href=\"#installation\">Installation\u003C\u002Fa>).\u003C\u002Fli>\n\u003Cli>Start it as a daemon, or let Quittio call it per document (\u003Ca href=\"#modes\">Modes\u003C\u002Fa>).\u003C\u002Fli>\n\u003Cli>Add \u003Ccode>kosit\u003C\u002Fcode> to \u003Ccode>validation.levels\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch3 id=\"installation\">Installation\u003Ca class=\"q-doc-anchor\" href=\"#installation\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>bash\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FFA657\">php\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> artisan\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> quittio:schemas:download\u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">           # into storage\u002Fquittio\u002Fvalidators\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FFA657\">php\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> artisan\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> quittio:schemas:download\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --path=\u002Fopt\u002Fvalidators\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --force\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --java=\u002Fusr\u002Fbin\u002Fjava\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FFA657\">php\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> artisan\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> quittio:schemas:download\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --without-peppol\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>The command downloads into the target directory:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>the validator \u003Ccode>1.6.3\u003C\u002Fcode> (standalone JAR from Maven Central) as \u003Ccode>validator.jar\u003C\u002Fcode>,\u003C\u002Fli>\n\u003Cli>the XRechnung validator configuration \u003Ccode>v2026-08-31\u003C\u002Fcode> (XRechnung 3.0.2) into \u003Ccode>xrechnung\u002F\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>It then compiles the Peppol BIS Billing 3.0 Schematron (\u003Ccode>v3.0.20\u003C\u002Fcode>, with SchXslt 1.10.1 and the Saxon bundled in the validator) into \u003Ccode>peppol\u002FPEPPOL-EN16931-UBL.xsl\u003C\u002Fcode>. Compiling needs Java; skip it with \u003Ccode>--without-peppol\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Existing files are kept unless \u003Ccode>--force\u003C\u002Fcode> is given. The PHP extension \u003Ccode>zip\u003C\u002Fcode> is required. Java 11 or newer is required to run the validator. At the end, the command prints the configuration to add and the command that starts the daemon on the port of \u003Ccode>validation.drivers.kosit.url\u003C\u002Fcode> (\u003Ccode>-P &lt;port&gt;\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Cp>Without Laravel use \u003Ccode>Quittio\\Core\\Validation\\Drivers\\KositArtifacts\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>download(string $target, bool $force = false)\u003C\u002Fcode> returns \u003Ccode>['jar' =&gt; …, 'scenarios' =&gt; …, 'repository' =&gt; …]\u003C\u002Fcode>,\u003C\u002Fli>\n\u003Cli>\u003Ccode>compilePeppol(string $target, string $java = 'java', bool $force = false)\u003C\u002Fcode> returns \u003Ccode>['scenarios' =&gt; …, 'repository' =&gt; …]\u003C\u002Fcode>. The scenario file \u003Ccode>peppol-scenarios.xml\u003C\u002Fcode> ships with the core (\u003Ccode>KositArtifacts::peppolScenarios()\u003C\u002Fcode>).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"modes\">Modes\u003Ca class=\"q-doc-anchor\" href=\"#modes\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Mode\u003C\u002Fth>\n\u003Cth>How\u003C\u002Fth>\n\u003Cth>Configuration\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>daemon\u003C\u002Fcode> (default, recommended)\u003C\u002Ftd>\n\u003Ctd data-label=\"How\">HTTP POST of the XML (\u003Ccode>Content-Type: application\u002Fxml\u003C\u002Fcode>) to \u003Ccode>url\u003C\u002Fcode>; a running validator answers with its report\u003C\u002Ftd>\n\u003Ctd data-label=\"Configuration\">\u003Ccode>url\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cli\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"How\">One JVM per document: \u003Ccode>java -jar {jar} -s {scenarios} -r {repository} … -o {tmp} document.xml\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Configuration\">\u003Ccode>jar\u003C\u002Fcode>, \u003Ccode>scenarios\u003C\u002Fcode> and \u003Ccode>repository\u003C\u002Fcode> and\u002For \u003Ccode>configurations\u003C\u002Fcode>, \u003Ccode>java\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Start a daemon with both configurations (paths as printed by the download command) on the port of the default URL \u003Ccode>http:\u002F\u002F127.0.0.1:8081\u003C\u002Fcode>. The validator itself listens on port 8080 unless it is started with \u003Ccode>-P\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>bash\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">cd\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> storage\u002Fquittio\u002Fvalidators\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FFA657\">java\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> -jar\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> validator.jar\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    -s\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> xrechnung\u002Fscenarios.xml\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> -r\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> xrechnung\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    -s\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> ..\u002F..\u002F..\u002Fvendor\u002Fquittio\u002Fcore\u002Fresources\u002Fkosit\u002Fpeppol-scenarios.xml\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> -r\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> .\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    -D\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> -P\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> 8081\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>The repository of Quittio contains a Docker image with the same setup (\u003Ccode>tools\u002Fdocker\u002Fkosit\u002FDockerfile\u003C\u002Fcode>). It listens on 8080 inside the container:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>bash\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FFA657\">docker\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> build\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> -t\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> quittio\u002Fkosit\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> -f\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> tools\u002Fdocker\u002Fkosit\u002FDockerfile\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> .\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FFA657\">docker\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> run\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --rm\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> -p\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 8081:8080\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> quittio\u002Fkosit\u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">       # maps it to the default port 8081\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>With another port, set \u003Ccode>QUITTIO_KOSIT_URL\u003C\u002Fcode> (without Laravel \u003Ccode>validation.kosit.url\u003C\u002Fcode>) accordingly. Any endpoint that accepts the POST and returns a KoSIT report works.\u003C\u002Fp>\n\u003Cp>\u003Ccode>validation.drivers.kosit\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Key\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003Cth>Default\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>mode\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">\u003Ccode>daemon\u003C\u002Fcode> or \u003Ccode>cli\u003C\u002Fcode> (other values throw \u003Ccode>InvalidArgumentException\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>daemon\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>url\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">daemon endpoint\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>http:\u002F\u002F127.0.0.1:8081\u003C\u002Fcode> (\u003Ccode>QUITTIO_KOSIT_URL\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>jar\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">path of \u003Ccode>validator.jar\u003C\u002Fcode> (cli)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>null\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>scenarios\u003C\u002Fcode>, \u003Ccode>repository\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">main configuration (cli)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>null\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>configurations\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">further configurations (cli), \u003Ccode>[['scenarios' =&gt; …, 'repository' =&gt; …]]\u003C\u002Fcode>, e.g. Peppol\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>[]\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>java\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Java binary (cli)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>java\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>timeout\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">seconds per document (HTTP timeout or process limit)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>30\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>fail_on_unavailable\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">an unreachable validator is an error (\u003Ccode>true\u003C\u002Fcode>) or a warning (\u003Ccode>false\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>true\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Add \u003Ccode>kosit\u003C\u002Fcode> to \u003Ccode>validation.levels\u003C\u002Fcode>. Without Laravel, the same keys go to \u003Ccode>validation.kosit\u003C\u002Fcode> with \u003Ccode>enabled =&gt; true\u003C\u002Fcode>; use \u003Ccode>configurations\u003C\u002Fcode> for all scenario sets there.\u003C\u002Fp>\n\u003Ch3 id=\"findings\">Findings\u003Ca class=\"q-doc-anchor\" href=\"#findings\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Every message of the report becomes a finding with:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>the rule code of the report (\u003Ccode>BR-DE-15\u003C\u002Fcode>, \u003Ccode>PEPPOL-EN16931-R010\u003C\u002Fcode> …),\u003C\u002Fli>\n\u003Cli>the severity of the report (\u003Ccode>error\u003C\u002Fcode>, \u003Ccode>warning\u003C\u002Fcode>, otherwise \u003Ccode>info\u003C\u002Fcode>); a level the scenario sets for the rule (\u003Ccode>customLevel\u003C\u002Fcode>, e.g. \u003Ccode>BR-CL-13\u003C\u002Fcode> as information in XRechnung) takes precedence, as in the validator's own assessment,\u003C\u002Fli>\n\u003Cli>the business term found in the text,\u003C\u002Fli>\n\u003Cli>the XPath location.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Findings of the schema step of the validator have the level L4, all others L5. A message of the schema step without a code of its own gets the code \u003Ccode>KOSIT-XSD\u003C\u002Fcode>. Additional codes:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Code\u003C\u002Fth>\n\u003Cth>Severity\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>KOSIT-UNAVAILABLE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error or warning (\u003Ccode>fail_on_unavailable\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">No report: daemon unreachable or HTTP status other than 200, 406 or 422, JAR, configuration or Java missing, timeout\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>KOSIT-NO-SCENARIO\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">The configuration has no scenario for the document (e.g. Factur-X EXTENDED); only the XML schema was checked\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>KOSIT-REJECT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">The validator recommends rejection although no message is an error\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>KOSIT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">from the report\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Message without code\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>The raw report of the last call is available from the driver instance with \u003Ccode>lastReport()\u003C\u002Fcode>, e.g. for archiving the test report. \u003Ccode>KositReportParser::parse($report)\u003C\u002Fcode> returns \u003Ccode>['accepted' =&gt; bool, 'scenario' =&gt; ?string, 'messages' =&gt; list&lt;ValidationMessage&gt;]\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"verapdf-l6\">veraPDF (L6)\u003Ca class=\"q-doc-anchor\" href=\"#verapdf-l6\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>veraPDF is an open-source validator for PDF\u002FA. \u003Ccode>Quittio\\Core\\Validation\\Drivers\\VeraPdfValidator\u003C\u002Fcode> checks the rendered PDF against PDF\u002FA-3b (\u003Ccode>--flavour 3b\u003C\u002Fcode>, machine readable report, at most 5 failures per rule). It runs for formats that produce a PDF.\u003C\u002Fp>\n\u003Ch3 id=\"installing-verapdf\">Installing veraPDF\u003Ca class=\"q-doc-anchor\" href=\"#installing-verapdf\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>veraPDF runs in one of two modes:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Mode\u003C\u002Fth>\n\u003Cth>How\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cli\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"How\">local veraPDF installation (Java); the PDF is written to a temporary file and passed to \u003Ccode>binary\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>docker\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"How\">\u003Ccode>docker run --rm -i {image}\u003C\u002Fcode>; the PDF is passed via stdin\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>For mode \u003Ccode>docker\u003C\u002Fcode>, Docker is enough; fetch the image once with \u003Ccode>docker pull verapdf\u002Fcli\u003C\u002Fcode>. For mode \u003Ccode>cli\u003C\u002Fcode>, install veraPDF locally and make its \u003Ccode>verapdf\u003C\u002Fcode> command available (or set \u003Ccode>binary\u003C\u002Fcode>). Then add \u003Ccode>verapdf\u003C\u002Fcode> to \u003Ccode>validation.levels\u003C\u002Fcode>; without Laravel use \u003Ccode>validation.verapdf\u003C\u002Fcode> with \u003Ccode>enabled =&gt; true\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>\u003Ccode>validation.drivers.verapdf\u003C\u002Fcode> (all keys are in the published configuration):\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Key\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003Cth>Default\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>mode\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">\u003Ccode>cli\u003C\u002Fcode> or \u003Ccode>docker\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>cli\u003C\u002Fcode> in the Laravel configuration, \u003Ccode>docker\u003C\u002Fcode> without Laravel\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>binary\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">veraPDF binary (cli)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>verapdf\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>image\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Docker image (docker)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>verapdf\u002Fcli\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>docker\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Docker binary (docker)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>docker\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>timeout\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">seconds\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>120\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>fail_on_unavailable\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">an unavailable veraPDF is an error (\u003Ccode>true\u003C\u002Fcode>) or a warning (\u003Ccode>false\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003Ctd data-label=\"Default\">\u003Ccode>true\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Findings of veraPDF:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Code\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PDFA-{clause}-{test}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Failed rule, e.g. \u003Ccode>PDFA-6.2.2-1\u003C\u002Fcode>; the hint names specification, clause and description, the path the PDF object\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>VERAPDF-NOT-COMPLIANT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Not compliant without a failed rule in the report\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>VERAPDF-NOT-PARSED\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">veraPDF could not validate the file\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>VERAPDF-UNAVAILABLE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">veraPDF could not be run, e.g. \u003Ccode>verapdf\u003C\u002Fcode> or \u003Ccode>docker\u003C\u002Fcode> not installed. It is reported as a finding, not thrown: an error with \u003Ccode>fail_on_unavailable\u003C\u002Fcode> (in mode \u003Ccode>error\u003C\u002Fcode> the run then stops with a \u003Ccode>ValidationException\u003C\u002Fcode>), otherwise a warning\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>All findings of the external validators are merged into the result of the run like the PHP findings.\u003C\u002Fp>\n\u003Ch2 id=\"rule-sets\">Rule sets\u003Ca class=\"q-doc-anchor\" href=\"#rule-sets\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The PHP driver (\u003Ccode>Quittio\\Core\\Validation\\Drivers\\PhpRulesDriver\u003C\u002Fcode>, name \u003Ccode>php\u003C\u002Fcode>) runs these rule sets, filtered by the configured levels:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Rule set\u003C\u002Fth>\n\u003Cth>Level\u003C\u002Fth>\n\u003Cth>Codes\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>StructureRules\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L1\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">\u003Ccode>QUITTIO-NOT-CALCULATED\u003C\u002Fcode> (no totals), \u003Ccode>QUITTIO-FORMAT-COUNTRY\u003C\u002Fcode> (BT-40, BT-55 not two upper case letters), \u003Ccode>QUITTIO-FORMAT-CURRENCY\u003C\u002Fcode> (BT-5, BT-6 not three upper case letters), \u003Ccode>QUITTIO-PRECISION\u003C\u002Fcode> (warning, more decimals than \u003Ccode>max_decimals\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>FieldMatrixRule\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L2\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">\u003Ccode>QUITTIO-PROFILE-REQUIRED\u003C\u002Fcode> (error: mandatory field of the profile missing), \u003Ccode>QUITTIO-PROFILE-NOT-ALLOWED\u003C\u002Fcode> (warning: field is not part of the profile and is not written), \u003Ccode>QUITTIO-PROFILE-EXTENDED-ONLY\u003C\u002Fcode>, \u003Ccode>QUITTIO-PROFILE-XRECHNUNG-EXTENSION-ONLY\u003C\u002Fcode>, \u003Ccode>QUITTIO-PROFILE-SUBLINES\u003C\u002Fcode> (errors). The matrix comes from the mapping attributes of the data model (\u003Ca href=\"\u002Fdocs\u002Ffield-reference\">field reference\u003C\u002Fa>) plus the business terms the profile requires (XRechnung: BT-10, BT-34, BT-49, BG-6, BG-16); BT-23 is not required when the profile sets a default business process\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>En16931Rules\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L3\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">\u003Ccode>BR-02\u003C\u002Fcode>, \u003Ccode>BR-04\u003C\u002Fcode> to \u003Ccode>BR-07\u003C\u002Fcode>, \u003Ccode>BR-09\u003C\u002Fcode>, \u003Ccode>BR-11\u003C\u002Fcode>, \u003Ccode>BR-16\u003C\u002Fcode> to \u003Ccode>BR-18\u003C\u002Fcode>, \u003Ccode>BR-20\u003C\u002Fcode>, \u003Ccode>BR-21\u003C\u002Fcode>, \u003Ccode>BR-25\u003C\u002Fcode>, \u003Ccode>BR-27\u003C\u002Fcode> to \u003Ccode>BR-30\u003C\u002Fcode>, \u003Ccode>BR-33\u003C\u002Fcode>, \u003Ccode>BR-38\u003C\u002Fcode>, \u003Ccode>BR-42\u003C\u002Fcode>, \u003Ccode>BR-44\u003C\u002Fcode>, \u003Ccode>BR-48\u003C\u002Fcode> to \u003Ccode>BR-50\u003C\u002Fcode>, \u003Ccode>BR-52\u003C\u002Fcode> to \u003Ccode>BR-57\u003C\u002Fcode>, \u003Ccode>BR-61\u003C\u002Fcode>, \u003Ccode>BR-CO-03\u003C\u002Fcode>, \u003Ccode>BR-CO-09\u003C\u002Fcode> to \u003Ccode>BR-CO-18\u003C\u002Fcode>, \u003Ccode>BR-CO-25\u003C\u002Fcode>, \u003Ccode>BR-CO-26\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>VatCategoryRules\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L3\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">per category (\u003Ccode>BR-S\u003C\u002Fcode>, \u003Ccode>BR-Z\u003C\u002Fcode>, \u003Ccode>BR-E\u003C\u002Fcode>, \u003Ccode>BR-AE\u003C\u002Fcode>, \u003Ccode>BR-IC\u003C\u002Fcode>, \u003Ccode>BR-G\u003C\u002Fcode>, \u003Ccode>BR-O\u003C\u002Fcode>, \u003Ccode>BR-AF\u003C\u002Fcode> for L, \u003Ccode>BR-AG\u003C\u002Fcode> for M): \u003Ccode>-01\u003C\u002Fcode> breakdown present, \u003Ccode>-02\u003C\u002Fcode> party identifiers, \u003Ccode>-05\u003C\u002Fcode> rate, \u003Ccode>-08\u003C\u002Fcode> taxable amount, \u003Ccode>-09\u003C\u002Fcode> tax amount, \u003Ccode>-10\u003C\u002Fcode> exemption reason; \u003Ccode>-02\u003C\u002Fcode> and \u003Ccode>-05\u003C\u002Fcode> also cover document level allowances and charges (the Schematron rules \u003Ccode>-03\u003C\u002Fcode>, \u003Ccode>-04\u003C\u002Fcode>, \u003Ccode>-06\u003C\u002Fcode>, \u003Ccode>-07\u003C\u002Fcode>). Plus \u003Ccode>BR-IC-11\u003C\u002Fcode>, \u003Ccode>BR-IC-12\u003C\u002Fcode>, \u003Ccode>BR-O-11\u003C\u002Fcode>, \u003Ccode>BR-B-01\u003C\u002Fcode> (split payment only in a domestic Italian invoice: every country code is \u003Ccode>IT\u003C\u002Fcode>), \u003Ccode>BR-B-02\u003C\u002Fcode> (no category S next to B) and \u003Ccode>QUITTIO-IGIC-ZERO-RATE-CII\u003C\u002Fcode> (warning, see below)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>CodeListRules\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L3\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">\u003Ccode>BR-CL-01\u003C\u002Fcode>, \u003Ccode>-04\u003C\u002Fcode> to \u003Ccode>-08\u003C\u002Fcode>, \u003Ccode>-10\u003C\u002Fcode>, \u003Ccode>-11\u003C\u002Fcode>, \u003Ccode>-13\u003C\u002Fcode>, \u003Ccode>-14\u003C\u002Fcode>, \u003Ccode>-16\u003C\u002Fcode>, \u003Ccode>-19\u003C\u002Fcode> to \u003Ccode>-26\u003C\u002Fcode> (official code lists; \u003Ccode>-24\u003C\u002Fcode> reports \u003Ccode>MimeType::Xml\u003C\u002Fcode> outside the XRechnung extension)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QuittioRules\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L3\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">package rules, see below\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PlausibilityRules\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L7\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">see \u003Ca href=\"#plausibility-l7\">plausibility\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>profile rules\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L3\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">Peppol BIS profile: \u003Ccode>PEPPOL-EN16931-R001\u003C\u002Fcode>, \u003Ccode>-R002\u003C\u002Fcode>, \u003Ccode>-R003\u003C\u002Fcode>, \u003Ccode>-R005\u003C\u002Fcode> (warning), \u003Ccode>-R007\u003C\u002Fcode>, \u003Ccode>-R008\u003C\u002Fcode>, \u003Ccode>-R010\u003C\u002Fcode>, \u003Ccode>-R020\u003C\u002Fcode>, \u003Ccode>-R040\u003C\u002Fcode>, \u003Ccode>-R041\u003C\u002Fcode>, \u003Ccode>-R042\u003C\u002Fcode>, \u003Ccode>-R046\u003C\u002Fcode>, \u003Ccode>-R055\u003C\u002Fcode>, \u003Ccode>-R061\u003C\u002Fcode>, \u003Ccode>-R110\u003C\u002Fcode>, \u003Ccode>-R111\u003C\u002Fcode>, \u003Ccode>-R120\u003C\u002Fcode>, \u003Ccode>-R121\u003C\u002Fcode>, \u003Ccode>-R130\u003C\u002Fcode>, \u003Ccode>-CL007\u003C\u002Fcode>, \u003Ccode>-CL008\u003C\u002Fcode>, \u003Ccode>-F001\u003C\u002Fcode>, \u003Ccode>-P0100\u003C\u002Fcode>, \u003Ccode>-P0101\u003C\u002Fcode>, \u003Ccode>-P0104\u003C\u002Fcode> to \u003Ccode>-P0112\u003C\u002Fcode>, \u003Ccode>PEPPOL-COMMON-R040\u003C\u002Fcode> to \u003Ccode>-R047\u003C\u002Fcode>, \u003Ccode>-R049\u003C\u002Fcode>, \u003Ccode>-R050\u003C\u002Fcode>, \u003Ccode>-R052\u003C\u002Fcode>, \u003Ccode>-R053\u003C\u002Fcode> (\u003Ccode>-R044\u003C\u002Fcode> to \u003Ccode>-R047\u003C\u002Fcode>, \u003Ccode>-R052\u003C\u002Fcode>, \u003Ccode>-R053\u003C\u002Fcode> warnings), see \u003Ca href=\"#peppol-rules\">Peppol rules\u003C\u002Fa>; XRechnung profiles (country pack DE): \u003Ccode>BR-DE-…\u003C\u002Fcode>, \u003Ccode>DE-XRECHNUNG-EXT-01\u003C\u002Fcode>; XRechnung extension: \u003Ccode>BR-DEX-02\u003C\u002Fcode> (warning), \u003Ccode>BR-DEX-04\u003C\u002Fcode> to \u003Ccode>-10\u003C\u002Fcode>, \u003Ccode>-12\u003C\u002Fcode> to \u003Ccode>-15\u003C\u002Fcode>; XRechnung CVD: \u003Ccode>BR-DE-CVD-01\u003C\u002Fcode> to \u003Ccode>BR-DE-CVD-06-b\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>country pack rules\u003C\u002Ftd>\n\u003Ctd data-label=\"Level\">L3, L7\u003C\u002Ftd>\n\u003Ctd data-label=\"Codes\">\u003Ccode>rules()\u003C\u002Fcode> of the seller's pack and \u003Ccode>buyerCountryRules()\u003C\u002Fcode> of the buyer's pack; Germany: \u003Ccode>DE-USTG-01\u003C\u002Fcode> … \u003Ccode>DE-USTG-15\u003C\u002Fcode> (L3), \u003Ccode>DE-LEITWEG-ID\u003C\u002Fcode>, \u003Ccode>DE-LEITWEG-ID-SUSPECT\u003C\u002Fcode>, \u003Ccode>DE-TAX-NUMBER\u003C\u002Fcode> (L7), see \u003Ca href=\"\u002Fdocs\u002Fcountry-packs\">Country packs\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>All EN 16931, code list, VAT category and Peppol rules report errors unless noted. The PHP rules check the invoice data before any XML is written, with readable messages: the EN 16931 rules, the XRechnung rules (\u003Ccode>BR-DE-…\u003C\u002Fcode>, \u003Ccode>BR-DEX-…\u003C\u002Fcode>, \u003Ccode>BR-DE-CVD-…\u003C\u002Fcode>) and the Peppol rules that invoice data can violate. Rules that the builder or the writers always fulfil are not checked again; they are listed with the reason (\u003Ca href=\"\u002Fdocs\u002Fcountry-packs#xrechnung-rules\">XRechnung rules\u003C\u002Fa>, \u003Ca href=\"#peppol-rules\">Peppol rules\u003C\u002Fa>). The PHP rules do not replace the official Schematron (L5), which checks the written XML.\u003C\u002Fp>\n\u003Cp>A profile can replace rules with its own (\u003Ccode>Profiles\\Capabilities\\ReplacesRules\u003C\u002Fcode>); the driver then does not run them for that profile. The XRechnung extension replaces \u003Ccode>BR-CL-10\u003C\u002Fcode>, \u003Ccode>-11\u003C\u002Fcode>, \u003Ccode>-21\u003C\u002Fcode>, \u003Ccode>-25\u003C\u002Fcode>, \u003Ccode>-26\u003C\u002Fcode> with \u003Ccode>BR-DEX-04\u003C\u002Fcode> to \u003Ccode>-08\u003C\u002Fcode>, accepts the MIME code \u003Ccode>application\u002Fxml\u003C\u002Fcode> in \u003Ccode>BR-CL-24\u003C\u002Fcode> (\u003Ccode>BR-DEX-01\u003C\u002Fcode>) and, in UBL, \u003Ccode>BR-CO-16\u003C\u002Fcode> with \u003Ccode>BR-DEX-09\u003C\u002Fcode> and \u003Ccode>QUITTIO-SUBLINES\u003C\u002Fcode> with \u003Ccode>BR-DEX-02\u003C\u002Fcode>, as its official validator configuration does (\u003Ca href=\"\u002Fdocs\u002Fcountry-packs#xrechnung-rules\">XRechnung rules\u003C\u002Fa>).\u003C\u002Fp>\n\u003Ch3 id=\"package-rules-quittio-\">Package rules (\u003Ccode>QUITTIO-…\u003C\u002Fcode>)\u003Ca class=\"q-doc-anchor\" href=\"#package-rules-quittio-\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Code\u003C\u002Fth>\n\u003Cth>Severity\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-NEGATIVE-TOTAL\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Commercial invoice (380) with a negative amount due; consider a credit note\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-SUBLINES\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Net amount of a line differs from the sum of its sub lines (XRechnung extension in UBL: \u003Ccode>BR-DEX-02\u003C\u002Fcode>, warning)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-LINE-ID-DUPLICATE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">A line identifier (BT-126) is used more than once (data not built with \u003Ccode>InvoiceBuilder\u003C\u002Fcode>, which rejects duplicates)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-SUBLINE-VAT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Sub line with another VAT category or rate than its parent line\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-PRECEDING-INVOICES-CII\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">More than one preceding invoice (BG-3): CII transmits only the first\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-IGIC-ZERO-RATE-CII\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Category L (IGIC) with the rate 0 in a profile that renders CII: EN 16931 and the UBL Schematron accept it, the CII Schematron requires a rate greater than zero (BR-AF-05 to BR-AF-07); use UBL\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-EXEMPTION-CONFLICT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Lines of one VAT group with different exemption reason codes: the code (BT-121) is omitted, the texts are joined\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-DECLARED-AMOUNTS\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Declared amounts of an existing document were outside the tolerance and recalculated\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-THIRD-PARTY-PAYMENTS\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Third party payments (BG-DEX-09) outside an XRechnung UBL invoice of the extension\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-CREDIT-NOTE-DUE-DATE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">UBL credit note with a due date (BT-9) but without payment instructions (BG-16): the UBL binding has no place for the date there, it is left out\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-VAT-ROUNDING\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">VAT amount differs from taxable amount × rate within the tolerance of BR-CO-17\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-CANCELLATION-VAT-ALIGNED\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">info\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">VAT of a partial cancellation aligned with the earlier ones (cumulative rounding)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-LINE-ROUNDING\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Declared line net amount differs from quantity × price ± allowances and charges\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-ATTACHMENT-FILENAME\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">File name of an attached document used twice\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-ATTACHMENT-SIZE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Attachments larger than \u003Ccode>attachment_max_bytes\u003C\u002Fcode> or \u003Ccode>attachments_max_total_bytes\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-INVALID-CHARACTERS\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">A text contains control characters (e.g. a vertical tab from a spreadsheet cell) or invalid UTF-8, which XML cannot represent; XML writers refuse such data\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-GENERIC-COUNTRY\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">No country pack for the seller's country: only EN 16931 is checked\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-PROFILE-NOT-EINVOICE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Profile that is no EN 16931 e-invoice (MINIMUM, BASIC WL)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-STANDARD-VERSION\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">The profile does not support the EN 16931 version of the invoice\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-PROFORMA\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Meaning\">Type code 325 in the invoice pipeline; use \u003Ccode>Quittio::proforma()\u003C\u002Fcode> or \u003Ccode>DocumentBuilder::proforma()\u003C\u002Fcode> (\u003Ca href=\"\u002Fdocs\u002Fdocuments#proforma-invoices\">documents\u003C\u002Fa>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch3 id=\"peppol-rules\">Peppol rules\u003Ca class=\"q-doc-anchor\" href=\"#peppol-rules\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>The Peppol BIS Billing 3.0 Schematron (3.0.20) has 59 rule ids of its own (\u003Ccode>PEPPOL-EN16931-…\u003C\u002Fcode>, \u003Ccode>PEPPOL-COMMON-…\u003C\u002Fcode>); the national rules it contains (\u003Ccode>NO-R-…\u003C\u002Fcode>, \u003Ccode>DK-R-…\u003C\u002Fcode>, \u003Ccode>SE-R-…\u003C\u002Fcode> …) are not ported. In the Peppol profile the PHP rules check every rule that the data of an invoice can break. The others need no PHP rule:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Rules\u003C\u002Fth>\n\u003Cth>Why there is no PHP rule\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PEPPOL-EN16931-R004\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Why there is no PHP rule\">The writer takes the specification identifier (BT-24) from the profile.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PEPPOL-EN16931-R043\u003C\u002Fcode>, \u003Ccode>-R044\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Why there is no PHP rule\">The writer writes the charge indicator itself, \u003Ccode>false\u003C\u002Fcode> for the price discount (BT-147).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PEPPOL-EN16931-R051\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Why there is no PHP rule\">The writer gives every amount the invoice currency (BT-5), BT-111 the VAT accounting currency (BT-6).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PEPPOL-EN16931-R053\u003C\u002Fcode>, \u003Ccode>-R054\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Why there is no PHP rule\">The writer writes one \u003Ccode>cac:TaxTotal\u003C\u002Fcode> with the VAT breakdown and a second one with BT-111 only together with BT-6. A missing breakdown or BT-111 is reported by \u003Ccode>BR-CO-18\u003C\u002Fcode> and \u003Ccode>BR-53\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PEPPOL-EN16931-R080\u003C\u002Fcode>, \u003Ccode>-R100\u003C\u002Fcode>, \u003Ccode>-R101\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Why there is no PHP rule\">The data holds one project reference (BT-11) and one invoiced object per line (BT-128); the writer gives the line reference the type code 130.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PEPPOL-EN16931-CL001\u003C\u002Fcode>, \u003Ccode>-CL002\u003C\u002Fcode>, \u003Ccode>-CL003\u003C\u002Fcode>, \u003Ccode>-CL006\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Why there is no PHP rule\">The lists equal those of \u003Ccode>BR-CL-24\u003C\u002Fcode>, \u003Ccode>BR-CL-19\u003C\u002Fcode>, \u003Ccode>BR-CL-20\u003C\u002Fcode> and \u003Ccode>BR-CL-06\u003C\u002Fcode>, which report the code once (\u003Ccode>BR-CL-24\u003C\u002Fcode> reports \u003Ccode>MimeType::Xml\u003C\u002Fcode>, the only case outside the list).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>PEPPOL-COMMON-R048\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Why there is no PHP rule\">Commented out in the Schematron.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Where a Peppol rule overlaps an EN 16931 rule, the Peppol code is reported only for what the Peppol rule adds: \u003Ccode>-CL007\u003C\u002Fcode> for currencies of the EN 16931 list that the Peppol copy of ISO 4217 lacks (e.g. \u003Ccode>XCG\u003C\u002Fcode>), \u003Ccode>-P0100\u003C\u002Fcode> and \u003Ccode>-P0101\u003C\u002Fcode> for type codes of the EN 16931 list that business process 01 does not allow, \u003Ccode>-R008\u003C\u002Fcode> for optional values of only whitespace (the writer leaves out empty values; mandatory ones are reported as missing by \u003Ccode>BR-02\u003C\u002Fcode> …), \u003Ccode>-R007\u003C\u002Fcode> for a business process in another format (a missing one is \u003Ccode>-R001\u003C\u002Fcode>). The narrower code lists \u003Ccode>CodeList::PEPPOL_CURRENCIES\u003C\u002Fcode>, \u003Ccode>PEPPOL_INVOICE_TYPES\u003C\u002Fcode> and \u003Ccode>PEPPOL_CREDIT_NOTE_TYPES\u003C\u002Fcode> are generated from the Schematron like \u003Ccode>PEPPOL_EAS\u003C\u002Fcode> (\u003Ccode>tools\u002Fcodelists\u002Fupdate.php\u003C\u002Fcode>). \u003Ccode>PEPPOL-COMMON-R040\u003C\u002Fcode> to \u003Ccode>-R053\u003C\u002Fcode> check the format and check digits of identifiers with the schemes 0088 (GLN), 0192, 0184, 0208, 0201, 0210, 9907 (electronic address only), 0211, 0007, 0151, 0096 and 0198 in electronic addresses (BT-34, BT-49), party identifiers (BT-29, BT-46, BT-60) and legal registration identifiers (BT-30, BT-47, BT-61).\u003C\u002Fp>\n\u003Ch3 id=\"plausibility-l7\">Plausibility (L7)\u003Ca class=\"q-doc-anchor\" href=\"#plausibility-l7\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Code\u003C\u002Fth>\n\u003Cth>Severity\u003C\u002Fth>\n\u003Cth>Check\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-IBAN\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">Check digits (ISO 13616, mod 97) of BT-84 and BT-91, for values that start like an IBAN\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-BIC\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">Format of BT-86\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-VATID-FORMAT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">Format of BT-31, BT-48 and BT-63 by country prefix (no check digits); unknown prefixes and small business identification numbers (suffix \u003Ccode>EX\u003C\u002Fcode>) are not judged\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-SME-ID\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">info\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">BT-31, BT-48 or BT-63 holds a small business identification number of the cross-border small business scheme (suffix \u003Ccode>EX\u003C\u002Fcode>, Article 284 (3) VAT Directive). It is no VAT identifier: a seller states it as tax registration (BT-32)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-EMAIL\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error \u002F warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">Electronic addresses with scheme \u003Ccode>EM\u003C\u002Fcode> (BT-34, BT-49: error) and contact e-mails (BT-43, BT-58: warning)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-DUE-DATE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">Due date (BT-9) before the issue date\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-VAT-K-DOMESTIC\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">Category K (intra-community supply) with a destination in the seller's member state\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-VAT-K-OUTSIDE-EU\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">Category K with a destination outside the EU VAT territory\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-VAT-G-INSIDE-EU\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">warning\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">Category G (export) with a destination inside the EU VAT territory\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-VIES\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">error\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">VIES reports the VAT identifier as invalid (only with a VAT identifier verifier)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>QUITTIO-VIES-UNAVAILABLE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Severity\">info\u003C\u002Ftd>\n\u003Ctd data-label=\"Check\">VIES could not answer\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>The destination is the deliver-to country (BT-80), otherwise the buyer's country (BT-55). The seller's member state comes from the prefix of BT-31 or BT-63, otherwise from BT-40. Territories outside the EU VAT area (e.g. Heligoland, the Canary Islands) are recognised by postcode.\u003C\u002Fp>\n\u003Cp>The helpers are public: \u003Ccode>Quittio\\Core\\Validation\\Plausibility\\Iban::isValid($iban)\u003C\u002Fcode>, \u003Ccode>Iban::normalize($iban)\u003C\u002Fcode> and \u003Ccode>VatIdFormat::isValid($vatId)\u003C\u002Fcode> (\u003Ccode>null\u003C\u002Fcode> for an unknown prefix).\u003C\u002Fp>\n\u003Ch3 id=\"vat-identifiers-and-vies\">VAT identifiers and VIES\u003Ca class=\"q-doc-anchor\" href=\"#vat-identifiers-and-vies\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>VIES is the EU service that confirms VAT identification numbers online. The online check is off by default.\u003C\u002Fp>\n\u003Cp>In Laravel, switch it on with \u003Ccode>validation.drivers.vies.enabled = true\u003C\u002Fcode> (\u003Ccode>timeout\u003C\u002Fcode> in seconds, default 5; \u003Ccode>cache_ttl\u003C\u002Fcode> in seconds, default 86400). A \u003Ccode>Quittio\\Core\\Validation\\Plausibility\\VatIdVerifier\u003C\u002Fcode> bound in the container replaces the VIES client, e.g. in tests.\u003C\u002Fp>\n\u003Cp>Without Laravel, give the PHP driver a verifier:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\Drivers\\PhpRulesDriver\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\Plausibility\\ViesVerifier\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$drivers \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">validators\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">clearValidators\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">foreach\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($drivers \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">as\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $driver) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    $quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">addValidator\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($driver \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">instanceof\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> PhpRulesDriver\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> ?\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $driver\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">withVatIdVerifier\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> ViesVerifier\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FFA657\">timeout\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">5\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FFA657\">cacheTtl\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">86400\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)) \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $driver);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>\u003Ccode>ViesVerifier\u003C\u002Fcode> uses the VIES REST interface:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>It checks only identifiers of EU member states (Greece \u003Ccode>EL\u003C\u002Fcode>) and Northern Ireland (\u003Ccode>XI\u003C\u002Fcode>) whose format is valid. Others are reported as not supported and skipped.\u003C\u002Fli>\n\u003Cli>Only the answers &quot;valid&quot; and &quot;invalid&quot; are results. They are cached per verifier instance.\u003C\u002Fli>\n\u003Cli>Errors and unreachable services give \u003Ccode>valid = null\u003C\u002Fcode>, are not cached and never block (\u003Ccode>QUITTIO-VIES-UNAVAILABLE\u003C\u002Fcode>).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Ccode>verify($vatId)\u003C\u002Fcode> returns a \u003Ccode>VatIdVerification\u003C\u002Fcode> with \u003Ccode>vatId\u003C\u002Fcode>, \u003Ccode>valid\u003C\u002Fcode>, \u003Ccode>name\u003C\u002Fcode>, \u003Ccode>address\u003C\u002Fcode>, \u003Ccode>error\u003C\u002Fcode>, \u003Ccode>supported\u003C\u002Fcode> and \u003Ccode>toArray()\u003C\u002Fcode>. Own verifiers implement \u003Ccode>VatIdVerifier::verify(string $vatId): VatIdVerification\u003C\u002Fcode> and must not throw when a service is unavailable.\u003C\u002Fp>\n\u003Ch2 id=\"own-rules-and-drivers\">Own rules and drivers\u003Ca class=\"q-doc-anchor\" href=\"#own-rules-and-drivers\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>A driver implements \u003Ccode>Quittio\\Core\\Validation\\ValidationDriver\u003C\u002Fcode> (\u003Ccode>name()\u003C\u002Fcode>, \u003Ccode>levels()\u003C\u002Fcode>, \u003Ccode>supports(ValidationSubject $subject)\u003C\u002Fcode>, \u003Ccode>validate(ValidationSubject $subject): ValidationResult\u003C\u002Fcode>). Its levels decide the stage: L6 runs on the PDF, L4 or L5 on the XML, everything else on the data.\u003C\u002Fp>\n\u003Cp>The subject holds:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>invoice\u003C\u002Fcode>: the calculated \u003Ccode>InvoiceData\u003C\u002Fcode>,\u003C\u002Fli>\n\u003Cli>\u003Ccode>context\u003C\u002Fcode>: the \u003Ccode>ValidationContext\u003C\u002Fcode> with \u003Ccode>profile\u003C\u002Fcode>, \u003Ccode>countryPacks\u003C\u002Fcode>, \u003Ccode>locale\u003C\u002Fcode>, \u003Ccode>options\u003C\u002Fcode>, \u003Ccode>option()\u003C\u002Fcode>, \u003Ccode>intOption()\u003C\u002Fcode>, \u003Ccode>leadingCountry()\u003C\u002Fcode>, \u003Ccode>hasCountry()\u003C\u002Fcode>, \u003Ccode>profileIs()\u003C\u002Fcode>, \u003Ccode>translator()\u003C\u002Fcode>,\u003C\u002Fli>\n\u003Cli>\u003Ccode>xml\u003C\u002Fcode>, \u003Ccode>syntax\u003C\u002Fcode> and \u003Ccode>pdf\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Rules are easiest written as \u003Ccode>CallbackRule\u003C\u002Fcode>: \u003Ccode>CallbackRule::l3()\u003C\u002Fcode>, \u003Ccode>CallbackRule::l7()\u003C\u002Fcode> or \u003Ccode>new CallbackRule($code, $level, $fallback, $check, $namespace)\u003C\u002Fcode>. The closure receives the invoice and a \u003Ccode>RuleReporter\u003C\u002Fcode> with \u003Ccode>error()\u003C\u002Fcode>, \u003Ccode>warning()\u003C\u002Fcode> and \u003Ccode>info()\u003C\u002Fcode> (arguments \u003Ccode>$bt\u003C\u002Fcode>, \u003Ccode>$path\u003C\u002Fcode>, \u003Ccode>$replace\u003C\u002Fcode>) and \u003Ccode>context()\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Data\\InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\Rules\\CallbackRule\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\Rules\\RuleReporter\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">{\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">ValidationDriver\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">ValidationLevel\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">ValidationResult\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">ValidationSubject\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">};\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">final\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> class\u003C\u002Fspan>\u003Cspan style=\"color:#FFA657\"> AcmeRules\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> implements\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> ValidationDriver\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FF7B72\">    public\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\"> name\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> string\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> { \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">return\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'acme'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">; }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FF7B72\">    public\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\"> levels\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> array\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> { \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">return\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">ValidationLevel\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">L3\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">]; }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FF7B72\">    public\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\"> supports\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">ValidationSubject\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $subject)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> bool\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> { \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">return\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> true\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">; }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FF7B72\">    public\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\"> validate\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">ValidationSubject\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $subject)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">:\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> ValidationResult\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#E6EDF3\">        $rule \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> CallbackRule\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">l3\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'ACME-PO'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'Invoices to :value need a purchase order number (BT-13).'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">function\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $i, \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">RuleReporter\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $report)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> void\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:14ch;text-indent:-14ch\">\u003Cspan style=\"color:#FF7B72\">            if\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($i\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">purchaseOrderReference \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">===\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> null\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:18ch;text-indent:-18ch\">\u003Cspan style=\"color:#E6EDF3\">                $report\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">error\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'BT-13'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'purchaseOrderReference'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'value'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $i\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">buyer\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">name]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:14ch;text-indent:-14ch\">\u003Cspan style=\"color:#E6EDF3\">            }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#E6EDF3\">        }, \u003C\u002Fspan>\u003Cspan style=\"color:#FFA657\">namespace\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'acme'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#FF7B72\">        return\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> ValidationResult\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">([\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">...\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">$rule\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">check\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($subject\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">invoice, $subject\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">context)], \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">$this\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">levels\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">());\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Register it in Laravel and add its name to the levels. The factory receives the container and \u003Ccode>validation.drivers.acme\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">extend\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'validator'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'acme'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">fn\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($app, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">array\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $config) => \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> AcmeRules\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#8B949E\">\u002F\u002F config\u002Fquittio.php: 'levels' => ['php', 'xsd', 'acme']\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Without Laravel: \u003Ccode>$quittio-&gt;addValidator(new AcmeRules)\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>The message of \u003Ccode>ACME-PO\u003C\u002Fcode> is looked up as \u003Ccode>acme::rules.ACME-PO.message\u003C\u002Fcode>, otherwise the fallback text is used. Register the catalog in Laravel with \u003Ccode>loadTranslationsFrom(…, 'acme')\u003C\u002Fcode>, in the core with \u003Ccode>Translations::translator()-&gt;addPath($dir, 'acme')\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Other ways to add rules:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Implement \u003Ccode>Quittio\\Core\\Validation\\Rule\u003C\u002Fcode> (\u003Ccode>code()\u003C\u002Fcode>, \u003Ccode>level()\u003C\u002Fcode>, \u003Ccode>check(InvoiceData, ValidationContext): iterable&lt;ValidationMessage&gt;\u003C\u002Fcode>) and build the messages with \u003Ccode>Messages::make()\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Give such rules to \u003Ccode>new PhpRulesDriver(additionalRules: [...])\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Return them from a country pack (\u003Ccode>rules()\u003C\u002Fcode>, \u003Ccode>buyerCountryRules()\u003C\u002Fcode>) or a profile (\u003Ccode>rules()\u003C\u002Fcode>). Country packs may only add or tighten rules.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Ccode>Quittio\\Core\\Validation\\InvoiceValidator\u003C\u002Fcode> runs a list of drivers on a \u003Ccode>ValidationSubject\u003C\u002Fcode> outside a render run.\u003C\u002Fp>\n\u003Ch2 id=\"switching-rules-off-and-changing-their-severity\">Switching rules off and changing their severity\u003Ca class=\"q-doc-anchor\" href=\"#switching-rules-off-and-changing-their-severity\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Every PHP rule is addressed by the code of its messages, e.g. \u003Ccode>DE-USTG-15\u003C\u002Fcode> or \u003Ccode>QUITTIO-PRECISION\u003C\u002Fcode>. \u003Ccode>validation.rules\u003C\u002Fcode> switches rules off, changes the severity of their findings or, with an own implementation, replaces them. A trailing \u003Ccode>*\u003C\u002Fcode> matches by prefix:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#8B949E\">\u002F\u002F config\u002Fquittio.php\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#A5D6FF\">'validation'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#A5D6FF\">    'rules'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'disabled'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'QUITTIO-GENERIC-COUNTRY'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'DE-USTG-1*'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'severity'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'DE-USTG-08'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'warning'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'QUITTIO-*'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'info'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'allow_official'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> false\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    ],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">],\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cul>\n\u003Cli>\u003Ccode>disabled\u003C\u002Fcode> drops the rules and every finding with a matching code. Rules that report several codes are covered too, e.g. \u003Ccode>QUITTIO-PROFILE-NOT-ALLOWED\u003C\u002Fcode> of the field matrix.\u003C\u002Fli>\n\u003Cli>\u003Ccode>severity\u003C\u002Fcode> sets \u003Ccode>error\u003C\u002Fcode>, \u003Ccode>warning\u003C\u002Fcode> or \u003Ccode>info\u003C\u002Fcode>. An exact code wins over a prefix, a longer prefix over a shorter one.\u003C\u002Fli>\n\u003Cli>A code that no rule has throws a \u003Ccode>ConfigurationException\u003C\u002Fcode> when the core is built, so typing errors do not switch nothing off silently. \u003Ccode>$quittio-&gt;ruleCodes()\u003C\u002Fcode> lists the known codes.\u003C\u002Fli>\n\u003Cli>The rules of EN 16931 (\u003Ccode>BR-…\u003C\u002Fcode>) and Peppol (\u003Ccode>PEPPOL-…\u003C\u002Fcode>) are official: receivers and the KoSIT validator reject invoices that break them. Changing them needs \u003Ccode>'allow_official' =&gt; true\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>The overrides change the PHP rules only (L1, L2, L3, L7). The findings of the XML schema, KoSIT and veraPDF are never changed.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>A rule of your own replaces a rule with the same code:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\Rules\\CallbackRule\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\Rules\\RuleReporter\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Laravel\\Facades\\Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">extend\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'rule'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'DE-USTG-15'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">fn\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($app) => \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">CallbackRule\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">l7\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'DE-USTG-15'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'Own check of the service date.'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">function\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($invoice, \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">RuleReporter\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $report)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> void\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#8B949E\">    \u002F\u002F …\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">}, \u003C\u002Fspan>\u003Cspan style=\"color:#FFA657\">namespace\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'quittio-de'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">));\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Without Laravel, \u003Ccode>Quittio::create()\u003C\u002Fcode> reads the same keys under \u003Ccode>validation.rules\u003C\u002Fcode>, and \u003Ccode>configureRules()\u003C\u002Fcode> sets them on an instance:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\RuleOverrides\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Validation\\Severity\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">configureRules\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> RuleOverrides\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FFA657\">    disabled\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'QUITTIO-GENERIC-COUNTRY'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FFA657\">    severities\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'DE-USTG-08'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Severity\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">Warning\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FFA657\">    replacements\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'DE-USTG-15'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $ownRule],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">));\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch2 id=\"incoming-files\">Incoming files\u003Ca class=\"q-doc-anchor\" href=\"#incoming-files\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>To check e-invoices you receive, validate the file itself:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$report \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">validateFile\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($content);   \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F content (bytes) of an XML or PDF e-invoice, never a path\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$report \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">validatePath\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($path);      \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F the same from a local file\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Both read the file (\u003Ca href=\"\u002Fdocs\u002Freading\">Reading incoming invoices\u003C\u002Fa>) and run every configured driver that supports it, independent of the stage and of \u003Ccode>validation.mode\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>They never throw a \u003Ccode>ValidationException\u003C\u002Fcode>. The reader exceptions (\u003Ccode>UnsafeXmlException\u003C\u002Fcode>, \u003Ccode>PdfException\u003C\u002Fcode>, \u003Ccode>UnreadableInvoiceException\u003C\u002Fcode>) are thrown.\u003C\u002Fli>\n\u003Cli>The result starts with the reader's findings (level L1, \u003Ccode>QUITTIO-DECLARED-TOTALS\u003C\u002Fcode> L3).\u003C\u002Fli>\n\u003Cli>The rules use the profile detected from the specification identifier (BT-24), otherwise the configured default profile. They also use the country packs of the parties and the syntax of the file.\u003C\u002Fli>\n\u003Cli>XSD and KoSIT check the XML; for a PDF, the embedded XML. veraPDF runs only when the input was a PDF.\u003C\u002Fli>\n\u003Cli>The read data is checked as declared, without recalculation.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>On the command line:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>bash\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FFA657\">php\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> artisan\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> quittio:validate\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> invoice.pdf\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --profile=en16931\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --kosit\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --verapdf\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> --json\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>\u003Ccode>--profile\u003C\u002Fcode> fails the command when the detected profile differs. \u003Ccode>--kosit\u003C\u002Fcode> and \u003Ccode>--verapdf\u003C\u002Fcode> add the drivers for this call with the configured \u003Ccode>validation.drivers.*\u003C\u002Fcode> settings (see \u003Ca href=\"\u002Fdocs\u002Fcommands\">Artisan commands\u003C\u002Fa>).\u003C\u002Fp>\n\u003Ch2 id=\"mandatory-field-guard\">Mandatory field guard\u003Ca class=\"q-doc-anchor\" href=\"#mandatory-field-guard\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The template decides what the PDF shows. After rendering a PDF or HTML invoice, the guard checks that the template printed every mandatory value: invoice number and date, names and addresses, quantities and units, VAT rows, amount due, legal notes and the values the country pack requires. It does not run for \u003Ca href=\"\u002Fdocs\u002Fdocuments\">documents\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Mode\u003C\u002Fth>\n\u003Cth>Behaviour\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>exception\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour\">throws \u003Ccode>Quittio\\Core\\View\\MandatoryFieldMissing\u003C\u002Fcode> (\u003Ccode>$e-&gt;fields\u003C\u002Fcode>: list of \u003Ccode>MandatoryField\u003C\u002Fcode> with \u003Ccode>accessKey\u003C\u002Fcode>, \u003Ccode>description\u003C\u002Fcode>, \u003Ccode>legalBasis\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>log\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour\">logs a warning (PSR-3 logger) and continues\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>off\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour\">no check\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Set the mode with \u003Ccode>validation.mandatory_field_guard\u003C\u002Fcode> (Laravel; default \u003Ccode>exception\u003C\u002Fcode> outside production, \u003Ccode>log\u003C\u002Fcode> in production) or \u003Ccode>mandatory_fields\u003C\u002Fcode> (\u003Ccode>Quittio::create()\u003C\u002Fcode>, default \u003Ccode>exception\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Cp>In every mode except \u003Ccode>off\u003C\u002Fcode>, a missing value calls the listener of \u003Ccode>$quittio-&gt;onMandatoryFieldsMissing(fn (InvoiceData $invoice, array $fields) =&gt; …)\u003C\u002Fcode>. Laravel dispatches the event \u003Ccode>Quittio\\Laravel\\Events\\MandatoryFieldMissing($invoice, $fields)\u003C\u002Fcode>. Which values count as printed is described in \u003Ca href=\"\u002Fdocs\u002Ftemplates#mandatory-field-guard\">Templates\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"germany-bmf-error-classes\">Germany: BMF error classes\u003Ca class=\"q-doc-anchor\" href=\"#germany-bmf-error-classes\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The German Federal Ministry of Finance (BMF) groups e-invoice errors into classes in its letter of 15 October 2025. The German country pack sorts findings into these classes:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Country\\DE\\CountryDE\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Country\\DE\\Rules\\BmfErrorClass\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$classes \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> CountryDE\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">errorClassification\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($result);   \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F ['format' => [...], 'business_rule' => [...], 'content' => [...]]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">BmfErrorClass\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">of\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($message)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">label\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'de'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);                    \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F \"Formatfehler (Rz. 6a)\", the German label of \"format error (marginal no. 6a)\"\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Errors and warnings (no infos) are grouped by class:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Class\u003C\u002Fth>\n\u003Cth>Value\u003C\u002Fth>\n\u003Cth>Findings\u003C\u002Fth>\n\u003Cth>\u003Ccode>voidsEInvoice()\u003C\u002Fcode>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Format error (marginal no. 6a)\u003C\u002Ftd>\n\u003Ctd data-label=\"Value\">\u003Ccode>format\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Findings\">L1, L2, L4, L6\u003C\u002Ftd>\n\u003Ctd data-label=\"voidsEInvoice()\">\u003Ccode>true\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Business rule error (marginal no. 6b)\u003C\u002Ftd>\n\u003Ctd data-label=\"Value\">\u003Ccode>business_rule\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Findings\">L3, L5\u003C\u002Ftd>\n\u003Ctd data-label=\"voidsEInvoice()\">\u003Ccode>false\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Content error (marginal no. 35a)\u003C\u002Ftd>\n\u003Ctd data-label=\"Value\">\u003Ccode>content\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Findings\">every \u003Ccode>DE-USTG-…\u003C\u002Fcode> rule, L7\u003C\u002Ftd>\n\u003Ctd data-label=\"voidsEInvoice()\">\u003Ccode>false\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Ccode>label(string $locale = 'de')\u003C\u002Fcode> returns the German name, any other locale the English name. Classes without findings are not in the array.\u003C\u002Fp>\n\u003Ch2 id=\"json-input\">JSON input\u003Ca class=\"q-doc-anchor\" href=\"#json-input\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Invoice data can also arrive as JSON, e.g. from an API. Check it against the shipped schema (\u003Ccode>packages\u002Fcore\u002Fresources\u002Fschema\u002Finvoice.schema.json\u003C\u002Fcode>, \u003Ccode>JsonSchemaGenerator::defaultPath()\u003C\u002Fcode>) before hydrating it. This needs the optional package \u003Ccode>opis\u002Fjson-schema\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>php\u003C\u002Fspan>\u003Cbutton type=\"button\" class=\"q-doc-copy\" data-copy aria-label=\"Copy code\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fsvg>\u003Cspan>Copy\u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki github-dark-default\" style=\"background-color:#0d1117;color:#e6edf3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Serialization\\JsonSchemaValidator\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Core\\Data\\InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#FF7B72\">if\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">JsonSchemaValidator\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">available\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    $errors \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> JsonSchemaValidator\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">validate\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($json);   \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F list&#x3C;string> \"path: message\", at most 20; [] = valid\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$invoice \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">fromJson\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($json);\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Without the package, \u003Ccode>validate()\u003C\u002Fcode> throws a \u003Ccode>RuntimeException\u003C\u002Fcode>; invalid JSON throws a \u003Ccode>JsonException\u003C\u002Fcode>. The schema checks the structure only. The business rules run when the invoice is rendered or checked.\u003C\u002Fp>\n",[111,115,119,122,125,128,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,189,192,195,198,201],{"id":112,"text":113,"level":114},"errors-while-rendering","Errors while rendering",2,{"id":116,"text":117,"level":118},"reading-a-message","Reading a message",3,{"id":120,"text":121,"level":118},"handling-the-exception","Handling the exception",{"id":123,"text":124,"level":118},"warnings","Warnings",{"id":126,"text":127,"level":118},"checking-without-rendering","Checking without rendering",{"id":64,"text":65,"level":114},{"id":130,"text":131,"level":118},"per-call","Per call",{"id":133,"text":134,"level":118},"settings","Settings",{"id":136,"text":137,"level":118},"options-for-rules","Options for rules",{"id":139,"text":140,"level":114},"validation-levels","Validation levels",{"id":142,"text":143,"level":114},"when-validation-runs","When validation runs",{"id":145,"text":146,"level":114},"the-result","The result",{"id":148,"text":149,"level":114},"messages-and-translations","Messages and translations",{"id":151,"text":152,"level":114},"xml-schema-l4","XML schema (L4)",{"id":154,"text":155,"level":114},"kosit-validator-l5","KoSIT validator (L5)",{"id":157,"text":158,"level":118},"installation","Installation",{"id":160,"text":161,"level":118},"modes","Modes",{"id":163,"text":164,"level":118},"findings","Findings",{"id":166,"text":167,"level":114},"verapdf-l6","veraPDF (L6)",{"id":169,"text":170,"level":118},"installing-verapdf","Installing veraPDF",{"id":172,"text":173,"level":114},"rule-sets","Rule sets",{"id":175,"text":176,"level":118},"package-rules-quittio-","Package rules (QUITTIO-…)",{"id":178,"text":179,"level":118},"peppol-rules","Peppol rules",{"id":181,"text":182,"level":118},"plausibility-l7","Plausibility (L7)",{"id":184,"text":185,"level":118},"vat-identifiers-and-vies","VAT identifiers and VIES",{"id":187,"text":188,"level":114},"own-rules-and-drivers","Own rules and drivers",{"id":190,"text":191,"level":114},"switching-rules-off-and-changing-their-severity","Switching rules off and changing their severity",{"id":193,"text":194,"level":114},"incoming-files","Incoming files",{"id":196,"text":197,"level":114},"mandatory-field-guard","Mandatory field guard",{"id":199,"text":200,"level":114},"germany-bmf-error-classes","Germany: BMF error classes",{"id":202,"text":203,"level":114},"json-input","JSON input","https:\u002F\u002Fgithub.com\u002FQuittio\u002Fquittio\u002Fedit\u002Fmaster\u002Fdocs\u002Fvalidation.md","\u002Fdocs\u002Fvalidation.md",{"slug":46,"title":47},{"slug":52,"title":53}]