2
0

[13.0][FIX]account_chart_update refactor tax update

This commit is contained in:
Luc De Meyer 2020-09-15 12:32:42 +02:00 committed by Luis J. Salvatierra
parent eefe80e215
commit 7a7f0f447c
3 changed files with 136 additions and 34 deletions

View File

@ -7,7 +7,7 @@
{ {
"name": "Detect changes and update the Account Chart from a template", "name": "Detect changes and update the Account Chart from a template",
"summary": "Wizard to update a company's account chart from a template", "summary": "Wizard to update a company's account chart from a template",
"version": "14.0.1.0.1", "version": "14.0.2.0.0",
"author": "Tecnativa, BCIM, Okia, Odoo Community Association (OCA)", "author": "Tecnativa, BCIM, Okia, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-financial-tools", "website": "https://github.com/OCA/account-financial-tools",
"depends": ["account"], "depends": ["account"],

View File

@ -6,6 +6,7 @@
# Copyright 2016 Jairo Llopis <jairo.llopis@tecnativa.com> # Copyright 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
# Copyright 2016 Jacques-Etienne Baudoux <je@bcim.be> # Copyright 2016 Jacques-Etienne Baudoux <je@bcim.be>
# Copyright 2018 Tecnativa - Pedro M. Baeza # Copyright 2018 Tecnativa - Pedro M. Baeza
# Copyright 2020 Noviat - Luc De Meyer
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging import logging
@ -66,6 +67,16 @@ class WizardUpdateChartsAccounts(models.TransientModel):
default=True, default=True,
help="Existing taxes are updated. Taxes are searched by name.", help="Existing taxes are updated. Taxes are searched by name.",
) )
update_tax_repartition_line_account = fields.Boolean(
string="Update Tax Accounts",
default=True,
help="Update account_id field on existing Tax repartition lines",
)
update_tax_repartition_line_tags = fields.Boolean(
string="Update Tax Tags",
default=True,
help="Update tag_ids field on existing Tax repartition lines",
)
update_account = fields.Boolean( update_account = fields.Boolean(
string="Update accounts", string="Update accounts",
default=True, default=True,
@ -354,7 +365,7 @@ class WizardUpdateChartsAccounts(models.TransientModel):
_logger.addHandler(handler) _logger.addHandler(handler)
# Create or update the records. # Create or update the records.
if self.update_tax: if self.update_tax:
self._update_taxes() todo_dict = self._update_taxes()
perform_rest = True perform_rest = True
if self.update_account: if self.update_account:
self._update_accounts() self._update_accounts()
@ -367,7 +378,7 @@ class WizardUpdateChartsAccounts(models.TransientModel):
# queried before account creation) # queried before account creation)
self.find_account_by_templates.clear_cache(self) self.find_account_by_templates.clear_cache(self)
if self.update_tax and perform_rest: if self.update_tax and perform_rest:
self._update_taxes_pending_for_accounts() self._update_taxes_pending_for_accounts(todo_dict)
if self.update_fiscal_position and perform_rest: if self.update_fiscal_position and perform_rest:
self._update_fiscal_positions() self._update_fiscal_positions()
# Store new chart in the company # Store new chart in the company
@ -429,23 +440,50 @@ class WizardUpdateChartsAccounts(models.TransientModel):
@tools.ormcache("templates", "current_repartition") @tools.ormcache("templates", "current_repartition")
def find_repartition_by_templates( def find_repartition_by_templates(
self, templates, current_repartition, inverse_name self, templates, current_repartition, tax, inverse_name
): ):
upd_acc = self.update_tax_repartition_line_account
upd_tags = self.update_tax_repartition_line_tags
result = [] result = []
for tpl in templates: existing_ids = []
tax_id = self.find_tax_by_templates(tpl[inverse_name]) for i, tpl in enumerate(templates):
factor_percent = tpl.factor_percent factor_percent = tpl.factor_percent
repartition_type = tpl.repartition_type repartition_type = tpl.repartition_type
account_id = self.find_account_by_templates(tpl.account_id) account_id = self.find_account_by_templates(tpl.account_id)
rep_obj = self.env["account.tax.repartition.line"] tags = self.env["account.account.tag"]
existing = rep_obj.search( tags += tpl.plus_report_line_ids.mapped("tag_ids").filtered(
[ lambda x: not x.tax_negate
(inverse_name, "=", tax_id),
("factor_percent", "=", factor_percent),
("repartition_type", "=", repartition_type),
("account_id", "=", account_id),
]
) )
tags += tpl.minus_report_line_ids.mapped("tag_ids").filtered(
lambda x: x.tax_negate
)
tags += tpl.tag_ids
existing = self.env["account.tax.repartition.line"]
existing_candidates = current_repartition.filtered(
lambda r: r.factor_percent == factor_percent
and r.repartition_type == repartition_type
)
if len(existing_candidates) == 1:
existing = existing_candidates
elif len(existing_candidates) > 1:
# We may have this situation in case of e.g. 50%/50% on tax.
# In this case we assume that the repartition line order
# is the same between templates and actual tax objects
existing_candidate = current_repartition[i]
if existing_candidate in existing_candidates:
existing = existing_candidate
if existing:
existing_ids.append(existing.id)
upd_vals = {}
if upd_acc and existing.account_id.id != account_id:
upd_vals["account_id"] = account_id
if upd_tags:
if existing.tag_ids != tags:
upd_vals["tag_ids"] = [(6, 0, tags.ids)]
if upd_vals:
# update record
result.append((1, existing.id, upd_vals))
if not existing: if not existing:
# create a new mapping # create a new mapping
result.append( result.append(
@ -453,19 +491,18 @@ class WizardUpdateChartsAccounts(models.TransientModel):
0, 0,
0, 0,
{ {
inverse_name: tax_id, inverse_name: tax.id,
"factor_percent": factor_percent, "factor_percent": factor_percent,
"repartition_type": repartition_type, "repartition_type": repartition_type,
"account_id": account_id, "account_id": account_id,
"tag_ids": [(6, 0, tpl.tag_ids.ids)], "tag_ids": [(6, 0, tags.ids)],
}, },
) )
) )
else:
current_repartition -= existing
# Mark to be removed the lines not found # Mark to be removed the lines not found
if current_repartition: remove_ids = [x for x in current_repartition.ids if x not in existing_ids]
result += [(2, x.id) for x in current_repartition] result += [(2, x) for x in remove_ids]
return result return result
@api.model @api.model
@ -676,11 +713,15 @@ class WizardUpdateChartsAccounts(models.TransientModel):
) )
elif relation == "account.tax.repartition.line.template": elif relation == "account.tax.repartition.line.template":
expected = self.find_repartition_by_templates( expected = self.find_repartition_by_templates(
template[key], real[key], field.inverse_name template[key], real[key], real, field.inverse_name
) )
# Register detected differences # Register detected differences
if expected is not None: if expected is not None:
if expected != [] and expected != real[key]: if expected != [] and (
key
in ["invoice_repartition_line_ids", "refund_repartition_line_ids"]
or expected != real[key]
):
result[key] = expected result[key] = expected
else: else:
template_value = template[key] template_value = template[key]
@ -899,9 +940,14 @@ class WizardUpdateChartsAccounts(models.TransientModel):
"""Process taxes to create/update/deactivate.""" """Process taxes to create/update/deactivate."""
# First create taxes in batch # First create taxes in batch
taxes_to_create = self.tax_ids.filtered(lambda x: x.type == "new") taxes_to_create = self.tax_ids.filtered(lambda x: x.type == "new")
taxes_to_create.mapped("tax_id")._generate_tax(self.company_id) todo_dict = taxes_to_create.mapped("tax_id")._generate_tax(self.company_id)
for wiz_tax in taxes_to_create: for wiz_tax in taxes_to_create:
_logger.info(_("Created tax %s."), "'%s'" % wiz_tax.tax_id.name) new_tax = self.env["account.tax"].browse(
todo_dict["tax_template_to_tax"][wiz_tax.tax_id.id]
)
_logger.info(
_("Created tax %s."), "'{}' (ID:{})".format(new_tax.name, new_tax.id)
)
for wiz_tax in self.tax_ids.filtered(lambda x: x.type != "new"): for wiz_tax in self.tax_ids.filtered(lambda x: x.type != "new"):
template, tax = wiz_tax.tax_id, wiz_tax.update_tax_id template, tax = wiz_tax.tax_id, wiz_tax.update_tax_id
# Deactivate tax # Deactivate tax
@ -910,20 +956,26 @@ class WizardUpdateChartsAccounts(models.TransientModel):
_logger.info(_("Deactivated tax %s."), "'%s'" % tax.name) _logger.info(_("Deactivated tax %s."), "'%s'" % tax.name)
continue continue
else: else:
updated = False
for key, value in self.diff_fields(template, tax).items(): for key, value in self.diff_fields(template, tax).items():
# We defer update because account might not be created yet # We defer update because account might not be created yet
if key in { if key in [
"cash_basis_transition_account_id",
"cash_basis_base_account_id",
"invoice_repartition_line_ids", "invoice_repartition_line_ids",
"refund_repartition_line_ids", "refund_repartition_line_ids",
}: ]:
continue continue
tax[key] = value tax[key] = value
updated = True
if updated:
_logger.info(_("Updated tax %s."), "'%s'" % template.name) _logger.info(_("Updated tax %s."), "'%s'" % template.name)
if self.recreate_xml_ids and self.missing_xml_id(template, tax): if self.recreate_xml_ids and self.missing_xml_id(template, tax):
self.recreate_xml_id(template, tax) self.recreate_xml_id(template, tax)
_logger.info( _logger.info(
_("Updated tax %s. (Recreated XML-IDs)"), "'%s'" % template.name _("Updated tax %s. (Recreated XML-IDs)"), "'%s'" % template.name
) )
return todo_dict
def _update_accounts(self): def _update_accounts(self):
"""Process accounts to create/update.""" """Process accounts to create/update."""
@ -993,29 +1045,69 @@ class WizardUpdateChartsAccounts(models.TransientModel):
if not self.continue_on_errors: if not self.continue_on_errors:
break break
def _update_taxes_pending_for_accounts(self): def _update_taxes_pending_for_accounts(self, todo_dict):
"""Updates the taxes (created or updated on previous steps) to set """Updates the taxes (created or updated on previous steps) to set
the references to the accounts (the taxes where created/updated first, the references to the accounts (the taxes where created/updated first,
when the referenced accounts are still not available). when the referenced accounts are still not available).
""" """
for wiz_tax in self.tax_ids: done = self.env["account.tax"]
if wiz_tax.type == "deleted" or not wiz_tax.update_tax_id: for k, v in todo_dict["account_dict"]["account.tax"].items():
continue vals = {}
for fld in [
"cash_basis_transition_account_id",
"cash_basis_base_account_id",
]:
if v[fld]:
acc_id = self.find_account_by_templates(
self.env["account.account.template"].browse(v[fld])
)
if acc_id:
vals[fld] = acc_id
else:
raise exceptions.UserError(
_("No real account found for template account with ID %s")
% v[fld]
)
if vals:
tax = self.env["account.tax"].browse(k)
tax.write(vals)
done |= tax
for k, v in todo_dict["account_dict"]["account.tax.repartition.line"].items():
if v["account_id"]:
rep_line = self.env["account.tax.repartition.line"].browse(k)
acc_id = self.find_account_by_templates(
self.env["account.account.template"].browse(v["account_id"])
)
if acc_id:
rep_line.write({"account_id": acc_id})
done |= rep_line.invoice_tax_id or rep_line.refund_tax_id
else:
raise exceptions.UserError(
_("No real account found for template account with ID %s")
% v["account_id"]
)
for wiz_tax in self.tax_ids.filtered(lambda r: r.type == "updated"):
template = wiz_tax.tax_id template = wiz_tax.tax_id
tax = wiz_tax.update_tax_id tax = wiz_tax.update_tax_id
done = False
vals = {} vals = {}
for key, value in self.diff_fields(template, tax).items(): for key, value in self.diff_fields(template, tax).items():
if key in { if key in {
"cash_basis_transition_account_id",
"cash_basis_base_account_id",
"invoice_repartition_line_ids", "invoice_repartition_line_ids",
"refund_repartition_line_ids", "refund_repartition_line_ids",
}: }:
vals[key] = value vals[key] = value
done = True
if vals: if vals:
tax.write(vals) tax.write(vals)
if done: done |= tax
_logger.info(_("Post-updated tax %s."), "'%s'" % tax.name)
if done:
_logger.info(
_("Post-updated account fields for taxes with IDs %s."), "%s" % done.ids
)
def _prepare_fp_vals(self, fp_template): def _prepare_fp_vals(self, fp_template):
# Tax mappings # Tax mappings

View File

@ -92,6 +92,16 @@
name="page_fields_taxes" name="page_fields_taxes"
attrs="{'invisible': [('update_tax', '=', False)]}" attrs="{'invisible': [('update_tax', '=', False)]}"
> >
<group>
<field
name="update_tax_repartition_line_account"
attrs="{'invisible':[('update_tax', '=', False)]}"
/>
<field
name="update_tax_repartition_line_tags"
attrs="{'invisible':[('update_tax', '=', False)]}"
/>
</group>
<field <field
name="tax_field_ids" name="tax_field_ids"
widget="many2many_checkboxes" widget="many2many_checkboxes"