[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs:testing":3},{"versions":4,"version":26,"nav":28,"path":70,"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":71,"description":108,"html":109,"headings":110,"editUrl":149,"markdownUrl":150,"prev":151,"next":152},"This page shows how to test code that creates invoices: fast feature tests with a fake, checks that your e-invoices are valid, test data and the official validators in CI.","\u003Ch1 id=\"testing\">Testing\u003C\u002Fh1>\n\u003Cp>This page shows how to test code that creates invoices: fast feature tests with a fake, checks that your e-invoices are valid, test data and the official validators in CI. The examples use Pest; the same methods work in PHPUnit.\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>You want to test\u003C\u002Fth>\n\u003Cth>Use\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>That your code renders an invoice, without the cost of a real run\u003C\u002Ftd>\n\u003Ctd data-label=\"Use\">\u003Ca href=\"#fake\">\u003Ccode>Quittio::fake()\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>That the invoice data is a valid e-invoice, without rendering\u003C\u002Ftd>\n\u003Ctd data-label=\"Use\">\u003Ca href=\"#validating-the-invoice-data\">\u003Ccode>check()\u003C\u002Fcode>\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Storage, events, the queue or mail with real rendering\u003C\u002Ftd>\n\u003Ctd data-label=\"Use\">\u003Ca href=\"#laravel-fakes\">Laravel fakes\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>That a rendered PDF or XML is a valid e-invoice, or that the XML has not changed\u003C\u002Ftd>\n\u003Ctd data-label=\"Use\">\u003Ca href=\"#assertions\">Assertions\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>An invoice to test with, without writing a builder chain\u003C\u002Ftd>\n\u003Ctd data-label=\"Use\">\u003Ca href=\"#factory\">Factory\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Realistic sample invoices: many lines, reverse charge, foreign currency …\u003C\u002Ftd>\n\u003Ctd data-label=\"Use\">\u003Ca href=\"#scenarios\">Scenarios\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Your files with the official validators (KoSIT, veraPDF)\u003C\u002Ftd>\n\u003Ctd data-label=\"Use\">\u003Ca href=\"#official-validators-in-ci\">Official validators in CI\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Models of the Managed layer\u003C\u002Ftd>\n\u003Ctd data-label=\"Use\">\u003Ca href=\"#managed-layer-factories\">Managed layer factories\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>The factory and the scenarios are part of \u003Ccode>quittio\u002Fcore\u003C\u002Fcode> and work without Laravel. The fake and the assertions need \u003Ccode>quittio\u002Flaravel\u003C\u002Fcode>. Terms such as ZUGFeRD, profile or reverse charge are explained in \u003Ca href=\"\u002Fdocs\u002Fconcepts\">E-invoicing basics\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"fake\">Fake\u003Ca class=\"q-doc-anchor\" href=\"#fake\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The most common test checks that your code renders an invoice, e.g. when an order ships. \u003Ccode>Quittio::fake()\u003C\u002Fcode> replaces the rendering with a fast fake that records every render call. Afterwards you assert what was rendered:\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\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Laravel\\Rendering\\RenderedInvoice\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:#D2A8FF\">it\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'renders the invoice of an order'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">function\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\">    $fake \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\">fake\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:#79C0FF\">    $this\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">post\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'\u002Forders\u002F42\u002Finvoice'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertOk\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:#79C0FF\">    Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertRenderedCount\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">1\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertRendered\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">fn\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">RenderedInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $r) => $r\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">format\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">() \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">===\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'zugferd'\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#FF7B72\">        &#x26;&#x26;\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $r\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">data\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">totals\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">amountDue\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">isEqualTo\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'1234.56'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">));\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#D2A8FF\">    expect\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($fake\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">rendered\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()[\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">]\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">data\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">number)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">toBe\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'RE-2026-0042'\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>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cul>\n\u003Cli>\u003Ccode>assertRenderedCount(1)\u003C\u002Fcode> checks that exactly one invoice was rendered.\u003C\u002Fli>\n\u003Cli>\u003Ccode>assertRendered()\u003C\u002Fcode> with a callback checks that at least one rendered invoice matches: here one in the format ZUGFeRD (\u003Ccode>zugferd\u003C\u002Fcode>, a PDF with embedded XML) with the expected amount due. The callback receives a \u003Ccode>RenderedInvoice\u003C\u002Fcode>; its \u003Ccode>data()\u003C\u002Fcode> holds the calculated invoice with totals.\u003C\u002Fli>\n\u003Cli>\u003Ccode>Quittio::fake()\u003C\u002Fcode> returns the fake. \u003Ccode>$fake-&gt;rendered()\u003C\u002Fcode> lists the recorded results, in order.\u003C\u002Fli>\n\u003Cli>The fake skips validation. To test that the invoice is a valid e-invoice, add a test with \u003Ca href=\"#validating-the-invoice-data\">\u003Ccode>check()\u003C\u002Fcode>\u003C\u002Fa>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>A complete example with an order, a mail and both kinds of test is \u003Ca href=\"\u002Fdocs\u002Fexamples#testing\">Testing\u003C\u002Fa> on the Examples page.\u003C\u002Fp>\n\u003Ch3 id=\"how-the-fake-works\">How the fake works\u003Ca class=\"q-doc-anchor\" href=\"#how-the-fake-works\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>\u003Ccode>Quittio::fake()\u003C\u002Fcode> replaces the manager with a \u003Ccode>Quittio\\Laravel\\Testing\\QuittioFake\u003C\u002Fcode> and returns it. It is swapped into the facade and into the container. So code that injects \u003Ccode>QuittioManager\u003C\u002Fcode>, queued \u003Ccode>RenderInvoice\u003C\u002Fcode> jobs and the Managed layer use the fake as well.\u003C\u002Fp>\n\u003Cp>The fake takes the decisions of a real run: it calls \u003Ccode>prepare()\u003C\u002Fcode> of the core without validators. Then it returns placeholder results instead of rendering. It skips validation, XML, template and PDF:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>\u003C\u002Fth>\n\u003Cth>Behaviour of the fake\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Calculation\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">Real: totals, VAT breakdown and the due date of \u003Ccode>defaults.due_days\u003C\u002Fcode>, so \u003Ccode>data()\u003C\u002Fcode> holds the amounts\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Format\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">As in a real run: \u003Ccode>format()\u003C\u002Fcode>\u002F\u003Ccode>formats()\u003C\u002Fcode>, then \u003Ccode>defaults.format\u003C\u002Fcode>, then the automatic choice (country rules, \u003Ccode>format_resolver\u003C\u002Fcode>, Peppol lookup). Every format of the call is recorded under the main result, so \u003Ccode>formats()\u003C\u002Fcode> and \u003Ccode>as()\u003C\u002Fcode> work.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Profile\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">As in a real run: \u003Ccode>profile()\u003C\u002Fcode> with a key, alias or \u003Ccode>Profile\u003C\u002Fcode> object, \u003Ccode>defaults.profile\u003C\u002Fcode>, the profile of the automatic choice or of the format, the EXTENDED upgrade; \u003Ccode>null\u003C\u002Fcode> for formats without XML\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Errors\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">An unknown format or profile, or a profile the format does not allow, throws a \u003Ccode>ConfigurationException\u003C\u002Fcode> like a real run\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Validation\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">None: \u003Ccode>validation()\u003C\u002Fcode> is an empty \u003Ccode>ValidationResult\u003C\u002Fcode>, no \u003Ccode>ValidationException\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Outputs\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">Placeholders according to the format: XML \u003Ccode>&lt;fake number=&quot;…&quot;\u002F&gt;\u003C\u002Fcode>, PDF \u003Ccode>%PDF-1.7\u003C\u002Fcode> with a comment, HTML \u003Ccode>&lt;p&gt;{number}&lt;\u002Fp&gt;\u003C\u002Fcode>, JSON of the data\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>File name\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">\u003Ccode>Invoice_{number}.{ext}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Documents\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">Calculated; fake HTML and, unless \u003Ccode>htmlOnly()\u003C\u002Fcode>, a fake PDF; file name \u003Ccode>{number}.{ext}\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Events\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">As in a real run: \u003Ccode>InvoiceRendering\u003C\u002Fcode>, \u003Ccode>InvoiceValidated\u003C\u002Fcode> (with the empty result, not in mode \u003Ccode>off\u003C\u002Fcode>) and \u003Ccode>InvoiceRendered\u003C\u002Fcode>, so \u003Ccode>Event::fake()\u003C\u002Fcode> with \u003Ccode>Event::assertDispatched(InvoiceRendered::class)\u003C\u002Fcode> works\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Queue\u003C\u002Ftd>\n\u003Ctd data-label=\"Behaviour of the fake\">\u003Ccode>queue()-&gt;save()\u003C\u002Fcode> records the job (\u003Ccode>queued()\u003C\u002Fcode>, \u003Ccode>assertQueued()\u003C\u002Fcode>) and dispatches it like a real run: \u003Ccode>Queue::fake()\u003C\u002Fcode> sees it, a \u003Ccode>sync\u003C\u002Fcode> queue renders it with the fake\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Not faked: \u003Ccode>check()\u003C\u002Fcode>, \u003Ccode>prepare()\u003C\u002Fcode>, \u003Ccode>read()\u003C\u002Fcode>, \u003Ccode>readFile()\u003C\u002Fcode>, \u003Ccode>validateFile()\u003C\u002Fcode>, \u003Ccode>validatePath()\u003C\u002Fcode> and \u003Ccode>cancellation()\u003C\u002Fcode> run the real core. Responses, \u003Ccode>save()\u003C\u002Fcode> and mail attachments work on the fake results.\u003C\u002Fp>\n\u003Cp>The fake stays active until the application is rebuilt for the next test.\u003C\u002Fp>\n\u003Ch3 id=\"assertions-of-the-fake\">Assertions of the fake\u003Ca class=\"q-doc-anchor\" href=\"#assertions-of-the-fake\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>These methods belong to the fake and are also callable through the facade (\u003Ccode>Quittio::assertRendered()\u003C\u002Fcode>):\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Method\u003C\u002Fth>\n\u003Cth>Asserts \u002F returns\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertRendered(?callable $callback = null)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">At least one invoice was rendered; with a callback, at least one \u003Ccode>RenderedInvoice\u003C\u002Fcode> for which it returns \u003Ccode>true\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertRenderedCount(int $count)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">Exactly \u003Ccode>$count\u003C\u002Fcode> invoices were rendered\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertNothingRendered()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">No invoice was rendered\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertDocumentRendered(?callable $callback = null)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">At least one document (quote, reminder, …) was rendered; with a callback, one \u003Ccode>RenderedDocument\u003C\u002Fcode> matches\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>rendered(): array\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">The recorded \u003Ccode>RenderedInvoice\u003C\u002Fcode> results (the main format of each call), in order\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>documents(): array\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">The recorded \u003Ccode>RenderedDocument\u003C\u002Fcode> results, in order\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertQueued(?callable $callback = null)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">At least one invoice was queued with \u003Ccode>queue()-&gt;save()\u003C\u002Fcode>; with a callback, one \u003Ccode>RenderInvoice\u003C\u002Fcode> job matches (\u003Ccode>$job-&gt;data()\u003C\u002Fcode> is the invoice, \u003Ccode>$job-&gt;disk\u003C\u002Fcode>, \u003Ccode>$job-&gt;path\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertNothingQueued()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">No invoice and no document was queued\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertDocumentQueued(?callable $callback = null)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">At least one document was queued with \u003Ccode>Quittio::document(…)-&gt;queue()-&gt;save()\u003C\u002Fcode>; with a callback, one \u003Ccode>RenderDocument\u003C\u002Fcode> job matches (\u003Ccode>$job-&gt;data()\u003C\u002Fcode> is the document)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>queued(): array\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts \u002F returns\">The recorded \u003Ccode>RenderInvoice\u003C\u002Fcode> jobs, in order\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Documents such as quotes and reminders (\u003Ca href=\"\u002Fdocs\u002Fdocuments\">Quotes and other documents\u003C\u002Fa>) are recorded separately from invoices:\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\">$fake \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\">fake\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\">document\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($quote)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">htmlOnly\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\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#D2A8FF\">expect\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($fake\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">documents\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">())\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">toHaveCount\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">1\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#FF7B72\">    ->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">and\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($fake\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">documents\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()[\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">0\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">]\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">hasPdf\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">())\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">toBeFalse\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch2 id=\"validating-the-invoice-data\">Validating the invoice data\u003Ca class=\"q-doc-anchor\" href=\"#validating-the-invoice-data\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>A test with the fake does not show whether the invoice is a valid e-invoice. \u003Ccode>check()\u003C\u002Fcode> runs the real validation, including the XML, without rendering a PDF. It is never faked, so it also works while the fake is active:\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:#D2A8FF\">it\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'builds a valid e-invoice for an order'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">function\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\">    $order \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Order\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\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:2ch;text-indent:-2ch\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\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\">($order)\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 the real validation, without rendering\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:#D2A8FF\">    expect\u003C\u002Fspan>\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>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">toBeTrue\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#FF7B72\">        ->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">and\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($report\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">warnings\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">())\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">toBe\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>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cul>\n\u003Cli>\u003Ccode>Order\u003C\u002Fcode> is a model of your application that implements \u003Ccode>ProvidesInvoiceData\u003C\u002Fcode> (\u003Ca href=\"\u002Fdocs\u002Fexamples#invoices-for-orders\">Invoices for orders\u003C\u002Fa>). Any invoice data works the same way: \u003Ccode>Quittio::make($invoice)-&gt;check()\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Ccode>check()\u003C\u002Fcode> returns a \u003Ccode>ValidationResult\u003C\u002Fcode> and never throws a \u003Ccode>ValidationException\u003C\u002Fcode> for invalid data. \u003Ccode>isValid()\u003C\u002Fcode> is \u003Ccode>true\u003C\u002Fcode> without errors; \u003Ccode>warnings()\u003C\u002Fcode> lists the warnings (\u003Ca href=\"\u002Fdocs\u002Fvalidation#the-result\">The result\u003C\u002Fa>).\u003C\u002Fli>\n\u003Cli>It validates in the same formats and profiles as \u003Ccode>render()\u003C\u002Fcode> would. The PDF\u002FA check (level L6) does not run, because it needs the rendered PDF (\u003Ca href=\"\u002Fdocs\u002Fvalidation#when-validation-runs\">When validation runs\u003C\u002Fa>).\u003C\u002Fli>\n\u003Cli>To validate a rendered PDF or XML file, use \u003Ca href=\"#assertions\">\u003Ccode>assertValidEInvoice()\u003C\u002Fcode>\u003C\u002Fa>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"laravel-fakes\">Laravel fakes\u003Ca class=\"q-doc-anchor\" href=\"#laravel-fakes\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Without \u003Ccode>Quittio::fake()\u003C\u002Fcode> the real core renders. Then the usual Laravel fakes test the integration end to end: files on a disk, events and queued jobs. \u003Ccode>InvoiceData::factory()\u003C\u002Fcode> builds the test invoice (\u003Ca href=\"#factory\">Factory\u003C\u002Fa>):\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\"> Illuminate\\Support\\Facades\\Event\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\"> Illuminate\\Support\\Facades\\Queue\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\"> Illuminate\\Support\\Facades\\Storage\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\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Laravel\\Events\\InvoiceRendered\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\\Events\\InvoiceValidationFailed\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\">\u003Cspan style=\"color:#FF7B72\">use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Quittio\\Laravel\\Jobs\\RenderInvoice\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:#D2A8FF\">it\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'stores the PDF'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">function\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> () {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    Storage\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">fake\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'invoices'\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:#79C0FF\">    Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">())\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\">'zugferd'\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:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">save\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'invoices'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'2026\u002F'\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:#79C0FF\">    Storage\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">disk\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'invoices'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertExists\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'2026\u002FRechnung_RE-2026-0042.pdf'\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>\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:#D2A8FF\">it\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'dispatches the events'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">function\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> () {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    Event\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">fake\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">([\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceRendered\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::class\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceValidationFailed\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::class\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:#79C0FF\">    Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">())\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\">'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\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    Event\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertDispatched\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceRendered\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::class\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">fn\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($e) => $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\">format\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">() \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">===\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'cii'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    Event\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertNotDispatched\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceValidationFailed\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::class\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>\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:#D2A8FF\">it\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'queues the rendering'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">function\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> () {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    Queue\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">fake\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:#79C0FF\">    Quittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">())\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">queue\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">save\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'invoices'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'queued\u002F'\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:#79C0FF\">    Queue\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertPushedOn\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'quittio'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">RenderInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::class\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">fn\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">RenderInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $job) => $job\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">path \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">===\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'queued\u002F'\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>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cul>\n\u003Cli>The factory's invoice is German (locale \u003Ccode>de\u003C\u002Fcode>), so the file name starts with the German title &quot;Rechnung&quot; (invoice).\u003C\u002Fli>\n\u003Cli>The events are described in \u003Ca href=\"\u002Fdocs\u002Flaravel#events\">Events\u003C\u002Fa>, the queue in \u003Ca href=\"\u002Fdocs\u002Flaravel#queueing\">Queueing\u003C\u002Fa>. \u003Ccode>quittio\u003C\u002Fcode> is the default queue name.\u003C\u002Fli>\n\u003Cli>Rendered results are \u003Ccode>Attachable\u003C\u002Fcode>. So \u003Ccode>Mail::fake()\u003C\u002Fcode> with \u003Ccode>Mail::assertSent(YourMail::class, fn ($mail) =&gt; $mail-&gt;hasAttachment($result))\u003C\u002Fcode> checks mail attachments.\u003C\u002Fli>\n\u003Cli>After changing \u003Ccode>config('quittio.…')\u003C\u002Fcode> inside a test, the next call uses the new configuration (\u003Ca href=\"\u002Fdocs\u002Fconfiguration\">Configuration\u003C\u002Fa>).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"assertions\">Assertions\u003Ca class=\"q-doc-anchor\" href=\"#assertions\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The trait \u003Ccode>Quittio\\Laravel\\Testing\\InteractsWithQuittio\u003C\u002Fcode> adds two assertions for rendered files to a test case. \u003Ccode>assertValidEInvoice()\u003C\u002Fcode> checks that a PDF or XML is a valid e-invoice. \u003Ccode>assertXmlMatchesSnapshot()\u003C\u002Fcode> checks that the XML has not changed since you last accepted it. Add the trait to your tests:\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 PHPUnit\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\\Testing\\InteractsWithQuittio\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\">class\u003C\u002Fspan>\u003Cspan style=\"color:#FFA657\"> InvoiceTest\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> extends\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> TestCase\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\">    use\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> InteractsWithQuittio\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>\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:#8B949E\">\u002F\u002F Pest, in a single test file\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#D2A8FF\">uses\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InteractsWithQuittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::class\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:#8B949E\">\u002F\u002F Pest, for all tests of a directory (in tests\u002FPest.php)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#D2A8FF\">pest\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">use\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InteractsWithQuittio\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::class\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">in\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'Feature'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>After each test the trait also resets the process-wide state of Quittio (\u003Ccode>Quittio\\Core\\Quittio::resetState()\u003C\u002Fcode>), e.g. base rates that a test registered.\u003C\u002Fp>\n\u003Cp>Then use the assertions on the outputs of a rendered invoice:\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\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">())\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:#A5D6FF\">'xrechnung-ubl'\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\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">$this\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertValidEInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($result\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">pdf\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(), \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'en16931'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">$this\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertValidEInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($result\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">as\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xrechnung-ubl'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">xml\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(), \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xrechnung'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">$this\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertXmlMatchesSnapshot\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($result\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">xml\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(), \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'zugferd-default'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Method\u003C\u002Fth>\n\u003Cth>Asserts\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertValidEInvoice(string $pdfOrXml, ?string $profile = null)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts\">Reads the PDF or XML content and validates it with all configured levels (\u003Ccode>quittio.validation.levels\u003C\u002Fcode>, see \u003Ca href=\"#official-validators-in-ci\">below\u003C\u002Fa>). Fails with the code and message of every error; warnings do not fail. With \u003Ccode>$profile\u003C\u002Fcode>, the profile read from the file must be that profile (aliases are resolved, e.g. \u003Ccode>comfort\u003C\u002Fcode>).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>assertXmlMatchesSnapshot(string $xml, ?string $name = null)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Asserts\">Compares the canonicalised XML (whitespace between elements removed, re-indented) with a stored snapshot. The first run writes the snapshot and passes. Not well-formed XML fails.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>The profile is the set of rules the file follows, e.g. \u003Ccode>en16931\u003C\u002Fcode> or \u003Ccode>xrechnung\u003C\u002Fcode> (\u003Ca href=\"\u002Fdocs\u002Fconcepts#profiles\">Profiles\u003C\u002Fa>).\u003C\u002Fp>\n\u003Ch3 id=\"snapshots\">Snapshots\u003Ca class=\"q-doc-anchor\" href=\"#snapshots\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>A snapshot is a stored copy of the XML. Later runs compare the XML with it, so that an unintended change of the output fails the test.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Snapshots are stored in \u003Ccode>__snapshots__\u002Fquittio\u002F{name}.xml\u003C\u002Fcode> next to the test file.\u003C\u002Fli>\n\u003Cli>The name is reduced to letters, digits, \u003Ccode>.\u003C\u002Fcode>, \u003Ccode>_\u003C\u002Fcode> and \u003Ccode>-\u003C\u002Fcode>. Without a name it is \u003Ccode>{TestClass}__{test name}\u003C\u002Fcode>. Pest generates class and test names, so pass a name there.\u003C\u002Fli>\n\u003Cli>To accept a changed XML, delete the snapshot file and run the test again.\u003C\u002Fli>\n\u003Cli>Override the protected methods \u003Ccode>quittioSnapshotDirectory()\u003C\u002Fcode> and \u003Ccode>quittioSnapshotName()\u003C\u002Fcode> to change the location and the default name.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"outside-test-case-classes\">Outside test case classes\u003Ca class=\"q-doc-anchor\" href=\"#outside-test-case-classes\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Outside test case classes, e.g. in Pest helper functions, \u003Ccode>Quittio\\Laravel\\Testing\\EInvoiceAssertions\u003C\u002Fcode> provides the same assertions:\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\\Testing\\EInvoiceAssertions\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\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> EInvoiceAssertions\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertValidEInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($pdf, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xrechnung'\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\">new\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> EInvoiceAssertions\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">base_path\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'tests\u002F__snapshots__'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)))\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertXmlMatchesSnapshot\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($xml, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'order-42'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Its constructor takes the snapshot directory (default \u003Ccode>tests\u002F__snapshots__\u002Fquittio\u003C\u002Fcode> below the working directory). Its default snapshot name is \u003Ccode>xml\u003C\u002Fcode>, so pass a name per snapshot.\u003C\u002Fp>\n\u003Ch2 id=\"factory\">Factory\u003Ca class=\"q-doc-anchor\" href=\"#factory\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Most tests need an invoice. \u003Ccode>InvoiceData::factory()\u003C\u002Fcode> (or \u003Ccode>Quittio\\Core\\Testing\\InvoiceFactory::new()\u003C\u002Fcode>) builds one in a single line. The test invoices are deterministic: they contain no random values, so XML snapshots stay stable. Every method returns a new factory.\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\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();                                   \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F one line, 19 %\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">reverseCharge\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">withLines\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">5\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">intraCommunity\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">calculated\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">b2c\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">currency\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'USD'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">number\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'X-1'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">creditNote\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">state\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">fn\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($builder) => $builder\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">buyerReference\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'04011000-12345-03'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">))\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>The base invoice is the one of the scenarios (\u003Ccode>Scenarios::base()\u003C\u002Fcode>):\u003C\u002Fp>\n\u003Cul>\n\u003Cli>number \u003Ccode>RE-2026-0042\u003C\u002Fcode>, issue date 2026-10-03, delivery date 2026-09-30, locale \u003Ccode>de\u003C\u002Fcode>;\u003C\u002Fli>\n\u003Cli>seller Muster GmbH (\u003Ccode>DE123456789\u003C\u002Fcode>, Musterstadt), buyer Kunde AG (\u003Ccode>DE987654321\u003C\u002Fcode>), buyer reference \u003Ccode>PO-4711\u003C\u002Fcode>;\u003C\u002Fli>\n\u003Cli>payment terms 14 days and a SEPA credit transfer.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>With the German country pack the automatic choice renders these invoices as ZUGFeRD, and with \u003Ccode>b2c()\u003C\u002Fcode> as plain PDF. \u003Ccode>withLines(3)\u003C\u002Fcode> gives net 140.00, VAT 26.60 and an amount due of 166.60.\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Method\u003C\u002Fth>\n\u003Cth>Effect\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>withLines(int $count)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Number of lines (at least 1). Line \u003Cem>i\u003C\u002Fem>: &quot;Item \u003Cem>i\u003C\u002Fem>&quot;, quantity \u003Cem>i\u003C\u002Fem> pieces, net price 10 × \u003Cem>i\u003C\u002Fem>, VAT 19 % (or the category of the VAT mode)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>reverseCharge()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Buyer Client SARL (Paris, \u003Ccode>FR12345678901\u003C\u002Fcode>), lines in category \u003Ccode>AE\u003C\u002Fcode> (reverse charge) with \u003Ccode>VATEX-EU-AE\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>intraCommunity()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Buyer Cliente S.r.l. (Rome, \u003Ccode>IT12345678901\u003C\u002Fcode>), lines in category \u003Ccode>K\u003C\u002Fcode> (intra-community supply) with \u003Ccode>VATEX-EU-IC\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>export()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Buyer Customer Inc. (New York, no VAT identifier), lines in category \u003Ccode>G\u003C\u002Fcode> (export) with \u003Ccode>VATEX-EU-G\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>b2c()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Consumer buyer Erika Mustermann (Berlin), no buyer reference\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>currency(string $currency)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Invoice currency; other than EUR adds the VAT accounting currency EUR (rate 0.9 of 2026-10-02) and a credit transfer\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>number(string $number)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Invoice number (default \u003Ccode>RE-2026-0042\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>creditNote()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Type code 381 with the preceding invoice RE-2026-0001 of 2026-09-01\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>state(callable $state)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Calls \u003Ccode>$state(InvoiceBuilder $builder)\u003C\u002Fcode> for free changes; several states run in order\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>builder(): InvoiceBuilder\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">The prepared builder\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>make(): InvoiceData\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Invoice data, not calculated (as passed to \u003Ccode>Quittio::make()\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>calculated(?TotalsCalculator $calculator = null): InvoiceData\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Effect\">Invoice data with totals and VAT breakdown, calculated with \u003Ccode>$calculator\u003C\u002Fcode> (default \u003Ccode>En16931Calculator\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Ccode>VATEX-EU-…\u003C\u002Fcode> are the codes of the VAT exemption reasons (\u003Ca href=\"\u002Fdocs\u002Fbuilding-invoices#exemption-reasons-in-the-vat-breakdown\">Exemption reasons in the VAT breakdown\u003C\u002Fa>).\u003C\u002Fp>\n\u003Ch2 id=\"scenarios\">Scenarios\u003Ca class=\"q-doc-anchor\" href=\"#scenarios\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Ccode>Quittio\\Core\\Testing\\Scenarios\u003C\u002Fcode> holds realistic sample invoices: the ones of the preview, the visual tests and the official validation runs. Use them when a test needs special content, e.g. 60 lines for page breaks or sub lines. They are country neutral: they use VAT categories directly, not the tax presets of a country pack.\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\\Testing\\Scenarios\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:#E6EDF3\">$invoice \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Scenarios\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'sub-lines'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">number\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'T-1'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">build\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\">$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\">profile\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">Scenarios\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">profile\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'sub-lines'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">))\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\">'zugferd'\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>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>\u003Ccode>php artisan quittio:preview --scenario=simple\u003C\u002Fcode> renders a scenario with your template (\u003Ca href=\"\u002Fdocs\u002Fcommands#quittiopreview\">quittio:preview\u003C\u002Fa>).\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Method\u003C\u002Fth>\n\u003Cth>Returns\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Scenarios::names(): array\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">All scenario names\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Scenarios::make(string $name): InvoiceBuilder\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">The builder of a scenario; an unknown name throws an \u003Ccode>InvalidArgumentException\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Scenarios::profile(string $name): string\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">Best profile: \u003Ccode>extended\u003C\u002Fcode> for \u003Ccode>sub-lines\u003C\u002Fcode>, \u003Ccode>peppol\u003C\u002Fcode> for \u003Ccode>peppol\u003C\u002Fcode>, otherwise \u003Ccode>en16931\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Scenarios::base(): InvoiceBuilder\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Returns\">Seller, buyer, dates and payment of all scenarios, without lines\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Each scenario also has a static method (\u003Ccode>Scenarios::simple()\u003C\u002Fcode>, \u003Ccode>manyLines()\u003C\u002Fcode>, \u003Ccode>longTexts()\u003C\u002Fcode>, \u003Ccode>mixedVat()\u003C\u002Fcode>, \u003Ccode>reverseCharge()\u003C\u002Fcode>, \u003Ccode>intraEu()\u003C\u002Fcode>, \u003Ccode>export()\u003C\u002Fcode>, \u003Ccode>cancellation()\u003C\u002Fcode>, \u003Ccode>subLines()\u003C\u002Fcode>, \u003Ccode>foreignCurrency()\u003C\u002Fcode>, \u003Ccode>b2cGross()\u003C\u002Fcode>, \u003Ccode>allowances()\u003C\u002Fcode>, \u003Ccode>attachments()\u003C\u002Fcode>, \u003Ccode>peppol()\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Name\u003C\u002Fth>\n\u003Cth>Content\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>simple\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Two lines (24 h web development, monthly hosting with a period), 19 %, 2 % cash discount within 7 days\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>many-lines\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">60 lines with item numbers, 7 % and 19 % (page breaks)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>long-texts\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Long note and description, item attributes\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>mixed-vat\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">7 %, 19 % and zero rated lines, 10 % document discount\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>reverse-charge\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">French buyer, reverse charge (\u003Ccode>AE\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>intra-eu\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Italian buyer, intra-community supply (\u003Ccode>K\u003C\u002Fcode>), delivery address, country of origin, HS code\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>export\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">US buyer, export (\u003Ccode>G\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>cancellation\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Credit note ST-2026-0007 cancelling RE-2026-0042\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>sub-lines\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Line with three sub lines, invoicee and delivery terms (profile EXTENDED)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>foreign-currency\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">USD invoice with the VAT accounting currency EUR\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>b2c-gross\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Consumer buyer, gross prices, 7 % and 19 %\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>allowances\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Line allowance and charge, document charge and allowance, price base quantity, list price with discount\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>attachments\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Embedded CSV time sheet and an external document reference\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>peppol\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Content\">Belgian buyer, Peppol endpoints (\u003Ccode>0208\u003C\u002Fcode>, \u003Ccode>9930\u003C\u002Fcode>), reverse charge\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch2 id=\"official-validators-in-ci\">Official validators in CI\u003Ca class=\"q-doc-anchor\" href=\"#official-validators-in-ci\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>By default, rendering and \u003Ccode>assertValidEInvoice()\u003C\u002Fcode> use Quittio's PHP rules and the XSD schemas (levels \u003Ccode>php\u003C\u002Fcode> and \u003Ccode>xsd\u003C\u002Fcode>). Two official validators check more (\u003Ca href=\"\u002Fdocs\u002Fconcepts#rules-and-validation\">Rules and validation\u003C\u002Fa>):\u003C\u002Fp>\n\u003Cul>\n\u003Cli>the KoSIT validator (level L5) with the official Schematron rules of EN 16931, XRechnung and Peppol; KoSIT is the German agency that publishes XRechnung;\u003C\u002Fli>\n\u003Cli>veraPDF (level L6), which checks that a PDF is a valid PDF\u002FA file.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>They need Java and veraPDF. Run them in a separate test group, so that your fast tests do not need them:\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\\Drivers\\KositArtifacts\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\">function\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\"> useOfficialValidators\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> void\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:#E6EDF3\">    $root \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\"> storage_path\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'quittio\u002Fvalidators'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);            \u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">\u002F\u002F php artisan quittio:schemas:download\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:#D2A8FF\">    config\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">set\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'quittio.validation.levels'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, [\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'php'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xsd'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'kosit'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'verapdf'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">]);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#D2A8FF\">    config\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">set\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'quittio.validation.drivers.kosit'\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\"> 'cli'\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\">        'jar'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $root\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">.\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'\u002Fvalidator.jar'\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\">        'scenarios'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $root\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">.\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'\u002Fxrechnung\u002Fscenarios.xml'\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\">        'repository'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $root\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">.\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'\u002Fxrechnung'\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\">        'configurations'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> [[\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'scenarios'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> KositArtifacts\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">peppolScenarios\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(), \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'repository'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> $root]],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#A5D6FF\">        'timeout'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> 120\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:#D2A8FF\">    config\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">set\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'quittio.validation.drivers.verapdf'\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>\u003Cspan style=\"color:#A5D6FF\">'image'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'verapdf\u002Fcli'\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>\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:#D2A8FF\">it\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'produces valid ZUGFeRD and XRechnung'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">function\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> () {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#D2A8FF\">    useOfficialValidators\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\">    $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\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">state\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">fn\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\"> ($b) => $b\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">buyerReference\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'04011000-12345-03'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">))\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\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\">    $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\">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:#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\">\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    $this\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertValidEInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($result\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">pdf\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(), \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'en16931'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#79C0FF\">    $this\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">assertValidEInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($result\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">as\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\">xml\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(), \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'xrechnung'\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\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">group\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'official'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">);\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cul>\n\u003Cli>\u003Ccode>php artisan quittio:schemas:download\u003C\u002Fcode> downloads the validator and prints the values for \u003Ccode>jar\u003C\u002Fcode>, \u003Ccode>scenarios\u003C\u002Fcode>, \u003Ccode>repository\u003C\u002Fcode> and \u003Ccode>configurations\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>In mode \u003Ccode>cli\u003C\u002Fcode> every validation starts a JVM (Java virtual machine). For many documents, run the validator as a daemon instead: \u003Ccode>mode\u003C\u002Fcode> \u003Ccode>daemon\u003C\u002Fcode> with \u003Ccode>QUITTIO_KOSIT_URL\u003C\u002Fcode> (\u003Ca href=\"\u002Fdocs\u002Fvalidation#kosit-validator-l5\">KoSIT validator\u003C\u002Fa>).\u003C\u002Fli>\n\u003Cli>The download command also prints the start command of the daemon, with \u003Ccode>-P 8081\u003C\u002Fcode> for the default URL \u003Ccode>http:\u002F\u002F127.0.0.1:8081\u003C\u002Fcode>. The validator's own default port is 8080.\u003C\u002Fli>\n\u003Cli>An unreachable validator fails the validation with \u003Ccode>KOSIT-UNAVAILABLE\u003C\u002Fcode>, unless \u003Ccode>fail_on_unavailable\u003C\u002Fcode> is \u003Ccode>false\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>A GitHub Actions job for this group:\u003C\u002Fp>\n\u003Cdiv class=\"q-doc-code\">\u003Cdiv class=\"q-doc-code-bar\">\u003Cspan>yaml\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:#7EE787\">official-validation\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:4ch;text-indent:-4ch\">\u003Cspan style=\"color:#7EE787\">  runs-on\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">ubuntu-latest\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:4ch;text-indent:-4ch\">\u003Cspan style=\"color:#7EE787\">  steps\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>\u003Cspan style=\"color:#7EE787\">uses\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">actions\u002Fcheckout@v7\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    - \u003C\u002Fspan>\u003Cspan style=\"color:#7EE787\">uses\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">shivammathur\u002Fsetup-php@v2\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:8ch;text-indent:-8ch\">\u003Cspan style=\"color:#7EE787\">      with\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#7EE787\">        php\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'8.4'\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#7EE787\">        extensions\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">dom, libxml, mbstring, xmlwriter, zlib, intl, gd, bcmath, zip\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    - \u003C\u002Fspan>\u003Cspan style=\"color:#7EE787\">uses\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">actions\u002Fsetup-java@v6\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:8ch;text-indent:-8ch\">\u003Cspan style=\"color:#7EE787\">      with\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#7EE787\">        distribution\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">temurin\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#7EE787\">        java-version\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'21'\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    - \u003C\u002Fspan>\u003Cspan style=\"color:#7EE787\">uses\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">actions\u002Fcache@v6\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:8ch;text-indent:-8ch\">\u003Cspan style=\"color:#7EE787\">      with\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#7EE787\">        path\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">storage\u002Fquittio\u002Fvalidators\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:10ch;text-indent:-10ch\">\u003Cspan style=\"color:#7EE787\">        key\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">quittio-validators-${{ hashFiles('composer.lock') }}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    - \u003C\u002Fspan>\u003Cspan style=\"color:#7EE787\">run\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">composer install --no-interaction --no-progress\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    - \u003C\u002Fspan>\u003Cspan style=\"color:#7EE787\">run\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">php artisan quittio:schemas:download\u003C\u002Fspan>\u003Cspan style=\"color:#8B949E\">     # keeps existing files\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    - \u003C\u002Fspan>\u003Cspan style=\"color:#7EE787\">run\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">docker pull verapdf\u002Fcli\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\" style=\"padding-left:6ch;text-indent:-6ch\">\u003Cspan style=\"color:#E6EDF3\">    - \u003C\u002Fspan>\u003Cspan style=\"color:#7EE787\">run\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">: \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">vendor\u002Fbin\u002Fpest --group=official\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Exclude the group from the fast test job with \u003Ccode>--exclude-group=official\u003C\u002Fcode>. To check a single file by hand: \u003Ccode>php artisan quittio:validate invoice.pdf --profile=en16931 --kosit --verapdf\u003C\u002Fcode> (\u003Ca href=\"\u002Fdocs\u002Fcommands#quittiovalidate\">Artisan commands\u003C\u002Fa>).\u003C\u002Fp>\n\u003Ch2 id=\"managed-layer-factories\">Managed layer factories\u003Ca class=\"q-doc-anchor\" href=\"#managed-layer-factories\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The \u003Ca href=\"\u002Fdocs\u002Fmanaged\">Managed layer\u003C\u002Fa> is the optional package \u003Ccode>quittio\u002Fmanaged\u003C\u002Fcode>: it stores invoices in your database, numbers and archives them. It ships Eloquent factories for its models (namespace \u003Ccode>Quittio\\Managed\\Database\\Factories\u003C\u002Fcode>). Tests need the published Managed migrations (\u003Ccode>quittio:install --managed\u003C\u002Fcode>, see \u003Ca href=\"\u002Fdocs\u002Fmanaged#installation\">Installation\u003C\u002Fa>) and a refreshed database.\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\\Managed\\Models\\Invoice\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\\Managed\\Models\\Issuer\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\">$issuer \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Issuer\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">default\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\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:2ch;text-indent:-2ch\">\u003Cspan style=\"color:#E6EDF3\">$invoice \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Invoice\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($issuer)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">create\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">issue\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'2026-10-05'\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\">$other \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Issuer\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">company\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'Andere AG'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">, \u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'DE111111111'\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">create\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">([\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\">'key'\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#A5D6FF\"> 'tenant-b'\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\">$draft \u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\"> Invoice\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">for\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">($issuer)\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">data\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">(\u003C\u002Fspan>\u003Cspan style=\"color:#79C0FF\">InvoiceData\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">::\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">factory\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">reverseCharge\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">()\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">make\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">())\u003C\u002Fspan>\u003Cspan style=\"color:#FF7B72\">->\u003C\u002Fspan>\u003Cspan style=\"color:#D2A8FF\">create\u003C\u002Fspan>\u003Cspan style=\"color:#E6EDF3\">();\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>\u003Ccode>Issuer::factory()\u003C\u002Fcode> (\u003Ccode>IssuerFactory\u003C\u002Fcode>) creates issuer profiles, the companies that issue invoices:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>State\u003C\u002Fth>\n\u003Cth>Attributes\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>(definition)\u003C\u002Ftd>\n\u003Ctd data-label=\"Attributes\">Key \u003Ccode>issuer-{10 random characters}\u003C\u002Fcode>; seller Muster GmbH with a random German VAT identifier (\u003Ccode>DE\u003C\u002Fcode> + 9 digits), Hauptstraße 1, 12345 Musterstadt, contact Max Muster, e-mail and electronic address \u003Ccode>rechnung@muster.de\u003C\u002Fcode>; country \u003Ccode>DE\u003C\u002Fcode>, time zone \u003Ccode>Europe\u002FBerlin\u003C\u002Fcode>, bank account \u003Ccode>DE02120300000000202051\u003C\u002Fcode> \u002F \u003Ccode>BYLADEM1001\u003C\u002Fcode>, defaults \u003Ccode>locale\u003C\u002Fcode> \u003Ccode>de\u003C\u002Fcode> and \u003Ccode>due_days\u003C\u002Fcode> 14; not the default issuer. Every issuer is a company of its own and gets its own number space.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>default()\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Attributes\">Key \u003Ccode>default\u003C\u002Fcode>, default issuer, seller VAT identifier \u003Ccode>DE123456789\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>company(string $name, string $vatId)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Attributes\">Another company: own name and VAT identifier, Marktplatz 2, 54321 Anderstadt, electronic address \u003Ccode>rechnung@{slug of the name}.de\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>\u003Ccode>Invoice::factory()\u003C\u002Fcode> (\u003Ccode>InvoiceFactory\u003C\u002Fcode>) creates drafts:\u003C\u002Fp>\n\u003Ctable class=\"q-doc-table q-stack-table\">\n\u003Cthead>\n\u003Ctr>\n\u003Cth>State\u003C\u002Fth>\n\u003Cth>Attributes\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>(definition)\u003C\u002Ftd>\n\u003Ctd data-label=\"Attributes\">Draft (\u003Ccode>status\u003C\u002Fcode> draft, \u003Ccode>kind\u003C\u002Fcode> invoice) with the data of \u003Ccode>InvoiceData::factory()-&gt;withLines(2)-&gt;make()\u003C\u002Fcode> (number empty, totals not yet calculated), for a new issuer (\u003Ccode>Issuer::factory()\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data(InvoiceData $data)\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd data-label=\"Attributes\">The columns of your invoice data instead\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Issuing takes the number from the issuer's sequence. The documents are rendered in a queued job after the transaction. In tests, use \u003Ccode>Queue::fake()\u003C\u002Fcode>, or set \u003Ccode>quittio-managed.queue.render_sync\u003C\u002Fcode> to render in the same request. See \u003Ca href=\"\u002Fdocs\u002Fmanaged\">Managed layer\u003C\u002Fa> for the lifecycle and \u003Ca href=\"\u002Fdocs\u002Fmanaged#testing-against-mysql-and-postgresql\">Testing against MySQL and PostgreSQL\u003C\u002Fa>.\u003C\u002Fp>\n",[111,115,119,122,125,128,131,134,137,140,143,146],{"id":112,"text":113,"level":114},"fake","Fake",2,{"id":116,"text":117,"level":118},"how-the-fake-works","How the fake works",3,{"id":120,"text":121,"level":118},"assertions-of-the-fake","Assertions of the fake",{"id":123,"text":124,"level":114},"validating-the-invoice-data","Validating the invoice data",{"id":126,"text":127,"level":114},"laravel-fakes","Laravel fakes",{"id":129,"text":130,"level":114},"assertions","Assertions",{"id":132,"text":133,"level":118},"snapshots","Snapshots",{"id":135,"text":136,"level":118},"outside-test-case-classes","Outside test case classes",{"id":138,"text":139,"level":114},"factory","Factory",{"id":141,"text":142,"level":114},"scenarios","Scenarios",{"id":144,"text":145,"level":114},"official-validators-in-ci","Official validators in CI",{"id":147,"text":148,"level":114},"managed-layer-factories","Managed layer factories","https:\u002F\u002Fgithub.com\u002FQuittio\u002Fquittio\u002Fedit\u002Fmaster\u002Fdocs\u002Ftesting.md","\u002Fdocs\u002Ftesting.md",{"slug":67,"title":68},{"slug":73,"title":74}]