From 0bee015dd67cb809fd235215b43d331074824e42 Mon Sep 17 00:00:00 2001 From: Anael Closson Date: Wed, 18 Jun 2014 14:33:35 +0200 Subject: [PATCH 01/11] [FIX] mail: more robust parsing of In-Reply-To/References (OPW 608919) When parsing incoming messages, ignore white-space around In-Reply-To headers, and extract message-id items inside the References header using a regex. This actually serves as a workaround for broken MTAs mangling References (such as outlook.com nesting past ones with commas, violating RFC2822). Closes #516 as a manual rebase. --- addons/mail/mail_thread.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 5691cb9ac73..7ff1af038f0 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -29,6 +29,7 @@ import re import socket import time import xmlrpclib +import re from email.message import Message from openerp import tools @@ -42,6 +43,8 @@ from openerp.tools.translate import _ _logger = logging.getLogger(__name__) +mail_header_msgid_re = re.compile('<[^<>]+>') + def decode_header(message, header, separator=' '): return separator.join(map(decode, filter(None, message.get_all(header, [])))) @@ -916,13 +919,13 @@ class mail_thread(osv.AbstractModel): msg_dict['date'] = stored_date.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) if message.get('In-Reply-To'): - parent_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', decode(message['In-Reply-To']))]) + parent_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', decode(message['In-Reply-To'].strip()))]) if parent_ids: msg_dict['parent_id'] = parent_ids[0] if message.get('References') and 'parent_id' not in msg_dict: - parent_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', 'in', - [x.strip() for x in decode(message['References']).split()])]) + msg_list = mail_header_msgid_re.findall(decode(message['References'])) + parent_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', 'in', [x.strip() for x in msg_list])]) if parent_ids: msg_dict['parent_id'] = parent_ids[0] From 57b48602fb7afa5d0539e8d0caa8d1e10c3910e5 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 2 Sep 2014 17:32:37 +0200 Subject: [PATCH 02/11] [FIX] web: chain close action on wizard confirm If a wizard has several steps, or laucnh a second wizard, the view from where has been loaded the initial wizard is finally reloaded --- addons/web/static/src/js/views.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 78accfd4da4..b59e86b2192 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -373,6 +373,10 @@ instance.web.ActionManager = instance.web.Widget.extend({ } var widget = executor.widget(); if (executor.action.target === 'new') { + var pre_dialog = this.dialog; + if (pre_dialog){ + pre_dialog.off('closing', null, pre_dialog.on_close); + } if (this.dialog_widget && !this.dialog_widget.isDestroyed()) { this.dialog_widget.destroy(); } @@ -380,7 +384,13 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog = new instance.web.Dialog(this, { dialogClass: executor.klass, }); - this.dialog.on("closing", null, options.on_close); + this.dialog.on_close = function(){ + options.on_close.apply(null, arguments); + if (pre_dialog && pre_dialog.on_close){ + pre_dialog.on_close(); + } + }; + this.dialog.on("closing", null, this.dialog.on_close); this.dialog.dialog_title = executor.action.name; if (widget instanceof instance.web.ViewManager) { _.extend(widget.flags, { From 1ff7ed275845589ea8b8d27c7dbd17e5a282626e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 12 Jun 2014 15:08:33 +0200 Subject: [PATCH 03/11] [IMP] Optimize the schedulers of the calendar, fetchmail and base_action_rules modules Disable the the crons when they'd have nothing to do, re-enable them when a task is (probably) introduced --- addons/base_action_rule/__openerp__.py | 2 +- addons/base_action_rule/base_action_rule.py | 16 +++++++ .../base_action_rule_data.xml | 1 + addons/calendar/__openerp__.py | 1 + addons/calendar/calendar.py | 45 ++++++++++++++++--- addons/calendar/calendar_cron.xml | 18 ++++++++ addons/calendar/calendar_data.xml | 17 +------ addons/fetchmail/__openerp__.py | 2 +- addons/fetchmail/fetchmail.py | 34 ++++++++------ openerp/addons/base/ir/ir_cron.py | 16 +++++++ 10 files changed, 114 insertions(+), 38 deletions(-) create mode 100644 addons/calendar/calendar_cron.xml diff --git a/addons/base_action_rule/__openerp__.py b/addons/base_action_rule/__openerp__.py index 5dd4b057514..d1bed2f1a27 100644 --- a/addons/base_action_rule/__openerp__.py +++ b/addons/base_action_rule/__openerp__.py @@ -37,9 +37,9 @@ trigger an automatic reminder email. 'website': 'http://www.openerp.com', 'depends': ['base', 'resource', 'mail'], 'data': [ + 'base_action_rule_data.xml', 'base_action_rule_view.xml', 'security/ir.model.access.csv', - 'base_action_rule_data.xml' ], 'demo': [], 'installable': True, diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py index 5189bcbc7df..e74e7193b62 100644 --- a/addons/base_action_rule/base_action_rule.py +++ b/addons/base_action_rule/base_action_rule.py @@ -227,10 +227,20 @@ class base_action_rule(osv.osv): updated = True return updated + def _update_cron(self, cr, uid, context=None): + try: + cron = self.pool['ir.model.data'].get_object( + cr, uid, 'base_action_rule', 'ir_cron_crm_action', context=context) + except ValueError: + return False + + return cron.toggle(model=self._name, domain=[('kind', '=', 'on_time')]) + def create(self, cr, uid, vals, context=None): res_id = super(base_action_rule, self).create(cr, uid, vals, context=context) if self._register_hook(cr, [res_id]): openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) + self._update_cron(cr, uid, context=context) return res_id def write(self, cr, uid, ids, vals, context=None): @@ -239,8 +249,14 @@ class base_action_rule(osv.osv): super(base_action_rule, self).write(cr, uid, ids, vals, context=context) if self._register_hook(cr, ids): openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) + self._update_cron(cr, uid, context=context) return True + def unlink(self, cr, uid, ids, context=None): + res = super(base_action_rule, self).unlink(cr, uid, ids, context=context) + self._update_cron(cr, uid, context=context) + return res + def onchange_model_id(self, cr, uid, ids, model_id, context=None): data = {'model': False, 'filter_pre_id': False, 'filter_id': False} if model_id: diff --git a/addons/base_action_rule/base_action_rule_data.xml b/addons/base_action_rule/base_action_rule_data.xml index d4b12f5d4a3..78988554e86 100644 --- a/addons/base_action_rule/base_action_rule_data.xml +++ b/addons/base_action_rule/base_action_rule_data.xml @@ -11,6 +11,7 @@ + diff --git a/addons/calendar/__openerp__.py b/addons/calendar/__openerp__.py index 2f06a0b5cb9..69ea5908083 100644 --- a/addons/calendar/__openerp__.py +++ b/addons/calendar/__openerp__.py @@ -40,6 +40,7 @@ If you need to manage your meetings, you should install the CRM module. 'website': 'http://www.openerp.com', 'demo': ['calendar_demo.xml'], 'data': [ + 'calendar_cron.xml', 'security/calendar_security.xml', 'security/ir.model.access.csv', 'calendar_view.xml', diff --git a/addons/calendar/calendar.py b/addons/calendar/calendar.py index 5420f67acc0..6903e698e6a 100644 --- a/addons/calendar/calendar.py +++ b/addons/calendar/calendar.py @@ -431,11 +431,12 @@ class calendar_alarm_manager(osv.AbstractModel): return res def get_next_mail(self, cr, uid, context=None): - cron = self.pool.get('ir.cron').search(cr, uid, [('model', 'ilike', self._name)], context=context) - if cron and len(cron) == 1: - cron = self.pool.get('ir.cron').browse(cr, uid, cron[0], context=context) - else: - _logger.exception("Cron for " + self._name + " can not be identified !") + try: + cron = self.pool['ir.model.data'].get_object( + cr, uid, 'calendar', 'ir_cron_scheduler_alarm', context=context) + except ValueError: + _logger.error("Cron for " + self._name + " can not be identified !") + return False if cron.interval_type == "weeks": cron_interval = cron.interval_number * 7 * 24 * 60 * 60 @@ -447,9 +448,12 @@ class calendar_alarm_manager(osv.AbstractModel): cron_interval = cron.interval_number * 60 elif cron.interval_type == "seconds": cron_interval = cron.interval_number + else: + cron_interval = False if not cron_interval: - _logger.exception("Cron delay can not be computed !") + _logger.error("Cron delay can not be computed !") + return False all_events = self.get_next_potential_limit_alarm(cr, uid, cron_interval, notif=False, context=context) @@ -574,6 +578,35 @@ class calendar_alarm(osv.Model): 'interval': 'hours', } + def _update_cron(self, cr, uid, context=None): + try: + cron = self.pool['ir.model.data'].get_object( + cr, uid, 'calendar', 'ir_cron_scheduler_alarm', context=context) + except ValueError: + return False + return cron.toggle(model=self._name, domain=[('type', '=', 'email')]) + + def create(self, cr, uid, values, context=None): + res = super(calendar_alarm, self).create(cr, uid, values, context=context) + + self._update_cron(cr, uid, context=context) + + return res + + def write(self, cr, uid, ids, values, context=None): + res = super(calendar_alarm, self).write(cr, uid, ids, values, context=context) + + self._update_cron(cr, uid, context=context) + + return res + + def unlink(self, cr, uid, ids, context=None): + res = super(calendar_alarm, self).unlink(cr, uid, ids, context=context) + + self._update_cron(cr, uid, context=context) + + return res + class ir_values(osv.Model): _inherit = 'ir.values' diff --git a/addons/calendar/calendar_cron.xml b/addons/calendar/calendar_cron.xml new file mode 100644 index 00000000000..313a0211fa4 --- /dev/null +++ b/addons/calendar/calendar_cron.xml @@ -0,0 +1,18 @@ + + + + + + Run Event Reminder + + + 30 + minutes + -1 + + + + + + + \ No newline at end of file diff --git a/addons/calendar/calendar_data.xml b/addons/calendar/calendar_data.xml index 822236b033e..143ffad0d7f 100644 --- a/addons/calendar/calendar_data.xml +++ b/addons/calendar/calendar_data.xml @@ -71,22 +71,7 @@ days email - - - - - Run Event Reminder - - - 30 - minutes - -1 - - - - - - + Customer Meeting diff --git a/addons/fetchmail/__openerp__.py b/addons/fetchmail/__openerp__.py index 84a26d5ec40..082d53df5e9 100644 --- a/addons/fetchmail/__openerp__.py +++ b/addons/fetchmail/__openerp__.py @@ -56,8 +56,8 @@ For more specific needs, you may also assign custom-defined actions """, 'website': 'http://www.openerp.com', 'data': [ - 'fetchmail_view.xml', 'fetchmail_data.xml', + 'fetchmail_view.xml', 'security/ir.model.access.csv', 'fetchmail_installer_view.xml' ], diff --git a/addons/fetchmail/fetchmail.py b/addons/fetchmail/fetchmail.py index 565996bf961..37a0f165435 100644 --- a/addons/fetchmail/fetchmail.py +++ b/addons/fetchmail/fetchmail.py @@ -251,27 +251,33 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p server.write({'date': time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)}) return True - def cron_update(self, cr, uid, context=None): - if context is None: - context = {} - if not context.get('fetchmail_cron_running'): - # Enabled/Disable cron based on the number of 'done' server of type pop or imap - ids = self.search(cr, uid, [('state','=','done'),('type','in',['pop','imap'])]) - try: - cron_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fetchmail', 'ir_cron_mail_gateway_action')[1] - self.pool.get('ir.cron').write(cr, 1, [cron_id], {'active': bool(ids)}) - except ValueError: - # Nevermind if default cron cannot be found - pass + def _update_cron(self, cr, uid, context=None): + if context and context.get('fetchmail_cron_running'): + return + + try: + cron = self.pool['ir.model.data'].get_object( + cr, uid, 'fetchmail', 'ir_cron_mail_gateway_action', context=context) + except ValueError: + # Nevermind if default cron cannot be found + return + + # Enabled/Disable cron based on the number of 'done' server of type pop or imap + cron.toggle(model=self._name, domain=[('state','=','done'), ('type','in',['pop','imap'])]) def create(self, cr, uid, values, context=None): res = super(fetchmail_server, self).create(cr, uid, values, context=context) - self.cron_update(cr, uid, context=context) + self._update_cron(cr, uid, context=context) return res def write(self, cr, uid, ids, values, context=None): res = super(fetchmail_server, self).write(cr, uid, ids, values, context=context) - self.cron_update(cr, uid, context=context) + self._update_cron(cr, uid, context=context) + return res + + def unlink(self, cr, uid, ids, context=None): + res = super(fetchmail_server, self).unlink(cr, uid, ids, context=context) + self._update_cron(cr, uid, context=context) return res class mail_mail(osv.osv): diff --git a/openerp/addons/base/ir/ir_cron.py b/openerp/addons/base/ir/ir_cron.py index 8f85beb820c..029c2471f49 100644 --- a/openerp/addons/base/ir/ir_cron.py +++ b/openerp/addons/base/ir/ir_cron.py @@ -294,4 +294,20 @@ class ir_cron(osv.osv): res = super(ir_cron, self).unlink(cr, uid, ids, context=context) return res + def try_write(self, cr, uid, ids, values, context=None): + try: + with cr.savepoint(): + cr.execute("""SELECT id FROM "%s" WHERE id IN %%s FOR UPDATE NOWAIT""" % self._table, + (tuple(ids),), log_exceptions=False) + except psycopg2.OperationalError: + pass + else: + return super(ir_cron, self).write(cr, uid, ids, values, context=context) + return False + + def toggle(self, cr, uid, ids, model, domain, context=None): + active = bool(self.pool[model].search_count(cr, uid, domain, context=context)) + + return self.try_write(cr, uid, ids, {'active': active}, context=context) + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From c77c3f934cc609d85e1c97c4b55e214a3b01f3e5 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 2 Sep 2014 18:43:22 +0200 Subject: [PATCH 04/11] [FIX] account_payment: lin2bank correct fallback condition --- addons/account_payment/account_move_line.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account_payment/account_move_line.py b/addons/account_payment/account_move_line.py index 35c30c686e8..9cc300d2e4b 100644 --- a/addons/account_payment/account_move_line.py +++ b/addons/account_payment/account_move_line.py @@ -104,7 +104,7 @@ class account_move_line(osv.osv): if bank.state in bank_type: line2bank[line.id] = bank.id break - if line.id not in line2bank and line.partner_id.bank_ids: + if not line2bank.get(line.id) and line.partner_id.bank_ids: line2bank[line.id] = line.partner_id.bank_ids[0].id else: raise osv.except_osv(_('Error!'), _('There is no partner defined on the entry line.')) From c0d838ddb34dd5062f663dee9a5d96e7863e1332 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 2 Sep 2014 19:42:24 +0200 Subject: [PATCH 05/11] [IMP] web: extra comments to explain commit 57b4860 Added some cryptic comments so we remember a bit why we have a complicated dance with on_close. Basically we do not want to reload the original form view until the last popup is closed, in the case where several wizard (steps) are opened one after the other. --- addons/web/static/src/js/views.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index b59e86b2192..1fac5794679 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -375,18 +375,29 @@ instance.web.ActionManager = instance.web.Widget.extend({ if (executor.action.target === 'new') { var pre_dialog = this.dialog; if (pre_dialog){ + // prevent previous dialog to consider itself closed, + // right now, as we're opening a new one (prevents + // reload of original form view) pre_dialog.off('closing', null, pre_dialog.on_close); } if (this.dialog_widget && !this.dialog_widget.isDestroyed()) { this.dialog_widget.destroy(); } + // explicitly passing a closing action to dialog_stop() prevents + // it from reloading the original form view this.dialog_stop(executor.action); this.dialog = new instance.web.Dialog(this, { dialogClass: executor.klass, }); + + // chain on_close triggers with previous dialog, if any this.dialog.on_close = function(){ options.on_close.apply(null, arguments); if (pre_dialog && pre_dialog.on_close){ + // no parameter passed to on_close as this will + // only be called when the last dialog is truly + // closing, and *should* trigger a reload of the + // underlying form view (see comments above) pre_dialog.on_close(); } }; @@ -404,6 +415,9 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog.open(); return initialized; } else { + // explicitly passing a closing action to dialog_stop() prevents + // it from reloading the original form view - we're opening a + // completely new action anyway this.dialog_stop(executor.action); this.inner_action = executor.action; this.inner_widget = widget; From 00ea919699d0927604a21fdd5bc3974defad8317 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 3 Sep 2014 15:19:26 +0200 Subject: [PATCH 06/11] [FIX] payment_paypal: avoid json decode error with post.pop('custom', '{}'), if the key 'custom' is not there, it will return '{}', but if the key is there, but the value is equivalent to False, the json decode will fail. --- addons/payment_paypal/controllers/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/payment_paypal/controllers/main.py b/addons/payment_paypal/controllers/main.py index e07fa3d738f..94c8171da14 100644 --- a/addons/payment_paypal/controllers/main.py +++ b/addons/payment_paypal/controllers/main.py @@ -24,7 +24,7 @@ class PaypalController(http.Controller): """ Extract the return URL from the data coming from paypal. """ return_url = post.pop('return_url', '') if not return_url: - custom = json.loads(post.pop('custom', '{}')) + custom = json.loads(post.pop('custom', False) or '{}') return_url = custom.get('return_url', '/') return return_url From 73072272de8ab32b0fe199d54a90986dc02d1dbc Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 3 Sep 2014 18:25:19 +0200 Subject: [PATCH 07/11] [FIX] mrp: do not reset back stock moves to confirm For instance, setting a BOM Phantom with: Finished product: stockable, MTO Manufacture Components: stockable, MTS, Buy. Inventory set to 1000 Stock moves of components are directly set to assigned once the procurement confirmed thanks to JIT The stock moves should not be set back to confirmed after they have been assigned --- addons/mrp/stock.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/mrp/stock.py b/addons/mrp/stock.py index 60a50c90d1e..51c237672a0 100644 --- a/addons/mrp/stock.py +++ b/addons/mrp/stock.py @@ -160,9 +160,11 @@ class StockPicking(osv.osv): def action_explode(self, cr, uid, move_ids, *args): """Explodes moves by expanding kit components""" move_obj = self.pool.get('stock.move') - todo = move_ids[:] + todo = list(super(StockPicking, self).action_explode(cr, uid, move_ids, *args)) for move in move_obj.browse(cr, uid, move_ids): - todo.extend(move_obj._action_explode(cr, uid, move)) + result = move_obj._action_explode(cr, uid, move) + moves = move_obj.browse(cr, uid, result) + todo.extend(move.id for move in moves if move.state not in ['confirmed', 'assigned', 'done']) return list(set(todo)) StockPicking() From e1e928ef86d8dafde82538002a6799075cb69371 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 4 Sep 2014 10:17:18 +0200 Subject: [PATCH 08/11] [IMP] crm_partner_assign: remove inexistant onchange This field is readonly so a onchange is useless anyway (opw 612593) --- addons/crm_partner_assign/crm_portal_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/crm_partner_assign/crm_portal_view.xml b/addons/crm_partner_assign/crm_portal_view.xml index dab831dcb4b..3c0a2b6d140 100644 --- a/addons/crm_partner_assign/crm_portal_view.xml +++ b/addons/crm_partner_assign/crm_portal_view.xml @@ -114,7 +114,7 @@ From 5872c2485d8351b6e0569009b4828448fed69622 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 4 Sep 2014 12:28:16 +0200 Subject: [PATCH 09/11] [FIX] stock: on partial picking, do no open a new window action if not needed This is related to rev. dd4d72d Not opening a new window action allows to keep the current list of stock picking being threated, and to use the next an previous arrow of the forom view of the web client. --- addons/stock/wizard/stock_partial_picking.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/stock/wizard/stock_partial_picking.py b/addons/stock/wizard/stock_partial_picking.py index 7358855924d..6d41deeb85e 100644 --- a/addons/stock/wizard/stock_partial_picking.py +++ b/addons/stock/wizard/stock_partial_picking.py @@ -218,6 +218,8 @@ class stock_partial_picking(osv.osv_memory): # We don't need to find which view is required, stock.picking does it. done = stock_picking.do_partial( cr, uid, [partial.picking_id.id], partial_data, context=context) + if done[partial.picking_id.id]['delivered_picking'] == partial.picking_id.id: + return {'type': 'ir.actions.act_window_close'} return { 'type': 'ir.actions.act_window', 'res_model': context.get('active_model', 'stock.picking'), From cce70fd4c9e281245fceff5d9275770dfa30d29a Mon Sep 17 00:00:00 2001 From: Somesh Khare Date: Tue, 26 Aug 2014 11:55:23 +0530 Subject: [PATCH 10/11] [FIX] document: display Attachment(s) menu only on form view The attachment menu (list and add) has no effect in tree view (not supporting multi-items upload and display), the menu should then only be displayed in these view (opw 612534) --- addons/document/static/src/js/document.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/document/static/src/js/document.js b/addons/document/static/src/js/document.js index e4bce2da76e..5b353d5b0dd 100644 --- a/addons/document/static/src/js/document.js +++ b/addons/document/static/src/js/document.js @@ -3,8 +3,10 @@ openerp.document = function (instance) { instance.web.Sidebar.include({ init : function(){ this._super.apply(this, arguments); - this.sections.splice(1, 0, { 'name' : 'files', 'label' : _t('Attachment(s)'), }); - this.items['files'] = []; + if (this.getParent().view_type == "form"){ + this.sections.splice(1, 0, { 'name' : 'files', 'label' : _t('Attachment(s)'), }); + this.items['files'] = []; + } }, on_attachments_loaded: function(attachments) { //to display number in name if more then one attachment which has same name. From 59b76ee92701a28032822f6f3a45b7939255bb02 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 21 Aug 2014 18:25:49 +0530 Subject: [PATCH 11/11] [FIX] sale: keep page when confirming a sale order To keep the pager and view changer after confirmation of a sale order, do not reload the view (quotation and sale order view are the same anyway) Fixes #250 --- addons/sale/sale.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 264c2d9650f..1244cf09f5f 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -581,22 +581,8 @@ class sale_order(osv.osv): assert len(ids) == 1, 'This option should only be used for a single id at a time.' wf_service = netsvc.LocalService('workflow') wf_service.trg_validate(uid, 'sale.order', ids[0], 'order_confirm', cr) - - # redisplay the record as a sales order - view_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'sale', 'view_order_form') - view_id = view_ref and view_ref[1] or False, - return { - 'type': 'ir.actions.act_window', - 'name': _('Sales Order'), - 'res_model': 'sale.order', - 'res_id': ids[0], - 'view_type': 'form', - 'view_mode': 'form', - 'view_id': view_id, - 'target': 'current', - 'nodestroy': True, - } - + return True + def action_wait(self, cr, uid, ids, context=None): context = context or {} for o in self.browse(cr, uid, ids):