← Back to team overview

openerp-community-reviewer team mailing list archive

[Merge] lp:~akretion-team/account-financial-tools/7-account-journal-sale-refund-link-cde into lp:account-financial-tools

 

Chafique DELLI has proposed merging lp:~akretion-team/account-financial-tools/7-account-journal-sale-refund-link-cde into lp:account-financial-tools.

Commit message:
 add module account_journal_sale_refund_link

Requested reviews:
  Akretion Team (akretion-team)

For more details, see:
https://code.launchpad.net/~akretion-team/account-financial-tools/7-account-journal-sale-refund-link-cde/+merge/223022

add module 'account_journal_sale_refund_link' who was in the branch 'lp:account-extra-addons' in version 6.1 and that i ported in version 7.0
-- 
https://code.launchpad.net/~akretion-team/account-financial-tools/7-account-journal-sale-refund-link-cde/+merge/223022
Your team OpenERP Community Reviewer/Maintainer is subscribed to branch lp:account-financial-tools.
=== added directory 'account_journal_sale_refund_link'
=== added file 'account_journal_sale_refund_link/__init__.py'
--- account_journal_sale_refund_link/__init__.py	1970-01-01 00:00:00 +0000
+++ account_journal_sale_refund_link/__init__.py	2014-06-13 07:34:28 +0000
@@ -0,0 +1,25 @@
+# -*- encoding: utf-8 -*-
+#################################################################################
+#
+#    account_journal_sale_refund_link for OpenERP
+#    Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#                  2014 Akretion Chafique DELLI <chafique.delli@xxxxxxxxxxxx>
+#
+#    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 (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+#################################################################################
+
+
+import account
+import account_invoice_refund

=== added file 'account_journal_sale_refund_link/__openerp__.py'
--- account_journal_sale_refund_link/__openerp__.py	1970-01-01 00:00:00 +0000
+++ account_journal_sale_refund_link/__openerp__.py	2014-06-13 07:34:28 +0000
@@ -0,0 +1,40 @@
+# -*- encoding: utf-8 -*-
+#################################################################################
+#
+#    account_journal_sale_refund_link for OpenERP
+#    Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#                  2014 Akretion Chafique DELLI <chafique.delli@xxxxxxxxxxxx>
+#
+#    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 (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+#################################################################################
+
+
+{
+    'name': 'account_journal_sale_refund_link',
+    'version': '0.1',
+    'category': 'Generic Modules/Others',
+    'license': 'AGPL-3',
+    'description': """empty""",
+    'author': 'Akretion',
+    'website': 'http://www.akretion.com/',
+    'depends': ['account'],
+    'init_xml': [],
+    'update_xml': [
+           'account_view.xml',
+    ],
+    'demo_xml': [],
+    'installable': True,
+    'active': False,
+}

=== added file 'account_journal_sale_refund_link/account.py'
--- account_journal_sale_refund_link/account.py	1970-01-01 00:00:00 +0000
+++ account_journal_sale_refund_link/account.py	2014-06-13 07:34:28 +0000
@@ -0,0 +1,35 @@
+# -*- encoding: utf-8 -*-
+#################################################################################
+#
+#    account_journal_sale_refund_link for OpenERP
+#    Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#                  2014 Akretion Chafique DELLI <chafique.delli@xxxxxxxxxxxx>
+#
+#    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 (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+#################################################################################
+
+from openerp.osv import fields, orm
+
+
+class account_journal(orm.Model):
+
+    _inherit = "account.journal"
+
+
+    _columns = {
+        'refund_journal_id':fields.many2one('account.journal', 'Refund Journal',
+                                            domain=[('type', '=', 'sale_refund')]),
+    }
+

=== added file 'account_journal_sale_refund_link/account_invoice_refund.py'
--- account_journal_sale_refund_link/account_invoice_refund.py	1970-01-01 00:00:00 +0000
+++ account_journal_sale_refund_link/account_invoice_refund.py	2014-06-13 07:34:28 +0000
@@ -0,0 +1,41 @@
+# -*- encoding: utf-8 -*-
+#################################################################################
+#
+#    account_journal_sale_refund_link for OpenERP
+#    Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#                  2014 Akretion Chafique DELLI <chafique.delli@xxxxxxxxxxxx>
+#
+#    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 (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+#################################################################################
+
+from openerp.osv import orm
+
+
+class account_invoice_refund(orm.TransientModel):
+
+    _inherit = "account.invoice.refund"
+
+    def _get_journal(self, cr, uid, context=None):
+        invoice_id = context.get('invoice_ids', [context['active_id']])[0]
+        invoice = self.pool.get('account.invoice').browse(cr, uid, invoice_id, context=context)
+        refund_journal_id = invoice.journal_id.refund_journal_id
+        if refund_journal_id:
+            return refund_journal_id.id
+        else:
+            return super(account_invoice_refund, self)._get_journal(cr, uid, context)
+
+    _defaults = {
+    'journal_id': _get_journal,
+    }

=== added file 'account_journal_sale_refund_link/account_view.xml'
--- account_journal_sale_refund_link/account_view.xml	1970-01-01 00:00:00 +0000
+++ account_journal_sale_refund_link/account_view.xml	2014-06-13 07:34:28 +0000
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<openerp>
+    <data>
+
+        <!-- INHERITED VIEW FOR THE OBJECT : account_journal -->
+
+		<record id="account_journal_sale_refund_link_account_journal_view_form" model="ir.ui.view">
+			<field name="model">account.journal</field>
+			<field name="inherit_id" ref="account.view_account_journal_form" />
+            <field eval="16" name="priority"/>
+			<field name="type">form</field>
+			<field name="arch" type="xml">
+				<data>
+					<field name="type" position="after">
+						<field name="refund_journal_id" attrs="{'invisible' : [('type', '!=', 'sale')]}"/>
+					</field>
+				</data>
+			</field>
+		</record>
+
+    </data>
+</openerp>

=== modified file 'account_tax_update/__openerp__.py'
--- account_tax_update/__openerp__.py	2013-12-05 15:59:30 +0000
+++ account_tax_update/__openerp__.py	2014-06-13 07:34:28 +0000
@@ -4,6 +4,7 @@
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2012 Therp BV (<http://therp.nl>).
 #    Copyright (C) 2013 Camptocamp SA.
+#    Copyright (C) 2013 Akretion SA.
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -22,7 +23,7 @@
 {
     "name": "Update tax wizard",
     "version": "1.0.44",
-    "author": "Therp BV/Camptocamp SA",
+    "author": "Therp BV/Camptocamp SA/Akretion",
     "category": 'Base',
     'complexity': "normal",
     "description": """
@@ -41,7 +42,7 @@
 and sales taxes can be set at independent times. During the transition,
 the old taxes can still be selected manually on invoice lines etc.
 
-You can select to also duplicate linked tax code 
+You can select to also duplicate linked tax code
 
 After the transition, the old taxes can be made inactive.
 

=== modified file 'account_tax_update/model/__init__.py'
--- account_tax_update/model/__init__.py	2013-11-12 14:04:34 +0000
+++ account_tax_update/model/__init__.py	2014-06-13 07:34:28 +0000
@@ -4,6 +4,7 @@
 #    OpenERP, Open Source Management Solution
 #    This module copyright (C) 2012 Therp BV (<http://therp.nl>).
 #    This module copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>).
+#    This module copyright (C) 2013 Akretion (<http://www.akretion.com>).
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -23,3 +24,4 @@
 from . import update_tax_config
 from . import select_taxes
 from . import account_tax
+from . import account_invoice

=== added file 'account_tax_update/model/account_invoice.py'
--- account_tax_update/model/account_invoice.py	1970-01-01 00:00:00 +0000
+++ account_tax_update/model/account_invoice.py	2014-06-13 07:34:28 +0000
@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    This module copyright (C) 2012 Therp BV (<http://therp.nl>).
+#    This module copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>).
+#    This module copyright (C) 2013 Akretion (<http://www.akretion.com>).
+#
+#    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 (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+from openerp.tools.translate import _
+from lxml import etree
+import logging
+
+
+_logger = logging.getLogger(__name__)
+
+class account_invoice(orm.Model):
+    _inherit = 'account.invoice'
+
+    def invoice_validate(self, cr, uid, ids, context=None):
+        config_obj = self.pool.get('account.update.tax.config')
+        #To avoid lost of performance the test is only apply
+        #when a config is in the confirm state
+        if config_obj.exist_confirm_config(cr, uid):
+            if config_obj.automatic_tax_update(cr, uid):
+                self.update_invoice_tax(cr, uid, ids,
+                    context=context,
+                    automatic_update=True)
+
+        res = super(account_invoice, self).invoice_validate(cr, uid, ids, context=context)
+        #Check on tax is done after calling super because the date
+        #can be empty
+        if config_obj.exist_confirm_config(cr, uid):
+            tax_obj = self.pool['account.tax']
+            for invoice in self.browse(cr, uid, ids, context=None):
+                for line in invoice.invoice_line:
+                    for tax in line.invoice_line_tax_id:
+                        tax_obj._check_tax_validity(cr, uid, tax,
+                            invoice.date_invoice,
+                            raise_exception=True,
+                            context=context)
+        return res
+
+    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
+        result = super(account_invoice, self).fields_view_get(cr, uid,
+                                                              view_id, view_type,
+                                                              context, toolbar=toolbar,
+                                                              submenu=submenu)
+        if view_type == 'form':
+            config_obj = self.pool.get('account.update.tax.config')
+            if config_obj.exist_confirm_config(cr, uid):
+                eview = etree.fromstring(result['arch'])
+                header = eview.xpath("//header")[0]
+                element = etree.Element('button', name='update_invoice_tax', string='Update Invoice Tax', type='object')
+                header.insert(-1, element)
+                result['arch'] = etree.tostring(eview, pretty_print=True)
+        return result
+
+    def update_invoice_tax(self, cr, uid, ids, context=None, automatic_update=False):
+        tax_obj = self.pool['account.tax']
+        for invoice in self.browse(cr, uid, ids, context=None):
+            #If the date is empty we use the tody date. If the final date used
+            #on the invoice is different, there is no big deal as the check on
+            #tax will fail
+            if not invoice.date_invoice:
+                _logger.debug('No date define on the invoice %s, take the today '
+                    'date in order to update the tax rate'%invoice.id)
+                date = fields.date.context_today(self, cr, uid, context=context)
+            else:
+                date = invoice.date_invoice
+            for line in invoice.invoice_line:
+                tax_ids = []
+                need_to_update = False
+                for tax in line.invoice_line_tax_id:
+                    if tax_obj._check_tax_validity(cr, uid, tax,
+                            date, context=context):
+                        tax_ids.append(tax.id)
+                    else:
+                        new_tax_id = tax_obj._map_tax(cr, uid, tax,
+                            date,
+                            automatic_update=automatic_update,
+                            context=context)
+                        tax_ids.append(new_tax_id)
+                        need_to_update = True
+                if need_to_update:
+                    line.write({'invoice_line_tax_id': [(6, 0, tax_ids)]})
+            invoice.button_reset_taxes()
+        return True
+
+class account_tax(orm.Model):
+    _inherit = 'account.tax'
+
+    def _check_tax_validity(self, cr, uid, tax, date, raise_exception=False, context=None):
+        if tax.valid_until and tax.valid_until < date:
+            if raise_exception:
+                raise orm.except_orm(_("User Error"),
+                    _("The tax %s can be only use until the %s. Fix it")
+                    %(tax.name, tax.valid_until))
+            else:
+                return False
+        elif tax.valid_from and tax.valid_from > date:
+            if raise_exception:
+                raise orm.except_orm(_("User Error"),
+                    _("The tax %s can be only use from the %s. Fix it")
+                    %(tax.name, tax.valid_from))
+            else:
+                return False
+        return True
+
+    def _map_tax(self, cr, uid, tax, date, automatic_update=False, context=None):
+        config_line_obj = self.pool.get('account.update.tax.config.line')
+        domain = ['|',
+            '&',
+                ('sale_config_id.switch_date', '>', date),
+                ('target_tax_id', '=', tax.id),
+            '&',
+                ('sale_config_id.switch_date', '<=', date),
+                ('source_tax_id', '=', tax.id),
+            ]
+        if automatic_update:
+            domain.append(('sale_config_id.automatic_tax_update', '=', True))
+        line_id = config_line_obj.search(cr, uid, domain, context=context)
+
+        if not line_id:
+            raise orm.except_orm(_('Configuration Error'),
+                    _('No mapping found for the tax %s')%tax.name)
+        elif len(line_id) > 1:
+            raise orm.except_orm(_('Configuration Error'),
+                    _('Too many mapping found for the tax %s')%tax.name)
+        else:
+            line = config_line_obj.browse(cr, uid, line_id[0], context=context)
+            if line.sale_config_id.switch_date <= date:
+                return line.target_tax_id.id
+            else:
+                return line.source_tax_id.id

=== modified file 'account_tax_update/model/account_tax.py'
--- account_tax_update/model/account_tax.py	2013-11-12 14:04:34 +0000
+++ account_tax_update/model/account_tax.py	2014-06-13 07:34:28 +0000
@@ -4,6 +4,8 @@
 #    OpenERP, Open Source Management Solution
 #    This module copyright (C) 2012 Therp BV (<http://therp.nl>).
 #    This module copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>).
+#    This module copyright (C) 2013 Akretion (<http://www.akretion.com>).
+#
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -20,12 +22,22 @@
 #
 ##############################################################################
 
-from openerp.osv import orm
+from openerp.osv import orm, fields
 
 
 class account_tax(orm.Model):
     _inherit = 'account.tax'
 
+    _columns = {
+        'valid_until': fields.date('Valid Until'),
+        'valid_from': fields.date('Valid From'),
+    }
+
+    _sql_constraints = [
+        ('check_valid_date', 'CHECK(valid_until>valid_from)',
+         'Date valid_from must be less than the date valid_until.'),
+        ]
+
     def name_get(self, cr, uid, ids, context=None):
         if not ids:
             return []

=== modified file 'account_tax_update/model/update_tax_config.py'
--- account_tax_update/model/update_tax_config.py	2013-11-12 14:38:07 +0000
+++ account_tax_update/model/update_tax_config.py	2014-06-13 07:34:28 +0000
@@ -4,6 +4,7 @@
 #    OpenERP, Open Source Management Solution
 #    This module copyright (C) 2012 Therp BV (<http://therp.nl>).
 #    This module copyright (C) 2013 Camptocamp (<http://www.camptocamp.com>).
+#    This module copyright (C) 2013 Akretion (<http://www.akretion.com>).
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
@@ -20,11 +21,14 @@
 #
 ##############################################################################
 
-from datetime import datetime
+from datetime import datetime, date, timedelta
 import pickle
 from openerp.osv import orm, fields
 from openerp.tools.translate import _
-
+from openerp.tools import (DEFAULT_SERVER_DATE_FORMAT,
+                           DEFAULT_SERVER_DATETIME_FORMAT,
+                           ormcache)
+import pytz
 
 class UpdateTaxConfig(orm.Model):
     """
@@ -40,6 +44,25 @@
     """
     _name = 'account.update.tax.config'
     _description = 'Update taxes'
+
+    def _state_get_selection(self, cr, uid, ids, field_name=None, arg=None, context=None):
+        res = {}
+        refresh_cache = False
+        for config in self.browse(cr, uid, ids, context=context):
+            if config.sale_set_defaults and config.purchase_set_defaults\
+                 and config.sale_set_inactive and config.purchase_set_inactive:
+                res[config.id] = 'done'
+                refresh_cache = True
+            elif config.confirm:
+                res[config.id] = 'confirm'
+                refresh_cache = True
+            else:
+                res[config.id] = 'draft'
+        if refresh_cache:
+            self.exist_confirm_config.clear_cache(self)
+            self.automatic_tax_update.clear_cache(self)
+        return res
+
     _columns = {
         'name': fields.char(
             'Legacy taxes prefix', size=64, required=True,
@@ -54,13 +77,23 @@
             'account.update.tax.config.line',
             'sale_config_id',
             'Sales taxes'),
-        'state': fields.selection(
-            [('draft', 'Draft'),
-             ('confirm', 'Confirm'),
-             ('update_sales', 'Sales updated'),
-             ('update_purchase', 'Purchase updated'),
-             ('done', 'Done'),
-             ], 'State', readonly=True),
+        'state': fields.function(_state_get_selection,
+            type='selection',
+            string='State',
+            readonly=True,
+            selection=[
+                ('draft', 'Draft'),
+                ('confirm', 'Confirm'),
+                ('done', 'Done'),
+            ],
+             store={
+                 'account.update.tax.config':(
+                     lambda self, cr, uid, ids, c={}: ids,
+                     ['sale_set_defaults', 'purchase_set_defaults',
+                     'sale_set_inactive', 'purchase_set_inactive', 'confirm'],
+                     10)
+             },
+        ),
         'default_amount': fields.float(
             'Default new amount', digits=(14, 4),
             help=("Although it is possible to specify a distinct new amount "
@@ -77,12 +110,37 @@
         'purchase_set_inactive': fields.boolean(
             'Purchase taxes have been set to inactive',
             readonly=True),
+        'automatic_tax_update': fields.boolean(
+            'Automatic tax update',
+            help=('By default if the tax are unvalid OpenERP will raise an error '
+                'if you tick that box the rate will be automatically updated. '
+                'Take care OpenERP will no recompute the unit price so maybe the '
+                'total amount will be different after updating the tax.')),
         'duplicate_tax_code': fields.boolean(
             'Duplicate Tax code linked'),
+        'confirm': fields.boolean('Confirm', readonly=True),
+        'switch_date': fields.date('Switch Date', required=True),
+        'sale_set_defaults_cron_id': fields.many2one(
+                'ir.cron',
+                'Cron Replace Sale Tax'),
+        'purchase_set_defaults_cron_id': fields.many2one(
+                'ir.cron',
+                'Cron Replace Purchase Tax'),
+        'sale_set_inactive_cron_id': fields.many2one(
+                'ir.cron',
+                'Cron Inactive Sale Tax'),
+        'purchase_set_inactive_cron_id': fields.many2one(
+                'ir.cron',
+                'Cron Inactive Purchase Tax'),
         }
 
     _defaults = {
         'state': 'draft',
+        'confirm': False,
+        'sale_set_defaults_cron_id': False,
+        'purchase_set_defaults_cron_id': False,
+        'sale_set_inactive_cron_id': False,
+        'purchase_set_inactive_cron_id': False,
         }
 
     _sql_constraints = [
@@ -152,10 +210,15 @@
                 )
             # Switch names around, not violating the uniqueness constraint
             tax_old_name = line.source_tax_id.name
+            valid_until = datetime.strptime(config.switch_date,
+                                            DEFAULT_SERVER_DATE_FORMAT)
+            valid_until -= timedelta(days=1)
+            valid_until = datetime.strftime(valid_until, DEFAULT_SERVER_DATE_FORMAT)
             tax_pool.write(
-                cr, uid, line.source_tax_id.id,
-                {'name': '[%s] %s' % (config.name, tax_old_name)},
-                context=context)
+                cr, uid, line.source_tax_id.id, {
+                    'name': '[%s] %s' % (config.name, tax_old_name),
+                    'valid_until': valid_until,
+                    }, context=context)
             if line.source_tax_id.amount in [1.0, -1.0, 0]:
                 amount_new = line.source_tax_id.amount
             else:
@@ -189,7 +252,7 @@
                     ## Check if with have the same tax code for base_code_id
                     if line.source_tax_id.ref_base_code_id.id == line.source_tax_id.base_code_id.id:
                         cp_ref_base_code_id = cp_base_code_id
-                    else:    
+                    else:
                         cp_ref_base_code_id = tax_code_pool.copy(cr, uid,
                                                                  line.source_tax_id.ref_base_code_id.id)
                         rename_old = '[%s] %s' % (config.name,
@@ -220,13 +283,15 @@
                  'amount': amount_new,
                  'parent_id': False,
                  'child_ids': [(6, 0, [])],
+                 'valid_from': config.switch_date,
+                 'valid_until': False,
                 }, context=context)
             tax_pool.write(
                 cr, uid, target_tax_id, {'name': tax_old_name,
                                          'base_code_id': cp_base_code_id,
                                          'ref_base_code_id': cp_ref_base_code_id,
                                          'tax_code_id': cp_tax_code_id,
-                                         'ref_tax_code_id': cp_ref_tax_code_id 
+                                         'ref_tax_code_id': cp_ref_tax_code_id,
                                          }, context=context
                            )
             tax_map[line.source_tax_id.id] = target_tax_id
@@ -268,7 +333,7 @@
                     ))
         self.write(
             cr, uid, ids[0],
-            {'state': 'confirm', 'log': log}, context=context)
+            {'confirm': True, 'log': log}, context=context)
         return {
             'name': self._description,
             'view_type': 'form',
@@ -432,6 +497,104 @@
             'nodestroy': True,
             }
 
+    def _create_cron(self, cr, uid, ids, name, link_field, callback,
+                     type_tax_use, delta_day_exc=None, context=None):
+        if not context or not context.get('tz'):
+            raise orm.except_orm(_('USER ERROR'), 
+                _('Timezone must be specify in context'))
+        for config in self.browse(cr, uid, ids, context=context):
+            date = datetime.strptime(config.switch_date, DEFAULT_SERVER_DATE_FORMAT)
+            local = pytz.timezone(context['tz'])
+            local_datetime = local.localize(date, is_dst=None)
+            utc_datetime = local_datetime.astimezone(pytz.utc)
+            if delta_day_exc:
+                utc_datetime += timedelta(days=delta_day_exc)
+            exc_date = datetime.strftime(utc_datetime, DEFAULT_SERVER_DATETIME_FORMAT)
+            vals = {
+                'name': name,
+                'active': 1,
+                'user_id': uid,
+                'interval_number': 1,
+                'interval_type': 'days',
+                'nextcall': utc_datetime,
+                'numbercall': 1,
+                'doall': 1,
+                'model': 'account.update.tax.config',
+                'function': callback,
+                'args': "([%s], {'type_tax_use': '%s'})"%(config.id, type_tax_use),
+            }
+            cron_obj = self.pool.get('ir.cron')
+            cron_id = cron_obj.create(cr, uid, vals, context=context)
+            config.write({link_field: cron_id})
+        return True
+
+    def create_cron_set_defaults_sale(self, cr, uid, ids, context=None):
+        return self._create_cron(cr, uid, ids,
+                "Scheduler for replacing sale tax",
+                "sale_set_defaults_cron_id",
+                "set_defaults",
+                "sale",
+                context=context)
+
+    def create_cron_set_defaults_purchase(self, cr, uid, ids, context=None):
+        return self._create_cron(cr, uid, ids,
+                'Scheduler for replacing purchase tax',
+                'purchase_set_defaults_cron_id',
+                'set_defaults',
+                'purchase',
+                context=context)
+
+    def create_cron_set_inactive_sale(self, cr, uid, ids, context=None):
+        return self._create_cron(cr, uid, ids,
+                'Scheduler for inactivating old sale tax',
+                'sale_set_inactive_cron_id',
+                'set_inactive',
+                'sale',
+                delta_day_exc=60,
+                context=context)
+
+    def create_cron_set_inactive_purchase(self, cr, uid, ids, context=None):
+        return self._create_cron(cr, uid, ids,
+                'Scheduler for inactivating the old purchase tax',
+                'purchase_set_inactive_cron_id',
+                'set_inactive',
+                'purchase',
+                delta_day_exc=60,
+                context=context)
+
+    def unlink_cron(self, cr, uid, ids, context=None):
+        for config in self.browse(cr, uid, ids, context=context):
+            cron_ids = [
+                config.sale_set_defaults_cron_id.id,
+                config.purchase_set_defaults_cron_id.id,
+                config.sale_set_inactive_cron_id.id,
+              config.purchase_set_inactive_cron_id.id,
+                ]
+            self.pool.get('ir.cron').unlink(cr, uid, cron_ids, context)
+        return True
+
+    def write(self, cr, uid, ids, vals, context=None):
+        if "automatic_tax_update" in vals:
+            self.automatic_tax_update.clear_cache(self)
+        return super(UpdateTaxConfig, self).write(cr, uid, ids, vals, context=context)
+
+    @ormcache(skiparg=3)
+    def exist_confirm_config(self, cr, uid):
+        return self.search(cr, uid, [
+            ('state', '=', 'confirm'),
+            ]) and True or False
+
+    @ormcache(skiparg=3)
+    def automatic_tax_update(self, cr, uid):
+        return self.search(cr, uid, [
+            ('state', '=', 'confirm'),
+            ('automatic_tax_update', '=', True),
+            ]) and True or False
+
+    def unlink(self, cr, uid, ids, context=None):
+        self.exist_confirm_config.clear_cache(self)
+        self.automatic_tax_update.clear_cache(self)
+        return super(UpdateTaxConfig, self).unlink(cr, uid, ids, context=context)
 
 class UpdateTaxConfigLine(orm.Model):
     _name = 'account.update.tax.config.line'

=== modified file 'account_tax_update/view/account_tax.xml'
--- account_tax_update/view/account_tax.xml	2013-10-23 08:35:47 +0000
+++ account_tax_update/view/account_tax.xml	2014-06-13 07:34:28 +0000
@@ -13,5 +13,16 @@
                 </tree>
             </field>
         </record>
+
+        <record id="view_tax_form" model="ir.ui.view">
+            <field name="model">account.tax</field>
+            <field name="inherit_id" ref="account.view_tax_form" />
+            <field name="arch" type="xml">
+                <field name="description" position="after">
+                    <field name="valid_from"/>
+                    <field name="valid_until"/>
+                </field>
+            </field>
+        </record>
     </data>
 </openerp>

=== modified file 'account_tax_update/view/update_tax_config.xml'
--- account_tax_update/view/update_tax_config.xml	2013-10-23 08:35:47 +0000
+++ account_tax_update/view/update_tax_config.xml	2014-06-13 07:34:28 +0000
@@ -17,10 +17,20 @@
                     <field name="default_amount"
                            attrs="{'readonly': [('state', '!=', 'draft')]}"
                            />
+                    <field name="switch_date"
+                           attrs="{'readonly': [('state', '!=', 'draft')]}"
+                           />
+                    <field name="automatic_tax_update"/>
+                    <button colspan="1" name="unlink_cron"
+                                            string="Delete Crons Tax"
+                                            type="object"
+                                            class="oe_highlight"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'done'), '&amp;', ('sale_set_defaults_cron_id', '=', False), '&amp;', ('sale_set_inactive_cron_id', '=', False), '&amp;', ('purchase_set_defaults_cron_id', '=', False), ('purchase_set_inactive_cron_id', '=', False)]}"
+                                            />
                     <notebook colspan="4">
                         <page string="Taxes">
-                            <group string="Sales taxes" col="4" colspan="4">
-                                <field name="sale_line_ids" height="200" 
+                            <group string="Sales taxes" col="3" colspan="4">
+                                <field name="sale_line_ids" height="200"
                                        nolabel="1" colspan="4"
                                        context="{'tax_real_name': 1}"
                                        />
@@ -29,18 +39,39 @@
                                         string="Add sale taxes"
                                         context="{'type_tax_use': 'sale'}"
                                         states="draft"/>
-                                <button name="set_defaults"
-                                        string="Replace sales tax defaults"
-                                        type="object"
-                                        context="{'type_tax_use': 'sale'}"
-                                        attrs="{'invisible': ['|', ('state', '!=', 'confirm'), ('sale_set_defaults', '!=', False)]}"
-                                        />
-                                <button name="set_inactive"
-                                        string="Set legacy sales taxes inactive"
-                                        type="object"
-                                        context="{'type_tax_use': 'sale'}"
-                                        attrs="{'invisible': ['|', ('state', '!=', 'confirm'), ('sale_set_inactive', '!=', False)]}"
-                                        />
+                                <group col="2">
+                                    <button colspan="2" name="set_defaults"
+                                            string="Immediately replace sales tax defaults"
+                                            type="object"
+                                            context="{'type_tax_use': 'sale'}"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'confirm'), '|', ('sale_set_defaults', '!=', False), ('sale_set_defaults_cron_id', '!=', False)]}"
+                                            />
+                                    <button colspan="1" name="create_cron_set_defaults_sale"
+                                            string="Schedule to replace sales tax defaults"
+                                            type="object"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'confirm'), '|', ('sale_set_defaults', '!=', False), ('sale_set_defaults_cron_id', '!=', False)]}"
+                                            />
+
+                                    <field name="sale_set_defaults_cron_id" nolabel="1"
+                                            attrs="{'invisible': [('sale_set_defaults_cron_id', '=', False)]}"
+                                            />
+                                </group>
+                                <group col="2">
+                                    <button colspan="2" name="set_inactive"
+                                            string="Immediately set legacy sales taxes inactive"
+                                            type="object"
+                                            context="{'type_tax_use': 'sale'}"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'confirm'), '|', ('sale_set_inactive', '!=', False), ('sale_set_inactive_cron_id', '!=', False)]}"
+                                            />
+                                    <button colspan="1" name="create_cron_set_inactive_sale"
+                                            string="Schedule to set legacy sales taxes inactive"
+                                            type="object"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'confirm'), '|', ('sale_set_inactive', '!=', False), ('sale_set_inactive_cron_id', '!=', False)]}"
+                                            />
+                                    <field name="sale_set_inactive_cron_id" nolabel="1"
+                                            attrs="{'invisible': [('sale_set_inactive_cron_id', '=', False)]}"
+                                            />
+                                </group>
                             </group>
                             <group string="Purchase taxes" col="4" colspan="4">
                                 <field name="purchase_line_ids"
@@ -52,36 +83,63 @@
                                         string="Add purchase taxes"
                                         context="{'type_tax_use': 'purchase'}"
                                         states="draft"/>
-                                <button name="set_defaults"
-                                        string="Replace purchase tax defaults"
-                                        type="object"
-                                        context="{'type_tax_use': 'purchase'}"
-                                        attrs="{'invisible': ['|', ('state', '!=', 'confirm'), ('purchase_set_defaults', '!=', False)]}"
-                                        />
-                                
-                                <button name="set_inactive"
-                                        string="Set legacy purchase taxes inactive"
-                                        type="object"
-                                        attrs="{'invisible': ['|', ('state', '!=', 'confirm'), ('purchase_set_inactive', '!=', False)]}"
-                                        context="{'type_tax_use': 'purchase'}"
-                                        />
+                                <group col="2">
+                                    <button colspan="2" name="set_defaults"
+                                            string="Immediately replace purchase tax defaults"
+                                            type="object"
+                                            context="{'type_tax_use': 'purchase'}"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'confirm'), '|', ('purchase_set_defaults', '!=', False), ('purchase_set_defaults_cron_id', '!=', False)]}"
+                                            />
+                                    <button colspan="1" name="create_cron_set_defaults_purchase"
+                                            string="Schedule to replace purchase tax defaults"
+                                            type="object"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'confirm'), '|', ('purchase_set_defaults', '!=', False), ('purchase_set_defaults_cron_id', '!=', False)]}"
+                                            />
+                                    <field name="purchase_set_defaults_cron_id" nolabel="1"
+                                            attrs="{'invisible': [('purchase_set_defaults_cron_id', '=', False)]}"
+                                            />
+                                </group>
+                                <group col="2">
+                                    <button colspan="2" name="set_inactive"
+                                            string="Immediately set legacy purchase taxes inactive"
+                                            type="object"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'confirm'), '|', ('purchase_set_inactive', '!=', False), ('purchase_set_inactive_cron_id', '!=', False)]}"
+                                            context="{'type_tax_use': 'purchase'}"
+                                            />
+                                    <button colspan="1" name="create_cron_set_inactive_purchase"
+                                            string="Schedule to set legacy purchase taxes inactive"
+                                            type="object"
+                                            attrs="{'invisible': ['|', ('state', '!=', 'confirm'), '|', ('purchase_set_inactive', '!=', False), ('purchase_set_inactive_cron_id', '!=', False)]}"
+                                            />
+                                    <field name="purchase_set_inactive_cron_id" nolabel="1"
+                                            attrs="{'invisible': [('purchase_set_inactive_cron_id', '=', False)]}"
+                                            />
+
+                                </group>
                             </group>
+                            <button name="confirm"
+                                string="Create tax mappings"
+                                states="draft"
+                                type="object"
+                                class="oe_highlight"
+                                help="When you are done configuring the new tax amounts, click here to create the new taxes and a mapping between the new and old taxes"
+                                />
                             <field name="purchase_set_inactive" invisible="1"/>
                             <field name="sale_set_inactive" invisible="1"/>
                             <field name="purchase_set_defaults" invisible="1"/>
                             <field name="sale_set_defaults" invisible="1"/>
+                            <field name="confirm" invisible="1"/>
+                            <separator name="note" string="Note"/>
+                            <label string='During the transision periode, (configuration is in the state "confirm"). All of the tax on the Invoice
+                            will be tested before the validation. When every action will be done, that mean replacing all the tax
+                            and inactivating the old one, the configuration will be set to the state "done". After that the invoice will be
+                            not tested anymore to avoid waste of perfomance.' colspan="2"/>
                         </page>
                         <page string="Log">
                             <field name="log" colspan="4" nolabel="1"/>
                         </page>
                     </notebook>
-                    <button name="confirm"
-                            string="Create tax mappings"
-                            states="draft"
-                            type="object"
-                            help="When you are done configuring the new tax amounts, click here to create the new taxes and a mapping between the new and old taxes"
-                            />
-                </form>  
+                </form>
             </field>
         </record>
         <record id="update_tax_config_line_tree" model="ir.ui.view">


Follow ups