From b547a6fd5dff6edf90d40b41fcc26d58d5a6b87c Mon Sep 17 00:00:00 2001 From: Carlos Roca Date: Mon, 17 May 2021 12:43:20 +0200 Subject: [PATCH] [FIX] website_sale_product_minimal_price: Take into account all pricelist items Previous approach only considered pricelist items in the same pricelist as the current one, but you can have some items that point to another pricelists, so we are changing the approach to get all possible items, no matter the pricelist, get the minimal quantity which they apply to, and then get the price for that quantity to see if with the price computation, they return a different value, marking them in the scale table. With this, we get a compromise between performance and accuracy. NOTE: There are still left intentionally items for "All products" that can have other scaled prices, but as this can have a lot of impact in performance and it's improbable that someone configures pricelists this way, it's better to not include them. TT29708 --- .../controllers/main.py | 72 ++++++++----------- .../js/website_sale_product_minimal_price.js | 8 ++- 2 files changed, 34 insertions(+), 46 deletions(-) diff --git a/website_sale_product_minimal_price/controllers/main.py b/website_sale_product_minimal_price/controllers/main.py index d3ea503dbe..ae26177267 100644 --- a/website_sale_product_minimal_price/controllers/main.py +++ b/website_sale_product_minimal_price/controllers/main.py @@ -1,7 +1,7 @@ # Copyright 2020 Tecnativa - Carlos Roca # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo.addons.website_sale.controllers.main import WebsiteSale -from odoo import http, fields +from odoo import http from odoo.http import request @@ -16,48 +16,34 @@ def get_combination_info_pricelist_atributes( """Special route to use website logic in get_combination_info override. This route is called in JS by appending _website to the base route. """ - actual_qty = int(actual_qty) product = request.env["product.product"].browse(product_id) - current_website = request.env["website"].get_current_website() - today = fields.Date.today() + pricelist = request.env["website"].get_current_website().get_current_pricelist() + # Getting all min_quantity of the current product to compute the posible + # price scale. + qty_list = request.env["product.pricelist.item"].search([ + "|", + ("product_id", "=", product.id), + "|", + ("product_tmpl_id", "=", product.product_tmpl_id.id), + ("categ_id", "in", list(map( + int, product.categ_id.parent_path.split('/')[0:-1]))), + ("min_quantity", ">", 0), + ]).mapped("min_quantity") + qty_list = sorted(set(qty_list)) res = [] - pricelist = current_website.get_current_pricelist() - pricelist_items = pricelist.item_ids.filtered( - lambda i: i.product_id == product - and (not i.date_start or i.date_start <= today) - and (not i.date_end or today <= i.date_end) - and i.min_quantity > 0) - pricelist_items = pricelist_items + pricelist.item_ids.filtered( - lambda i: i.product_tmpl_id == product.product_tmpl_id - and (not i.date_start or i.date_start <= today) - and (not i.date_end or today <= i.date_end) - and i.min_quantity > 0 - and (i.min_quantity < min( - pricelist_items.mapped('min_quantity')) if pricelist_items else True)) - pricelist_items = pricelist_items + pricelist.item_ids.filtered( - lambda i: i.categ_id.id in list( - map(int, product.categ_id.parent_path.split('/')[0:-1])) - and (not i.date_start or i.date_start <= today) - and (not i.date_end or today <= i.date_end) - and i.min_quantity > 0 - and (i.min_quantity < min( - pricelist_items.mapped('min_quantity')) if pricelist_items else True)) - res = self._prepare_dictionary(pricelist_items, product, pricelist) - res.sort(key=lambda i: i.get('min_qty', 0)) - return res - - def _prepare_dictionary(self, pricelist_items, product, pricelist): - res = [] - for item in pricelist_items: - ctx = dict( - request.env.context, pricelist=pricelist.id, quantity=item.min_quantity) - final_price = product.with_context(ctx).price - res.append({ - "min_qty": item.min_quantity, - "price": final_price, - "currency": { - "position": product.currency_id.position, - "symbol": product.currency_id.symbol, - }, - }) + ctx = dict(request.env.context, pricelist=pricelist.id, quantity=0) + last_price = product.with_context(ctx).price + for min_qty in qty_list: + ctx["quantity"] = min_qty + new_price = product.with_context(ctx).price + if new_price != last_price: + res.append({ + "min_qty": min_qty, + "price": new_price, + "currency": { + "position": product.currency_id.position, + "symbol": product.currency_id.symbol, + }, + }) + last_price = new_price return res diff --git a/website_sale_product_minimal_price/static/src/js/website_sale_product_minimal_price.js b/website_sale_product_minimal_price/static/src/js/website_sale_product_minimal_price.js index dca14994a7..31d9851f32 100644 --- a/website_sale_product_minimal_price/static/src/js/website_sale_product_minimal_price.js +++ b/website_sale_product_minimal_price/static/src/js/website_sale_product_minimal_price.js @@ -44,16 +44,18 @@ odoo.define("website_sale_product_minimal_price.load", function (require) { ); // We define a limit of displayed columns as 4 var limit_col = 4; - var $div = undefined; + var $div; for (var i in unit_prices) { if (unit_prices[i].price === 0) { continue; } if (i % limit_col === 0) { var id = i/limit_col; + var first = '
'; $form.append( - '
'); - $div = $('#row_' + id); // eslint-disable-line no-undef-init + first + id + end); + $div = $('#row_' + id); } var monetary_u = field_utils.format.monetary( unit_prices[i].price,