From 939076737673f67bad81c5ca886404e87dbaf3d4 Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Thu, 31 Jul 2014 14:43:42 +0200 Subject: [PATCH 01/10] [FIX] website_customer: check that country id exists before access the name, else traceback when we come from a non existing id via the url/controller --- addons/website_customer/controllers/main.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/addons/website_customer/controllers/main.py b/addons/website_customer/controllers/main.py index 810faf8bdf6..1c316bf0847 100644 --- a/addons/website_customer/controllers/main.py +++ b/addons/website_customer/controllers/main.py @@ -42,11 +42,12 @@ class WebsiteCustomer(http.Controller): if country_id: domain += [('country_id', '=', country_id)] if not any(x['country_id'][0] == country_id for x in countries): - country = country_obj.browse(cr, uid, country_id, context) - countries.append({ - 'country_id_count': 0, - 'country_id': (country_id, country.name) - }) + country = country_obj.read(cr, uid, country_id, ['name'], context) + if country: + countries.append({ + 'country_id_count': 0, + 'country_id': (country_id, country['name']) + }) countries.sort(key=lambda d: d['country_id'][1]) countries.insert(0, { From 5ddc0305cd0bef77632ee50fb19ae7372ae5cb68 Mon Sep 17 00:00:00 2001 From: Cedric Snauwaert Date: Mon, 28 Jul 2014 17:07:47 +0200 Subject: [PATCH 02/10] [FIX] web: fix tooltip that were stuck visible tooltip stuck visible should be removed on click + remove tooltip container except for modal in order to prevent them for staying visible in some rare occasion --- addons/web/static/src/js/chrome.js | 3 ++- addons/web/static/src/js/core.js | 14 +++++++++++++- addons/web/static/src/js/view_form.js | 1 - 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index cd22f10fb02..4dd5e9ed027 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -115,6 +115,7 @@ instance.web.Dialog = instance.web.Widget.extend({ this.init_dialog(); } this.$buttons.insertAfter(this.$dialog_box.find(".modal-body")); + $('.tooltip').remove(); //remove open tooltip if any to prevent them staying when modal is opened //add to list of currently opened modal opened_modal.push(this.$dialog_box); return this; @@ -1121,7 +1122,7 @@ instance.web.Client = instance.web.Widget.extend({ }, 0); }); instance.web.bus.on('click', this, function(ev) { - $.fn.tooltip('destroy'); + $('.tooltip').remove(); if (!$(ev.target).is('input[type=file]')) { self.$el.find('.oe_dropdown_menu.oe_opened, .oe_dropdown_toggle.oe_opened').removeClass('oe_opened'); } diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index 23645e22bf1..47e2a30a3d5 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -772,7 +772,7 @@ instance.web.unblockUI = function() { /* Bootstrap defaults overwrite */ $.fn.tooltip.Constructor.DEFAULTS.placement = 'auto top'; $.fn.tooltip.Constructor.DEFAULTS.html = true; -$.fn.tooltip.Constructor.DEFAULTS.container = 'body'; +$.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover focus click'; //overwrite bootstrap tooltip method to prevent showing 2 tooltip at the same time var bootstrap_show_function = $.fn.tooltip.Constructor.prototype.show; $.fn.tooltip.Constructor.prototype.show = function () { @@ -786,6 +786,18 @@ $.fn.tooltip.Constructor.prototype.show = function () { if (e.isDefaultPrevented() || !inDom) return; return bootstrap_show_function.call(this); }; +//overwrite bootstrap tooltip init method in order to check if tooltip is in a modal or not and +//if so it needs to have a container body in order to be visible +var bootstrap_init_tooltip_fnct = $.fn.tooltip.Constructor.prototype.init; +$.fn.tooltip.Constructor.prototype.init = function (type, element, options) { + options = options || {} + if ($('.modal[aria-hidden="false"]').length !== 0){ + if (options && !options.container){ + options = _.extend({container: 'body'},options); + } + } + return bootstrap_init_tooltip_fnct.call(this, type, element, options); +} /** * Registry for all the client actions key: tag value: widget diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 15a2aaad37b..5dc160f78f5 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -1871,7 +1871,6 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi trigger = trigger || this.$el; options = _.extend({ delay: { show: 500, hide: 0 }, - trigger: 'hover', title: function() { var template = widget.template + '.tooltip'; if (!QWeb.has_template(template)) { From cd31cbf556cc11950ce6188041cf5c2fcd89e0f8 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 31 Jul 2014 18:05:17 +0200 Subject: [PATCH 03/10] [FIX] account: on_change_unit_amount do not reset uom to default --- addons/account/account_analytic_line.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/addons/account/account_analytic_line.py b/addons/account/account_analytic_line.py index f3617106f28..077a4090769 100644 --- a/addons/account/account_analytic_line.py +++ b/addons/account/account_analytic_line.py @@ -74,13 +74,17 @@ class account_analytic_line(osv.osv): product_obj = self.pool.get('product.product') analytic_journal_obj =self.pool.get('account.analytic.journal') product_price_type_obj = self.pool.get('product.price.type') + product_uom_obj = self.pool.get('product.uom') j_id = analytic_journal_obj.browse(cr, uid, journal_id, context=context) prod = product_obj.browse(cr, uid, prod_id, context=context) result = 0.0 if prod_id: - unit = prod.uom_id.id + unit_obj = product_uom_obj.browse(cr, uid, unit, context=context) + if prod.uom_id.category_id.id != unit_obj.category_id.id: + unit = prod.uom_id.id if j_id.type == 'purchase': - unit = prod.uom_po_id.id + if prod.uom_po_id.category_id.id != unit_obj.category_id.id: + unit = prod.uom_po_id.id if j_id.type <> 'sale': a = prod.property_account_expense.id if not a: From 7c5bf67a5f9378fe4ae01eeffff24889f7bdcdc5 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 31 Jul 2014 18:15:41 +0200 Subject: [PATCH 04/10] [FIX] account: unit arg of on_change_unit_amount can be False --- addons/account/account_analytic_line.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/addons/account/account_analytic_line.py b/addons/account/account_analytic_line.py index 077a4090769..e620359959c 100644 --- a/addons/account/account_analytic_line.py +++ b/addons/account/account_analytic_line.py @@ -79,11 +79,13 @@ class account_analytic_line(osv.osv): prod = product_obj.browse(cr, uid, prod_id, context=context) result = 0.0 if prod_id: - unit_obj = product_uom_obj.browse(cr, uid, unit, context=context) - if prod.uom_id.category_id.id != unit_obj.category_id.id: + unit_obj = False + if unit: + unit_obj = product_uom_obj.browse(cr, uid, unit, context=context) + if not unit_obj or prod.uom_id.category_id.id != unit_obj.category_id.id: unit = prod.uom_id.id if j_id.type == 'purchase': - if prod.uom_po_id.category_id.id != unit_obj.category_id.id: + if not unit_obj or prod.uom_po_id.category_id.id != unit_obj.category_id.id: unit = prod.uom_po_id.id if j_id.type <> 'sale': a = prod.property_account_expense.id From 2d17c18c7dda7fce75b0fc2c9e4c4954151151de Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 31 Jul 2014 19:38:00 +0200 Subject: [PATCH 05/10] [FIX] crm: base_partner_merge, search with lowercase for name,email and without spaces for vat --- addons/crm/base_partner_merge.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/addons/crm/base_partner_merge.py b/addons/crm/base_partner_merge.py index c07a32579f0..11cacc57ce6 100644 --- a/addons/crm/base_partner_merge.py +++ b/addons/crm/base_partner_merge.py @@ -378,11 +378,20 @@ class MergePartnerAutomatic(osv.TransientModel): return {'type': 'ir.actions.act_window_close'} def _generate_query(self, fields, maximum_group=100): - group_fields = ', '.join(fields) + sql_fields = [] + for field in fields: + if field in ['email', 'name']: + sql_fields.append('lower(%s)' % field) + elif field in ['vat']: + sql_fields.append("replace(%s, ' ', '')" % field) + else: + sql_fields.append(field) + + group_fields = ', '.join(sql_fields) filters = [] for field in fields: - if field in ['email', 'name']: + if field in ['email', 'name', 'vat']: filters.append((field, 'IS NOT', 'NULL')) criteria = ' AND '.join('%s %s %s' % (field, operator, value) From f247bdd0b66d3d467de21ed1b966713c42c886aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Closson?= Date: Fri, 20 Jun 2014 13:13:23 +0200 Subject: [PATCH 06/10] [FIX] mail: message-id not parsed properly in message_route Same as for rev 4bad513, the references were not correctly parsed, added missing regex --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 279294d49ff..213463340f3 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -859,7 +859,7 @@ class mail_thread(osv.AbstractModel): thread_references = references or in_reply_to # 1. message is a reply to an existing message (exact match of message_id) - msg_references = thread_references.split() + msg_references = mail_header_msgid_re.findall(thread_references) mail_message_ids = mail_msg_obj.search(cr, uid, [('message_id', 'in', msg_references)], context=context) if mail_message_ids: original_msg = mail_msg_obj.browse(cr, SUPERUSER_ID, mail_message_ids[0], context=context) From a9bce700dc5f566df69e393c9e0ab4641e5ee0c3 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 1 Aug 2014 10:05:56 +0200 Subject: [PATCH 07/10] [FIX] account: avoid to propagate context in send by email button There is no reason to propagate the context in those buttons. Besides, it leads to issues concerning the email template, rendering the wrong res_id because the active_id was wrongly propagated --- addons/account/account_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index d0dc2ec8b42..8b5f15ff04c 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -426,7 +426,7 @@ class account_invoice(osv.osv): compose_form_id = ir_model_data.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form')[1] except ValueError: compose_form_id = False - ctx = dict(context) + ctx = dict() ctx.update({ 'default_model': 'account.invoice', 'default_res_id': ids[0], From cc9205d1d1a75b10452d9f339ea7ad47103bdb9e Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Fri, 1 Aug 2014 11:25:41 +0200 Subject: [PATCH 08/10] [FIX] mass_mailing: allow to add a user/email to a specific mailing list and not always the last as previously. --- addons/mass_mailing/controllers/main.py | 2 +- addons/mass_mailing/models/mass_mailing.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/addons/mass_mailing/controllers/main.py b/addons/mass_mailing/controllers/main.py index 935b51c612c..666a7bb46e4 100644 --- a/addons/mass_mailing/controllers/main.py +++ b/addons/mass_mailing/controllers/main.py @@ -68,7 +68,7 @@ class MassMailController(http.Controller): contact_ids = Contacts.search(cr, SUPERUSER_ID, [('list_id', '=', int(list_id)), ('email', '=', email)], context=context) if not contact_ids: - Contacts.name_create(cr, SUPERUSER_ID, email, context=context) + Contacts.add_to_list(cr, SUPERUSER_ID, email, int(list_id), context=context) # add email to session request.session['mass_mailing_email'] = email return True diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index eafab5272bd..c2d75880065 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -52,15 +52,24 @@ class MassMailingContact(osv.Model): 'list_id': _get_latest_list } - def name_create(self, cr, uid, name, context=None): + def get_name_email(self, name, context): name, email = self.pool['res.partner']._parse_partner_name(name, context=context) if name and not email: email = name if email and not name: name = email + return name, email + + def name_create(self, cr, uid, name, context=None): + name, email = self.get_name_email(name, context=context) rec_id = self.create(cr, uid, {'name': name, 'email': email}, context=context) return self.name_get(cr, uid, [rec_id], context)[0] + def add_to_list(self, cr, uid, name, list_id, context=None): + name, email = self.get_name_email(name, context=context) + rec_id = self.create(cr, uid, {'name': name, 'email': email, 'list_id': list_id}, context=context) + return self.name_get(cr, uid, [rec_id], context)[0] + def message_get_default_recipients(self, cr, uid, ids, context=None): res = {} for record in self.browse(cr, uid, ids, context=context): From 29cdfc62a79db6b1ef1806369cd5c52f6c8a65f4 Mon Sep 17 00:00:00 2001 From: Cedric Snauwaert Date: Thu, 31 Jul 2014 16:09:50 +0200 Subject: [PATCH 09/10] [FIX] web: remove unneeded overflow-y on modal-body class Will fix problem where opened dropdown list were hidden behind the modal footer --- addons/web/static/src/xml/base.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 6017dcf2e50..864353ab891 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -40,7 +40,7 @@ - From e79a3675d13eacfd3d38e9725bbb354c778f0252 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 1 Aug 2014 12:34:41 +0200 Subject: [PATCH 10/10] [FIX] orm.search_count: ignore `limit`, `offset` and most importantly `order` These parameters are (or should be) irrelevant for a search_count(), and they could actually break the result or make it significantly slower (e.g applying `order` on large tables). This fixes a performance regression introduced by 0f43032b. We could also raise an error offset/limit are passed in combination with count, but that seems unnecessary. Also switched to "SELECT count(1)" for the count query, as it is simpler and just as fast. We'd get the same perf with * or any constant value, as in "SELECT count('me in')", but let's keep it simple ;-) --- openerp/osv/orm.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 79d6d213939..808276c4639 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -4606,18 +4606,19 @@ class BaseModel(object): order_by = self._generate_order_by(order, query) from_clause, where_clause, where_clause_params = query.get_sql() - limit_str = limit and ' limit %d' % limit or '' - offset_str = offset and ' offset %d' % offset or '' where_str = where_clause and (" WHERE %s" % where_clause) or '' - query_str = 'SELECT "%s".id FROM ' % self._table + from_clause + where_str + order_by + limit_str + offset_str if count: - # /!\ the main query must be executed as a subquery, otherwise - # offset and limit apply to the result of count()! - cr.execute('SELECT count(*) FROM (%s) AS count' % query_str, where_clause_params) + # Ignore order, limit and offset when just counting, they don't make sense and could + # hurt performance + query_str = 'SELECT count(1) FROM ' + from_clause + where_str + cr.execute(query_str, where_clause_params) res = cr.fetchone() return res[0] + limit_str = limit and ' limit %d' % limit or '' + offset_str = offset and ' offset %d' % offset or '' + query_str = 'SELECT "%s".id FROM ' % self._table + from_clause + where_str + order_by + limit_str + offset_str cr.execute(query_str, where_clause_params) res = cr.fetchall()