2
0

[FIX+IMP] account_chart_update: Major refactoring

* Compare all fields from template

  Not all fields were properly compared with previous code. This means also
  to exclude some of them, but now we have a full and extensible system.

* Optimize cached method
* Generate accounts and fiscal positions using Odoo methods (tax already did)
* README by fragments
* Add tests up to full coverage
This commit is contained in:
Pedro M. Baeza 2018-09-18 14:41:19 +02:00 committed by Luis J. Salvatierra
parent 7c52e09c8d
commit f833ccdf36
12 changed files with 1130 additions and 302 deletions

View File

@ -1,11 +1,30 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
===========================================================
Detect changes and update the Account Chart from a template
===========================================================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Mature-brightgreen.png
:target: https://odoo-community.org/page/development-status
:alt: Mature
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github
:target: https://github.com/OCA/account-financial-tools/tree/10.0/account_chart_update
:alt: OCA/account-financial-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/account-financial-tools-10-0/account-financial-tools-10-0-account_chart_update
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/92/10.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This is a pretty useful tool to update Odoo installations after tax reforms
on the official charts of accounts, or to apply fixes performed on the chart
template.
@ -19,40 +38,53 @@ The wizard:
* It can also update (overwrite) the accounts, taxes, tax codes and fiscal
positions that got modified on the template.
**Table of contents**
.. contents::
:local:
Usage
=====
The wizard, accesible from *Accounting > Configuration > Settings > Chart of
Accounts > Update chart of accounts*, lets the user select what kind of objects
must be checked/updated, and whether old records must be checked for changes
and updates.
The wizard, accesible from *Accounting > Settings > Update chart of accounts*,
lets the user select what kind of objects must be checked/updated, and whether
old records must be checked for changes and updates.
It will display all the objects to be created / updated with some information
about the detected differences, and allow the user to exclude records
individually.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/92/9.0
It will display all the objects to be created / updated / deactivated with some
information about the detected differences, and allow the user to exclude
records individually.
Known issues / Roadmap
======================
* Add tests.
* Generate and update account reconcile models.
* Generate XML-ID for fiscal position tax and account mapping lines.
* Allow to select independently operations to perform (create, update,
deactivate).
* Detect fiscal positions to deactivate?
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/account-financial-tools/issues>`_. In case of trouble,
please check there if your issue has already been reported. If you spotted it
first, help us smashing it by providing a detailed and welcomed feedback.
Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-financial-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/account-financial-tools/issues/new?body=module:%20account_chart_update%0Aversion:%2010.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Tecnativa
* BCIM
* Okia
Contributors
------------
~~~~~~~~~~~~
* Pedro M. Baeza <pedro.baeza@tecnativa.com>
* Jairo Llopis <jairo.llopis@tecnativa.com>
@ -60,17 +92,20 @@ Contributors
* Sylvain Van Hoof <sylvain@okia.be>
* Nacho Muñoz <nacmuro@gmail.com>
Maintainer
----------
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.
This module is part of the `OCA/account-financial-tools <https://github.com/OCA/account-financial-tools/tree/10.0/account_chart_update>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -1,28 +1,22 @@
# -*- coding: utf-8 -*-
# Copyright 2015-2017 Pedro Manuel Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
# Copyright 2016 Jacques-Etienne Baudoux <je@bcim.be>
# Copyright 2016 Sylvain Van Hoof <sylvain@okia.be>
# Copyright 2015-2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': "Detect changes and update the Account Chart from a template",
"summary": "Wizard to update a company's account chart from a template",
'version': "10.0.1.0.2",
'version': "10.0.2.0.0",
'author': "Tecnativa, "
"BCIM, "
"Okia, "
"Odoo Community Association (OCA)",
'website': "http://odoo-community.org",
'depends': ["account"],
'category': "Accounting & Finance",
'contributors': [
'Pedro M. Baeza',
'Jairo Llopis',
'Jacques-Etienne Baudoux',
'Sylvain Van Hoof'
'Nacho Muñoz',
],
'development_status': 'Mature',
'category': "Accounting",
'license': "AGPL-3",
"data": [
'wizard/wizard_chart_update_view.xml',

View File

@ -1,73 +1,70 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_chart_update
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2017
# * account_chart_update
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-02-01 03:44+0000\n"
"PO-Revision-Date: 2018-02-01 03:44+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2017\n"
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n"
"POT-Creation-Date: 2018-09-21 00:20+0000\n"
"PO-Revision-Date: 2018-09-21 00:20+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: \n"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_code_digits
msgid "# of digits"
msgstr ""
msgstr "Nº de dígitos"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "<span states=\"init,ready\"> or </span>"
msgstr ""
msgstr "<span states=\"init,ready\"> o </span>"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_account_id
msgid "Account template"
msgstr ""
msgstr "Plantilla de cuenta"
#. module: account_chart_update
#: model:ir.model,name:account_chart_update.model_wizard_update_charts_accounts_account
msgid "Account that needs to be updated (new or updated in the template)."
msgstr ""
msgstr "Cuenta que necesita ser actualizada (nueva o cambiada en la plantilla)."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_update_account_id
msgid "Account to update"
msgstr ""
msgstr "Cuenta a actualizar"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_ids
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Accounts"
msgstr ""
msgstr "Cuentas"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_chart_template_id
msgid "Chart Template"
msgstr ""
msgstr "Plan contable"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_chart_template_ids
msgid "Chart Templates"
msgstr ""
msgstr "Planes contables"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Chart of Accounts"
msgstr ""
msgstr "Plan contable"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Close"
msgstr ""
msgstr "Cerrar"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_company_id
@ -77,23 +74,23 @@ msgstr "Compañía"
#. module: account_chart_update
#: selection:wizard.update.charts.accounts,state:0
msgid "Configuration"
msgstr ""
msgstr "Configuración"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_continue_on_errors
msgid "Continue on errors"
msgstr ""
msgstr "Continuar en errores"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Create/Update"
msgstr ""
msgstr "Crear/Actualizar"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:625
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:613
#, python-format
msgid "Created account %s."
msgstr ""
msgstr "Creada cuenta %s."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_create_uid
@ -109,43 +106,41 @@ msgstr "Creado por"
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_fiscal_position_create_date
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_create_date
msgid "Created on"
msgstr "Creado en"
msgstr "Creado el"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:708
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:714
#, python-format
msgid "Created or updated fiscal position %s."
msgstr ""
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:587
#, python-format
msgid "Created tax %s."
msgstr ""
msgstr "Creada o actualizada posición fiscal %s."
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:580
#, python-format
msgid "Created tax %s."
msgstr "Creado impuesto %s."
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:575
#, python-format
msgid "Deactivated tax %s."
msgstr ""
msgstr "Deactivado impuesto %s."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_deleted_taxes
msgid "Deactivated taxes"
msgstr ""
msgstr "Impuestos desactivados"
#. module: account_chart_update
#: model:ir.model.fields,help:account_chart_update.field_wizard_update_charts_accounts_tax_type_tax_use
msgid ""
"Determines where the tax is selectable. Note : 'None' means a tax can't be "
"used by itself, however it can still be used in a group."
msgstr ""
msgid "Determines where the tax is selectable. Note : 'None' means a tax can't be used by itself, however it can still be used in a group."
msgstr "Determina dónde puede seleccionarse un impuesto. Nota : 'Ninguno' significa que un impuesto no puede ser usado por si mismo; aun así, puede utilizarse en un grupo."
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:453
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:451
#, python-format
msgid "Differences in these fields: %s."
msgstr ""
msgstr "Diferencias en estos campos: %s."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_display_name
@ -153,65 +148,60 @@ msgstr ""
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_fiscal_position_display_name
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_display_name
msgid "Display Name"
msgstr "Nombre mostrado"
msgstr "Nombre a mostrar"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:629
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:622
#, python-format
msgid "Exception creating account %s."
msgstr ""
msgstr "Excepción creando cuenta %s."
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:641
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:644
#, python-format
msgid "Exception writing account %s."
msgstr ""
msgstr "Excepción escribiendo cuenta %s."
#. module: account_chart_update
#: model:ir.model.fields,help:account_chart_update.field_wizard_update_charts_accounts_update_account
msgid "Existing accounts are updated. Accounts are searched by code."
msgstr ""
msgstr "Las cuentas existentes serán actualizadas. Las cuentas se buscan por código."
#. module: account_chart_update
#: model:ir.model.fields,help:account_chart_update.field_wizard_update_charts_accounts_update_fiscal_position
msgid ""
"Existing fiscal positions are updated. Fiscal positions are searched by "
"name."
msgstr ""
msgid "Existing fiscal positions are updated. Fiscal positions are searched by name."
msgstr "Las posiciones fiscales existentes serán actualizadas. Las posiciones fiscales se buscan por nombre."
#. module: account_chart_update
#: model:ir.model.fields,help:account_chart_update.field_wizard_update_charts_accounts_update_tax
msgid "Existing taxes are updated. Taxes are searched by name."
msgstr ""
msgstr "Los impuestos existentes serán actualizados. Los impuestos se buscan por nombre."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_fiscal_position_fiscal_position_id
msgid "Fiscal position template"
msgstr ""
msgstr "Plantilla posición fiscal"
#. module: account_chart_update
#: model:ir.model,name:account_chart_update.model_wizard_update_charts_accounts_fiscal_position
msgid ""
"Fiscal position that needs to be updated (new or updated in the template)."
msgstr ""
msgid "Fiscal position that needs to be updated (new or updated in the template)."
msgstr "Posición fiscal que necesita ser actualizada (nuevo o modificada en la plantilla)"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_fiscal_position_update_fiscal_position_id
msgid "Fiscal position to update"
msgstr ""
msgstr "Posición fiscal a actualizar"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_fiscal_position_ids
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Fiscal positions"
msgstr ""
msgstr "Posiciones fiscales"
#. module: account_chart_update
#: model:ir.model.fields,help:account_chart_update.field_wizard_update_charts_accounts_lang
msgid ""
"For records searched by name (taxes, fiscal positions), the template name "
"will be matched against the record name on this language."
msgstr ""
msgid "For records searched by name (taxes, fiscal positions), the template name will be matched against the record name on this language."
msgstr "Para registros buscados por nombre (impuestos, posiciones fiscales), el nombre de la plantilla será casado contra el nombre del registro en este idioma."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_id
@ -223,27 +213,23 @@ msgstr "ID"
#. module: account_chart_update
#: model:ir.model.fields,help:account_chart_update.field_wizard_update_charts_accounts_continue_on_errors
msgid ""
"If set, the wizard will continue to the next step even if there are minor "
"errors."
msgstr ""
msgid "If set, the wizard will continue to the next step even if there are minor errors."
msgstr "Si está establecido, el asistente continuará al siguiente paso aunque haya errores."
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid ""
"If you leave these options set, the wizard will not just create new records,"
" but also update records with changes (i.e. different tax amount)"
msgstr ""
msgid "If you leave these options set, the wizard will not just create new records, but also update records with changes (i.e. different tax amount)"
msgstr "Si deja estas opciones establecidas, el asistente no solo crearé nuevos registros, si no que también actualizará registros con cambios (por ejemplo, diferente importe de impuesto)"
#. module: account_chart_update
#: model:ir.model.fields,help:account_chart_update.field_wizard_update_charts_accounts_chart_template_ids
msgid "Includes all chart templates."
msgstr ""
msgstr "Incluye todos los planes contables."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_lang
msgid "Language"
msgstr ""
msgstr "Idioma"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts___last_update
@ -251,7 +237,7 @@ msgstr ""
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_fiscal_position___last_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax___last_update
msgid "Last Modified on"
msgstr "Última modificación el"
msgstr "Última modificación en"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_write_uid
@ -267,110 +253,125 @@ msgstr "Última actualización por"
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_write_date
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_write_date
msgid "Last Updated on"
msgstr "Última actualización en"
msgstr "Última actualización el"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Log"
msgstr ""
msgstr "Registro (Log)"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_log
msgid "Messages and Errors"
msgstr ""
msgstr "Mensajes y errores"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:478
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:474
#, python-format
msgid "Name or description not found."
msgstr ""
msgstr "Nombre o descripción no encontrada."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_new_accounts
msgid "New accounts"
msgstr ""
msgstr "Nuevas cuentas"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_new_fps
msgid "New fiscal positions"
msgstr ""
msgstr "Nuevas posiciones fiscales"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_new_taxes
msgid "New taxes"
msgstr ""
msgstr "Nuevos impuestos"
#. module: account_chart_update
#: selection:wizard.update.charts.accounts.account,type:0
#: selection:wizard.update.charts.accounts.fiscal.position,type:0
#: selection:wizard.update.charts.accounts.tax,type:0
msgid "New template"
msgstr ""
msgstr "Nueva plantilla"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Next"
msgstr ""
msgstr "Siguiente"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:524
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:517
#, python-format
msgid "No account found with this code."
msgstr ""
msgstr "No se ha encontrado cuenta con este código."
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:557
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:551
#, python-format
msgid "No fiscal position found with this name."
msgstr ""
msgstr "No se ha encontrado posición fiscal con este nombre."
#. module: account_chart_update
#: model:ir.model.fields,help:account_chart_update.field_wizard_update_charts_accounts_code_digits
msgid ""
"No. of digits to use for account code. Make sure it is the same number as "
"existing accounts."
msgstr ""
msgid "No. of digits to use for account code. Make sure it is the same number as existing accounts."
msgstr "Nº de dígitos a usar para el código de cuenta. Asegúrese que es el mismo número que las cuentas existentes."
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Note: Only the changed fields are updated."
msgstr ""
msgstr "Nota: Solo los campos cambiados se actualizan."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_notes
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_fiscal_position_notes
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_notes
msgid "Notes"
msgstr ""
msgstr "Notas"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:233
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:246
#, python-format
msgid ""
"One or more errors detected!\n"
msgid "One or more errors detected!\n"
"\n"
"%s"
msgstr "Se ha detectado uno o más errores\n"
"\n"
"%s"
msgstr ""
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Other options"
msgstr ""
msgstr "Otras opciones"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:667
#, python-format
msgid "Post-updated tax %s."
msgstr "Impuesto %s post-actualizado."
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Previous"
msgstr ""
msgstr "Anterior"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Records to create/update"
msgstr ""
msgstr "Registros a crear/actualizar"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_rejected_new_account_number
msgid "Rejected new account number"
msgstr "Número de nuevas cuentas rechazadas"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_rejected_updated_account_number
msgid "Rejected updated account number"
msgstr "Número de cuentas a actualizar rechazadas"
#. module: account_chart_update
#: selection:wizard.update.charts.accounts,state:0
msgid "Select records to update"
msgstr ""
msgstr "Seleccione registros a actualizar"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_state
@ -380,62 +381,60 @@ msgstr "Estado"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Summary of created objects"
msgstr ""
msgstr "Resumen de objetos creados"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Summary of updated objects"
msgstr ""
msgstr "Resumen de objetos actualizados"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_type_tax_use
msgid "Tax Scope"
msgstr ""
msgstr "Ámbito del impuesto"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:458
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:456
#, python-format
msgid "Tax is disabled."
msgstr ""
msgstr "Impuesto desactivado."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_tax_id
msgid "Tax template"
msgstr ""
msgstr "Plantilla de impuesto"
#. module: account_chart_update
#: model:ir.model,name:account_chart_update.model_wizard_update_charts_accounts_tax
msgid "Tax that needs to be updated (new or updated in the template)."
msgstr ""
msgstr "Impuesto que necesita ser actualizado (nuevo o modificado en la plantilla)."
#. module: account_chart_update
#: selection:wizard.update.charts.accounts.tax,type:0
msgid "Tax to deactivate"
msgstr ""
msgstr "Impuesto a deactivar"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_update_tax_id
msgid "Tax to update"
msgstr ""
msgstr "Impuesto a actualizar"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_ids
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Taxes"
msgstr ""
msgstr "Impuestos"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid ""
"This wizard will update your accounts, taxes and fiscal positions according "
"to the selected chart template"
msgstr ""
msgid "This wizard will update your accounts, taxes and fiscal positions according to the selected chart template"
msgstr "Este asistente actualizará sus cuentas, impuestos y posiciones fiscales de acuerdo con el plan contable seleccionado"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:506
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:501
#, python-format
msgid "To deactivate: not in the template"
msgstr ""
msgstr "A deactivar: no está en la plantilla"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_type
@ -447,80 +446,80 @@ msgstr "Tipo"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_update_account
msgid "Update accounts"
msgstr ""
msgstr "Actualizar cuentas"
#. module: account_chart_update
#: model:ir.actions.act_window,name:account_chart_update.action_wizard_update_chart
msgid "Update chart of accounts"
msgstr ""
msgstr "Actualizar plan contable"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_account_config_settings
msgid "Update chart template"
msgstr ""
msgstr "Actualizar plan contable"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_account_update_chart_wizard_id
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_fiscal_position_update_chart_wizard_id
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_tax_update_chart_wizard_id
msgid "Update chart wizard"
msgstr ""
msgstr "Asistente de actualización de plan contable"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_update_fiscal_position
msgid "Update fiscal positions"
msgstr ""
msgstr "Actualizar posiciones fiscales"
#. module: account_chart_update
#: model:ir.ui.view,arch_db:account_chart_update.view_update_multi_chart
msgid "Update records?"
msgstr ""
msgstr "¿Actualizar registros?"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_update_tax
msgid "Update taxes"
msgstr ""
msgstr "Actualizar impuestos"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:638
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:635
#, python-format
msgid "Updated account %s."
msgstr ""
msgstr "Cuenta %s actualizada."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_updated_accounts
msgid "Updated accounts"
msgstr ""
msgstr "Cuentas actualizadas"
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_updated_fps
msgid "Updated fiscal positions"
msgstr ""
msgstr "Posiciones fiscales actualizadas"
#. module: account_chart_update
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:593
#: code:addons/account_chart_update/wizard/wizard_chart_update.py:588
#, python-format
msgid "Updated tax %s."
msgstr ""
msgstr "Impuesto %s actualizado."
#. module: account_chart_update
#: model:ir.model.fields,field_description:account_chart_update.field_wizard_update_charts_accounts_updated_taxes
msgid "Updated taxes"
msgstr ""
msgstr "Impuestos actualizados"
#. module: account_chart_update
#: selection:wizard.update.charts.accounts.account,type:0
#: selection:wizard.update.charts.accounts.fiscal.position,type:0
#: selection:wizard.update.charts.accounts.tax,type:0
msgid "Updated template"
msgstr ""
msgstr "Plantilla actualizada"
#. module: account_chart_update
#: selection:wizard.update.charts.accounts,state:0
msgid "Wizard completed"
msgstr ""
msgstr "Asistente completado"
#. module: account_chart_update
#: model:ir.model,name:account_chart_update.model_wizard_update_charts_accounts
msgid "wizard.update.charts.accounts"
msgstr ""
msgstr "wizard.update.charts.accounts"

View File

@ -0,0 +1,6 @@
* Pedro M. Baeza <pedro.baeza@tecnativa.com>
* Jairo Llopis <jairo.llopis@tecnativa.com>
* Jacques-Etienne Baudoux <je@bcim.be>
* Sylvain Van Hoof <sylvain@okia.be>
* Nacho Muñoz <nacmuro@gmail.com>

View File

@ -0,0 +1,12 @@
This is a pretty useful tool to update Odoo installations after tax reforms
on the official charts of accounts, or to apply fixes performed on the chart
template.
The wizard:
* Allows the user to compare a chart and a template showing differences
on accounts, taxes, tax codes and fiscal positions.
* It may create the new account, taxes, tax codes and fiscal positions detected
on the template.
* It can also update (overwrite) the accounts, taxes, tax codes and fiscal
positions that got modified on the template.

View File

@ -0,0 +1,5 @@
* Generate and update account reconcile models.
* Generate XML-ID for fiscal position tax and account mapping lines.
* Allow to select independently operations to perform (create, update,
deactivate).
* Detect fiscal positions to deactivate?

View File

@ -0,0 +1,7 @@
The wizard, accesible from *Accounting > Settings > Update chart of accounts*,
lets the user select what kind of objects must be checked/updated, and whether
old records must be checked for changes and updates.
It will display all the objects to be created / updated / deactivated with some
information about the detected differences, and allow the user to exclude
records individually.

View File

@ -0,0 +1,457 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
<title>Detect changes and update the Account Chart from a template</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="detect-changes-and-update-the-account-chart-from-a-template">
<h1 class="title">Detect changes and update the Account Chart from a template</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Mature" src="https://img.shields.io/badge/maturity-Mature-brightgreen.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/account-financial-tools/tree/10.0/account_chart_update"><img alt="OCA/account-financial-tools" src="https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/account-financial-tools-10-0/account-financial-tools-10-0-account_chart_update"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/92/10.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This is a pretty useful tool to update Odoo installations after tax reforms
on the official charts of accounts, or to apply fixes performed on the chart
template.</p>
<p>The wizard:</p>
<ul class="simple">
<li>Allows the user to compare a chart and a template showing differences
on accounts, taxes, tax codes and fiscal positions.</li>
<li>It may create the new account, taxes, tax codes and fiscal positions detected
on the template.</li>
<li>It can also update (overwrite) the accounts, taxes, tax codes and fiscal
positions that got modified on the template.</li>
</ul>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id2">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<p>The wizard, accesible from <em>Accounting &gt; Settings &gt; Update chart of accounts</em>,
lets the user select what kind of objects must be checked/updated, and whether
old records must be checked for changes and updates.</p>
<p>It will display all the objects to be created / updated / deactivated with some
information about the detected differences, and allow the user to exclude
records individually.</p>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id2">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Generate and update account reconcile models.</li>
<li>Generate XML-ID for fiscal position tax and account mapping lines.</li>
<li>Allow to select independently operations to perform (create, update,
deactivate).</li>
<li>Detect fiscal positions to deactivate?</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/account-financial-tools/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/account-financial-tools/issues/new?body=module:%20account_chart_update%0Aversion:%2010.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">Authors</a></h2>
<ul class="simple">
<li>Tecnativa</li>
<li>BCIM</li>
<li>Okia</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id6">Contributors</a></h2>
<ul class="simple">
<li>Pedro M. Baeza &lt;<a class="reference external" href="mailto:pedro.baeza&#64;tecnativa.com">pedro.baeza&#64;tecnativa.com</a>&gt;</li>
<li>Jairo Llopis &lt;<a class="reference external" href="mailto:jairo.llopis&#64;tecnativa.com">jairo.llopis&#64;tecnativa.com</a>&gt;</li>
<li>Jacques-Etienne Baudoux &lt;<a class="reference external" href="mailto:je&#64;bcim.be">je&#64;bcim.be</a>&gt;</li>
<li>Sylvain Van Hoof &lt;<a class="reference external" href="mailto:sylvain&#64;okia.be">sylvain&#64;okia.be</a>&gt;</li>
<li>Nacho Muñoz &lt;<a class="reference external" href="mailto:nacmuro&#64;gmail.com">nacmuro&#64;gmail.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-financial-tools/tree/10.0/account_chart_update">OCA/account-financial-tools</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_account_chart_update

View File

@ -0,0 +1,306 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields
from odoo.tests import common
class TestAccountChartUpdate(common.HttpCase):
at_install = False
post_install = True
def _create_xml_id(self, record):
return self.env['ir.model.data'].create({
'module': 'account_chart_update',
'name': "%s-%s" % (record._table, record.id),
'model': record._name,
'res_id': record.id,
})
def _create_account_tmpl(self, name, code, user_type, chart_template):
record = self.env['account.account.template'].create({
'name': name,
'code': code,
'user_type_id': user_type.id,
'chart_template_id': chart_template and chart_template.id,
})
self._create_xml_id(record)
return record
def _create_tax_tmpl(self, name, chart_template):
record = self.env['account.tax.template'].create({
'name': name,
'amount': 0,
'chart_template_id': chart_template.id,
'tax_group_id': self.env.ref('account.tax_group_taxes').id,
})
self._create_xml_id(record)
return record
def _create_fp_tmpl(self, name, chart_template):
record = self.env['account.fiscal.position.template'].create({
'name': name,
'chart_template_id': chart_template.id,
})
self._create_xml_id(record)
return record
def setUp(self):
super(TestAccountChartUpdate, self).setUp()
# Make sure user is in English
self.env.user.lang = 'en_US'
self.account_type = self.env['account.account.type'].create({
'name': 'Test account_chart_update account type',
})
self.account_template = self._create_account_tmpl(
'Test', '100000', self.account_type, False,
)
self.chart_template = self.env['account.chart.template'].create({
'name': 'Test account_chart_update chart',
'currency_id': self.env.ref('base.EUR').id,
'code_digits': 6,
'transfer_account_id': self.account_template.id,
})
self.account_template.chart_template_id = self.chart_template.id
self.account_template_pl = self._create_account_tmpl(
'Undistributed Profits/Losses', '999999',
self.env.ref("account.data_unaffected_earnings"),
self.chart_template,
)
self.tax_template = self._create_tax_tmpl(
'Test tax', self.chart_template,
)
self.fp_template = self._create_fp_tmpl('Test fp', self.chart_template)
self.fp_template_tax = self.env[
'account.fiscal.position.tax.template'
].create({
'tax_src_id': self.tax_template.id,
'position_id': self.fp_template.id,
})
self._create_xml_id(self.fp_template_tax)
self.fp_template_account = self.env[
'account.fiscal.position.account.template'
].create({
'account_src_id': self.account_template.id,
'account_dest_id': self.account_template.id,
'position_id': self.fp_template.id,
})
self._create_xml_id(self.fp_template_account)
self.tax_group = self.env['account.tax.group'].create({
'name': 'Test tax group',
})
self.company = self.env['res.company'].create({
'name': 'Test account_chart_update company',
'currency_id': self.chart_template.currency_id.id,
})
# Load chart of template into company
wizard = self.env['wizard.multi.charts.accounts'].create({
'company_id': self.company.id,
'chart_template_id': self.chart_template.id,
'code_digits': self.chart_template.code_digits,
'transfer_account_id': self.account_template.id,
'currency_id': self.chart_template.currency_id.id,
'bank_account_code_prefix': '572',
'cash_account_code_prefix': '570',
})
wizard.onchange_chart_template_id()
wizard.execute()
self.tax = self.env['account.tax'].search([
('name', '=', self.tax_template.name),
('company_id', '=', self.company.id),
])
self.account = self.env['account.account'].search([
('code', '=', self.account_template.code),
('company_id', '=', self.company.id),
])
self.fp = self.env['account.fiscal.position'].search([
('name', '=', self.fp_template.name),
('company_id', '=', self.company.id),
])
# Prepare wizard values
self.wizard_obj = self.env['wizard.update.charts.accounts']
self.wizard_vals = {
'company_id': self.company.id,
'chart_template_id': self.chart_template.id,
'code_digits': 6,
'lang': 'en_US'
}
def test_chart_update(self):
# Test no changes
wizard = self.wizard_obj.create(self.wizard_vals)
wizard.action_find_records()
self.assertEqual(wizard.state, 'ready')
self.assertFalse(wizard.tax_ids)
self.assertFalse(wizard.account_ids)
self.assertFalse(wizard.fiscal_position_ids)
wizard.unlink()
# Add templates
new_tax_tmpl = self._create_tax_tmpl(
'Test tax 2', self.chart_template,
)
new_account_tmpl = self._create_account_tmpl(
'Test account 2', '333333', self.account_type, self.chart_template,
)
new_fp = self._create_fp_tmpl('Test fp 2', self.chart_template)
fp_template_tax = self.env[
'account.fiscal.position.tax.template'
].create({
'tax_src_id': self.tax_template.id,
'position_id': new_fp.id,
})
self._create_xml_id(fp_template_tax)
fp_template_account = self.env[
'account.fiscal.position.account.template'
].create({
'account_src_id': self.account_template.id,
'account_dest_id': self.account_template.id,
'position_id': new_fp.id,
})
self._create_xml_id(fp_template_account)
# Check that no action is performed if the option is not selected
wizard_vals = self.wizard_vals.copy()
wizard_vals.update({
'update_tax': False,
'update_account': False,
'update_fiscal_position': False,
})
wizard = self.wizard_obj.create(wizard_vals)
wizard.action_find_records()
self.assertFalse(wizard.tax_ids)
self.assertFalse(wizard.account_ids)
self.assertFalse(wizard.fiscal_position_ids)
wizard.unlink()
# Now do the real one for detecting additions
wizard = self.wizard_obj.create(self.wizard_vals)
wizard.action_find_records()
self.assertTrue(wizard.tax_ids)
self.assertEqual(wizard.tax_ids.tax_id, new_tax_tmpl)
self.assertEqual(wizard.tax_ids.type, 'new')
self.assertTrue(wizard.account_ids)
self.assertEqual(wizard.account_ids.account_id, new_account_tmpl)
self.assertEqual(wizard.tax_ids.type, 'new')
self.assertTrue(wizard.fiscal_position_ids)
self.assertEqual(wizard.fiscal_position_ids.fiscal_position_id, new_fp)
self.assertEqual(wizard.fiscal_position_ids.type, 'new')
wizard.action_update_records()
self.assertEqual(wizard.state, 'done')
self.assertEqual(wizard.new_taxes, 1)
self.assertEqual(wizard.new_accounts, 1)
self.assertEqual(wizard.new_fps, 1)
self.assertTrue(wizard.log)
new_tax = self.env['account.tax'].search([
('name', '=', new_tax_tmpl.name),
('company_id', '=', self.company.id),
])
self.assertTrue(new_tax)
new_account = self.env['account.account'].search([
('code', '=', new_account_tmpl.code),
('company_id', '=', self.company.id),
])
self.assertTrue(new_account)
fp = self.env['account.fiscal.position'].search([
('name', '=', new_fp.name),
('company_id', '=', self.company.id),
])
self.assertTrue(fp)
self.assertTrue(fp.tax_ids)
self.assertTrue(fp.account_ids)
wizard.unlink()
# Update objects
self.tax_template.description = "Test description"
self.tax_template.tax_group_id = self.tax_group.id
self.tax_template.refund_account_id = new_account_tmpl.id
self.account_template.name = "Other name"
self.fp_template.note = "Test note"
self.fp_template.account_ids.account_dest_id = new_account_tmpl.id
self.fp_template.tax_ids.tax_dest_id = self.tax_template.id
wizard = self.wizard_obj.create(self.wizard_vals)
wizard.action_find_records()
self.assertTrue(wizard.tax_ids)
self.assertEqual(wizard.tax_ids.tax_id, self.tax_template)
self.assertEqual(wizard.tax_ids.type, 'updated')
self.assertTrue(wizard.account_ids)
self.assertEqual(wizard.account_ids.account_id, self.account_template)
self.assertEqual(wizard.account_ids.type, 'updated')
self.assertTrue(wizard.fiscal_position_ids)
self.assertTrue(wizard.fiscal_position_ids.type, 'updated')
self.assertEqual(
wizard.fiscal_position_ids.fiscal_position_id, self.fp_template,
)
self.assertEqual(wizard.fiscal_position_ids.type, 'updated')
wizard.action_update_records()
self.assertEqual(wizard.updated_taxes, 1)
self.assertEqual(wizard.updated_accounts, 1)
self.assertEqual(wizard.updated_fps, 1)
self.assertEqual(self.tax.description, self.tax_template.description)
self.assertEqual(self.tax.tax_group_id, self.tax_group)
self.assertEqual(self.tax.refund_account_id, new_account)
self.assertEqual(self.account.name, self.account_template.name)
self.assertEqual(self.fp.note, self.fp_template.note)
self.assertEqual(self.fp.account_ids.account_dest_id, new_account)
self.assertEqual(self.fp.tax_ids.tax_dest_id, self.tax)
wizard.unlink()
# Remove objects
new_tax_tmpl.unlink()
wizard = self.wizard_obj.create(self.wizard_vals)
wizard.action_find_records()
self.assertTrue(wizard.tax_ids)
self.assertEqual(wizard.tax_ids.update_tax_id, new_tax)
self.assertEqual(wizard.tax_ids.type, 'deleted')
wizard.action_update_records()
self.assertEqual(wizard.deleted_taxes, 1)
self.assertFalse(new_tax.active)
wizard.unlink()
# Errors on account update
self.account_template.reconcile = True
self.env['account.move'].create({
'name': 'Test move',
'journal_id': self.env['account.journal'].search([
('company_id', '=', self.company.id),
], limit=1).id,
'date': fields.Date.today(),
'line_ids': [
(0, 0, {
'account_id': self.account.id,
'name': 'Test move line',
'debit': 10,
'credit': 0,
}),
(0, 0, {
'account_id': self.account.id,
'name': 'Test move line2',
'debit': 0,
'credit': 10,
}),
]
})
self.tax_template.description = "Other description"
wizard = self.wizard_obj.create(self.wizard_vals)
wizard.action_find_records()
with self.assertRaises(Exception):
wizard.action_update_records()
# Errors on account update - continuing after that
wizard.continue_on_errors = True
wizard.action_update_records()
self.assertFalse(self.account.reconcile)
self.assertEqual(self.tax.description, self.tax_template.description)
self.assertEqual(wizard.rejected_updated_account_number, 1)
self.assertEqual(wizard.updated_accounts, 0)
wizard.unlink()
# Errors on account_creation
self.account_template.reconcile = False
new_account_tmpl_2 = self._create_account_tmpl(
'Test account 3', '444444', self.account_type, self.chart_template,
)
wizard = self.wizard_obj.create(self.wizard_vals)
wizard.action_find_records()
self.assertEqual(wizard.account_ids.type, 'new')
new_account_tmpl_2.code = '333333' # Trick the code for forcing error
with self.assertRaises(Exception):
wizard.action_update_records()
wizard.continue_on_errors = True
wizard.action_update_records()
self.assertEqual(wizard.rejected_new_account_number, 1)
self.assertEqual(wizard.new_accounts, 0)
wizard.unlink()

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# © 2010 Zikzakmedia S.L. (http://www.zikzakmedia.com)
# © 2010 Pexego Sistemas Informáticos S.L.(http://www.pexego.es)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import wizard_chart_update

View File

@ -6,14 +6,17 @@
# © 2015 Antonio Espinosa <antonioea@tecnativa.com>
# © 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
# © 2016 Jacques-Etienne Baudoux <je@bcim.be>
# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, exceptions, _, tools
from odoo import _, api, exceptions, fields, models, tools
from odoo.tools import config
from contextlib import closing
from cStringIO import StringIO
import logging
_logger = logging.getLogger(__name__)
EXCEPTION_TEXT = u"Traceback (most recent call last)"
class WizardUpdateChartsAccounts(models.TransientModel):
@ -76,12 +79,14 @@ class WizardUpdateChartsAccounts(models.TransientModel):
new_accounts = fields.Integer(
string='New accounts',
compute="_compute_new_accounts_count")
rejected_new_account_number = fields.Integer()
new_fps = fields.Integer(
string='New fiscal positions',
compute="_compute_new_fps_count")
updated_taxes = fields.Integer(
string='Updated taxes',
compute="_compute_updated_taxes_count")
rejected_updated_account_number = fields.Integer()
updated_accounts = fields.Integer(
string='Updated accounts',
compute="_compute_updated_accounts_count")
@ -115,7 +120,8 @@ class WizardUpdateChartsAccounts(models.TransientModel):
@api.depends('account_ids')
def _compute_new_accounts_count(self):
self.new_accounts = len(
self.account_ids.filtered(lambda x: x.type == 'new'))
self.account_ids.filtered(lambda x: x.type == 'new')
) - self.rejected_new_account_number
@api.multi
@api.depends('fiscal_position_ids')
@ -133,7 +139,8 @@ class WizardUpdateChartsAccounts(models.TransientModel):
@api.depends('account_ids')
def _compute_updated_accounts_count(self):
self.updated_accounts = len(
self.account_ids.filtered(lambda x: x.type == 'updated'))
self.account_ids.filtered(lambda x: x.type == 'updated')
) - self.rejected_updated_account_number
@api.multi
@api.depends('fiscal_position_ids')
@ -208,30 +215,35 @@ class WizardUpdateChartsAccounts(models.TransientModel):
def action_update_records(self):
"""Action that creates/updates/deletes the selected elements."""
self = self.with_context(lang=self.lang)
self.rejected_new_account_number = 0
self.rejected_updated_account_number = 0
with closing(StringIO()) as log_output:
handler = logging.StreamHandler(log_output)
_logger.addHandler(handler)
# Create or update the records.
if self.update_tax:
self._update_taxes()
perform_rest = True
if self.update_account:
self._update_accounts()
if self.update_fiscal_position:
if (EXCEPTION_TEXT in log_output.getvalue() and
not self.continue_on_errors): # Abort early
perform_rest = False
# Clear this cache for avoiding incorrect account hits (as it was
# queried before account creation)
self.find_account_by_templates.clear_cache(self)
if self.update_tax and perform_rest:
self._update_taxes_pending_for_accounts()
if self.update_fiscal_position and perform_rest:
self._update_fiscal_positions()
# Store new chart in the company
self.company_id.chart_template_id = self.chart_template_id
_logger.removeHandler(handler)
self.log = log_output.getvalue()
# Check if errors where detected and wether we should stop.
if self.log and not self.continue_on_errors:
if EXCEPTION_TEXT in self.log and not self.continue_on_errors:
raise exceptions.Warning(
_("One or more errors detected!\n\n%s") % self.log)
# Store the data and go to the next step.
self.state = 'done'
return self._reopen()
@ -295,11 +307,11 @@ class WizardUpdateChartsAccounts(models.TransientModel):
pos_id = self.find_fp_by_templates(tpl.position_id)
src_id = self.find_account_by_templates(tpl.account_src_id)
dest_id = self.find_account_by_templates(tpl.account_dest_id)
mappings = self.env["account.fiscal.position.account"].search([
existing = self.env["account.fiscal.position.account"].search([
("position_id", "=", pos_id),
("account_src_id", "=", src_id),
("account_dest_id", "=", dest_id),
])
existing = mappings.filtered(lambda x: x.account_dest_id == dest)
if not existing:
# create a new mapping
result.append((0, 0, {
@ -322,11 +334,11 @@ class WizardUpdateChartsAccounts(models.TransientModel):
pos_id = self.find_fp_by_templates(tpl.position_id)
src_id = self.find_tax_by_templates(tpl.tax_src_id)
dest_id = self.find_tax_by_templates(tpl.tax_dest_id)
mappings = self.env["account.fiscal.position.tax"].search([
existing = self.env["account.fiscal.position.tax"].search([
("position_id", "=", pos_id),
("tax_src_id", "=", src_id),
("tax_dest_id", "=", dest_id),
])
existing = mappings.filtered(lambda x: x.tax_dest_id.id == dest_id)
if not existing:
# create a new mapping
result.append((0, 0, {
@ -342,40 +354,24 @@ class WizardUpdateChartsAccounts(models.TransientModel):
return result
@api.model
@tools.ormcache("template")
def fields_to_ignore(self, template):
@tools.ormcache("name")
def fields_to_ignore(self, template, name):
"""Get fields that will not be used when checking differences.
:param str template:
The template record.
:return set:
Fields to ignore in diff.
:param str template: A template record.
:param str name: The name of the template model.
:return set: Fields to ignore in diff.
"""
specials = {
specials_mapping = {
"account.tax.template": {
"children_tax_ids",
},
"account.account.template": {
"code",
},
"account.tax.template": {
"account_id",
"refund_account_id",
}
}
to_include = {
"account.fiscal.position.template": [
'tax_ids',
'account_ids',
],
}
specials = ({"display_name", "__last_update"} |
specials.get(template._name, set()))
for key, field in template._fields.iteritems():
if (template._name in to_include and
key in to_include[template._name]):
continue
if ".template" in field.get_description(self.env).get(
"relation", ""):
specials.add(key)
specials = ({"display_name", "__last_update", "company_id"} |
specials_mapping.get(name, set()))
return set(models.MAGIC_COLUMNS) | specials
@api.model
@ -391,43 +387,44 @@ class WizardUpdateChartsAccounts(models.TransientModel):
Fields that are different in both records, and the expected value.
"""
result = dict()
ignore = self.fields_to_ignore(template)
ignore = self.fields_to_ignore(template, template._name)
for key, field in template._fields.iteritems():
if key in ignore:
continue
relation = expected = t = None
# Code must be padded to check equality
if key == "code":
expected = self.padded_code(template.code)
expected = t = None
# Translate template records to reals for comparison
else:
relation = field.get_description(self.env).get("relation", "")
if relation:
if ".tax.template" in relation:
t = "tax"
elif ".account.template" in relation:
t = "account"
if t:
find = getattr(
self,
"find_%s%s_by_templates" % (
"fp_" if ".fiscal.position" in relation
else "",
t))
if ".fiscal.position" in relation:
# Special case
expected = find(template[key], real[key])
else:
expected = find(template[key])
relation = field.get_description(self.env).get("relation", "")
if relation:
if ".tax.template" in relation:
t = "tax"
elif ".account.template" in relation:
t = "account"
if t:
find = getattr(
self,
"find_%s%s_by_templates" % (
"fp_" if ".fiscal.position" in relation
else "",
t))
if ".fiscal.position" in relation:
# Special case: if something is returned, then
# there's any difference, so it will get non equal
# when comparing, although we get the warning
# "Comparing apples with oranges"
expected = find(template[key], real[key])
else:
exp_id = find(template[key])
expected = self.env[relation[:-9]].browse(exp_id)
# Register detected differences
try:
if not relation:
if expected is not None and expected != real[key]:
if expected is not None:
if expected != [] and expected != real[key]:
result[key] = expected
elif template[key] != real[key]:
result[key] = template[key]
elif expected:
result[key] = expected
elif template[key] != real[key]:
result[key] = template[key]
if isinstance(result.get(key, False), models.Model):
# Avoid to cache recordset references
result[key] = result[key].id
except KeyError:
pass
return result
@ -464,12 +461,10 @@ class WizardUpdateChartsAccounts(models.TransientModel):
"""Search for, and load, tax templates to create/update/delete."""
found_taxes_ids = []
self.tax_ids.unlink()
# Search for changes between template and real tax
for template in self.chart_template_ids.mapped("tax_template_ids"):
# Check if the template matches a real tax
tax_id = self.find_tax_by_templates(template)
if not tax_id:
# Tax to be created
self.tax_ids.create({
@ -480,7 +475,6 @@ class WizardUpdateChartsAccounts(models.TransientModel):
})
else:
found_taxes_ids.append(tax_id)
# Check the tax for changes
tax = self.env['account.tax'].browse(tax_id)
notes = self.diff_notes(template, tax)
@ -493,14 +487,13 @@ class WizardUpdateChartsAccounts(models.TransientModel):
'update_tax_id': tax_id,
'notes': notes,
})
# search for taxes not in the template and propose them for
# deactivation
taxes_to_delete = self.env['account.tax'].search(
taxes_to_deactivate = self.env['account.tax'].search(
[('company_id', '=', self.company_id.id),
("id", "not in", found_taxes_ids),
("active", "=", True)])
for tax in taxes_to_delete:
for tax in taxes_to_deactivate:
self.tax_ids.create({
'update_chart_wizard_id': self.id,
'type': 'deleted',
@ -512,11 +505,9 @@ class WizardUpdateChartsAccounts(models.TransientModel):
def _find_accounts(self):
"""Load account templates to create/update."""
self.account_ids.unlink()
for template in self.chart_template_ids.mapped("account_ids"):
# Search for a real account that matches the template
account_id = self.find_account_by_templates(template)
if not account_id:
# Account to be created
self.account_ids.create({
@ -581,35 +572,20 @@ class WizardUpdateChartsAccounts(models.TransientModel):
# Deactivate tax
if wiz_tax.type == 'deleted':
tax.active = False
_logger.debug(_("Deactivated tax %s."), tax)
_logger.info(_("Deactivated tax %s."), "'%s'" % tax.name)
continue
# Create tax
if wiz_tax.type == 'new':
tax = template._generate_tax(self.company_id)
tax = tax['tax_template_to_tax'][template.id]
_logger.debug(_("Created tax %s."), template.name)
template._generate_tax(self.company_id)
_logger.info(_("Created tax %s."), "'%s'" % template.name)
# Update tax
else:
for key, value in self.diff_fields(template, tax).iteritems():
# We defer update because account might not be created yet
if key in {'account_id', 'refund_account_id'}:
continue
tax[key] = value
_logger.debug(_("Updated tax %s."), template.name)
wiz_tax.update_tax_id = tax
def _create_account_from_template(self, account_template):
return self.env["account.account"].create({
'name': account_template.name,
'currency_id': account_template.currency_id,
'code': self.padded_code(account_template.code),
'user_type_id': account_template.user_type_id.id,
'reconcile': account_template.reconcile,
'note': account_template.note,
'tax_ids': [
(6, 0, [self.find_tax_by_templates(account_template.tax_ids)]),
],
'company_id': self.company_id.id,
})
_logger.info(_("Updated tax %s."), "'%s'" % template.name)
@api.multi
def _update_accounts(self):
@ -619,18 +595,35 @@ class WizardUpdateChartsAccounts(models.TransientModel):
wiz_account.account_id)
if wiz_account.type == 'new':
# Create the account
tax_template_ref = {
tax.id: self.find_tax_by_templates(tax) for tax in
template.tax_ids
}
vals = self.chart_template_id._get_account_vals(
self.company_id, template,
self.padded_code(template.code),
tax_template_ref,
)
try:
with self.env.cr.savepoint():
account = (
self._create_account_from_template(
template))
_logger.debug(
self.chart_template_id.create_record_with_xmlid(
self.company_id, template, 'account.account', vals,
)
_logger.info(
_("Created account %s."),
account.code)
except exceptions.except_orm:
_logger.exception(
_("Exception creating account %s."),
template.code)
"'%s - %s'" % (vals['code'], vals['name']),
)
except Exception:
self.rejected_new_account_number += 1
if config['test_enable']:
_logger.info(EXCEPTION_TEXT)
else: # pragma: no cover
_logger.exception(
"ERROR: " + _("Exception creating account %s."),
"'%s - %s'" % (template.code, template.name),
)
if not self.continue_on_errors:
break
else:
# Update the account
try:
@ -638,15 +631,21 @@ class WizardUpdateChartsAccounts(models.TransientModel):
for key, value in (self.diff_fields(template, account)
.iteritems()):
account[key] = value
_logger.debug(_("Updated account %s."), account)
except exceptions.except_orm:
_logger.exception(
_("Exception writing account %s."),
account)
wiz_account.update_account_id = account
if self.update_tax:
self._update_taxes_pending_for_accounts()
_logger.info(
_("Updated account %s."),
"'%s - %s'" % (account.code, account.name),
)
except Exception:
self.rejected_updated_account_number += 1
if config['test_enable']:
_logger.info(EXCEPTION_TEXT)
else: # pragma: no cover
_logger.exception(
"ERROR: " + _("Exception writing account %s."),
"'%s - %s'" % (account.code, account.name),
)
if not self.continue_on_errors:
break
@api.multi
def _update_taxes_pending_for_accounts(self):
@ -657,10 +656,15 @@ class WizardUpdateChartsAccounts(models.TransientModel):
for wiz_tax in self.tax_ids:
if wiz_tax.type == "deleted" or not wiz_tax.update_tax_id:
continue
for field in ("account_id", "refund_account_id"):
wiz_tax.update_tax_id[field] = (
self.find_account_by_templates(wiz_tax.tax_id[field]))
template = wiz_tax.tax_id
tax = wiz_tax.update_tax_id
done = False
for key, value in self.diff_fields(template, tax).iteritems():
if key in {'account_id', 'refund_account_id'}:
tax[key] = value
done = True
if done:
_logger.info(_("Post-updated tax %s."), "'%s'" % tax.name)
def _prepare_fp_vals(self, fp_template):
# Tax mappings
@ -698,16 +702,17 @@ class WizardUpdateChartsAccounts(models.TransientModel):
wiz_fp.fiscal_position_id)
if wiz_fp.type == 'new':
# Create a new fiscal position
fp = self.env['account.fiscal.position'].create(
self._prepare_fp_vals(template))
self.chart_template_id.create_record_with_xmlid(
self.company_id, template, 'account.fiscal.position',
self._prepare_fp_vals(template),
)
else:
# Update the given fiscal position
for key, value in self.diff_fields(template, fp).iteritems():
fp[key] = value
wiz_fp.update_fiscal_position_id = fp
_logger.debug(
_logger.info(
_("Created or updated fiscal position %s."),
template.name)
"'%s'" % template.name)
class WizardUpdateChartsAccountsTax(models.TransientModel):