From 789cca58d634dbef096de4c2e0939b6824040d1d Mon Sep 17 00:00:00 2001 From: Jerther Date: Tue, 30 May 2017 16:53:26 -0400 Subject: [PATCH 01/13] [FIX] calendar: do not modify original channels list. Patch similar to d7b7b07. Closes #17318. --- addons/calendar/controllers/bus.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/calendar/controllers/bus.py b/addons/calendar/controllers/bus.py index 90203db4463..4ed07ebba9e 100644 --- a/addons/calendar/controllers/bus.py +++ b/addons/calendar/controllers/bus.py @@ -10,5 +10,6 @@ class CalendarBusController(BusController): # -------------------------- def _poll(self, dbname, channels, last, options): if request.session.uid: + channels = list(channels) channels.append((request.db, 'calendar.alarm', request.env.user.partner_id.id)) return super(CalendarBusController, self)._poll(dbname, channels, last, options) From 6e8516f9bf8186abe8df89211e07ee49379e1b5f Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Wed, 31 May 2017 17:23:15 +0200 Subject: [PATCH 02/13] [FIX] product: typo in search view --- addons/product/views/product_views.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product/views/product_views.xml b/addons/product/views/product_views.xml index da9cd96793c..517b9c3d26a 100644 --- a/addons/product/views/product_views.xml +++ b/addons/product/views/product_views.xml @@ -102,7 +102,7 @@ - + From c444b5a2935b6a025aff607e55f3469c58c1e2da Mon Sep 17 00:00:00 2001 From: Wolfgang Taferner Date: Tue, 30 May 2017 15:49:41 +0200 Subject: [PATCH 03/13] [FIX] google_account: fix google request exception management Error thrown by google request is an urllib2.HTTPError that can be read and loaded in JSON. However in some cases the result of the read may be void or not JSON-ready. This was causing a crash in the error management and hid the actual issue. This commit tries to read and JSON-load the error but fall back on simply displaying the raw error in case of issue when handling it. Closes #17308 . --- addons/google_account/models/google_service.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/google_account/models/google_service.py b/addons/google_account/models/google_service.py index d707ee8d188..4c9ee092104 100644 --- a/addons/google_account/models/google_service.py +++ b/addons/google_account/models/google_service.py @@ -139,7 +139,11 @@ class GoogleService(models.TransientModel): if error.code == 400: # invalid grant with registry(request.session.db).cursor() as cur: self.env(cur)['res.users'].browse(self.env.uid).write({'google_%s_rtoken' % service: False}) - error_key = json.loads(error.read()).get("error", "nc") + try: + error_file = error.read() + error_key = json.loads(error_file).get("error", "nc") + except: + error_key = error _logger.exception("Bad google request : %s !", error_key) error_msg = _("Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired [%s]") % error_key raise self.env['res.config.settings'].get_config_warning(error_msg) From 8184bb3dff06bb90560519aec312f58d92135ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 24 May 2017 10:59:21 +0200 Subject: [PATCH 04/13] [FIX] website_portal_sale: fix access rights issues when viewing quotes Portal users do not have access on invoices or invoice lines. However when viewing an online quotation in website_portal_sale some computation is performed based on invoices and invoice lines. We therefore iterate on invoice and invoice lines as superuser as we do not want to grant any additional access on those models for portal users. --- addons/website_portal_sale/controllers/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/website_portal_sale/controllers/main.py b/addons/website_portal_sale/controllers/main.py index 1b03ba6620d..33eb43a3c72 100644 --- a/addons/website_portal_sale/controllers/main.py +++ b/addons/website_portal_sale/controllers/main.py @@ -125,9 +125,12 @@ class website_account(website_account): order.check_access_rule('read') except AccessError: return request.render("website.403") - order_invoice_lines = {il.product_id.id: il.invoice_id for il in order.invoice_ids.mapped('invoice_line_ids')} + + order_sudo = order.sudo() + order_invoice_lines = {il.product_id.id: il.invoice_id for il in order_sudo.invoice_ids.mapped('invoice_line_ids')} + return request.render("website_portal_sale.orders_followup", { - 'order': order.sudo(), + 'order': order_sudo, 'order_invoice_lines': order_invoice_lines, }) From 6dc6b148efbe679948f4601c1b1fe29d26c5344f Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 1 Jun 2017 15:18:25 +0200 Subject: [PATCH 05/13] [FIX] service: No context in function tr The context is not in the kwargs when the integrity error is raised from a rpc request. So the user lang was lost and the sql error message was not translated. The part treating the callable message in sql error is depracated. opw:743259 --- odoo/service/model.py | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/odoo/service/model.py b/odoo/service/model.py index 1db02c3c09d..244f57fdfb0 100644 --- a/odoo/service/model.py +++ b/odoo/service/model.py @@ -57,10 +57,15 @@ def check(f): elif isinstance(kwargs, dict): if 'context' in kwargs: ctx = kwargs['context'] - elif 'kwargs' in kwargs: + elif 'kwargs' in kwargs and kwargs['kwargs'].get('context'): # http entry points such as call_kw() ctx = kwargs['kwargs'].get('context') - + else: + try: + from odoo.http import request + ctx = request.env.context + except Exception: + pass uid = 1 if args and isinstance(args[0], (long, int)): @@ -74,29 +79,6 @@ def check(f): # queries (as in IntegrityError) will invalidate the current one. cr = False - if hasattr(src, '__call__'): - # callable. We need to find the right parameters to call - # the orm._sql_message(self, cr, uid, ids, context) function, - # or we skip.. - # our signature is f(registry, dbname [,uid, obj, method, args]) - try: - if args and len(args) > 1: - # TODO self doesn't exist, but was already wrong before (it was not a registry but just the object_service. - obj = self.get(args[1]) - if len(args) > 3 and isinstance(args[3], (long, int, list)): - ids = args[3] - else: - ids = [] - cr = odoo.sql_db.db_connect(dbname).cursor() - return src(obj, cr, uid, ids, context=(ctx or {})) - except Exception: - pass - finally: - if cr: cr.close() - - return False # so that the original SQL error will - # be returned, it is the best we have. - try: cr = odoo.sql_db.db_connect(dbname).cursor() res = translate(cr, name=False, source_type=ttype, From dbdbfa74321e74353e969591b2dbacae73854ec4 Mon Sep 17 00:00:00 2001 From: Dharmraj Jhala Date: Fri, 3 Mar 2017 15:52:55 +0530 Subject: [PATCH 06/13] [FIX] website: properly rebind background events In carousel snippet, the target element for background snippet option is being changed manually. So for the new target, we have to rebind the associated events that were bound in `start` function of the snippet option. For that, some code is extracted from the `start` function and is used to rebind necessary events for new targets. In particular, this was preventing the carousel slides' backgrounds to be automatically removed when a background-color was selected. --- .../web_editor/static/src/js/snippets.options.js | 15 +++++++++------ .../static/src/js/website.snippets.editor.js | 3 +++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/addons/web_editor/static/src/js/snippets.options.js b/addons/web_editor/static/src/js/snippets.options.js index 4d533cadd00..1444f404ff6 100644 --- a/addons/web_editor/static/src/js/snippets.options.js +++ b/addons/web_editor/static/src/js/snippets.options.js @@ -576,15 +576,18 @@ odoo.define('web_editor.snippets.options', function (require) { registry.background = SnippetOption.extend({ start: function () { var res = this._super.apply(this, arguments); - this.$target.off(".background-option") - .on("background-color-event.background-option", (function (e, type) { - e.stopPropagation(); - if (e.currentTarget !== e.target) return; - this.$el.find("li:first > a").trigger(type); - }).bind(this)); + this.bind_bg_events(); return res; }, + bind_bg_events: function () { + this.$target.off(".background-option") + .on("background-color-event.background-option", (function (e, type) { + e.stopPropagation(); + if (e.currentTarget !== e.target) return; + this.$el.find("li:first > a").trigger(type); + }).bind(this)); + }, background: function (type, value, $li) { if (value && value.length) { this.$target.css("background-image", "url(" + value + ")"); diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js index 3bb1541b0bf..ff41acfc677 100644 --- a/addons/website/static/src/js/website.snippets.editor.js +++ b/addons/website/static/src/js/website.snippets.editor.js @@ -228,6 +228,9 @@ options.registry.carousel = options.registry.slider.extend({ s_option.$target = self.$target.find(".item.active"); s_option.set_active(); s_option.$target.trigger("snippet-option-change", [s_option]); + if (opt_name === 'background') { + s_option.bind_bg_events(); + } }); }); this.$target.trigger('slid.bs.carousel'); From 79477b8d96be47cca5609ce5e4dd84a7e7f64f0a Mon Sep 17 00:00:00 2001 From: Kishan Gajjar Date: Tue, 28 Feb 2017 17:55:05 +0530 Subject: [PATCH 07/13] [FIX] web_editor: hide customize menu when there are no options --- addons/web_editor/static/src/js/snippets.editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js index 993a541e199..91269285235 100644 --- a/addons/web_editor/static/src/js/snippets.editor.js +++ b/addons/web_editor/static/src/js/snippets.editor.js @@ -1118,7 +1118,7 @@ data.Editor = Class.extend({ }).bind(this)); // Activate the overlay - $style_button.toggleClass("hidden", $ul.children(":not(.divider):not(.hidden)").length === 0); + $style_button.toggleClass("hidden", $ul.children(":not(.o_main_header):not(.divider):not(.hidden)").length === 0); this.$overlay.toggleClass("oe_active", !!focus); function _do_action_focus(style, $dest) { From b5aeaa910d5c893c5db0189816b83420c92df4a3 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Thu, 1 Jun 2017 16:04:24 +0200 Subject: [PATCH 08/13] [FIX] website_forum: archived forum -> no ask An archived forum could still be posted in, something better should be done in the next version (eg. website published present on a lot of record type) but as of 10.0 just this improvement is done. opw-745510 closes #17365 --- addons/website_forum/controllers/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index 2294daf73de..19ec7e2713f 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -152,7 +152,7 @@ class WebsiteForum(http.Controller): question_ids = Post.search(domain, limit=self._post_per_page, offset=pager['offset'], order=sorting) - values = self._prepare_forum_values(forum=forum, searches=post) + values = self._prepare_forum_values(forum=forum, searches=post, header={'ask_hide': not forum.active}) values.update({ 'main_object': tag or forum, 'question_ids': question_ids, From 844d609cc9a5575d504cc4928ec3e38403d3ec58 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Fri, 2 Jun 2017 11:41:04 +0200 Subject: [PATCH 09/13] [FIX] web_tour: hide tooltips on printing opw-745872 --- addons/web_tour/static/src/less/tip.less | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/web_tour/static/src/less/tip.less b/addons/web_tour/static/src/less/tip.less index 8f994e64ee7..b2679e886c8 100644 --- a/addons/web_tour/static/src/less/tip.less +++ b/addons/web_tour/static/src/less/tip.less @@ -238,3 +238,9 @@ } } } + +@media print { + .o_tooltip { + display: none; + } +} From 7cc8420ea0cbd4de367bd36ab8c778fe51e38d96 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Fri, 2 Jun 2017 11:17:38 +0200 Subject: [PATCH 10/13] [FIX] product_extended: workcenter cost - Create a work center with a capacity of 1, an efficiency factor of 100% and a cost per hour of 40$ - Create a routing with two operations: one with a fixed duration of 30:00 minutes (OP1) and another with a duration computed on real time but with a default of 30:00 minutes (OP2) - Create a component with UOM "m" and a cost of 10$ - Create a finished product with an associated BoM - The BoM has a first line with 0.8m of component in the OP1 and a second line with 0.4m of component in the OP2 - Activate the Compute from BoM option on the finished product - The proposed cost is 32$ Expected cost: 52$ (30 minutes @40$/hour + 30 minutes @40$/hour + 1,2m @10$/m) We divide the WC cost by the number of operations, which does not make sense. opw-741032 --- addons/product_extended/models/product.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/product_extended/models/product.py b/addons/product_extended/models/product.py index 11a7bdc07ef..e2cf9ff3684 100644 --- a/addons/product_extended/models/product.py +++ b/addons/product_extended/models/product.py @@ -35,7 +35,6 @@ class ProductProduct(models.Model): def _calc_price(self, bom): price = 0.0 - workcenter_cost = 0.0 result, result2 = bom.explode(self, 1) for sbom, sbom_data in result2: if not sbom.attribute_value_ids: @@ -45,8 +44,7 @@ class ProductProduct(models.Model): total_cost = 0.0 for order in bom.routing_id.operation_ids: total_cost += (order.time_cycle_manual/60) * order.workcenter_id.costs_hour - workcenter_cost = total_cost / len(bom.routing_id.operation_ids) - price += bom.product_uom_id._compute_price(workcenter_cost, bom.product_id.uom_id) + price += bom.product_uom_id._compute_price(total_cost, bom.product_id.uom_id) # Convert on product UoM quantities if price > 0: price = bom.product_uom_id._compute_price(price / bom.product_qty, self.uom_id) From 46c85b4a821a7b9d62ec9ab81bd9e1450fcd5fce Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Fri, 2 Jun 2017 11:21:44 +0200 Subject: [PATCH 11/13] [FIX] product_extended: time cycle Use the field `time_cycle` for cost computation, which takes into account the routing configuration (fixed time of computed based on previous operations). --- addons/product_extended/models/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product_extended/models/product.py b/addons/product_extended/models/product.py index e2cf9ff3684..f0f886b66d4 100644 --- a/addons/product_extended/models/product.py +++ b/addons/product_extended/models/product.py @@ -43,7 +43,7 @@ class ProductProduct(models.Model): if bom.routing_id: total_cost = 0.0 for order in bom.routing_id.operation_ids: - total_cost += (order.time_cycle_manual/60) * order.workcenter_id.costs_hour + total_cost += (order.time_cycle/60) * order.workcenter_id.costs_hour price += bom.product_uom_id._compute_price(total_cost, bom.product_id.uom_id) # Convert on product UoM quantities if price > 0: From 380f59bd16254178881618bc5fb5b9f1bca0f2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Fri, 26 May 2017 17:37:31 +0300 Subject: [PATCH 12/13] [FIX] website_sale: filter products by attributes The attribute filters based on all products matching current domain was limited to the first page of result only. If all the products of the current page had no variant, no filter was displayed. Closes #17361 --- addons/website_sale/controllers/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index fd660dc61a5..fe963bc5b7e 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -235,7 +235,9 @@ class WebsiteSale(http.Controller): ProductAttribute = request.env['product.attribute'] if products: - attributes = ProductAttribute.search([('attribute_line_ids.product_tmpl_id', 'in', products.ids)]) + # get all products without limit + selected_products = Product.search(domain, limit=False) + attributes = ProductAttribute.search([('attribute_line_ids.product_tmpl_id', 'in', selected_products.ids)]) else: attributes = ProductAttribute.browse(attributes_ids) From 76cd8d2558d2a1fc11681dbc4a134ba06fb698c0 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 2 Jun 2017 22:13:36 +0200 Subject: [PATCH 13/13] [FIX] tools: verify path before opening --- odoo/tools/misc.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py index 36061213003..c54af653a00 100644 --- a/odoo/tools/misc.py +++ b/odoo/tools/misc.py @@ -196,7 +196,16 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): def _fileopen(path, mode, basedir, pathinfo, basename=None): - name = os.path.normpath(os.path.join(basedir, path)) + name = os.path.normpath(os.path.normcase(os.path.join(basedir, path))) + + import odoo.modules as addons + paths = addons.module.ad_paths + [config['root_path']] + for addons_path in paths: + addons_path = os.path.normpath(os.path.normcase(addons_path)) + os.sep + if name.startswith(addons_path): + break + else: + raise ValueError("Unknown path: %s" % name) if basename is None: basename = name