← all projects

mock-einvoice

A mock e-invoicing partner. It reads and writes UBL invoices and credit notes and holds them to their published rules, and it reads and writes the Peppol Invoice Response a buyer answers one with. Over HTTP it is a buyer that takes invoices in and answers them, and a supplier that sends them and takes the answers. One process is both, and two can be pointed at each other.

supplier ──Invoice (UBL)──▶  buyer   held to 1,144 rules: valid, 201
         ◀──Response AP───          accepted
         ◀──Response PD───          paid
         ──BT-115 999.99──▶  buyer   422  BR-CO-16: the parts come to 1190.00
buyer    ──Response UQ──▶  refused   409  OP-BR111-R004: nothing follows
                                          a payment in full
  • Zero dependencies. Python 3.8+ and the standard library, like its siblings. Every amount, quantity and percentage is a Decimal made from the text as written, and making one from a float is a TypeError.
  • Every published rule, under its publisher's name. All 979 of the EN 16931 core, all 165 of Peppol BIS Billing 3.0 (its own 63, the 31 for Germany and the 71 for seven other countries), the 34 of a standard XRechnung 3.0 document, and all 82 of the Invoice Response. A finding gives the rule's identifier, where it was found and a link to where the rule is published; the words are the project's own.
  • Not built is said, never assumed. A report lists the rules it ran and the published ones it did not. A document nothing was found wrong with is not judged, not valid, while a rule that could apply to it is missing. Since 0.2.0 every rule that can apply to a document it takes is built, so the verdict waits for the day a specification publishes a rule before the mock has it.
  • Held to other people's tests. Of the 1,137 unit test cases EN 16931 publishes, 1,126 agree and none disagree; all 678 statements in Peppol's 673 cases agree; and all 39 valid documents of the XRechnung test suite are valid. A disagreement is a failure until the published rule shows the case to be wrong.
  • The rules no validator checks. Peppol's guide gives the Invoice Response an order (acknowledged, in process, under query, conditionally accepted, rejected, accepted, paid) and says nothing follows a rejection or a payment in full. No Schematron file has those rules, so the buyer keeps to them and refuses a response that breaks one with 409 and the rule. "force" sends it anyway, because a seller's system has to cope with a buyer who does, and the supplier takes such a response and ignores it, as the guide says it may.
  • The arithmetic is the rules' own. The published rules are XPath, and XPath rounds a tie towards positive infinity, which is neither Python's round nor half up. A rule that could not be computed has failed, as it would in a real validator.
  • What it does not do is refused by name. A Cross Industry Invoice, an XRechnung Extension or CVD document, a document with a DOCTYPE, a specification it does not know: each is refused with a code and a sentence, not quietly held to the core alone.
  • Not real, and says where. There is no AS4 and no SMP lookup: an invoice is a POST and the other party is a URL. Nothing happens with time, so each status after the first is asked for, and nothing is kept on disk.
  • Worked end to end with the other mocks. E-invoice in mock-acme takes a supplier's UBL invoice in place of an 810, matches it against the order in mock-sap and the ship notice from mock-edi, posts it, and answers the supplier with Invoice Responses down to paid.
pip install mock-einvoice
mock-einvoice --port 8100
curl --data-binary @invoice.xml http://127.0.0.1:8100/invoices

Worked examples that use mock-einvoice: E-invoice.