[13.0][FIX]account_chart_update refactor tax update
This commit is contained in:
parent
eefe80e215
commit
7a7f0f447c
@ -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"],
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user