
E-Invoice Pre-Flight Checks
Run the EN 16931 rules against invoices before they leave, so a rejection arrives as a list of fields to fill in, not a code three days later.
Available for Odoo 16.0, Odoo 17.0, Odoo 18.0, Odoo 19.0. Technical name bambooforge_einvoice.
E-Invoice Pre-Flight Checks
What this is for
Odoo builds a technically valid UBL or CII file from whatever is on the invoice. Whether the receiving system accepts it is a different question, and the answer arrives days later as a rejection carrying a rule code and no context — usually from a customer's portal, sometimes from a tax authority.
This runs the same rules before the invoice leaves.
The checks
Accounting ▸ Configuration ▸ E-Invoice Checks
They install as records, so a company can switch off what its customers do not enforce and promote a warning to blocking once one of them has cost an invoice.
Blocking — these are refusals, not preferences:
seller and buyer name, and a real postal address for both (public-sector buyers reject on the buyer address more than on anything else);
a VAT number or legal registration for the seller;
a due date or payment terms when there is something to pay;
at least one line, a description on every line, and a VAT category on every line.
Warnings — accepted by most, enforced by some:
a unit of measure with no UN/ECE code. Units travel as UN/ECE Rec. 20 codes, and an unmapped one is usually read as "piece" — wrong on anything sold by weight or length, and invisible until a customer queries the quantity;
no buyer reference or order number, which every customer matching invoices to orders automatically will want.
Using it
Check E-Invoice on the invoice form, or the Check for e-invoicing action on a selection in the list. Findings appear on the invoice with what to fix, and Accounting ▸ Reporting ▸ E-Invoice Pre-Flight lists everything that would be rejected across the company.
A nightly pass checks posted invoices nobody has checked, so the problem surfaces the morning after posting rather than at send time.
For a send flow that should refuse to hand over a bad invoice, call move.bf_einvoice_assert_ready(); it checks first if nobody has.
Known limits
These are the semantic rules of EN 16931, not a schema validation. A national profile can add its own — Leitweg-ID for German public bodies, Chorus Pro service codes in France.
The unit map covers the units that actually turn up on invoices. The point is to notice an unmapped one, not to be exhaustive.
Passing every check does not guarantee acceptance. It removes the reasons that are yours to remove.
Screens


