diff --git a/addons/account/account_analytic_line.py b/addons/account/account_analytic_line.py index d5ec3496d92..0c122b2c925 100644 --- a/addons/account/account_analytic_line.py +++ b/addons/account/account_analytic_line.py @@ -74,13 +74,19 @@ 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 = 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': - unit = prod.uom_po_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 if not a: diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index bf9db602997..e509b7e9aa2 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -379,7 +379,7 @@ class account_invoice(models.Model): assert len(self) == 1, 'This option should only be used for a single id at a time.' template = self.env.ref('account.email_template_edi_invoice', False) compose_form = self.env.ref('mail.email_compose_message_wizard_form', False) - ctx = dict(self._context, + ctx = dict( default_model='account.invoice', default_res_id=self.id, default_use_template=bool(template), diff --git a/addons/crm/base_partner_merge.py b/addons/crm/base_partner_merge.py index 03311704613..9749e7ae884 100644 --- a/addons/crm/base_partner_merge.py +++ b/addons/crm/base_partner_merge.py @@ -377,11 +377,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) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 82b048b7e57..9125b775e49 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -935,7 +935,7 @@ class mail_thread(osv.AbstractModel): # 1. message is a reply to an existing message (exact match of message_id) ref_match = thread_references and tools.reference_re.search(thread_references) - 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 ref_match and mail_message_ids: original_msg = mail_msg_obj.browse(cr, SUPERUSER_ID, mail_message_ids[0], context=context) @@ -978,7 +978,7 @@ class mail_thread(osv.AbstractModel): email_from, email_to, message_id, model, thread_id, custom_values, uid) return [route] - # 2. Reply to a private message + # 3. Reply to a private message if in_reply_to: mail_message_ids = mail_msg_obj.search(cr, uid, [ ('message_id', '=', in_reply_to), @@ -995,7 +995,7 @@ class mail_thread(osv.AbstractModel): email_from, email_to, message_id, mail_message.id, custom_values, uid) return [route] - # 3. Look for a matching mail.alias entry + # 4. Look for a matching mail.alias entry # Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values # for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value. rcpt_tos = \ @@ -1030,7 +1030,7 @@ class mail_thread(osv.AbstractModel): routes.append(route) return routes - # 4. Fallback to the provided parameters, if they work + # 5. Fallback to the provided parameters, if they work if not thread_id: # Legacy: fallback to matching [ID] in the Subject match = tools.res_re.search(decode_header(message, 'Subject')) diff --git a/addons/mass_mailing/controllers/main.py b/addons/mass_mailing/controllers/main.py index 5eed0e38615..bfe975059c5 100644 --- a/addons/mass_mailing/controllers/main.py +++ b/addons/mass_mailing/controllers/main.py @@ -67,8 +67,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: - contact_ng = Contacts.name_create(cr, SUPERUSER_ID, email, context=context) - Contacts.write(cr, SUPERUSER_ID, [contact_ng[0]], {'list_id': int(list_id)}, 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 5844bcf4316..ae1a334f698 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): diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index b0e22f918c8..c2b0af4737a 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; @@ -1156,7 +1157,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 5767ffe5489..66e500507d9 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -1835,7 +1835,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)) { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index d77b8d3df46..2aeed9e6017 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -40,7 +40,7 @@ - diff --git a/addons/website_customer/controllers/main.py b/addons/website_customer/controllers/main.py index fcb2d0d8ded..d4b996a0ab6 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, { diff --git a/openerp/models.py b/openerp/models.py index 8c86f2ef339..6a6f232eb6c 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -4447,18 +4447,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()