[FIX] account: Defer recursive check
This bug is generally hidden in normal localizations because the `get_account_account` function reads `account.account-xx.csv` soon enough to create all the needed accounts. In `l10n_ng` there is no `account.account-ng.csv`, as it relies on the generic_coa. The chart_template's `get_account_tax` function reads `account.tax-ng.csv` before `get_ng_account_account` is called. The `defer` function should check the account_tax fields and postpone them until the creates are done, but it only checks the "first level" and doesn't check all the way down to `account_tax.repartition_line_ids.account_id` By making `defer` recursive we are able to properly postpone the creation of taxes after the accounts are made. related PR: odoo/odoo#148370 task-3607459 Part-of: odoo/odoo#157918
This commit is contained in:
@@ -507,31 +507,36 @@ class AccountChartTemplate(models.AbstractModel):
|
||||
|
||||
def defer(all_data):
|
||||
"""Defer writing some relations if the related records don't exist yet."""
|
||||
|
||||
def should_defer(created_models, yet_to_be_created_models, model, field_name, field_val, parent_models=None):
|
||||
parent_models = (parent_models or []) + [model]
|
||||
field = self.env[model]._fields.get(field_name)
|
||||
if not field or not field.relational or field.comodel_name in created_models:
|
||||
return False
|
||||
field_yet_to_be_created = field.comodel_name in parent_models + yet_to_be_created_models
|
||||
if not isinstance(field_val, list | tuple):
|
||||
return field_yet_to_be_created
|
||||
# Check recursively if there are subfields that should be delayed
|
||||
for element in field_val:
|
||||
match element:
|
||||
case Command.CREATE, _, dict() as values:
|
||||
for subkey, subvalue in values.items():
|
||||
if should_defer(created_models, yet_to_be_created_models, field.comodel_name, subkey, subvalue, parent_models):
|
||||
return True
|
||||
case int() as command, *_ if command in tuple(Command):
|
||||
if field_yet_to_be_created:
|
||||
return True
|
||||
return False
|
||||
|
||||
created_models = set()
|
||||
while all_data:
|
||||
(model, data), *all_data = all_data
|
||||
yet_to_be_created_models = [model for model, _data in all_data]
|
||||
to_delay = defaultdict(dict)
|
||||
for xml_id, vals in data.items():
|
||||
to_be_removed = []
|
||||
for field_name, field_val in vals.items():
|
||||
field = self.env[model]._fields.get(field_name, None)
|
||||
if (
|
||||
field
|
||||
and field.relational
|
||||
and field_val
|
||||
and ( # allow create commands but delay all other related fields
|
||||
not isinstance(field_val, (list, tuple))
|
||||
or (
|
||||
isinstance(field_val[0], (list, tuple))
|
||||
and {command for command, *dummy in field_val} != {Command.CREATE}
|
||||
)
|
||||
)
|
||||
and field.comodel_name not in created_models
|
||||
and (
|
||||
field.comodel_name in dict(all_data)
|
||||
or field.comodel_name == model
|
||||
)
|
||||
):
|
||||
if should_defer(created_models, yet_to_be_created_models, model, field_name, field_val):
|
||||
to_be_removed.append(field_name)
|
||||
to_delay[xml_id][field_name] = field_val
|
||||
for field_name in to_be_removed:
|
||||
@@ -1041,13 +1046,12 @@ class AccountChartTemplate(models.AbstractModel):
|
||||
|
||||
def _deref_account_tags(self, template_code, tax_data):
|
||||
mapper = self._get_tag_mapper(template_code)
|
||||
for tax in tax_data.values():
|
||||
for fname in ('invoice_repartition_line_ids', 'refund_repartition_line_ids', 'repartition_line_ids'):
|
||||
if tax.get(fname):
|
||||
for _command, _id, repartition in tax[fname]:
|
||||
tags = repartition.get('tag_ids')
|
||||
if isinstance(tags, str):
|
||||
repartition['tag_ids'] = [Command.set(mapper(*tags.split(TAX_TAG_DELIMITER)))]
|
||||
for tax_values in tax_data.values():
|
||||
for field_name in ('repartition_line_ids', 'invoice_repartition_line_ids', 'refund_repartition_line_ids'):
|
||||
for element in tax_values.get(field_name, []):
|
||||
match element:
|
||||
case Command(), _, {'tag_ids': str() as tags} as values:
|
||||
values['tag_ids'] = [Command.set(mapper(*tags.split(TAX_TAG_DELIMITER)))]
|
||||
|
||||
def _parse_csv(self, template_code, model, module=None):
|
||||
Model = self.env[model]
|
||||
|
||||
Reference in New Issue
Block a user