Skip to content

account_invoice_en16931: _post() validates the EN16931 configuration of every company, blocking unrelated ones #42

Description

@almumu

Context

account_move._post() runs the company-level configuration check for every sale document, with no condition:

# account_invoice_en16931/models/account_move.py:199-201 (18.0)
    def _post(self, soft=True):
        for move in self.filtered(lambda x: x.is_sale_document()):
            move.company_id._en16931_checks()

_en16931_checks() then requires every active sale tax of that company to carry a UNECE tax type and category, plus the three decimal.precision limits.

In a multi-company database where a single company is subject to the French reform, installing the module makes all companies unable to post customer invoices until their own tax configuration is UNECE-coded — including companies in other countries that will never emit an
EN16931 document. In the database we are working on that is about 130 active sale taxes across two other localisations.

One of those localisations makes the check unsatisfiable rather than merely tedious: the Italian split-payment taxes are group taxes (amount_type = 'group'). Without a UNECE type they fail "has no UNECE Tax Type"; with type VAT they fail the amount_type == 'percent' requirement.
There is no value that passes.

The check is already enforced where it matters

_generate_en16931_dict() already runs the same company check before building the document:

# account_invoice_en16931/models/account_move.py:706 (18.0)
        self._en16931_checks_upon_invoice_generation()
# account_invoice_en16931/models/account_move.py:273-275 (18.0)
    def _en16931_checks_upon_invoice_generation(self):
        self.ensure_one()
        self.company_id._en16931_checks()

So a company with an incomplete configuration cannot generate an EN16931 document in any case.
The call in _post() only anticipates the same error at posting time — and that is precisely what reaches companies that never generate one.

Precedent in this repository

l10n_fr_einvoicing._post() already scopes its own work to the companies and documents concerned:

# l10n_fr_einvoicing/models/account_move.py (16.0 backport of #33; same shape on 18.0)
    def _post(self, soft=True):
        for move in self:
            company = move.company_id
            if (
                move.is_sale_document()
                and company._fr_ctc_is_vat_registered(raise_if_misconfigured=True)
                and move.fr_einvoicing_required
            ):

The base module has no equivalent condition.

Proposal

In order of preference:

  1. Remove the _en16931_checks() call from _post(), relying on the generation-time check that already exists.
  2. Keep it, but conditional — for instance a company-level boolean ("this company issues EN16931 documents"), default off, that a localisation layer can set. l10n_fr_einvoicing already has the notion (fr_einvoicing_required, _fr_ctc_is_vat_registered()), but the base module cannot depend on it.

Related: #38 raises the same rigidity of _post() from a different angle (the per-line VAT tax lookup). Both would be addressed by making that method more configurable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions