Symptom
Setting the entity type on the issuer's partner — the very first step of the onboarding, via the Directory Sync button — kills the worker instantly:
File "odoo/api.py", line 485, in call_kw
model.env.flush_all()
File "l10n_fr_einvoicing/models/account_move.py", line 152, in _compute_einvoicing_required
move.move_type in ("out_invoice", "out_refund")
File "odoo/api.py", line 1123, in insert_missing
field_cache.setdefault(id_, val)
MemoryError
Nothing is written: the transaction dies before the first row. On the database where we hit it, the company holds 497 000 customer invoices out of 877 000 journal entries.
Seen on our 16.0 backport (#33), but the code is identical on 18.0 and 19.0 — so it should hit any customer with a real invoicing history, at the exact moment they switch the reform on.
Cause
fr_einvoicing_required is store=True and depends on fr_directory_company_entity_type, which is a related field on the company's partner:
fr_directory_company_entity_type = fields.Selection(
related="company_id.partner_id.fr_directory_entity_type", ...)
@api.depends(
"fr_directory_company_entity_type", # <-- one value, every invoice
"fr_directory_partner_entity_type",
"move_type",
"company_id.fr_ctc_disable_private_invoice_sending",
)
def _compute_einvoicing_required(self):
A single value therefore drives a stored field on every invoice of the company. Writing it once invalidates the entire history in one transaction.
The customer-side dependency (fr_directory_partner_entity_type) is fine: it is bounded by one partner's invoices, and the directory sync walks partners one at a time.
Suggested fix
The module already solves this exact problem for a neighbouring field: company_fr_directory_line_id depends on company_id alone, and res_company._fr_ctc_compute_invoice_company_dir_line() refreshes it on demand.
Applying the same treatment — drop the dependency, refresh explicitly in committed batches. The issuer's entity type only changes once, at activation, so an automatic dependency buys nothing and costs the whole history:
def _fr_ctc_recompute_einvoicing_required(self, batch_size=2000):
"""Refresh fr_einvoicing_required after the issuer's entity type changed."""
self.ensure_one()
domain = [("move_type", "in", ("out_invoice", "out_refund")),
("company_id", "=", self.id)]
if self.fiscalyear_lock_date:
domain.append(("date", ">", self.fiscalyear_lock_date))
move_ids = self.env["account.move"].search(domain).ids
for offset in range(0, len(move_ids), batch_size):
self.env["account.move"].browse(
move_ids[offset:offset + batch_size]
)._compute_einvoicing_required()
self.env.flush_all()
self.env.cr.commit()
self.env.invalidate_all()
Filtering on fiscalyear_lock_date — as _fr_ctc_compute_invoice_company_dir_line() already does — also keeps locked years out of the way.
I can send this as a PR against 18.0 if the approach suits you; it is already applied on the 16.0 and 19.0 migration branches.
Related
The same pattern bit us in l10n_fr_einvoicing_directory_import, where marking partners as registered blew up for the same reason: a stored field on account.move depending on a partner-level value. Both point at one underlying risk — such a field does not scale on a real production history, and the batched-commit workaround has to be explicit.
Symptom
Setting the entity type on the issuer's partner — the very first step of the onboarding, via the Directory Sync button — kills the worker instantly:
Nothing is written: the transaction dies before the first row. On the database where we hit it, the company holds 497 000 customer invoices out of 877 000 journal entries.
Seen on our 16.0 backport (#33), but the code is identical on 18.0 and 19.0 — so it should hit any customer with a real invoicing history, at the exact moment they switch the reform on.
Cause
fr_einvoicing_requiredisstore=Trueand depends onfr_directory_company_entity_type, which is a related field on the company's partner:A single value therefore drives a stored field on every invoice of the company. Writing it once invalidates the entire history in one transaction.
The customer-side dependency (
fr_directory_partner_entity_type) is fine: it is bounded by one partner's invoices, and the directory sync walks partners one at a time.Suggested fix
The module already solves this exact problem for a neighbouring field:
company_fr_directory_line_iddepends oncompany_idalone, andres_company._fr_ctc_compute_invoice_company_dir_line()refreshes it on demand.Applying the same treatment — drop the dependency, refresh explicitly in committed batches. The issuer's entity type only changes once, at activation, so an automatic dependency buys nothing and costs the whole history:
Filtering on
fiscalyear_lock_date— as_fr_ctc_compute_invoice_company_dir_line()already does — also keeps locked years out of the way.I can send this as a PR against 18.0 if the approach suits you; it is already applied on the 16.0 and 19.0 migration branches.
Related
The same pattern bit us in
l10n_fr_einvoicing_directory_import, where marking partners as registered blew up for the same reason: a stored field onaccount.movedepending on a partner-level value. Both point at one underlying risk — such a field does not scale on a real production history, and the batched-commit workaround has to be explicit.