Files
odoo_source/addons/account/models/ir_module.py
T
Antoine Dupuis (andu) cfb84de489 [FIX] account: Avoid ir_module.account_templates compute error
Issue / How to reproduce:

At the moment, if a localization's python module is not present,
the computation of the `ir.module.module.account_templates` field fails
with a ModuleNotFoundError

How to reproduce:
- Create a fresh DB with a localization e.g. l10n_be
- Remove the localization directory
- Start the DB again and navigate e.g. to Inventory > Configuration >
  Settings. You will see a traceback, whose root cause is that the
  computation of the `account_templates` field failed.

We noticed this in a runbot upgrade between 16.1 and 16.2, for a new
localization that was introduced in 16.0.

Solution:

Make the computation return False if the Python module cannot be found.
Also, filter out the modules where account_templates is False when
constructing the list of available chart templates.

closes odoo/odoo#113875

Signed-off-by: William André (wan) <wan@odoo.com>
2023-02-28 23:49:47 +01:00

71 lines
3.2 KiB
Python

from importlib import import_module
from inspect import getmembers, ismodule, isclass, isfunction
from odoo import models, fields
def get_flag(country_code):
# get the sequence of 2 regional indicator emoji forming the flag linked to the country code
return "".join(chr(int(f"1f1{ord(c)+165:02x}", base=16)) for c in country_code)
def templ(env, code, name=None, country='', **kwargs):
country_code = country or code.split('_')[0] if country is not None else None
country = country_code and env.ref(f"base.{country_code}", raise_if_not_found=False)
country_name = f"{get_flag(country.code)} {country.name}" if country else ''
return {
'name': country_name and (f"{country_name} - {name}" if name else country_name) or name,
'country_id': country and country.id,
'country_code': country and country.code,
**kwargs,
}
template_module = lambda m: ismodule(m) and m.__name__.split('.')[-1].startswith('template_')
template_class = isclass
template_function = lambda f: isfunction(f) and hasattr(f, '_l10n_template') and f._l10n_template[1] == 'template_data'
class IrModule(models.Model):
_inherit = "ir.module.module"
account_templates = fields.Binary(compute='_compute_account_templates', exportable=False)
def _compute_account_templates(self):
chart_category = self.env.ref('base.module_category_accounting_localizations_account_charts')
ChartTemplate = self.env['account.chart.template']
for module in self:
templates = {}
if module.category_id == chart_category or module.name == 'account':
try:
python_module = import_module(f"odoo.addons.{module.name}.models")
except ModuleNotFoundError:
templates = {}
else:
templates = {
fct._l10n_template[0]: {
'name': fct(ChartTemplate).get('name'),
'parent': fct(ChartTemplate).get('parent'),
'country': fct(ChartTemplate).get('country', ''),
'visible': fct(ChartTemplate).get('visible', True),
'module': module.name,
}
for _name, mdl in getmembers(python_module, template_module)
for _name, cls in getmembers(mdl, template_class)
for _name, fct in getmembers(cls, template_function)
}
module.account_templates = {
code: templ(self.env, code, **vals)
for code, vals in templates.items()
}
def write(self, vals):
# Instanciate the first template of the module on the current company upon installing the module
was_installed = len(self) == 1 and self.state == 'installed'
super().write(vals)
is_installed = len(self) == 1 and self.state == 'installed'
if not was_installed and is_installed and not self.env.company.chart_template and self.account_templates:
self.env['account.chart.template'].try_loading(
next(iter(self.account_templates)),
self.env.company,
)