From 0bee015dd67cb809fd235215b43d331074824e42 Mon Sep 17 00:00:00 2001 From: Anael Closson Date: Wed, 18 Jun 2014 14:33:35 +0200 Subject: [PATCH 1/5] [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 2/5] [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 c77c3f934cc609d85e1c97c4b55e214a3b01f3e5 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 2 Sep 2014 18:43:22 +0200 Subject: [PATCH 3/5] [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 4/5] [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 73072272de8ab32b0fe199d54a90986dc02d1dbc Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 3 Sep 2014 18:25:19 +0200 Subject: [PATCH 5/5] [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()