From bc483a106f54a409ec2e305eb2adbe73cdbe60a0 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sat, 28 Mar 2015 14:56:47 +0100 Subject: [PATCH] [IMP] account_chart_update: Whole refactoring * Fix calculated field when showing inactives + add field to view * Migrated to new API. * Provided hooks for detecting changes and for adding update/create values. * Purge dead error detection code (not applying). * Use global mapping dictionaries stored on class instead of passing arguments down to top and viceversa. * Number fields computed by a function field instead of being computed by hand. * Use recordsets as indexes instead of ids to avoid repetitive browses. * Re-enable local cache variables * README + authors --- account_chart_update/README.rst | 55 + account_chart_update/__openerp__.py | 35 +- .../model/account_tax_code.py | 10 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../views/account_tax_code_view.xml | 17 + .../wizard/wizard_chart_update.py | 2472 +++++++---------- .../wizard/wizard_chart_update_view.xml | 10 +- 7 files changed, 1041 insertions(+), 1558 deletions(-) create mode 100644 account_chart_update/README.rst create mode 100644 account_chart_update/static/description/icon.png create mode 100644 account_chart_update/views/account_tax_code_view.xml diff --git a/account_chart_update/README.rst b/account_chart_update/README.rst new file mode 100644 index 00000000..622e24ea --- /dev/null +++ b/account_chart_update/README.rst @@ -0,0 +1,55 @@ +Adds a wizard to update a company account chart from a chart template. +====================================================================== + +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. + +Usage +===== + +The wizard, accesible from *Accounting > Configuration > 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. + +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. + +Credits +======= + +Contributors +------------ + +* Jordi Esteve +* Borja López Soilán +* Pedro M. Baeza +* Joaquín Gutierrez +* invitu +* Stéphane Bidoul + +Maintainer +---------- + +.. 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 http://odoo-community.org. diff --git a/account_chart_update/__openerp__.py b/account_chart_update/__openerp__.py index 80afbf9f..dbb6eb19 100644 --- a/account_chart_update/__openerp__.py +++ b/account_chart_update/__openerp__.py @@ -6,7 +6,6 @@ # Copyright (c) 2010 Pexego Sistemas Informáticos S.L.(http://www.pexego.es) # Copyright (c) 2013 Joaquin Gutierrez (http://www.gutierrezweb.es) # Pedro Manuel Baeza -# $Id$ # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or @@ -27,8 +26,12 @@ { 'name': "Detect changes and update the Account Chart from a template", 'version': "1.2", - 'author': "Zikzakmedia SL,Odoo Community Association (OCA)", - 'website': "www.zikzakmedia.com", + 'author': "Zikzakmedia SL, " + "Pexego, " + "Serv. Tecnol. Avanzados - Pedro M. Baeza, " + "ACSONE A/V, " + "Odoo Community Association (OCA)", + 'website': "http://odoo-community.org", 'depends': ["account"], 'category': "Generic Modules/Accounting", 'contributors': [ @@ -37,31 +40,6 @@ 'invitu', 'Stéphane Bidoul', ], - 'description': """ -Adds a wizard to update a company account chart from a chart template. -====================================================================== - -This is a pretty useful tool to update OpenERP 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. - -The wizard 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 accounts to be created / updated with some information -about the detected differences, and allow the user to exclude records -individually. - -Any problem found while updating will be shown on the last step. -""", 'license': "AGPL-3", "depends": [ "account", @@ -70,6 +48,7 @@ Any problem found while updating will be shown on the last step. "demo": [], "data": [ 'wizard/wizard_chart_update_view.xml', + 'views/account_tax_code_view.xml', ], "active": False, 'installable': True diff --git a/account_chart_update/model/account_tax_code.py b/account_chart_update/model/account_tax_code.py index ae68fd81..3826b4c1 100644 --- a/account_chart_update/model/account_tax_code.py +++ b/account_chart_update/model/account_tax_code.py @@ -25,3 +25,13 @@ class AccountTaxCode(models.Model): _inherit = 'account.tax.code' active = fields.Boolean('Active', default=True) + + def _sum(self, cr, uid, ids, name, args, context, where='', + where_params=()): + try: + return super(AccountTaxCode, self)._sum( + cr, uid, ids, name, args, context, where=where, + where_params=where_params) + except: + cr.rollback() + return dict.fromkeys(ids, 0.0) diff --git a/account_chart_update/static/description/icon.png b/account_chart_update/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/account_chart_update/views/account_tax_code_view.xml b/account_chart_update/views/account_tax_code_view.xml new file mode 100644 index 00000000..ed774374 --- /dev/null +++ b/account_chart_update/views/account_tax_code_view.xml @@ -0,0 +1,17 @@ + + + + + + account.tax.code.form.active + account.tax.code + + + + + + + + + + diff --git a/account_chart_update/wizard/wizard_chart_update.py b/account_chart_update/wizard/wizard_chart_update.py index 14906044..89703ac7 100644 --- a/account_chart_update/wizard/wizard_chart_update.py +++ b/account_chart_update/wizard/wizard_chart_update.py @@ -19,24 +19,25 @@ # along with this program. If not, see . # ############################################################################## -from openerp.osv import fields, orm -from openerp.tools.translate import _ +from openerp import models, fields, api, exceptions, _ +from openerp.osv.orm import except_orm +from openerp.osv.osv import except_osv import logging -def _reopen(self, res_id, model): +def _reopen(self): return { 'type': 'ir.actions.act_window', 'view_mode': 'form', 'view_type': 'form', - 'res_id': res_id, + 'res_id': self.id, 'res_model': self._name, 'target': 'new', # save original model in context, # because selecting the list of available # templates requires a model in context 'context': { - 'default_model': model, + 'default_model': self._name, }, } @@ -50,17 +51,15 @@ class WizardLog: def __init__(self): self.messages = [] self.errors = [] + self._logger = logging.getLogger("account_chart_update") def add(self, message, is_error=False): - """ - Adds a message to the log. - """ - logger = logging.getLogger("account_chart_update") + """Adds a message to the log.""" if is_error: - logger.warning(u"Log line: %s" % message) + self._logger.warning(u"Log line: %s" % message) self.errors.append(message) else: - logger.debug(u"Log line: %s" % message) + self._logger.debug(u"Log line: %s" % message) self.messages.append(message) def has_errors(self): @@ -79,134 +78,182 @@ class WizardLog: return "".join(self.errors) -class wizard_update_charts_accounts(orm.TransientModel): +class WizardUpdateChartsAccounts(models.TransientModel): _name = 'wizard.update.charts.accounts' - def _get_lang_selection_options(self, cr, uid, context=None): - """ - Gets the available languages for the selection. - """ - obj = self.pool.get('res.lang') - ids = obj.search(cr, uid, [], context=context) - res = obj.read(cr, uid, ids, ['code', 'name'], context) - return [(r['code'], r['name']) for r in res] + [('', '')] + @api.model + def _get_lang_selection_options(self): + """Gets the available languages for the selection.""" + langs = self.env['res.lang'].search([]) + return [(lang.code, lang.name) for lang in langs] + [('', '')] - _columns = { - 'state': fields.selection([ - ('init', 'Step 1'), - ('ready', 'Step 2'), - ('done', 'Wizard completed') - ], 'Status', readonly=True), - 'company_id': fields.many2one( - 'res.company', - 'Company', - required=True, - ondelete='set null' - ), - 'chart_template_id': fields.many2one( - 'account.chart.template', - 'Chart Template', - ondelete='cascade', - required=True - ), - 'code_digits': fields.integer( - '# of digits', - required=True, - help="No. of digits to use for account code. " - "Make sure it is the same number as existing accounts." - ), - 'lang': fields.selection( - _get_lang_selection_options, - 'Language', - size=5, - help="For records searched by name " - "(taxes, tax codes, fiscal positions), " - "the template name will be matched against the record " - "name on this language." - ), - 'update_tax_code': fields.boolean( - 'Update tax codes', - help="Existing tax codes are updated." - " Tax codes are searched by name." - ), - 'update_tax': fields.boolean( - 'Update taxes', - help="Existing taxes are updated. Taxes are searched by name." - ), - 'update_account': fields.boolean( - 'Update accounts', - help="Existing accounts are updated. " - "Accounts are searched by code." - ), - 'update_fiscal_position': fields.boolean( - 'Update fiscal positions', - help="Existing fiscal positions are updated. " - "Fiscal positions are searched by name." - ), - 'update_children_accounts_parent': fields.boolean( - "Update children accounts parent", - help="Update the parent of accounts that seem (based on the code)" - " to be children of the newly created ones." - " If you had an account 430 with a child 4300000, and a 4300 " - "account is created, the 4300000 parent will be set to 4300." - ), - 'continue_on_errors': fields.boolean( - "Continue on errors", - help="If set, the wizard will continue to the next step even if " - "there are minor errors (for example the parent account " - "of a new account couldn't be set)." - ), - 'tax_code_ids': fields.one2many( - 'wizard.update.charts.accounts.tax.code', - 'update_chart_wizard_id', - 'Tax codes', - ondelete='cascade' - ), - 'tax_ids': fields.one2many( - 'wizard.update.charts.accounts.tax', - 'update_chart_wizard_id', - 'Taxes', - ondelete='cascade' - ), - 'account_ids': fields.one2many( - 'wizard.update.charts.accounts.account', - 'update_chart_wizard_id', - 'Accounts', - ondelete='cascade' - ), - 'fiscal_position_ids': fields.one2many( - 'wizard.update.charts.accounts.fiscal.position', - 'update_chart_wizard_id', - 'Fiscal positions', - ondelete='cascade' - ), - 'new_tax_codes': fields.integer('New tax codes', readonly=True), - 'new_taxes': fields.integer('New taxes', readonly=True), - 'new_accounts': fields.integer('New accounts', readonly=True), - 'new_fps': fields.integer('New fiscal positions', readonly=True), - 'updated_tax_codes': fields.integer( - 'Updated tax codes', - readonly=True - ), - 'updated_taxes': fields.integer('Updated taxes', readonly=True), - 'updated_accounts': fields.integer('Updated accounts', readonly=True), - 'updated_fps': fields.integer( - 'Updated fiscal positions', - readonly=True - ), - 'deleted_tax_codes': fields.integer( - 'Deactivated tax codes', - readonly=True - ), - 'deleted_taxes': fields.integer( - 'Deactivated taxes', - readonly=True - ), - 'log': fields.text('Messages and Errors', readonly=True) - } + @api.model + def _get_chart(self): + """Returns the default chart template.""" + templates = self.env['account.chart.template'].search([]) + return templates and templates[0] or False - def name_search(self, cr, user, name, - args=None, operator='ilike', context=None, limit=80): + state = fields.Selection( + selection=[('init', 'Step 1'), + ('ready', 'Step 2'), + ('done', 'Wizard completed')], + string='Status', readonly=True, default='init') + company_id = fields.Many2one( + comodel_name='res.company', string='Company', required=True, + ondelete='set null', default=lambda self: self.env.user.company_id.id) + chart_template_id = fields.Many2one( + comodel_name='account.chart.template', string='Chart Template', + ondelete='cascade', required=True, default=_get_chart) + code_digits = fields.Integer( + string='# of digits', required=True, + help="No. of digits to use for account code. " + "Make sure it is the same number as existing accounts.") + lang = fields.Selection( + _get_lang_selection_options, 'Language', size=5, + help="For records searched by name (taxes, tax codes, fiscal " + "positions), the template name will be matched against the " + "record name on this language.", + default=lambda self: self.env.context.get('lang') or self.user.lang) + update_tax_code = fields.Boolean( + string='Update tax codes', default=True, + help="Existing tax codes are updated. Tax codes are searched by name.") + update_tax = fields.Boolean( + string='Update taxes', default=True, + help="Existing taxes are updated. Taxes are searched by name.") + update_account = fields.Boolean( + string='Update accounts', default=True, + help="Existing accounts are updated. Accounts are searched by code.") + update_fiscal_position = fields.Boolean( + string='Update fiscal positions', default=True, + help="Existing fiscal positions are updated. Fiscal positions are " + "searched by name.") + update_children_accounts_parent = fields.Boolean( + string="Update children accounts parent", default=True, + help="Update the parent of accounts that seem (based on the code)" + " to be children of the newly created ones." + " If you had an account 430 with a child 4300000, and a 4300 " + "account is created, the 4300000 parent will be set to 4300.") + continue_on_errors = fields.Boolean( + string="Continue on errors", default=False, + help="If set, the wizard will continue to the next step even if " + "there are minor errors (for example the parent account " + "of a new account couldn't be set).") + tax_code_ids = fields.One2many( + comodel_name='wizard.update.charts.accounts.tax.code', + inverse_name='update_chart_wizard_id', string='Tax codes', + ondelete='cascade') + tax_ids = fields.One2many( + comodel_name='wizard.update.charts.accounts.tax', ondelete='cascade', + inverse_name='update_chart_wizard_id', string='Taxes') + account_ids = fields.One2many( + comodel_name='wizard.update.charts.accounts.account', + inverse_name='update_chart_wizard_id', string='Accounts', + ondelete='cascade') + fiscal_position_ids = fields.One2many( + comodel_name='wizard.update.charts.accounts.fiscal.position', + inverse_name='update_chart_wizard_id', string='Fiscal positions', + ondelete='cascade') + new_tax_codes = fields.Integer( + string='New tax codes', readonly=True, + compute="_get_new_tax_codes_count") + new_taxes = fields.Integer( + string='New taxes', readonly=True, compute="_get_new_taxes_count") + new_accounts = fields.Integer( + string='New accounts', readonly=True, + compute="_get_new_accounts_count") + new_fps = fields.Integer( + string='New fiscal positions', readonly=True, + compute="_get_new_fps_count") + updated_tax_codes = fields.Integer( + string='Updated tax codes', readonly=True, + compute="_get_updated_tax_codes_count") + updated_taxes = fields.Integer( + string='Updated taxes', readonly=True, + compute="_get_updated_taxes_count") + updated_accounts = fields.Integer( + string='Updated accounts', readonly=True, + compute="_get_updated_accounts_count") + updated_fps = fields.Integer( + string='Updated fiscal positions', readonly=True, + compute="_get_updated_fps_count") + deleted_tax_codes = fields.Integer( + string='Deactivated tax codes', readonly=True, + compute="_get_deleted_tax_codes_count") + deleted_taxes = fields.Integer( + string='Deactivated taxes', readonly=True, + compute="_get_deleted_taxes_count") + log = fields.Text(string='Messages and Errors', readonly=True) + + ########################################################################## + # Compute methods + ########################################################################## + + @api.one + @api.depends('tax_code_ids') + def _get_new_tax_codes_count(self): + self.new_tax_codes = len( + [x for x in self.tax_code_ids if x.type == 'new']) + + @api.one + @api.depends('tax_ids') + def _get_new_taxes_count(self): + self.new_taxes = len( + [x for x in self.tax_ids if x.type == 'new']) + + @api.one + @api.depends('account_ids') + def _get_new_accounts_count(self): + self.new_accounts = len( + [x for x in self.account_ids if x.type == 'new']) + + @api.one + @api.depends('fiscal_position_ids') + def _get_new_fps_count(self): + self.new_fps = len( + [x for x in self.fiscal_position_ids if x.type == 'new']) + + @api.one + @api.depends('tax_code_ids') + def _get_updated_tax_codes_count(self): + self.updated_tax_codes = len( + [x for x in self.tax_code_ids if x.type == 'updated']) + + @api.one + @api.depends('tax_ids') + def _get_updated_taxes_count(self): + self.updated_taxes = len( + [x for x in self.tax_ids if x.type == 'updated']) + + @api.one + @api.depends('account_ids') + def _get_updated_accounts_count(self): + self.updated_accounts = len( + [x for x in self.account_ids if x.type == 'updated']) + + @api.one + @api.depends('fiscal_position_ids') + def _get_updated_fps_count(self): + self.updated_fps = len( + [x for x in self.fiscal_position_ids if x.type == 'updated']) + + @api.one + @api.depends('tax_code_ids') + def _get_deleted_tax_codes_count(self): + self.deleted_tax_codes = len( + [x for x in self.tax_code_ids if x.type == 'deleted']) + + @api.one + @api.depends('tax_ids') + def _get_deleted_taxes_count(self): + self.deleted_taxes = len( + [x for x in self.tax_ids if x.type == 'deleted']) + + ########################################################################## + # Main methods + ########################################################################## + + @api.model + def name_search(self, name, args=None, operator='ilike', limit=80): """ Redefine the search to search by company name. """ @@ -214,1554 +261,927 @@ class wizard_update_charts_accounts(orm.TransientModel): name = '%' if not args: args = [] - if not context: - context = {} args = args[:] - ids = [] - ids = self.search( - cr, user, [('company_id', operator, name)] + args, limit=limit) - return self.name_get(cr, user, ids, context=context) + records = self.search([('company_id', operator, name)] + args, + limit=limit) + return records.name_get() - def name_get(self, cr, uid, ids, context=None): - """ - Use the company name and template as name. - """ - if context is None: - context = {} - if not len(ids): - return [] - records = self.browse(cr, uid, ids, context) + @api.multi + def name_get(self): + """Use the company name and template as name.""" res = [] - for record in records: - res.append((record.id, record.company_id.name + - ' - ' + record.chart_template_id.name)) + for record in self: + res.append( + (record.id, "%s - %s" % (record.company_id.name, + record.chart_template_id.name))) return res - def _get_chart(self, cr, uid, context=None): - """ - Returns the default chart template. - """ - if context is None: - context = {} - ids = self.pool.get( - 'account.chart.template').search(cr, uid, [], context=context) - if ids: - return ids[0] - return False - - def _get_code_digits(self, cr, uid, context=None, company_id=None): - """ - Returns the default code size for the accounts. + @api.model + def _get_code_digits(self, company=None): + """Returns the default code size for the accounts. To figure out the number of digits of the accounts it look at the code size of the default receivable account of the company (or user's company if any company is given). """ - if context is None: - context = {} - property_obj = self.pool.get('ir.property') - if not company_id: - user = self.pool.get('res.users').browse(cr, uid, uid, context) - company_id = user.company_id.id - property_ids = property_obj.search(cr, uid, [ - ('name', '=', 'property_account_receivable'), - ('company_id', '=', company_id), - ('res_id', '=', False), - ('value_reference', '!=', False) - ]) + property_obj = self.env['ir.property'] + if not company: + company = self.env.user.company_id + properties = property_obj.search( + [('name', '=', 'property_account_receivable'), + ('company_id', '=', company.id), + ('res_id', '=', False), + ('value_reference', '!=', False)]) number_digits = 6 - if not property_ids: + if not properties: # Try to get a generic (no-company) property - property_ids = property_obj.search(cr, uid, [ - ('name', '=', 'property_account_receivable'), - ('res_id', '=', False), - ('value_reference', '!=', False) - ]) - if property_ids: - prop = property_obj.browse( - cr, uid, property_ids[0], context=context) - account = property_obj.get_by_record(cr, uid, prop, - context=context) + properties = property_obj.search( + [('name', '=', 'property_account_receivable'), + ('res_id', '=', False), + ('value_reference', '!=', False)]) + if properties: + account = property_obj.get_by_record(properties[0]) if account: number_digits = len(account.code) return number_digits - _defaults = { - 'state': 'init', - 'company_id': lambda self, cr, uid, context: - self.pool.get('res.users').browse( - cr, uid, [uid], context)[0].company_id.id, - 'chart_template_id': _get_chart, - 'update_tax_code': True, - 'update_tax': True, - 'update_account': True, - 'update_fiscal_position': True, - 'update_children_accounts_parent': True, - 'continue_on_errors': False, - 'lang': lambda self, cr, uid, context: - context and context.get('lang') or None, - } + @api.onchange('company_id') + def onchange_company_id(self): + """Update the code digits when the company changes""" + self.code_digits = self._get_code_digits(company=self.company_id) - def onchange_company_id(self, cr, uid, ids, company_id, context=None): - """ - Update the code size when the company changes - """ - res = { - 'value': { - 'code_digits': self._get_code_digits( - cr, uid, context=context, company_id=company_id), - } - } - return res + @api.multi + def action_init(self): + """Initial action that sets the initial state.""" + self.write({'state': 'init'}) + return _reopen(self) - def action_init(self, cr, uid, ids, context=None): - """ - Initial action that sets the initial state. - """ - if context is None: - context = {} - wizard = self.browse(cr, uid, ids[0], context=context) - self.write(cr, uid, ids, {'state': 'init'}, context) - return _reopen(self, wizard.id, 'wizard.update.chart.accounts') + @api.multi + def action_find_records(self): + """Searchs for records to update/create and shows them.""" + self = self.with_context(lang=self.lang) + mapping_tax_codes = {} + mapping_taxes = {} + mapping_accounts = {} + mapping_fps = {} + # Get all chart templates involved + wiz_obj = self.env['wizard.multi.charts.accounts'] + chart_template_ids = wiz_obj._get_chart_parent_ids( + self.chart_template_id) + # Search for, and load, the records to create/update. + if self.update_tax_code: + self._find_tax_codes(mapping_tax_codes) + if self.update_tax: + self._find_taxes( + chart_template_ids, mapping_tax_codes, mapping_taxes, + mapping_accounts) + if self.update_account: + self._find_accounts(mapping_accounts) + if self.update_fiscal_position: + self._find_fiscal_positions( + chart_template_ids, mapping_taxes, mapping_accounts, + mapping_fps) + # Write the results, and go to the next step. + self.write({'state': 'ready'}) + return _reopen(self) + + @api.multi + def action_update_records(self): + """Action that creates/updates the selected elements.""" + self_lang = self.with_context(lang=self.lang) + log = WizardLog() + taxes_pending_for_accounts = {} + mapping_tax_codes = {} + mapping_taxes = {} + mapping_accounts = {} + # Create or update the records. + if self_lang.update_tax_code: + self_lang._update_tax_codes(log, mapping_tax_codes) + if self_lang.update_tax: + taxes_pending_for_accounts = self._update_taxes( + log, mapping_tax_codes, mapping_taxes) + if self_lang.update_account: + self_lang._update_accounts(log, mapping_taxes, mapping_accounts) + if self_lang.update_tax: + self_lang._update_taxes_pending_for_accounts( + log, taxes_pending_for_accounts, mapping_accounts) + if self_lang.update_fiscal_position: + self_lang._update_fiscal_positions( + log, mapping_taxes, mapping_accounts) + # Check if errors where detected and wether we should stop. + if log.has_errors() and not self_lang.continue_on_errors: + raise exceptions.Warning( + _("One or more errors detected!\n\n%s") % log.get_errors_str()) + # Store the data and go to the next step. + self_lang.write({'state': 'done', 'log': log()}) + return _reopen(self_lang) ########################################################################## # Helper methods ########################################################################## - def _map_tax_template(self, cr, uid, wizard, tax_templ_mapping, - tax_templ, context=None): - """ - Adds a tax template -> tax id to the mapping. - """ - if context is None: - context = {} - if not tax_templ: - return False - if tax_templ_mapping.get(tax_templ.id): - return tax_templ_mapping[tax_templ.id] - # In other case - tax_obj = self.pool['account.tax'] - criteria = ['|', - ('name', '=', tax_templ.name), - ('description', '=', tax_templ.name)] - if tax_templ.description: - criteria = (['|', '|'] + criteria + - [('description', '=', tax_templ.description), - ('name', '=', tax_templ.description)]) - criteria += [('company_id', '=', wizard.company_id.id)] - # search inactive taxes too, to avoid re-creating - # taxes that have been deactivated before - search_context = dict(context, active_test=False) - tax_ids = tax_obj.search(cr, uid, criteria, context=search_context) - tax_templ_mapping[tax_templ.id] = tax_ids and tax_ids[0] or False - return tax_templ_mapping[tax_templ.id] - - def _map_tax_code_template(self, cr, uid, wizard, - tax_code_templ_mapping, tax_code_template, - context=None): - """ - Adds a tax code template -> tax code id to the mapping. - """ - if not tax_code_template: - return False - if not wizard.chart_template_id: - return False - if tax_code_templ_mapping.get(tax_code_template.id): - return tax_code_templ_mapping[tax_code_template.id] - # prepare a search context in order to - # search inactive tax codes too, to avoid re-creating - # tax codes that have been deactivated before - search_context = dict(context, active_test=False) - tax_code_obj = self.pool['account.tax.code'] - root_tax_code_id = wizard.chart_template_id.tax_code_root_id.id - tax_code_code = tax_code_template.code - if tax_code_code: - tax_code_ids = tax_code_obj.search(cr, uid, [ - ('code', '=', tax_code_code), - ('company_id', '=', wizard.company_id.id) - ], context=search_context) - if not tax_code_code or not tax_code_ids: - tax_code_name = ((tax_code_template.id == root_tax_code_id) and - wizard.company_id.name or tax_code_template.name) - tax_code_ids = tax_code_obj.search(cr, uid, [ - ('name', '=', tax_code_name), - ('company_id', '=', wizard.company_id.id) - ], context=search_context) - tax_code_templ_mapping[tax_code_template.id] = (tax_code_ids and - tax_code_ids[0] or - False) - return tax_code_templ_mapping[tax_code_template.id] - - def _map_account_template(self, cr, uid, wizard, acc_templ_mapping, - acc_templ, context=None): - """ - Adds an account template -> account id to the mapping - """ - if not acc_templ: - return False - if acc_templ_mapping.get(acc_templ.id): - return acc_templ_mapping[acc_templ.id] - # In other case - acc_obj = self.pool['account.account'] - code = acc_templ.code or '' - if acc_templ.type != 'view': - if code and len(code) <= wizard.code_digits: - code = '%s%s' % (code, '0' * (wizard.code_digits - len(code))) - acc_ids = acc_obj.search(cr, uid, - [('code', '=', code), - ('company_id', '=', wizard.company_id.id)], - context=context) - acc_templ_mapping[acc_templ.id] = acc_ids and acc_ids[0] or False - return acc_templ_mapping[acc_templ.id] - - def _map_fp_template(self, cr, uid, wizard, fp_templ_mapping, - fp_template, context=None): - """ - Adds a fiscal position template -> fiscal position id to the mapping. - """ - if not fp_template: - return False - if fp_templ_mapping.get(fp_template.id): - return fp_templ_mapping[fp_template.id] - # In other case - fp_obj = self.pool['account.fiscal.position'] - fp_ids = fp_obj.search(cr, uid, - [('name', '=', fp_template.name), - ('company_id', '=', wizard.company_id.id)], - context=context) - fp_templ_mapping[fp_template.id] = fp_ids and fp_ids[0] or False - return fp_templ_mapping[fp_template.id] - - def _get_depth_first_tax_code_template_ids(self, cr, uid, root_tax_code_id, - context=None): - tax_code_templ_obj = self.pool['account.tax.code.template'] + @api.model + def _get_depth_first_tax_code_template_ids(self, root_tax_code): def get_children(tct): for child in tct.child_ids: - res.append(child.id) + res.append(child) get_children(child) - tct = tax_code_templ_obj.browse(cr, uid, root_tax_code_id, - context=context) - res = [tct.id] - get_children(tct) + res = [root_tax_code] + get_children(root_tax_code) return res - def _find_tax_codes(self, cr, uid, wizard, chart_template_ids, - context=None): - """ - Search for, and load, tax code templates to create/update. + @api.multi + def map_tax_code_template(self, tax_code_template, mapping_tax_codes): + """Adds a tax code template -> tax code id to the mapping.""" + if not tax_code_template or not self.chart_template_id: + return self.env['account.tax.code'] + if mapping_tax_codes.get(tax_code_template): + return mapping_tax_codes[tax_code_template] + # prepare a search context in order to + # search inactive tax codes too, to avoid re-creating + # tax codes that have been deactivated before + tax_code_obj = self.env['account.tax.code'].with_context( + active_test=False) + root_tax_code = self.chart_template_id.tax_code_root_id + tax_code_code = tax_code_template.code + if tax_code_code: + tax_codes = tax_code_obj.search( + [('code', '=', tax_code_code), + ('company_id', '=', self.company_id.id)]) + if not tax_code_code or not tax_codes: + tax_code_name = ( + tax_code_template == root_tax_code and + self.company_id.name or tax_code_template.name) + tax_codes = tax_code_obj.search( + [('name', '=', tax_code_name), + ('company_id', '=', self.company_id.id)]) + mapping_tax_codes[tax_code_template] = ( + tax_codes and tax_codes[0] or self.env['account.tax.code']) + return mapping_tax_codes[tax_code_template] - @param chart_template_ids: IDs of the chart templates to look on, - calculated once in the calling method. + @api.multi + def map_tax_template(self, tax_template, mapping_taxes): + """Adds a tax template -> tax id to the mapping.""" + if not tax_template: + return self.env['account.tax'] + if mapping_taxes.get(tax_template): + return mapping_taxes[tax_template] + # search inactive taxes too, to avoid re-creating + # taxes that have been deactivated before + tax_obj = self.env['account.tax'].with_context(active_test=False) + criteria = ['|', + ('name', '=', tax_template.name), + ('description', '=', tax_template.name)] + if tax_template.description: + criteria = ['|', '|'] + criteria + criteria += [('description', '=', tax_template.description), + ('name', '=', tax_template.description)] + criteria += [('company_id', '=', self.company_id.id)] + taxes = tax_obj.search(criteria) + mapping_taxes[tax_template] = ( + taxes and taxes[0] or self.env['account.tax']) + return mapping_taxes[tax_template] + + @api.multi + def map_account_template(self, account_template, mapping_accounts): + """Adds an account template -> account id to the mapping.""" + if not account_template: + return self.env['account.account'] + if mapping_accounts.get(account_template): + return mapping_accounts[account_template] + # In other case + acc_obj = self.env['account.account'] + code = account_template.code or '' + if account_template.type != 'view': + if code and len(code) <= self.code_digits: + code = '%s%s' % (code, '0' * (self.code_digits - len(code))) + accounts = acc_obj.search( + [('code', '=', code), + ('company_id', '=', self.company_id.id)]) + mapping_accounts[account_template] = ( + accounts and accounts[0] or self.env['account.account']) + return mapping_accounts[account_template] + + @api.multi + def map_fp_template(self, fp_template, mapping_fps): + """Adds a fiscal position template -> fiscal position id to the + mapping. """ - if not wizard.chart_template_id: - return {} - new_tax_codes = 0 - updated_tax_codes = 0 - tax_code_template_mapping = {} - tax_code_templ_obj = self.pool['account.tax.code.template'] - tax_code_obj = self.pool['account.tax.code'] - wiz_tax_code_obj = self.pool['wizard.update.charts.accounts.tax.code'] + if not fp_template: + return self.env['account.fiscal.position'] + if mapping_fps.get(fp_template): + return mapping_fps[fp_template] + # In other case + fps = self.env['account.fiscal.position'].search( + [('name', '=', fp_template.name), + ('company_id', '=', self.company_id.id)]) + mapping_fps[fp_template] = ( + fps and fps[0] or self.env['account.fiscal.position']) + return mapping_fps[fp_template] + + ########################################################################## + # Find methods + ########################################################################## + + def _is_different_tax_code( + self, tax_code, tax_code_template, mapping_tax_codes): + """Check the tax code for changes. + :return: An string that will be empty if no change detected. + """ + notes = "" + if tax_code.name != tax_code_template.name: + notes += _("The name field is different.\n") + if tax_code.code != tax_code_template.code: + notes += _("The code field is different.\n") + if tax_code.info != tax_code_template.info: + notes += _("The info field is different.\n") + if tax_code.sign != tax_code_template.sign: + notes += _("The sign field is different.\n") + if tax_code.notprintable != tax_code_template.notprintable: + notes += _("The notprintable field is different.\n") + if tax_code.sequence != tax_code_template.sequence: + notes += _("The sequence field is different.\n") + if tax_code.parent_id != self.map_tax_code_template( + tax_code_template.parent_id, mapping_tax_codes): + notes += _("The parent field is different.\n") + return notes + + @api.one + def _find_tax_codes(self, mapping_tax_codes): + """Search for, and load, tax code templates to create/update.""" + wiz_tax_code_obj = self.env['wizard.update.charts.accounts.tax.code'] # Remove previous tax codes - wiz_tax_code_obj.unlink(cr, uid, wiz_tax_code_obj.search(cr, uid, [])) + self.tax_code_ids.unlink() # Search for new / updated tax codes - root_tax_code_id = wizard.chart_template_id.tax_code_root_id.id children_tax_code_template = \ self._get_depth_first_tax_code_template_ids( - cr, uid, root_tax_code_id, context=context) - for tax_code_template in tax_code_templ_obj.browse( - cr, uid, - children_tax_code_template, context=context): - # Ensure the tax code template is on the map (search for the mapped - # tax code id). - tax_code_id = self._map_tax_code_template( - cr, uid, wizard, - tax_code_template_mapping, - tax_code_template, context=context - ) - if not tax_code_id: - new_tax_codes += 1 - wiz_tax_code_obj.create(cr, uid, { + self.chart_template_id.tax_code_root_id) + for tax_code_template in children_tax_code_template: + if tax_code_template == self.chart_template_id.tax_code_root_id: + continue + tax_code = self.map_tax_code_template( + tax_code_template, mapping_tax_codes) + if not tax_code: + wiz_tax_code_obj.create({ 'tax_code_id': tax_code_template.id, - 'update_chart_wizard_id': wizard.id, + 'update_chart_wizard_id': self.id, 'type': 'new', 'notes': _('Name or code not found.'), - }, context) - elif wizard.update_tax_code: - # Check the tax code for changes. - modified = False - notes = "" - tax_code = tax_code_obj.browse( - cr, uid, tax_code_id, context=context) - if tax_code.name != tax_code_template.name: - notes += _("The name field is different.\n") - modified = True - if tax_code.code != tax_code_template.code: - notes += _("The code field is different.\n") - modified = True - if tax_code.info != tax_code_template.info: - notes += _("The info field is different.\n") - modified = True - if tax_code.sign != tax_code_template.sign: - notes += _("The sign field is different.\n") - modified = True - if tax_code.notprintable != tax_code_template.notprintable: - notes += _("The notprintable field is different.\n") - modified = True - if tax_code.sequence != tax_code_template.sequence: - notes += _("The sequence field is different.\n") - modified = True - if tax_code.parent_id.id != self._map_tax_code_template( - cr, uid, wizard, - tax_code_template_mapping, - tax_code_template.parent_id, context=context): - notes += _("The parent field is different.\n") - modified = True - if modified: - # Tax code to update. - updated_tax_codes += 1 - wiz_tax_code_obj.create(cr, uid, { + }) + else: + notes = self._is_different_tax_code( + tax_code, tax_code_template, mapping_tax_codes) + if notes: + # Tax code to update + wiz_tax_code_obj.create({ 'tax_code_id': tax_code_template.id, - 'update_chart_wizard_id': wizard.id, + 'update_chart_wizard_id': self.id, 'type': 'updated', - 'update_tax_code_id': tax_code_id, + 'update_tax_code_id': tax_code.id, 'notes': notes, - }, context) - # search for tax codes not in the template - # and propose them for deletion - tax_code_ids = tax_code_obj.\ - search(cr, uid, [('company_id', '=', wizard.company_id.id)], - context=context) - tax_code_ids = set(tax_code_ids) - template_tax_code_ids = set(tax_code_template_mapping.values()) - tax_code_ids_to_delete = tax_code_ids - template_tax_code_ids - for tax_code_id in tax_code_ids_to_delete: - updated_tax_codes += 1 - wiz_tax_code_obj.create(cr, uid, { + }) + # search for tax codes not in the template and propose them for + # deactivation + root_code = self.map_tax_code_template( + self.chart_template_id.tax_code_root_id, mapping_tax_codes) + tax_codes_to_delete = self.env['account.tax.code'].search( + [('company_id', '=', self.company_id.id), + ('id', '!=', root_code.id)]) + for tax_code in mapping_tax_codes.values(): + if tax_code: + tax_codes_to_delete -= tax_code + for tax_code_to_delete in tax_codes_to_delete: + wiz_tax_code_obj.create({ 'tax_code_id': False, - 'update_chart_wizard_id': wizard.id, + 'update_chart_wizard_id': self.id, 'type': 'deleted', - 'update_tax_code_id': tax_code_id, - 'notes': "To deactivate: not in the template", - }, context) + 'update_tax_code_id': tax_code_to_delete.id, + 'notes': _("To deactivate: not in the template"), + }) - return { - 'new': new_tax_codes, - 'updated': updated_tax_codes, - 'mapping': tax_code_template_mapping - } - - def _find_taxes(self, cr, uid, wizard, chart_template_ids, context=None): + def _is_different_tax(self, tax, tax_template, mapping_tax_codes, + mapping_accounts): + """Check the tax for changes. + :return: An string that will be empty if no change detected. """ - Search for, and load, tax templates to create/update. + notes = "" + if tax.name != tax_template.name: + notes += _("The name field is different.\n") + if tax.description != tax_template.description: + notes += _("The description field is different.\n") + if tax.sequence != tax_template.sequence: + notes += _("The sequence field is different.\n") + if tax.amount != tax_template.amount: + notes += _("The amount field is different.\n") + if tax.type != tax_template.type: + notes += _("The type field is different.\n") + if tax.applicable_type != tax_template.applicable_type: + notes += _("The applicable type field is different.\n") + if tax.domain != tax_template.domain: + notes += _("The domain field is different.\n") + if tax.child_depend != tax_template.child_depend: + notes += _("The child depend field is different.\n") + if tax.python_compute != tax_template.python_compute: + notes += _("The python compute field is different.\n") + # if tax.tax_group != tax_template.tax_group: + # notes += _("The tax group field is different.\n") + if tax.base_sign != tax_template.base_sign: + notes += _("The base sign field is different.\n") + if tax.tax_sign != tax_template.tax_sign: + notes += _("The tax sign field is different.\n") + if tax.include_base_amount != tax_template.include_base_amount: + notes += _("The include base amount field is different.\n") + if tax.type_tax_use != tax_template.type_tax_use: + notes += _("The type tax use field is different.\n") + # compare tax code fields + if tax.base_code_id != self.map_tax_code_template( + tax_template.base_code_id, mapping_tax_codes): + notes += _("The base_code_id field is different.\n") + if tax.tax_code_id != self.map_tax_code_template( + tax_template.tax_code_id, mapping_tax_codes): + notes += _("The tax_code_id field is different.\n") + if tax.ref_base_code_id != self.map_tax_code_template( + tax_template.ref_base_code_id, mapping_tax_codes): + notes += _("The ref_base_code_id field is different.\n") + if tax.ref_tax_code_id != self.map_tax_code_template( + tax_template.ref_tax_code_id, mapping_tax_codes): + notes += _("The ref_tax_code_id field is different.\n") + # compare tax account fields + if tax.account_paid_id != self.map_account_template( + tax_template.account_paid_id, mapping_accounts): + notes += _("The account_paid field is different.\n") + if tax.account_collected_id != self.map_account_template( + tax_template.account_collected_id, mapping_accounts): + notes += _("The account_collected field is different.\n") + return notes + + @api.one + def _find_taxes(self, chart_template_ids, mapping_tax_codes, + mapping_taxes, mapping_accounts): + """Search for, and load, tax templates to create/update. @param chart_template_ids: IDs of the chart templates to look on, calculated once in the calling method. """ - new_taxes = 0 - updated_taxes = 0 - tax_templ_mapping = {} - tax_code_template_mapping = {} - acc_templ_mapping = {} - tax_obj = self.pool['account.tax'] - tax_templ_obj = self.pool['account.tax.template'] - wiz_taxes_obj = self.pool['wizard.update.charts.accounts.tax'] + wiz_taxes_obj = self.env['wizard.update.charts.accounts.tax'] delay_wiz_tax = [] # Remove previous taxes - wiz_taxes_ids = wiz_taxes_obj.search(cr, uid, [], context=context) - wiz_taxes_obj.unlink(cr, uid, wiz_taxes_ids, context=context) + self.tax_ids.unlink() # Search for new / updated taxes - tax_templ_ids = tax_templ_obj.search( - cr, uid, [('chart_template_id', 'in', chart_template_ids)], - context=context) - for tax_templ in tax_templ_obj.browse(cr, uid, tax_templ_ids, - context=context): + tax_templates = self.env['account.tax.template'].search( + [('chart_template_id', 'in', chart_template_ids)]) + for tax_template in tax_templates: # Ensure tax template is on the map (search for the mapped tax id) - tax_id = self._map_tax_template(cr, uid, wizard, - tax_templ_mapping, - tax_templ, context=context) - if not tax_id: - new_taxes += 1 + tax = self.map_tax_template(tax_template, mapping_taxes) + if not tax: vals_wiz = { - 'tax_id': tax_templ.id, - 'update_chart_wizard_id': wizard.id, + 'tax_id': tax_template.id, + 'update_chart_wizard_id': self.id, 'type': 'new', 'notes': _('Name or description not found.'), } - if not tax_templ.parent_id: - wiz_taxes_obj.create(cr, uid, vals_wiz, context) + if not tax_template.parent_id: + wiz_taxes_obj.create(vals_wiz) else: delay_wiz_tax.append(vals_wiz) - elif wizard.update_tax: + else: # Check the tax for changes. - modified = False - notes = "" - tax = tax_obj.browse(cr, uid, tax_id, context=context) - if tax.sequence != tax_templ.sequence: - notes += _("The sequence field is different.\n") - modified = True - if tax.amount != tax_templ.amount: - notes += _("The amount field is different.\n") - modified = True - if tax.type != tax_templ.type: - notes += _("The type field is different.\n") - modified = True - if tax.applicable_type != tax_templ.applicable_type: - notes += _("The applicable type field is different.\n") - modified = True - if tax.domain != tax_templ.domain: - notes += _("The domain field is different.\n") - modified = True - if tax.child_depend != tax_templ.child_depend: - notes += _("The child depend field is different.\n") - modified = True - if tax.python_compute != tax_templ.python_compute: - notes += _("The python compute field is different.\n") - modified = True - # if tax.tax_group != tax_templ.tax_group: - # notes += _("The tax group field is different.\n") - # modified = True - if tax.base_sign != tax_templ.base_sign: - notes += _("The base sign field is different.\n") - modified = True - if tax.tax_sign != tax_templ.tax_sign: - notes += _("The tax sign field is different.\n") - modified = True - if tax.include_base_amount != tax_templ.include_base_amount: - notes += _("The include base amount field is different.\n") - modified = True - if tax.type_tax_use != tax_templ.type_tax_use: - notes += _("The type tax use field is different.\n") - modified = True - # compare tax code fields - if tax.base_code_id.id != self._map_tax_code_template( - cr, uid, wizard, - tax_code_template_mapping, - tax_templ.base_code_id, context=context): - notes += _("The base_code_id field is different.\n") - modified = True - if tax.tax_code_id.id != self._map_tax_code_template( - cr, uid, wizard, - tax_code_template_mapping, - tax_templ.tax_code_id, context=context): - notes += _("The tax_code_id field is different.\n") - modified = True - if tax.ref_base_code_id.id != self._map_tax_code_template( - cr, uid, wizard, - tax_code_template_mapping, - tax_templ.ref_base_code_id, context=context): - notes += _("The ref_base_code_id field is different.\n") - modified = True - if tax.ref_tax_code_id.id != self._map_tax_code_template( - cr, uid, wizard, - tax_code_template_mapping, - tax_templ.ref_tax_code_id, context=context): - notes += _("The ref_tax_code_id field is different.\n") - modified = True - # compare tax account fields - if tax.account_paid_id.id != self._map_account_template( - cr, uid, wizard, - acc_templ_mapping, - tax_templ.account_paid_id, - context=context): - notes += _("The account_paid field is different.\n") - modified = True - if tax.account_collected_id.id != self._map_account_template( - cr, uid, wizard, - acc_templ_mapping, - tax_templ.account_collected_id, - context=context): - notes += _("The account_collected field is different.\n") - modified = True - # TODO: We could check other tax fields for changes... - if modified: + notes = self._is_different_tax( + tax, tax_template, mapping_tax_codes, mapping_accounts) + if notes: # Tax code to update. - updated_taxes += 1 - wiz_taxes_obj.create(cr, uid, { - 'tax_id': tax_templ.id, - 'update_chart_wizard_id': wizard.id, + wiz_taxes_obj.create({ + 'tax_id': tax_template.id, + 'update_chart_wizard_id': self.id, 'type': 'updated', - 'update_tax_id': tax_id, + 'update_tax_id': tax.id, 'notes': notes, - }, context) + }) for delay_vals_wiz in delay_wiz_tax: - wiz_taxes_obj.create(cr, uid, delay_vals_wiz, context) - # search for taxes not in the template - # and propose them for deletion - tax_ids = tax_obj.\ - search(cr, uid, [('company_id', '=', wizard.company_id.id)], - context=context) - tax_ids = set(tax_ids) - template_tax_ids = set(tax_templ_mapping.values()) - tax_ids_to_delete = tax_ids - template_tax_ids - for tax_id in tax_ids_to_delete: - updated_taxes += 1 - wiz_taxes_obj.create(cr, uid, { + wiz_taxes_obj.create(delay_vals_wiz) + # search for taxes not in the template and propose them for + # deactivation + taxes_to_delete = self.env['account.tax'].search( + [('company_id', '=', self.company_id.id)]) + for tax in mapping_taxes.values(): + if tax: + taxes_to_delete -= tax + for tax_to_delete in taxes_to_delete: + wiz_taxes_obj.create({ 'tax_id': False, - 'update_chart_wizard_id': wizard.id, + 'update_chart_wizard_id': self.id, 'type': 'deleted', - 'update_tax_id': tax_id, - 'notes': "To deactivate: not in the template", - }, context) + 'update_tax_id': tax_to_delete.id, + 'notes': _("To deactivate: not in the template"), + }) - return {'new': new_taxes, - 'updated': updated_taxes, - 'mapping': tax_templ_mapping} + def _is_different_account(self, account, account_template): + notes = "" + if (account.name != account_template.name and + account.name != self.company_id.name): + notes += _("The name is different.\n") + if account.type != account_template.type: + notes += _("The type is different.\n") + if account.user_type != account_template.user_type: + notes += _("The user type is different.\n") + if account.reconcile != account_template.reconcile: + notes += _("The reconcile is different.\n") + return notes - def _find_accounts(self, cr, uid, wizard, context=None): - """ - Search for, and load, account templates to create/update. - """ - if not wizard.chart_template_id: - return {} - new_accounts = 0 - updated_accounts = 0 - acc_templ_mapping = {} - acc_obj = self.pool['account.account'] - acc_templ_obj = self.pool['account.account.template'] - wiz_accounts = self.pool['wizard.update.charts.accounts.account'] + @api.one + def _find_accounts(self, mapping_accounts): + """Search for, and load, account templates to create/update.""" + wiz_accounts = self.env['wizard.update.charts.accounts.account'] # Remove previous accounts - wiz_accounts_ids = wiz_accounts.search(cr, uid, [], context=context) - wiz_accounts.unlink(cr, uid, wiz_accounts_ids, context=context) + self.account_ids.unlink() # Search for new / updated accounts - root_account_id = wizard.chart_template_id.account_root_id.id - acc_templ_criteria = [('chart_template_id', - '=', - wizard.chart_template_id.id)] + root_account_id = self.chart_template_id.account_root_id.id + acc_templ_criteria = [ + ('chart_template_id', '=', self.chart_template_id.id)] if root_account_id: - acc_templ_criteria = ( - ['|'] + acc_templ_criteria + - ['&', ('parent_id', 'child_of', [root_account_id]), - ('chart_template_id', '=', False)] - ) - acc_ids = acc_templ_obj.search(cr, uid, acc_templ_criteria, - context=context) - acc_ids.sort() - for acc_templ in acc_templ_obj.browse(cr, uid, acc_ids, - context=context): + acc_templ_criteria = ['|'] + acc_templ_criteria + acc_templ_criteria += [ + '&', ('parent_id', 'child_of', [root_account_id]), + ('chart_template_id', '=', False)] + account_templates = self.env['account.account.template'].search( + acc_templ_criteria) + for account_template in account_templates: # Ensure the account template is on the map (search for the mapped # account id). - account_id = self._map_account_template(cr, uid, wizard, - acc_templ_mapping, - acc_templ, - context=context) - if not account_id: - new_accounts += 1 - wiz_accounts.create(cr, uid, { - 'account_id': acc_templ.id, - 'update_chart_wizard_id': wizard.id, + account = self.map_account_template( + account_template, mapping_accounts) + if not account: + wiz_accounts.create({ + 'account_id': account_template.id, + 'update_chart_wizard_id': self.id, 'type': 'new', 'notes': _('Code not found.'), - }, context) - elif wizard.update_account: + }) + else: # Check the account for changes. - modified = False - notes = "" - account = acc_obj.browse(cr, uid, account_id, context=context) - if (account.name != acc_templ.name and - account.name != wizard.company_id.name): - notes += _("The name is different.\n") - modified = True - if account.type != acc_templ.type: - notes += _("The type is different.\n") - modified = True - if account.user_type != acc_templ.user_type: - notes += _("The user type is different.\n") - modified = True - if account.reconcile != acc_templ.reconcile: - notes += _("The reconcile is different.\n") - modified = True - # TODO: We could check other account fields for changes... - if modified: + notes = self._is_different_account(account, account_template) + if notes: # Account to update. - updated_accounts += 1 - wiz_accounts.create(cr, uid, { - 'account_id': acc_templ.id, - 'update_chart_wizard_id': wizard.id, + wiz_accounts.create({ + 'account_id': account_template.id, + 'update_chart_wizard_id': self.id, 'type': 'updated', - 'update_account_id': account_id, + 'update_account_id': account.id, 'notes': notes, - }, context) - return {'new': new_accounts, - 'updated': updated_accounts, - 'mapping': acc_templ_mapping} + }) - def _find_fiscal_positions(self, cr, uid, wizard, chart_template_ids, - context=None): - """ - Search for, and load, fiscal position templates to create/update. + def _is_different_fiscal_position(self, fp, fp_template, mapping_taxes, + mapping_accounts): + notes = "" + # Check fiscal position taxes for changes. + if fp_template.tax_ids and fp.tax_ids: + for fp_tax_templ in fp_template.tax_ids: + found = False + tax_src_id = self.map_tax_template( + fp_tax_templ.tax_src_id, mapping_taxes) + tax_dest_id = self.map_tax_template( + fp_tax_templ.tax_dest_id, mapping_taxes) + for fp_tax in fp.tax_ids: + if fp_tax.tax_src_id == tax_src_id: + if not fp_tax.tax_dest_id: + if not tax_dest_id: + found = True + break + else: + if fp_tax.tax_dest_id == tax_dest_id: + found = True + break + if not found: + msg = fp_tax_templ.tax_dest_id.name or _('None') + notes += _("Tax mapping not found on the fiscal position " + "instance: %s -> %s.\n") % ( + fp_tax_templ.tax_src_id.name, msg) + elif fp_template.tax_ids and not fp.tax_ids: + notes += _("The template has taxes the fiscal position instance " + "does not.\n") + # Check fiscal position accounts for changes + if fp_template.account_ids and fp.account_ids: + for fp_acc_templ in fp_template.account_ids: + found = False + acc_src_id = self.map_account_template( + fp_acc_templ.account_src_id, mapping_accounts) + acc_dest_id = self.map_account_template( + fp_acc_templ.account_dest_id, mapping_accounts) + for fp_acc in fp.account_ids: + if (fp_acc.account_src_id == acc_src_id and + fp_acc.account_dest_id == acc_dest_id): + found = True + break + if not found: + notes += _( + "Account mapping not found on the fiscal " + "position instance: %s -> %s.\n") % ( + fp_acc_templ.account_src_id.name, + fp_acc_templ.account_dest_id.name) + elif fp_template.account_ids and not fp.account_ids: + notes += _("The template has accounts the fiscal position " + "instance does not.\n") + return notes + + @api.one + def _find_fiscal_positions(self, chart_template_ids, mapping_taxes, + mapping_accounts, mapping_fps): + """Search for, and load, fiscal position templates to create/update. @param chart_template_ids: IDs of the chart templates to look on, calculated once in the calling method. """ - new_fps = 0 - updated_fps = 0 - fp_templ_mapping = {} - tax_templ_mapping = {} - acc_templ_mapping = {} - fp_templ_obj = self.pool['account.fiscal.position.template'] - fp_obj = self.pool['account.fiscal.position'] - wiz_fp = self.pool['wizard.update.charts.accounts.fiscal.position'] + wiz_fp = self.env['wizard.update.charts.accounts.fiscal.position'] # Remove previous fiscal positions - wiz_fp.unlink(cr, uid, wiz_fp.search(cr, uid, [])) + self.fiscal_position_ids.unlink() # Search for new / updated fiscal positions - fp_template_ids = fp_templ_obj.search(cr, uid, - [('chart_template_id', - 'in', - chart_template_ids)], - context=context) - for fp_templ in fp_templ_obj.browse(cr, uid, fp_template_ids, - context=context): + fp_templates = self.env['account.fiscal.position.template'].search( + [('chart_template_id', 'in', chart_template_ids)]) + for fp_template in fp_templates: # Ensure the fiscal position template is on the map (search for the # mapped fiscal position id). - fp_id = self._map_fp_template(cr, uid, wizard, fp_templ_mapping, - fp_templ, context=context) - if not fp_id: + fp = self.map_fp_template(fp_template, mapping_fps) + if not fp: # New fiscal position template. - new_fps += 1 - wiz_fp.create(cr, uid, { - 'fiscal_position_id': fp_templ.id, - 'update_chart_wizard_id': wizard.id, + wiz_fp.create({ + 'fiscal_position_id': fp_template.id, + 'update_chart_wizard_id': self.id, 'type': 'new', - 'notes': _('Name not found.'), - }, context=context) + 'notes': _('Name not found.') + }) continue # Check the fiscal position for changes - modified = False - notes = "" - fp = fp_obj.browse(cr, uid, fp_id, context=context) - # Check fiscal position taxes for changes. - if fp_templ.tax_ids and fp.tax_ids: - for fp_tax_templ in fp_templ.tax_ids: - found = False - tax_src_id = self._map_tax_template( - cr, uid, wizard, - tax_templ_mapping, - fp_tax_templ.tax_src_id, - context=None - ) - tax_dest_id = self._map_tax_template( - cr, uid, wizard, - tax_templ_mapping, - fp_tax_templ.tax_dest_id, - context=None - ) - for fp_tax in fp.tax_ids: - if fp_tax.tax_src_id.id == tax_src_id: - if not fp_tax.tax_dest_id: - if not tax_dest_id: - found = True - break - else: - if fp_tax.tax_dest_id.id == tax_dest_id: - found = True - break - if not found: - msg = (fp_tax_templ.tax_dest_id and - fp_tax_templ.tax_dest_id.name or - _('None')) - notes += _("Tax mapping not found on the fiscal " - "position instance: %s -> %s.\n") % ( - fp_tax_templ.tax_src_id.name, - msg - ) - modified = True - elif fp_templ.tax_ids and not fp.tax_ids: - notes += _("The template has taxes the fiscal " - "position instance does not.\n") - modified = True - # Check fiscal position accounts for changes - if fp_templ.account_ids and fp.account_ids: - for fp_acc_templ in fp_templ.account_ids: - found = False - acc_src_id = self._map_account_template( - cr, uid, wizard, acc_templ_mapping, - fp_acc_templ.account_src_id, context=context) - acc_dest_id = self._map_account_template( - cr, uid, wizard, acc_templ_mapping, - fp_acc_templ.account_dest_id, context=context) - for fp_acc in fp.account_ids: - if (fp_acc.account_src_id.id == acc_src_id and - fp_acc.account_dest_id.id == acc_dest_id): - found = True - break - if not found: - notes += _( - "Account mapping not found on the fiscal " - "position instance: %s -> %s.\n") \ - % (fp_acc_templ.account_src_id.name, - fp_acc_templ.account_dest_id.name) - modified = True - elif fp_templ.account_ids and not fp.account_ids: - notes += _("The template has accounts the fiscal position " - "instance does not.\n") - modified = True - if modified: + notes = self._is_different_fiscal_position( + fp, fp_template, mapping_taxes, mapping_accounts) + if notes: # Fiscal position template to update - updated_fps += 1 - wiz_fp.create(cr, uid, { - 'fiscal_position_id': fp_templ.id, - 'update_chart_wizard_id': wizard.id, + wiz_fp.create({ + 'fiscal_position_id': fp_template.id, + 'update_chart_wizard_id': self.id, 'type': 'updated', - 'update_fiscal_position_id': fp_id, + 'update_fiscal_position_id': fp.id, 'notes': notes, - }, context=context) - return {'new': new_fps, - 'updated': updated_fps, - 'mapping': fp_templ_mapping} + }) - def action_find_records(self, cr, uid, ids, context=None): - """ - Searchs for records to update/create and shows them - """ - if context is None: - context = {} - wizard = self.browse(cr, uid, ids[0], context=context) - if wizard.lang: - context['lang'] = wizard.lang - elif context.get('lang'): - del context['lang'] - # Defaults when calculations are not done - tax_codes_res = {} - taxes_res = {} - accounts_res = {} - fps_res = {} - # Get all chart templates involved - wiz_obj = self.pool['wizard.multi.charts.accounts'] - chart_template_ids = wiz_obj._get_chart_parent_ids( - cr, uid, wizard.chart_template_id, context=context) - # Search for, and load, the records to create/update. - if wizard.update_tax_code: - tax_codes_res = self._find_tax_codes(cr, uid, wizard, - chart_template_ids, - context=context) - if wizard.update_tax: - taxes_res = self._find_taxes(cr, uid, wizard, chart_template_ids, - context=context) - if wizard.update_account: - accounts_res = self._find_accounts(cr, uid, wizard, - context=context) - if wizard.update_fiscal_position: - fps_res = self._find_fiscal_positions(cr, uid, wizard, - chart_template_ids, - context=context) - # Write the results, and go to the next step. - self.write(cr, uid, [wizard.id], { - 'state': 'ready', - 'new_tax_codes': tax_codes_res.get('new', 0), - 'new_taxes': taxes_res.get('new', 0), - 'new_accounts': accounts_res.get('new', 0), - 'new_fps': fps_res.get('new', 0), - 'updated_tax_codes': tax_codes_res.get('updated', 0), - 'updated_taxes': taxes_res.get('updated', 0), - 'updated_accounts': accounts_res.get('updated', 0), - 'updated_fps': fps_res.get('updated', 0), - }, context) + ########################################################################## + # Update methods + ########################################################################## - return _reopen(self, wizard.id, 'wizard.update.chart.accounts') + def _prepare_tax_code_vals(self, tax_code_template, mapping_tax_codes): + parent_code = self.map_tax_code_template( + tax_code_template.parent_id, mapping_tax_codes) + return { + 'name': tax_code_template.name, + 'code': tax_code_template.code, + 'info': tax_code_template.info, + 'parent_id': parent_code.id, + 'company_id': self.company_id.id, + 'sign': tax_code_template.sign, + 'notprintable': tax_code_template.notprintable, + 'sequence': tax_code_template.sequence, + } - def _update_tax_codes(self, cr, uid, wizard, log, context=None): - """ - Search for, and load, tax code templates to create/update. - """ - taxcodes = self.pool.get('account.tax.code') - root_tax_code_id = wizard.chart_template_id.tax_code_root_id.id - new_tax_codes = 0 - updated_tax_codes = 0 - tax_code_template_mapping = {} + @api.multi + def _update_tax_codes(self, log, mapping_tax_codes): + """Process tax codes to create/update/deactivate.""" + tax_code_obj = self.env['account.tax.code'] # process new/updated - for wiz_tax_code in wizard.tax_code_ids: + for wiz_tax_code in self.tax_code_ids: if wiz_tax_code.type == 'deleted': continue tax_code_template = wiz_tax_code.tax_code_id - tax_code_name = ((root_tax_code_id == tax_code_template.id) and - wizard.company_id.name or tax_code_template.name) - # Ensure the parent tax code template is on the map. - self._map_tax_code_template(cr, uid, wizard, - tax_code_template_mapping, - tax_code_template.parent_id, - context=context) # Values - p_id = tax_code_template.parent_id.id - vals = { - 'name': tax_code_name, - 'code': tax_code_template.code, - 'info': tax_code_template.info, - 'parent_id': (tax_code_template.parent_id and - tax_code_template_mapping.get(p_id)), - 'company_id': wizard.company_id.id, - 'sign': tax_code_template.sign, - 'notprintable': tax_code_template.notprintable, - 'sequence': tax_code_template.sequence, - } - tax_code_id = None - modified = False + vals = self._prepare_tax_code_vals( + tax_code_template, mapping_tax_codes) if wiz_tax_code.type == 'new': # Create the tax code - tax_code_id = taxcodes.create(cr, uid, vals) - log.add(_("Created tax code %s.\n") % tax_code_name) - new_tax_codes += 1 - modified = True - elif wizard.update_tax_code and wiz_tax_code.update_tax_code_id: + tax_code = tax_code_obj.create(vals) + mapping_tax_codes[tax_code_template] = tax_code + log.add(_("Created tax code %s.\n") % vals['name']) + elif wiz_tax_code.update_tax_code_id: # Update the tax code - tax_code_id = wiz_tax_code.update_tax_code_id.id - taxcodes.write(cr, uid, [tax_code_id], vals) - log.add(_("Updated tax code %s.\n") % tax_code_name) - updated_tax_codes += 1 - modified = True - else: - tax_code_id = (wiz_tax_code.update_tax_code_id and - wiz_tax_code.update_tax_code_id.id) - modified = False - # Store the tax codes on the map - tax_code_template_mapping[tax_code_template.id] = tax_code_id - if modified: - # Detect errors - p_id = tax_code_template.parent_id.id - if (tax_code_template.parent_id and - not tax_code_template_mapping.get(p_id)): - log.add( - _("Tax code %s: The parent tax code %s " - "can not be set.\n") % ( - tax_code_name, tax_code_template.parent_id.name), - True - ) + wiz_tax_code.update_tax_code_id.write(vals) + log.add(_("Updated tax code %s.\n") % vals['name']) # process deleted - tax_code_ids_to_delete = [wtc.update_tax_code_id.id - for wtc in wizard.tax_code_ids - if wtc.type == 'deleted'] - taxcodes.write(cr, uid, tax_code_ids_to_delete, - {'active': False}, - context=context) - log.add(_("Deactivated %d tax codes\n" % len(tax_code_ids_to_delete))) - deleted_tax_codes = len(tax_code_ids_to_delete) + tax_codes_to_delete = self.tax_code_ids.filtered( + lambda x: x.type == 'deleted').mapped('update_tax_code_id') + tax_codes_to_delete.write({'active': False}) + log.add(_("Deactivated %d tax codes\n" % len(tax_codes_to_delete))) + + def _prepare_tax_vals(self, tax_template, mapping_tax_codes, + mapping_taxes): return { - 'new': new_tax_codes, - 'updated': updated_tax_codes, - 'deleted': deleted_tax_codes, - 'mapping': tax_code_template_mapping + 'name': tax_template.name, + 'sequence': tax_template.sequence, + 'amount': tax_template.amount, + 'type': tax_template.type, + 'applicable_type': tax_template.applicable_type, + 'domain': tax_template.domain, + 'parent_id': self.map_tax_template( + tax_template.parent_id, mapping_taxes).id, + 'child_depend': tax_template.child_depend, + 'python_compute': tax_template.python_compute, + 'python_compute_inv': tax_template.python_compute_inv, + 'python_applicable': tax_template.python_applicable, + 'base_code_id': ( + self.map_tax_code_template( + tax_template.base_code_id, mapping_tax_codes).id), + 'tax_code_id': ( + self.map_tax_code_template( + tax_template.tax_code_id, mapping_tax_codes).id), + 'base_sign': tax_template.base_sign, + 'tax_sign': tax_template.tax_sign, + 'ref_base_code_id': ( + self.map_tax_code_template( + tax_template.ref_base_code_id, mapping_tax_codes).id), + 'ref_tax_code_id': ( + self.map_tax_code_template( + tax_template.ref_tax_code_id, mapping_tax_codes).id), + 'ref_base_sign': tax_template.ref_base_sign, + 'ref_tax_sign': tax_template.ref_tax_sign, + 'include_base_amount': tax_template.include_base_amount, + 'description': tax_template.description, + 'company_id': self.company_id.id, + 'type_tax_use': tax_template.type_tax_use } - def _update_taxes(self, cr, uid, wizard, log, tax_code_template_mapping, - context=None): - """ - Search for, and load, tax templates to create/update. - """ - taxes = self.pool['account.tax'] - new_taxes = 0 - updated_taxes = 0 - tax_template_mapping = {} + @api.multi + def _update_taxes(self, log, mapping_tax_codes, mapping_taxes): + """Process taxes to create/update.""" + tax_obj = self.env['account.tax'] taxes_pending_for_accounts = {} - for wiz_tax in wizard.tax_ids: + for wiz_tax in self.tax_ids: if wiz_tax.type == 'deleted': continue tax_template = wiz_tax.tax_id - # Ensure the parent tax template is on the map. - self._map_tax_template(cr, uid, wizard, tax_template_mapping, - tax_template.parent_id, context) - # Ensure the referenced tax codes are on the map. - tax_code_templates_to_find = [ - tax_template.base_code_id, - tax_template.tax_code_id, - tax_template.ref_base_code_id, - tax_template.ref_tax_code_id - ] - for tax_code_template in \ - [tmpl for tmpl in tax_code_templates_to_find if tmpl]: - self._map_tax_code_template(cr, uid, wizard, - tax_code_template_mapping, - tax_code_template, context=context) - # Values - vals_tax = { - 'name': tax_template.name, - 'sequence': tax_template.sequence, - 'amount': tax_template.amount, - 'type': tax_template.type, - 'applicable_type': tax_template.applicable_type, - 'domain': tax_template.domain, - 'parent_id': ( - tax_template.parent_id and - tax_template_mapping.get(tax_template.parent_id.id) - ), - 'child_depend': tax_template.child_depend, - 'python_compute': tax_template.python_compute, - 'python_compute_inv': tax_template.python_compute_inv, - 'python_applicable': tax_template.python_applicable, - 'base_code_id': ( - tax_template.base_code_id and - tax_code_template_mapping.get(tax_template.base_code_id.id) - ), - 'tax_code_id': ( - tax_template.tax_code_id and - tax_code_template_mapping.get(tax_template.tax_code_id.id) - ), - 'base_sign': tax_template.base_sign, - 'tax_sign': tax_template.tax_sign, - 'ref_base_code_id': ( - tax_template.ref_base_code_id and - tax_code_template_mapping.get( - tax_template.ref_base_code_id.id - ) - ), - 'ref_tax_code_id': ( - tax_template.ref_tax_code_id and - tax_code_template_mapping.get( - tax_template.ref_tax_code_id.id) - ), - 'ref_base_sign': tax_template.ref_base_sign, - 'ref_tax_sign': tax_template.ref_tax_sign, - 'include_base_amount': tax_template.include_base_amount, - 'description': tax_template.description, - 'company_id': wizard.company_id.id, - 'type_tax_use': tax_template.type_tax_use - } - tax_id = None - modified = False + vals = self._prepare_tax_vals( + tax_template, mapping_taxes, mapping_tax_codes) if wiz_tax.type == 'new': # Create a new tax. - tax_id = taxes.create(cr, uid, vals_tax) + tax = tax_obj.create(vals) + mapping_taxes[tax_template] = tax log.add(_("Created tax %s.\n") % tax_template.name) - new_taxes += 1 - modified = True - elif wizard.update_tax and wiz_tax.update_tax_id: - # Update a tax. - tax_id = wiz_tax.update_tax_id.id - taxes.write(cr, uid, [tax_id], vals_tax) + elif wiz_tax.update_tax_id: + # Update the tax + wiz_tax.update_tax_id.write(vals) + tax = wiz_tax.update_tax_id log.add(_("Updated tax %s.\n") % tax_template.name) - updated_taxes += 1 - modified = True - else: - tax_id = wiz_tax.update_tax_id and wiz_tax.update_tax_id.id - # Update the tax template map - tax_template_mapping[tax_template.id] = tax_id - if modified: - # Add to the dict of taxes waiting for accounts. - taxes_pending_for_accounts[tax_id] = { - 'account_collected_id': ( - tax_template.account_collected_id and - tax_template.account_collected_id.id or False - ), - 'account_paid_id': ( - tax_template.account_paid_id and - tax_template.account_paid_id.id or False - ), - } - # Detect errors - if (tax_template.parent_id and not - tax_template_mapping.get(tax_template.parent_id.id)): - log.add( - _("Tax %s: The parent tax %s can not be set.\n") % ( - tax_template.name, tax_template.parent_id.name), - True - ) - if (tax_template.base_code_id and not - tax_code_template_mapping.get( - tax_template.base_code_id.id - )): - log.add( - _("Tax %s: The tax code for the base %s " - "can not be set.\n") % ( - tax_template.name, tax_template.base_code_id.name), - True - ) - if (tax_template.tax_code_id and not - tax_code_template_mapping.get( - tax_template.tax_code_id.id)): - log.add( - _("Tax %s: The tax code for the tax %s " - "can not be set.\n") % ( - tax_template.name, tax_template.tax_code_id.name - ), - True - ) - if (tax_template.ref_base_code_id and - not tax_code_template_mapping.get( - tax_template.ref_base_code_id.id)): - log.add( - _("Tax %s: The tax code for the base refund %s " - "can not be set.\n") % ( - tax_template.name, - tax_template.ref_base_code_id.name - ), - True - ) - if (tax_template.ref_tax_code_id and not - tax_code_template_mapping.get( - tax_template.ref_tax_code_id.id)): - log.add( - _("Tax %s: The tax code for the tax refund %s" - " can not be set.\n") % ( - tax_template.name, - tax_template.ref_tax_code_id.name - ), - True - ) + # Add to the dict of taxes waiting for accounts + taxes_pending_for_accounts[tax] = { + 'account_collected_id': tax_template.account_collected_id, + 'account_paid_id': tax_template.account_paid_id, + } # process deleted - tax_ids_to_delete = [wtc.update_tax_id.id - for wtc in wizard.tax_ids - if wtc.type == 'deleted'] - taxes.write(cr, uid, tax_ids_to_delete, - {'active': False}, - context=context) - log.add(_("Deactivated %d taxes\n" % len(tax_ids_to_delete))) - deleted_taxes = len(tax_ids_to_delete) - return { - 'new': new_taxes, - 'updated': updated_taxes, - 'deleted': deleted_taxes, - 'mapping': tax_template_mapping, - 'pending': taxes_pending_for_accounts - } + taxes_to_delete = self.tax_ids.filtered( + lambda x: x.type == 'deleted').mapped('update_tax_id') + taxes_to_delete.write({'active': False}) + log.add(_("Deactivated %d taxes\n" % len(taxes_to_delete))) + return taxes_pending_for_accounts - def _update_children_accounts_parent(self, cr, uid, wizard, - log, parent_account_id, context=None): - """ - Updates the parent_id of accounts that seem to be children of the + @api.multi + def _update_children_accounts_parent(self, log, parent_account): + """Updates the parent_id of accounts that seem to be children of the given account (accounts that start with the same code and are brothers of the first account). """ - account_account = self.pool.get('account.account') - parent_account = account_account.browse( - cr, uid, parent_account_id, context=context) - + account_obj = self.env['account.account'] if not parent_account.parent_id or not parent_account.code: return False - - children_ids = account_account.search(cr, uid, [ - ('company_id', '=', - parent_account.company_id and parent_account.company_id.id), - ('parent_id', '=', parent_account.parent_id.id), - ('code', '=like', "%s%%" % parent_account.code), - ('id', '!=', parent_account.id), - ], context=context) - - if children_ids: + children = account_obj.search( + [('company_id', '=', parent_account.company_id.id), + ('parent_id', '=', parent_account.parent_id.id), + ('code', '=like', "%s%%" % parent_account.code), + ('id', '!=', parent_account.id)]) + if children: try: - account_account.write(cr, uid, children_ids, - {'parent_id': parent_account.id}, - context=context) - except orm.except_orm, ex: - log.add( - _("Exception setting the parent of " - "account %s children: %s - %s.\n") % ( - parent_account.code, ex.name, ex.value - ), - True - ) - + children.write({'parent_id': parent_account.id}) + except (exceptions.Warning, except_orm, except_osv) as ex: + log.add(_("Exception setting the parent of account %s " + "children: %s - %s.\n") % (parent_account.code, + ex.name, ex.value), True) return True - def _update_accounts(self, cr, uid, wizard, log, tax_template_mapping, - context=None): - """ - Search for, and load, account templates to create/update. - """ - accounts = self.pool.get('account.account') - root_account_id = wizard.chart_template_id.account_root_id.id + def _prepare_account_vals(self, account_template, mapping_taxes, + mapping_accounts): + root_account_id = self.chart_template_id.account_root_id.id + # Get the taxes + taxes = [self._tax_mapping[tax_template] + for tax_template in account_template.tax_ids + if self.map_tax_template(tax_template, mapping_taxes)] + # Calculate the account code (we need to add zeros to non-view + # account codes) + code = account_template.code or '' + if account_template.type != 'view': + if len(code) and len(code) <= self.code_digits: + code = '%s%s' % (code, '0' * (self.code_digits - len(code))) + return { + 'name': ((root_account_id == account_template.id) and + self.company_id.name or account_template.name), + 'currency_id': account_template.currency_id, + 'code': code, + 'type': account_template.type, + 'user_type': account_template.user_type.id, + 'reconcile': account_template.reconcile, + 'shortcut': account_template.shortcut, + 'note': account_template.note, + 'parent_id': ( + self.map_account_template( + account_template.parent_id, mapping_accounts).id), + 'tax_ids': [(6, 0, taxes)], + 'company_id': self.company_id.id, + } + + @api.multi + def _update_accounts(self, log, mapping_taxes, mapping_accounts): + """Process accounts to create/update.""" + account_obj = self.env['account.account'] # Disable the parent_store computing on account_account # during the batch processing, - # we will force _parent_store_compute afterwards. - self.pool._init = True - new_accounts = 0 - updated_accounts = 0 - account_template_mapping = {} - for wiz_account in wizard.account_ids: + # We will force _parent_store_compute afterwards. + account_obj._init = True + for wiz_account in self.account_ids: account_template = wiz_account.account_id - # Ensure the parent account template is on the map. - self._map_account_template(cr, uid, wizard, - account_template_mapping, - account_template.parent_id, - context) - # Ensure the related tax templates are on the map. - for tax_template in account_template.tax_ids: - self._map_tax_template(cr, uid, wizard, tax_template_mapping, - tax_template, context) - # Get the tax ids - tax_ids = [tax_template_mapping[tax_template.id] - for tax_template in account_template.tax_ids - if tax_template_mapping[tax_template.id]] - # Calculate the account code (we need to add zeros to non-view - # account codes) - code = account_template.code or '' - if account_template.type != 'view': - if len(code) > 0 and len(code) <= wizard.code_digits: - code = '%s%s' % ( - code, '0' * (wizard.code_digits - len(code))) - # Values - p_id = account_template.parent_id.id - vals = { - 'name': ((root_account_id == account_template.id) and - wizard.company_id.name or - account_template.name), - 'currency_id': (account_template.currency_id and - account_template.currency_id.id or - False), - 'code': code, - 'type': account_template.type, - 'user_type': (account_template.user_type and - account_template.user_type.id or - False), - 'reconcile': account_template.reconcile, - 'shortcut': account_template.shortcut, - 'note': account_template.note, - 'parent_id': ( - account_template_mapping.get(p_id) - if account_template.parent_id - else False - ), - 'tax_ids': [(6, 0, tax_ids)], - 'company_id': wizard.company_id.id, - } - account_id = None - modified = False + vals = self._prepare_account_vals( + account_template, mapping_taxes, mapping_accounts) if wiz_account.type == 'new': # Create the account try: - account_id = accounts.create(cr, uid, vals) - log.add(_("Created account %s.\n") % code) - new_accounts += 1 - modified = True - except orm.except_orm, ex: - log.add(_("Exception creating account %s: %s - %s.\n") - % (code, ex.name, ex.value), True) - elif wizard.update_account and wiz_account.update_account_id: - # Update the account - account_id = wiz_account.update_account_id.id - try: - accounts.write(cr, uid, [account_id], vals) - log.add(_("Updated account %s.\n") % code) - updated_accounts += 1 - modified = True - except orm.except_orm, ex: - log.add(_("Exception writing account %s: %s - %s.\n") - % (code, ex.name, ex.value), True) + account = account_obj.create(vals) + mapping_accounts[account_template] = account + log.add(_("Created account %s.\n") % vals['code']) + except (exceptions.Warning, except_orm, except_osv) as ex: + log.add(_("Exception creating account %s: %s - %s.\n") % + (vals['code'], ex.name, ex.value), True) else: - account_id = (wiz_account.update_account_id and - wiz_account.update_account_id.id) - # Store the account on the map - account_template_mapping[account_template.id] = account_id - if modified: - # Detect errors - if (account_template.parent_id and not - account_template_mapping.get( - account_template.parent_id.id)): - log.add( - _("Account %s: The parent account %s " - "can not be set.\n") % ( - code, account_template.parent_id.code - ), - True - ) - # Set this account as the parent of the accounts that seem to - # be its children (brothers starting with the same code). - if wizard.update_children_accounts_parent: - self._update_children_accounts_parent( - cr, uid, wizard, log, account_id, context=context) + # Update the account + account = wiz_account.update_account_id + try: + account.write(vals) + log.add(_("Updated account %s.\n") % vals['code']) + except (exceptions.Warning, except_orm, except_osv) as ex: + log.add(_("Exception writing account %s: %s - %s.\n") % + (vals['code'], ex.name, ex.value), True) + # Set this account as the parent of the accounts that seem to + # be its children (brothers starting with the same code). + if self.update_children_accounts_parent: + self._update_children_accounts_parent(log, account) # Reenable the parent_store computing on account_account # and force the recomputation. - self.pool._init = False - self.pool.get('account.account')._parent_store_compute(cr) + account_obj._init = False + account_obj._parent_store_compute() + + @api.multi + def _update_taxes_pending_for_accounts( + self, log, taxes_pending_for_accounts, mapping_accounts): + """Updates the taxes (created or updated on previous steps) to set + the references to the accounts (the taxes where created/updated first, + when the referenced accounts are still not available). + """ + for tax, accounts in taxes_pending_for_accounts.items(): + # Ensure the related account templates are on the map. + for key, value in accounts.iteritems(): + if not value: + continue + if not self.map_account_template(value, mapping_accounts): + if key == 'account_collected_id': + log.add(_("Tax %s: The collected account can not be " + "set.\n") % tax.name, True) + else: + log.add(_("Tax %s: The paid account can not be set.\n") + % tax.name, True) + tax.write({key: self.map_account_template( + value, mapping_accounts).id}) + + def _prepare_fp_vals(self, fp_template, mapping_taxes, mapping_accounts): + # Tax mappings + tax_mapping = [] + for fp_tax in fp_template.tax_ids: + # Create the fp tax mapping + tax_mapping.append({ + 'tax_src_id': self.map_tax_template( + fp_tax.tax_src_id, mapping_taxes).id, + 'tax_dest_id': self.map_tax_template( + fp_tax.tax_dest_id, mapping_taxes).id, + }) + # Account mappings + account_mapping = [] + for fp_account in fp_template.account_ids: + # Create the fp account mapping + account_mapping.append({ + 'account_src_id': ( + self.map_account_template( + fp_account.account_src_id, mapping_accounts).id), + 'account_dest_id': ( + self.map_account_template( + fp_account.account_dest_id, mapping_accounts).id), + }) return { - 'new': new_accounts, - 'updated': updated_accounts, - 'mapping': account_template_mapping + 'company_id': self.company_id.id, + 'name': fp_template.name, + 'tax_ids': [(0, 0, x) for x in tax_mapping], + 'account_ids': [(0, 0, x) for x in account_mapping], } - def _update_taxes_pending_for_accounts(self, cr, uid, wizard, log, - taxes_pending_for_accounts, - acc_templ_mapping, context=None): - """ - Updates the taxes (created or updated on previous steps) to set - the references to the accounts (the taxes where created/updated first, - when the referenced accounts where still not available). - """ - taxes = self.pool['account.tax'] - accounts_template = self.pool['account.account.template'] - for key, value in taxes_pending_for_accounts.items(): - # Ensure the related account templates are on the map. - if value['account_collected_id']: - acc_templ = accounts_template.browse( - cr, uid, value['account_collected_id'], context=context) - self._map_account_template(cr, uid, wizard, acc_templ_mapping, - acc_templ, context=context) - if value['account_paid_id']: - acc_templ = accounts_template.browse( - cr, uid, value['account_paid_id'], context=context) - self._map_account_template(cr, uid, wizard, acc_templ_mapping, - acc_templ, context=context) - if value['account_collected_id'] or value['account_paid_id']: - if (acc_templ_mapping.get(value['account_collected_id']) and - acc_templ_mapping.get(value['account_paid_id'])): - vals = { - 'account_collected_id': acc_templ_mapping[ - value['account_collected_id'] - ], - 'account_paid_id': acc_templ_mapping[ - value['account_paid_id'] - ], - } - taxes.write(cr, uid, [key], vals) - else: - tax = taxes.browse(cr, uid, key) - val = value['account_collected_id'] - if not acc_templ_mapping.get(val): - log.add( - _("Tax %s: The collected account " - "can not be set.\n") % ( - tax.name - ), - True - ) - if not acc_templ_mapping.get(value['account_paid_id']): - log.add(_("Tax %s: The paid account can not be set.\n") - % (tax.name), True) - - def _update_fiscal_positions(self, cr, uid, wizard, log, - tax_template_mapping, - acc_templ_mapping, context=None): - """ - Search for, and load, fiscal position templates to create/update. - """ - fiscalpositions = self.pool.get('account.fiscal.position') - fiscalpositions_taxes = self.pool.get('account.fiscal.position.tax') - fiscalpositions_account = self.pool.get( - 'account.fiscal.position.account' - ) - - new_fps = 0 - updated_fps = 0 - - for wiz_fp in wizard.fiscal_position_ids: + @api.multi + def _update_fiscal_positions(self, log, mapping_taxes, mapping_accounts): + """Process fiscal position templates to create/update.""" + for wiz_fp in self.fiscal_position_ids: fp_template = wiz_fp.fiscal_position_id - fp_id = None - modified = False + vals = self._prepare_fp_vals( + fp_template, mapping_taxes, mapping_accounts) if wiz_fp.type == 'new': # Create a new fiscal position - vals_fp = { - 'company_id': wizard.company_id.id, - 'name': fp_template.name, - } - fp_id = fiscalpositions.create(cr, uid, vals_fp) - new_fps += 1 - modified = True - elif (wizard.update_fiscal_position and - wiz_fp.update_fiscal_position_id): + fp = self.env['account.fiscal.position'].create(vals) + else: # Update the given fiscal position (remove the tax and account # mappings, that will be regenerated later) - fp_id = wiz_fp.update_fiscal_position_id.id - updated_fps += 1 - modified = True - # Remove the tax mappings - fp_tax_ids = fiscalpositions_taxes.search( - cr, uid, [('position_id', '=', fp_id)]) - fiscalpositions_taxes.unlink(cr, uid, fp_tax_ids) - # Remove the account mappings - fp_account_ids = fiscalpositions_account.search( - cr, uid, [('position_id', '=', fp_id)]) - fiscalpositions_account.unlink(cr, uid, fp_account_ids) - else: - fp_id = (wiz_fp.update_fiscal_position_id and - wiz_fp.update_fiscal_position_id.id) - - if modified: - # (Re)create the tax mappings - for fp_tax in fp_template.tax_ids: - # Ensure the related tax templates are on the map. - self._map_tax_template(cr, uid, wizard, - tax_template_mapping, - fp_tax.tax_src_id, context) - if fp_tax.tax_dest_id: - self._map_tax_template(cr, uid, wizard, - tax_template_mapping, - fp_tax.tax_dest_id, context) - # Create the fp tax mapping - vals_tax = { - 'tax_src_id': tax_template_mapping.get( - fp_tax.tax_src_id.id - ), - 'tax_dest_id': (fp_tax.tax_dest_id and - tax_template_mapping.get( - fp_tax.tax_dest_id.id)), - 'position_id': fp_id, - } - fiscalpositions_taxes.create(cr, uid, vals_tax) - # Check for errors - if not tax_template_mapping.get(fp_tax.tax_src_id.id): - log.add( - _("Fiscal position %s: The source tax %s " - "can not be set.\n") % ( - fp_template.name, fp_tax.tax_src_id.code - ), - True - ) - if fp_tax.tax_dest_id and not tax_template_mapping.get( - fp_tax.tax_dest_id.id): - log.add( - _("Fiscal position %s: The destination" - "tax %s can not be set.\n") % ( - fp_template.name, fp_tax.tax_dest_id.name - ), - True - ) - # (Re)create the account mappings - for fp_account in fp_template.account_ids: - # Ensure the related account templates are on the map. - self._map_account_template(cr, uid, wizard, - acc_templ_mapping, - fp_account.account_src_id, - context=context) - if fp_account.account_dest_id: - self._map_account_template(cr, uid, wizard, - acc_templ_mapping, - fp_account.account_dest_id, - context=context) - # Create the fp account mapping - vals_account = { - 'account_src_id': acc_templ_mapping.get( - fp_account.account_src_id.id - ), - 'account_dest_id': ( - fp_account.account_dest_id and - acc_templ_mapping.get( - fp_account.account_dest_id.id - ) - ), - 'position_id': fp_id, - } - fiscalpositions_account.create(cr, uid, vals_account) - # Check for errors - if not acc_templ_mapping.get(fp_account.account_src_id.id): - log.add( - _("Fiscal position %s: The source account %s " - "can not be set.\n") % ( - fp_template.name, - fp_account.account_src_id.code - ), - True - ) - if (fp_account.account_dest_id and not - acc_templ_mapping.get( - fp_account.account_dest_id.id)): - log.add( - _("Fiscal position %s: The destination account %s " - "can not be set.\n") % ( - fp_template.name, - fp_account.account_dest_id.code - ), - True - ) - - log.add(_("Created or updated fiscal position %s.\n") - % fp_template.name) - return {'new': new_fps, 'updated': updated_fps} - - def action_update_records(self, cr, uid, ids, context=None): - """ - Action that creates/updates the selected elements. - """ - if context is None: - context = {} - wizard = self.browse(cr, uid, ids[0], context=context) - if wizard.lang: - context['lang'] = wizard.lang - elif context.get('lang'): - del context['lang'] - log = WizardLog() - # Defaults when calculations are not done - tax_codes_res = {'mapping': {}} - taxes_res = {'mapping': {}, 'pending': {}} - accounts_res = {'mapping': {}} - fps_res = {} - # Create or update the records. - if wizard.update_tax_code: - tax_codes_res = self._update_tax_codes(cr, uid, wizard, log, - context=context) - if wizard.update_tax: - taxes_res = self._update_taxes(cr, uid, wizard, log, - tax_codes_res['mapping'], - context=context) - if wizard.update_account: - accounts_res = self._update_accounts(cr, uid, wizard, log, - taxes_res['mapping'], - context=context) - if wizard.update_tax: - self._update_taxes_pending_for_accounts(cr, uid, wizard, log, - taxes_res['pending'], - accounts_res['mapping'], - context=context) - if wizard.update_fiscal_position: - fps_res = self._update_fiscal_positions(cr, uid, wizard, log, - taxes_res['mapping'], - accounts_res['mapping'], - context=context) - # Check if errors where detected and wether we should stop. - if log.has_errors() and not wizard.continue_on_errors: - raise orm.except_orm(_('Error'), _( - "One or more errors detected!\n\n%s") % log.get_errors_str()) - # Store the data and go to the next step. - self.write(cr, uid, [wizard.id], { - 'state': 'done', - 'new_tax_codes': tax_codes_res.get('new', 0), - 'new_taxes': taxes_res.get('new', 0), - 'new_accounts': accounts_res .get('new', 0), - 'new_fps': fps_res.get('new', 0), - 'updated_tax_codes': tax_codes_res.get('updated', 0), - 'updated_taxes': taxes_res.get('updated', 0), - 'updated_accounts': accounts_res.get('updated', 0), - 'updated_fps': fps_res.get('updated', 0), - 'deleted_tax_codes': tax_codes_res.get('deleted', 0), - 'deleted_taxes': taxes_res.get('deleted', 0), - 'log': log(), - }, context=context) - return _reopen(self, wizard.id, 'wizard.update.chart.accounts') + fp = wiz_fp.update_fiscal_position_id + fp.tax_ids.unlink() + fp.account_ids.unlink() + fp.write(vals) + log.add(_("Created or updated fiscal position %s.\n") % + fp_template.name) -class wizard_update_charts_accounts_tax_code(orm.TransientModel): - """ - ****************************************************************** - Tax code that needs to be updated (new or updated in the template). - ****************************************************************** - """ +class WizardUpdateChartsAccountsTaxCode(models.TransientModel): _name = 'wizard.update.charts.accounts.tax.code' - _columns = { - 'tax_code_id': fields.many2one( - 'account.tax.code.template', - 'Tax code template', - ondelete='set null' - ), - 'update_chart_wizard_id': fields.many2one( - 'wizard.update.charts.accounts', - 'Update chart wizard', - required=True, - ondelete='cascade' - ), - 'type': fields.selection([ - ('new', 'New tax code'), - ('updated', 'Updated tax code'), - ('deleted', 'Tax code to deactivate'), - ], 'Type'), - 'update_tax_code_id': fields.many2one( - 'account.tax.code', - 'Tax code to update', - required=False, - ondelete='set null' - ), - 'notes': fields.text('Notes'), - } - _defaults = { - } + _description = ("Tax code that needs to be updated (new or updated in the " + "template).") + + tax_code_id = fields.Many2one( + comodel_name='account.tax.code.template', string='Tax code template', + ondelete='set null') + update_chart_wizard_id = fields.Many2one( + comodel_name='wizard.update.charts.accounts', + string='Update chart wizard', required=True, ondelete='cascade') + type = fields.Selection( + selection=[('new', 'New tax code'), + ('updated', 'Updated tax code'), + ('deleted', 'Tax code to deactivate')], string='Type') + update_tax_code_id = fields.Many2one( + comodel_name='account.tax.code', string='Tax code to update', + required=False, ondelete='set null') + notes = fields.Text('Notes') -class wizard_update_charts_accounts_tax(orm.TransientModel): - """ - ************************************************************** - Tax that needs to be updated (new or updated in the template). - ************************************************************** - """ +class WizardUpdateChartsAccountsTax(models.TransientModel): _name = 'wizard.update.charts.accounts.tax' - _columns = { - 'tax_id': fields.many2one( - 'account.tax.template', - 'Tax template', - ondelete='set null' - ), - 'update_chart_wizard_id': fields.many2one( - 'wizard.update.charts.accounts', - 'Update chart wizard', - required=True, - ondelete='cascade' - ), - 'type': fields.selection([ - ('new', 'New template'), - ('updated', 'Updated template'), - ('deleted', 'Tax to deactivate'), - ], 'Type'), - 'update_tax_id': fields.many2one( - 'account.tax', - 'Tax to update', - required=False, - ondelete='set null' - ), - 'notes': fields.text('Notes'), - } + _description = ("Tax that needs to be updated (new or updated in the " + "template).") - _defaults = { - } + tax_id = fields.Many2one( + comodel_name='account.tax.template', string='Tax template', + ondelete='set null') + update_chart_wizard_id = fields.Many2one( + comodel_name='wizard.update.charts.accounts', + string='Update chart wizard', required=True, ondelete='cascade') + type = fields.Selection( + selection=[('new', 'New template'), + ('updated', 'Updated template'), + ('deleted', 'Tax to deactivate')], string='Type') + update_tax_id = fields.Many2one( + comodel_name='account.tax', string='Tax to update', required=False, + ondelete='set null') + notes = fields.Text('Notes') -class wizard_update_charts_accounts_account(orm.TransientModel): - """ - ****************************************************************** - Account that needs to be updated (new or updated in the template). - ******************************************************************* - """ +class WizardUpdateChartsAccountsAccount(models.TransientModel): _name = 'wizard.update.charts.accounts.account' - # The chart of accounts can have a lot of accounts, so we need an higher - # limit for the objects in memory to let the wizard create all the items - # at once. - _columns = { - 'account_id': fields.many2one( - 'account.account.template', - 'Account template', - required=True, - ondelete='set null' - ), - 'update_chart_wizard_id': fields.many2one( - 'wizard.update.charts.accounts', - 'Update chart wizard', - required=True, - ondelete='cascade' - ), - 'type': fields.selection([ - ('new', 'New template'), - ('updated', 'Updated template'), - ], 'Type'), - 'update_account_id': fields.many2one( - 'account.account', - 'Account to update', - required=False, - ondelete='set null' - ), - 'notes': fields.text('Notes'), - } + _description = ("Account that needs to be updated (new or updated in the " + "template).") - _defaults = { - } + account_id = fields.Many2one( + comodel_name='account.account.template', string='Account template', + required=True, ondelete='set null') + update_chart_wizard_id = fields.Many2one( + comodel_name='wizard.update.charts.accounts', + string='Update chart wizard', required=True, ondelete='cascade' + ) + type = fields.Selection( + selection=[('new', 'New template'), + ('updated', 'Updated template')], string='Type') + update_account_id = fields.Many2one( + comodel_name='account.account', string='Account to update', + required=False, ondelete='set null') + notes = fields.Text('Notes') -class wizard_update_charts_accounts_fiscal_position(orm.TransientModel): - """ - ************************************************************************** - Fiscal position that needs to be updated (new or updated in the template). - ************************************************************************** - """ +class WizardUpdateChartsAccountsFiscalPosition(models.TransientModel): _name = 'wizard.update.charts.accounts.fiscal.position' - _columns = { - 'fiscal_position_id': fields.many2one( - 'account.fiscal.position.template', - 'Fiscal position template', - required=True, - ondelete='set null' - ), - 'update_chart_wizard_id': fields.many2one( - 'wizard.update.charts.accounts', - 'Update chart wizard', - required=True, - ondelete='cascade' - ), - 'type': fields.selection([ - ('new', 'New template'), - ('updated', 'Updated template'), - ], 'Type'), - 'update_fiscal_position_id': fields.many2one( - 'account.fiscal.position', - 'Fiscal position to update', - required=False, - ondelete='set null' - ), - 'notes': fields.text('Notes'), - } - _defaults = { - } + _description = ("Fiscal position that needs to be updated (new or updated " + "in the template).") -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + fiscal_position_id = fields.Many2one( + comodel_name='account.fiscal.position.template', + string='Fiscal position template', required=True, ondelete='set null') + update_chart_wizard_id = fields.Many2one( + comodel_name='wizard.update.charts.accounts', + string='Update chart wizard', required=True, ondelete='cascade') + type = fields.Selection( + selection=[('new', 'New template'), + ('updated', 'Updated template')], string='Type') + update_fiscal_position_id = fields.Many2one( + comodel_name='account.fiscal.position', required=False, + string='Fiscal position to update', ondelete='set null') + notes = fields.Text('Notes') diff --git a/account_chart_update/wizard/wizard_chart_update_view.xml b/account_chart_update/wizard/wizard_chart_update_view.xml index f4f1586e..55af0eae 100644 --- a/account_chart_update/wizard/wizard_chart_update_view.xml +++ b/account_chart_update/wizard/wizard_chart_update_view.xml @@ -20,12 +20,14 @@ - + + domain="[('visible', '=', True)]" + attrs="{'invisible': [('state','!=','init')], 'required': True}" + />