Skip to content
Snippets Groups Projects
Commit 16b2cf8b authored by Denis Ledoux's avatar Denis Ledoux
Browse files

[FIX] l10n_latam_invoice_document: skip `document_type` computation on install


Skip the computation of the field `l10n_latam_document_type_id` at the module installation.

The case has been detected during an upgrade from Odoo 12.0 to Odoo 13.0,
but the case could really well happen outside the context of an upgrade,
for instance when you create a new subsidiary in Chile or Argentina
while you already have a lot of accounting entries in your other subsidiaries
(e.g. Odoo S.A. opens a new office in Chile and has to install `l10n_cl`)

Without this, at the module installation,
it would call `_compute_l10n_latam_document_type` on all existing records
which can take quite a while if you already have a lot of moves. It can even fail with a MemoryError.

In addition, it sets `_compute_l10n_latam_document_type = False` on all records
because this field depends on the many2many `l10n_latam_available_document_type_ids`,
which relies on having records for the model `l10n_latam.document.type`
which only happens once the according localization module is loaded.
(e.g. `l10n_cl/data/l10n_latam.document.type.csv`)

The localization module is loaded afterwards, because the localization module depends on this module,
(e.g. `l10n_cl` depends on `l10n_latam_invoice_document`, and therefore `l10n_cl` is loaded after)
and therefore there are no records for the model `l10n_latam.document.type` at the time this fields
gets computed on installation. Hence, all records' `_compute_l10n_latam_document_type` are set to `False`.

In addition, multiple localization module depends on this module (e.g. `l10n_cl`, `l10n_ar`)
So, imagine `l10n_cl` gets installed first, and then `l10n_ar` is installed next,
if `l10n_latam_document_type_id` needed to be computed on install,
the install of `l10n_cl` would call the compute method,
because `l10n_latam_invoice_document` would be installed at the same time,
but then `l10n_ar` would miss it, because `l10n_latam_invoice_document` would already be installed.

Besides, this field is computed only for drafts invoices, as stated in the compute method:
`for rec in self.filtered(lambda x: x.state == 'draft'):`
So, if we want this field to be computed on install, it must be done only on draft invoices, and only once
the localization modules are loaded.

It should be done in a dedicated post init hook,
filtering correctly the invoices for which it must be computed.

Though I don't think this is needed.
In practical, it's very rare to already have invoices (draft, in addition)
for a Chilian or Argentian company (`res.company`) before installing `l10n_cl` or `l10n_ar`.

```
Traceback (most recent call last):
  File "/src/odoo/13.0/odoo/service/server.py", line 1190, in preload_registries
    registry = Registry.new(dbname, update_module=update_module)
  File "/src/odoo/13.0/odoo/modules/registry.py", line 86, in new
    odoo.modules.load_modules(registry._db, force_demo, status, update_module)
  File "/src/odoo/13.0/odoo/modules/loading.py", line 423, in load_modules
    loaded_modules, update_module, models_to_check)
  File "/src/odoo/13.0/odoo/modules/loading.py", line 315, in load_marked_modules
    perform_checks=perform_checks, models_to_check=models_to_check
  File "/src/odoo/13.0/odoo/modules/loading.py", line 202, in load_module_graph
    registry.init_models(cr, model_names, {'module': package.name}, new_install)
  File "/src/odoo/13.0/odoo/modules/registry.py", line 364, in init_models
    env['base'].flush()
  File "/src/odoo/13.0/odoo/models.py", line 5458, in flush
    self.recompute()
  File "/src/odoo/13.0/odoo/models.py", line 5875, in recompute
    process(field)
  File "/src/odoo/13.0/odoo/models.py", line 5859, in process
    recs.mapped(field.name)
  File "/src/odoo/13.0/odoo/models.py", line 5266, in mapped
    recs = recs._mapped_func(operator.itemgetter(name))
  File "/src/odoo/13.0/odoo/models.py", line 5225, in _mapped_func
    vals = [func(rec) for rec in self]
  File "/src/odoo/13.0/odoo/models.py", line 5225, in <listcomp>
    vals = [func(rec) for rec in self]
  File "/src/odoo/13.0/odoo/models.py", line 5690, in __getitem__
    return self._fields[key].__get__(self, type(self))
  File "/src/odoo/13.0/odoo/fields.py", line 2329, in __get__
    return super().__get__(records, owner)
  File "/src/odoo/13.0/odoo/fields.py", line 995, in __get__
    self.compute_value(recs)
  File "/src/odoo/13.0/odoo/fields.py", line 1109, in compute_value
    records._compute_field_value(self)
  File "/src/odoo/13.0/odoo/models.py", line 3968, in _compute_field_value
    field.compute(self)
  File "/src/odoo/13.0/odoo/fields.py", line 579, in _compute_related
    record[self.name] = self._process_related(value[self.related_field.name])
  File "/src/odoo/13.0/odoo/models.py", line 5699, in __setitem__
    return self._fields[key].__set__(self, value)
  File "/src/odoo/13.0/odoo/fields.py", line 1070, in __set__
    self.write(protected_records, value)
  File "/src/odoo/13.0/odoo/fields.py", line 2564, in write
    cache.update(records, self, [cache_value] * len(records))
  File "/src/odoo/13.0/odoo/api.py", line 768, in update
    field_cache.setdefault(record_id, {})[key] = value
MemoryError
```

Upgrade request 49495

closes odoo/odoo#60572

X-original-commit: f2a08faa1e65cb381315cbd5d1a359901e8b7deb
Signed-off-by: default avatarDenis Ledoux (dle) <dle@odoo.com>
parent 63b081c4
Branches
Tags
No related merge requests found
......@@ -4,12 +4,45 @@ from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
import re
from odoo.tools.misc import formatLang
from odoo.tools.sql import column_exists, create_column
class AccountMove(models.Model):
_inherit = "account.move"
def _auto_init(self):
# Skip the computation of the field `l10n_latam_document_type_id` at the module installation
# Without this, at the module installation,
# it would call `_compute_l10n_latam_document_type` on all existing records
# which can take quite a while if you already have a lot of moves. It can even fail with a MemoryError.
# In addition, it sets `_compute_l10n_latam_document_type = False` on all records
# because this field depends on the many2many `l10n_latam_available_document_type_ids`,
# which relies on having records for the model `l10n_latam.document.type`
# which only happens once the according localization module is loaded.
# The localization module is loaded afterwards, because the localization module depends on this module,
# (e.g. `l10n_cl` depends on `l10n_latam_invoice_document`, and therefore `l10n_cl` is loaded after)
# and therefore there are no records for the model `l10n_latam.document.type` at the time this fields
# gets computed on installation. Hence, all records' `_compute_l10n_latam_document_type` are set to `False`.
# In addition, multiple localization module depends on this module (e.g. `l10n_cl`, `l10n_ar`)
# So, imagine `l10n_cl` gets installed first, and then `l10n_ar` is installed next,
# if `l10n_latam_document_type_id` needed to be computed on install,
# the install of `l10n_cl` would call the compute method,
# because `l10n_latam_invoice_document` would be installed at the same time,
# but then `l10n_ar` would miss it, because `l10n_latam_invoice_document` would already be installed.
# Besides, this field is computed only for drafts invoices, as stated in the compute method:
# `for rec in self.filtered(lambda x: x.state == 'draft'):`
# So, if we want this field to be computed on install, it must be done only on draft invoices, and only once
# the localization modules are loaded.
# It should be done in a dedicated post init hook,
# filtering correctly the invoices for which it must be computed.
# Though I don't think this is needed.
# In practical, it's very rare to already have invoices (draft, in addition)
# for a Chilian or Argentian company (`res.company`) before installing `l10n_cl` or `l10n_ar`.
if not column_exists(self.env.cr, "account_move", "l10n_latam_document_type_id"):
create_column(self.env.cr, "account_move", "l10n_latam_document_type_id", "int4")
return super()._auto_init()
l10n_latam_amount_untaxed = fields.Monetary(compute='_compute_l10n_latam_amount_and_taxes')
l10n_latam_tax_ids = fields.One2many(compute="_compute_l10n_latam_amount_and_taxes", comodel_name='account.move.line')
l10n_latam_available_document_type_ids = fields.Many2many('l10n_latam.document.type', compute='_compute_l10n_latam_available_document_types')
......
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, api, fields
from odoo.tools.sql import column_exists, create_column
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
def _auto_init(self):
# Skip the computation of the field `l10n_latam_document_type_id` at the module installation
# See `_auto_init` in `l10n_latam_invoice_document/models/account_move.py` for more information
if not column_exists(self.env.cr, "account_move_line", "l10n_latam_document_type_id"):
create_column(self.env.cr, "account_move_line", "l10n_latam_document_type_id", "int4")
return super()._auto_init()
l10n_latam_document_type_id = fields.Many2one(
related='move_id.l10n_latam_document_type_id', auto_join=True, store=True, index=True)
l10n_latam_price_unit = fields.Monetary(compute='compute_l10n_latam_prices_and_taxes')
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment