[MERGE] Foward-port saas-5 up to ee4df1e
authorOlivier Dony <odo@openerp.com>
Fri, 1 Aug 2014 12:24:07 +0000 (14:24 +0200)
committerOlivier Dony <odo@openerp.com>
Fri, 1 Aug 2014 12:24:07 +0000 (14:24 +0200)
12 files changed:
addons/account/account_analytic_line.py
addons/account/account_invoice.py
addons/crm/base_partner_merge.py
addons/mail/mail_thread.py
addons/mass_mailing/controllers/main.py
addons/mass_mailing/models/mass_mailing.py
addons/web/static/src/js/chrome.js
addons/web/static/src/js/core.js
addons/web/static/src/js/view_form.js
addons/web/static/src/xml/base.xml
addons/website_customer/controllers/main.py
openerp/models.py

index d5ec349..0c122b2 100644 (file)
@@ -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:
index bf9db60..e509b7e 100644 (file)
@@ -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),
index 0331170..9749e7a 100644 (file)
@@ -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)
index 82b048b..9125b77 100644 (file)
@@ -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'))
index 5eed0e3..bfe9750 100644 (file)
@@ -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
index 5844bcf..ae1a334 100644 (file)
@@ -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):
index b0e22f9..c2b0af4 100644 (file)
@@ -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');
             }
index 23645e2..47e2a30 100644 (file)
@@ -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
index 5767ffe..66e5005 100644 (file)
@@ -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)) {
index d77b8d3..2aeed9e 100644 (file)
@@ -40,7 +40,7 @@
                     <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
                     <h3 class="modal-title"><t t-raw="title"/></h3>
                 </div>
-                <div class="modal-body" style="overflow-y: auto;">
+                <div class="modal-body">
                 </div>
             </div>
         </div>
index fcb2d0d..d4b996a 100644 (file)
@@ -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, {
index 8c86f2e..6a6f232 100644 (file)
@@ -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()