From 79ebe1060d7a6303dbd5ff6e401aec5337161883 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 23 Oct 2014 17:14:19 +0200 Subject: [PATCH 01/16] [FIX] product: pricelist, uom and price_surcharge The price_surcharge attribute must be computed based on the reference unit of measure (divided by the factor). This is to make sure than 12 units and 1 dozen have the same price after pricelist computation (opw 599727). Added test checking the correctness of pricelist computation based on unit of measures. --- addons/product/pricelist.py | 7 ++- addons/product/tests/__init__.py | 3 +- addons/product/tests/test_pricelist.py | 70 ++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 addons/product/tests/test_pricelist.py diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index d4ed2567afc..0dd6b45acda 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -297,7 +297,12 @@ class product_pricelist(osv.osv): price = price * (1.0+(res['price_discount'] or 0.0)) if res['price_round']: price = tools.float_round(price, precision_rounding=res['price_round']) - price += (res['price_surcharge'] or 0.0) + if context.get('uom'): + # compute price_surcharge based on reference uom + factor = product_uom_obj.browse(cr, uid, context.get('uom'), context=context).factor + else: + factor = 1.0 + price += (res['price_surcharge'] or 0.0) / factor if res['price_min_margin']: price = max(price, price_limit+res['price_min_margin']) if res['price_max_margin']: diff --git a/addons/product/tests/__init__.py b/addons/product/tests/__init__.py index 850189ac0f4..4a1ce43351b 100644 --- a/addons/product/tests/__init__.py +++ b/addons/product/tests/__init__.py @@ -1,5 +1,6 @@ -from . import test_uom +from . import test_uom, test_pricelist fast_suite = [ test_uom, + test_pricelist ] diff --git a/addons/product/tests/test_pricelist.py b/addons/product/tests/test_pricelist.py new file mode 100644 index 00000000000..dd9130e1be5 --- /dev/null +++ b/addons/product/tests/test_pricelist.py @@ -0,0 +1,70 @@ +from openerp.tests.common import TransactionCase + +class TestPricelist(TransactionCase): + """Tests for unit of measure conversion""" + + def setUp(self): + super(TestPricelist, self).setUp() + cr, uid, context = self.cr, self.uid, {} + self.ir_model_data = self.registry('ir.model.data') + self.product_product = self.registry('product.product') + self.product_pricelist = self.registry('product.pricelist') + self.uom = self.registry('product.uom') + + self.usb_adapter_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_48')[1] + self.datacard_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_template_46')[1] + self.unit_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_uom_unit')[1] + self.dozen_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_uom_dozen')[1] + + self.public_pricelist_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'list0')[1] + self.sale_pricelist_id = self.product_pricelist.create(cr, uid, { + 'name': 'Sale pricelist', + 'type': 'sale', + 'version_id': [(0, 0, { + 'name': 'v1.0', + 'items_id': [(0, 0, { + 'name': 'Discount 10%', + 'base': 1, # based on public price + 'price_discount': -0.1, + 'product_id': self.usb_adapter_id + }), (0, 0, { + 'name': 'Discount -0.5', + 'base': 1, # based on public price + 'price_surcharge': -0.5, + 'product_id': self.datacard_id + })] + })] + }, context=context) + + def test_10_discount(self): + # Make sure the price using a pricelist is the same than without after + # applying the computation manually + cr, uid, context = self.cr, self.uid, {} + + public_context = dict(context, pricelist=self.public_pricelist_id) + pricelist_context = dict(context, pricelist=self.sale_pricelist_id) + + usb_adapter_without_pricelist = self.product_product.browse(cr, uid, self.usb_adapter_id, context=public_context) + usb_adapter_with_pricelist = self.product_product.browse(cr, uid, self.usb_adapter_id, context=pricelist_context) + self.assertEqual(usb_adapter_with_pricelist.price, usb_adapter_without_pricelist.price*0.9) + + datacard_without_pricelist = self.product_product.browse(cr, uid, self.datacard_id, context=public_context) + datacard_with_pricelist = self.product_product.browse(cr, uid, self.datacard_id, context=pricelist_context) + self.assertEqual(datacard_with_pricelist.price, datacard_without_pricelist.price-0.5) + + # Make sure that changing the unit of measure does not break the unit + # price (after converting) + unit_context = dict(context, + pricelist=self.sale_pricelist_id, + uom=self.unit_id) + dozen_context = dict(context, + pricelist=self.sale_pricelist_id, + uom=self.dozen_id) + + usb_adapter_unit = self.product_product.browse(cr, uid, self.usb_adapter_id, context=unit_context) + usb_adapter_dozen = self.product_product.browse(cr, uid, self.usb_adapter_id, context=dozen_context) + self.assertAlmostEqual(usb_adapter_unit.price*12, usb_adapter_dozen.price) + + datacard_unit = self.product_product.browse(cr, uid, self.datacard_id, context=unit_context) + datacard_dozen = self.product_product.browse(cr, uid, self.datacard_id, context=dozen_context) + self.assertAlmostEqual(datacard_unit.price*12, datacard_dozen.price) From 42bf0a567003168029508e0b501d6aef7876e41f Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 24 Oct 2014 16:07:55 +0200 Subject: [PATCH 02/16] [FIX] product_visible_discount: discount with different unit of measures The computation of the price without pricelist should take care of the unit of measure. e.g. if computing discount for objects in dozen (on a product with price in unit), returned unit price should be (price*12) where 12 is the factor to go from dozen to unit. Otherwise the compared prices (with and without pricelist) would not use the same unit of measure and the comparaison would be inconsistent. (opw 599727) --- addons/product_visible_discount/product_visible_discount.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/product_visible_discount/product_visible_discount.py b/addons/product_visible_discount/product_visible_discount.py index 595deba1983..f173e844b27 100644 --- a/addons/product_visible_discount/product_visible_discount.py +++ b/addons/product_visible_discount/product_visible_discount.py @@ -44,6 +44,7 @@ class sale_order_line(osv.osv): fiscal_position=False, flag=False, context=None): def get_real_price(res_dict, product_id, qty, uom, pricelist): + """Retrieve the price before applying the pricelist""" item_obj = self.pool.get('product.pricelist.item') price_type_obj = self.pool.get('product.price.type') product_obj = self.pool.get('product.product') @@ -60,9 +61,8 @@ class sale_order_line(osv.osv): factor = 1.0 if uom and uom != product.uom_id.id: - product_uom_obj = self.pool.get('product.uom') - uom_data = product_uom_obj.browse(cr, uid, product.uom_id.id) - factor = uom_data.factor + # the unit price is in a different uom + factor = self.pool['product.uom']._compute_qty(cr, uid, uom, 1.0, product.uom_id.id) return product_read[field_name] * factor From 8abd003ef0f1a59b57fbdd85f54b8aadad68bed2 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 27 Oct 2014 11:41:23 +0100 Subject: [PATCH 03/16] [FIX] product: reference in test --- addons/product/tests/test_pricelist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product/tests/test_pricelist.py b/addons/product/tests/test_pricelist.py index dd9130e1be5..4e61cb11b75 100644 --- a/addons/product/tests/test_pricelist.py +++ b/addons/product/tests/test_pricelist.py @@ -12,7 +12,7 @@ class TestPricelist(TransactionCase): self.uom = self.registry('product.uom') self.usb_adapter_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_48')[1] - self.datacard_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_template_46')[1] + self.datacard_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_46')[1] self.unit_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_uom_unit')[1] self.dozen_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_uom_dozen')[1] From d68d1d0434e870b7fed39665be2d8c33afe07eb6 Mon Sep 17 00:00:00 2001 From: Frederic van der Essen Date: Mon, 27 Oct 2014 12:28:47 +0100 Subject: [PATCH 04/16] [FIX] web: cors rpc calls were missing the session cookie, resulting in new sessions being created for every call --- addons/web/static/src/js/openerpframework.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/openerpframework.js b/addons/web/static/src/js/openerpframework.js index 5dcc2197944..34fe523753c 100644 --- a/addons/web/static/src/js/openerpframework.js +++ b/addons/web/static/src/js/openerpframework.js @@ -1018,11 +1018,11 @@ openerp.Session = openerp.Class.extend(openerp.PropertiesMixin, { }, check_session_id: function() { var self = this; - if (this.avoid_recursion || self.use_cors) + if (this.avoid_recursion) return $.when(); if (this.session_id) return $.when(); // we already have the session id - if (this.override_session || ! this.origin_server) { + if (!this.use_cors && (this.override_session || ! this.origin_server)) { // If we don't use the origin server we consider we should always create a new session. // Even if some browsers could support cookies when using jsonp that behavior is // not consistent and the browser creators are tending to removing that feature. From 0790682296e43989e4e232189009c3ba380e32ba Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Sat, 25 Oct 2014 14:26:52 +0200 Subject: [PATCH 05/16] [FIX] mail: read more show original message Instead of html cleaned html, to allow display blockquotes opw-614729 --- addons/mail/mail_message.py | 1 + addons/mail/static/src/js/mail.js | 12 +++++++++++- addons/mail/static/src/xml/mail.xml | 5 ++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 8ac047fb77e..be88fa9de60 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -373,6 +373,7 @@ class mail_message(osv.Model): 'type': message.type, 'subtype': message.subtype_id.name if message.subtype_id else False, 'body': body_html, + 'body_original': message.body if message.type == 'email' else None, 'model': message.model, 'res_id': message.res_id, 'record_name': message.record_name, diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 1f65058d4af..094a4f72de5 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -225,6 +225,7 @@ openerp.mail = function (session) { this.name = datasets.name || false, this.record_name = datasets.record_name || false, this.body = datasets.body || '', + this.body_original = datasets.body_original || '', this.vote_nb = datasets.vote_nb || 0, this.has_voted = datasets.has_voted || false, this.is_favorite = datasets.is_favorite || false, @@ -976,6 +977,7 @@ openerp.mail = function (session) { }, expender: function () { + var self = this; this.$('.oe_msg_body:first').expander({ slicePoint: this.options.truncate_limit, expandText: _t('read more'), @@ -983,7 +985,15 @@ openerp.mail = function (session) { detailClass: 'oe_msg_tail', moreClass: 'oe_mail_expand', lessClass: 'oe_mail_reduce', - }); + afterExpand: function(){ + self.$('.oe_msg_body').hide(); + self.$('.oe_msg_original').show(); + }, + onCollapse: function(){ + self.$('.oe_msg_body').show(); + self.$('.oe_msg_original').hide(); + }, + }); }, /** diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 1e52105c739..e57b9d7d7a2 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -257,7 +257,10 @@
- + +
+