[FIX] point_of_sale: improve get_price performance

Test case:
 ~ 16 000 products and using a pricelist with a fixed price for all products (so ~16 000 pricelist_item).

To reproduce:
 Open PoS and add an item to the order
 -> Very slow and not responsive: ~5 seconds to do the operation & around 2 minutes to fully load the PoS.

Issue:
 `get_price` JS method is called several times and is a bit slow (~200ms). Mostly because of the linear search in the pricelist to check if the product does match.

 Note that the function is called once per ProductItem rendered. Each time a product is added to the order the rendering is refreshed for all ProductItem displayed.
So the performance impact is significant if several of them are displayed.

To solve:
 As the pricelist per Product.id is constant, we store the possible applied pricelist records on the product itself.

After this commit:
 Order does take a few milliseconds to be added (2 ms VS 200ms)

Other notes:
 A. With the current OWL version, it is not possible to force the render on only some of the ProductItem. A more appropriate fix could be done with "fine-grained reactivity" using a more recent OWL version
 B. It was thought to store/cache the price value on the ProductItem itself. It does have its share of disadvantages (no check if the pricelist time period did start/end, etc.). Either way, with that being implemented, the PoS was still a bit slow (because of the 200ms per `_get_price` call)

OPW-2826122

closes odoo/odoo#90245

X-original-commit: 6f0bfb36a11e52e20b90ca85fc8847faadcdc95e
Signed-off-by: Trinh Jacky (trj) <trj@odoo.com>
Signed-off-by: Masereel Pierre <pim@odoo.com>
This commit is contained in:
Loan (lse)
2022-05-02 19:46:57 +02:00
parent f34d863257
commit eb805e85f4
+38 -4
View File
@@ -222,11 +222,47 @@ class PosGlobalState extends PosModel {
_loadResPartner() {
this.db.add_partners(this.partners);
}
_assignApplicableItems(pricelist, correspondingProduct, pricelistItem) {
if (!(pricelist.id in correspondingProduct.applicablePricelistItems)) {
correspondingProduct.applicablePricelistItems[pricelist.id] = [];
}
correspondingProduct.applicablePricelistItems[pricelist.id].push(pricelistItem);
}
_loadProductProduct(products) {
const productMap = {};
const productTemplateMap = {};
const modelProducts = products.map(product => {
product.pos = this;
product.applicablePricelistItems = {};
productMap[product.id] = product;
productTemplateMap[product.product_tmpl_id[0]] = (productTemplateMap[product.product_tmpl_id[0]] || []).concat(product);
return Product.create(product);
});
for (let pricelist of this.pricelists) {
for (const pricelistItem of pricelist.items) {
if (pricelistItem.product_id) {
let product_id = pricelistItem.product_id[0];
let correspondingProduct = productMap[product_id];
if (correspondingProduct) {
this._assignApplicableItems(pricelist, correspondingProduct, pricelistItem);
}
}
else if (pricelistItem.product_tmpl_id) {
let product_tmpl_id = pricelistItem.product_tmpl_id[0];
let correspondingProducts = productTemplateMap[product_tmpl_id];
for (let correspondingProduct of (correspondingProducts || [])) {
this._assignApplicableItems(pricelist, correspondingProduct, pricelistItem);
}
}
else {
for (const correspondingProduct of products) {
this._assignApplicableItems(pricelist, correspondingProduct, pricelistItem);
}
}
}
}
this.db.add_products(modelProducts)
}
_loadPosPaymentMethod() {
@@ -1076,10 +1112,8 @@ class Product extends PosModel {
category = category.parent;
}
var pricelist_items = _.filter(pricelist.items, function (item) {
return (! item.product_tmpl_id || item.product_tmpl_id[0] === self.product_tmpl_id) &&
(! item.product_id || item.product_id[0] === self.id) &&
(! item.categ_id || _.contains(category_ids, item.categ_id[0])) &&
var pricelist_items = _.filter(self.applicablePricelistItems[pricelist.id], function (item) {
return (! item.categ_id || _.contains(category_ids, item.categ_id[0])) &&
(! item.date_start || moment.utc(item.date_start).isSameOrBefore(date)) &&
(! item.date_end || moment.utc(item.date_end).isSameOrAfter(date));
});