From 265926f971d9f77322885c60e9e40ae45ca855f7 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 8 Apr 2019 11:40:08 +0000 Subject: [PATCH] [IMP] website_sale: overhead on every page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit website_sale adds a call to sale_get_order to ~every website page (in order to validate & display the shopping cart). Before this change, this calls get_pricelist_available() and triggers two different computations of property_product_pricelist on every page even for a public user with no cart / SO. This, in turn, generates ~20 queries and adds 20ms (total) / 10ms (sql) to ~every page load. Fix: early return if the user doesn't have an SO (either in session or in DB) and we're not in a case where we want to force one. Loading "/" with just website_sale installed on a new DB, - before: 53 queries, 31ms ±5 (sql), 75ms ±5 (all) - after: 32 queries, 21ms ±1 (sql), 53ms ±3 (all) closes odoo/odoo#32492 Signed-off-by: Xavier Morel (xmo) --- addons/website_sale/models/website.py | 130 +++++++++++++------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/addons/website_sale/models/website.py b/addons/website_sale/models/website.py index 6344a0bdd87..926899c3697 100644 --- a/addons/website_sale/models/website.py +++ b/addons/website_sale/models/website.py @@ -239,27 +239,32 @@ class Website(models.Model): self.ensure_one() partner = self.env.user.partner_id sale_order_id = request.session.get('sale_order_id') - if not sale_order_id: + if not sale_order_id and not self.env.user._is_public(): last_order = partner.last_website_so_id - available_pricelists = self.get_pricelist_available() - # Do not reload the cart of this user last visit if the cart uses a pricelist no longer available. - sale_order_id = last_order.pricelist_id in available_pricelists and last_order.id + if last_order: + available_pricelists = self.get_pricelist_available() + # Do not reload the cart of this user last visit if the cart uses a pricelist no longer available. + sale_order_id = last_order.pricelist_id in available_pricelists and last_order.id - pricelist_id = request.session.get('website_sale_current_pl') or self.get_current_pricelist().id + # Test validity of the sale_order_id + sale_order = self.env['sale.order'].sudo().browse(sale_order_id).exists() if sale_order_id else None + + if not (sale_order or force_create or code): + request.session['sale_order_id'] = None + return self.env['sale.order'] if self.env['product.pricelist'].browse(force_pricelist).exists(): pricelist_id = force_pricelist request.session['website_sale_current_pl'] = pricelist_id update_pricelist = True + else: + pricelist_id = request.session.get('website_sale_current_pl') or self.get_current_pricelist().id if not self._context.get('pricelist'): self = self.with_context(pricelist=pricelist_id) - # Test validity of the sale_order_id - sale_order = self.env['sale.order'].sudo().browse(sale_order_id).exists() if sale_order_id else None - - # create so if needed - if not sale_order and (force_create or code): + # cart creation was requested (either explicitly or to configure a promo code) + if not sale_order: # TODO cache partner_id session pricelist = self.env['product.pricelist'].browse(pricelist_id).sudo() so_data = self._prepare_sale_order_values(partner, pricelist) @@ -280,70 +285,65 @@ class Website(models.Model): request.session['sale_order_id'] = sale_order.id - if sale_order: - # case when user emptied the cart - if not request.session.get('sale_order_id'): - request.session['sale_order_id'] = sale_order.id + # case when user emptied the cart + if not request.session.get('sale_order_id'): + request.session['sale_order_id'] = sale_order.id - # check for change of pricelist with a coupon - pricelist_id = pricelist_id or partner.property_product_pricelist.id + # check for change of pricelist with a coupon + pricelist_id = pricelist_id or partner.property_product_pricelist.id - # check for change of partner_id ie after signup - if sale_order.partner_id.id != partner.id and request.website.partner_id.id != partner.id: - flag_pricelist = False - if pricelist_id != sale_order.pricelist_id.id: - flag_pricelist = True - fiscal_position = sale_order.fiscal_position_id.id + # check for change of partner_id ie after signup + if sale_order.partner_id.id != partner.id and request.website.partner_id.id != partner.id: + flag_pricelist = False + if pricelist_id != sale_order.pricelist_id.id: + flag_pricelist = True + fiscal_position = sale_order.fiscal_position_id.id - # change the partner, and trigger the onchange - sale_order.write({'partner_id': partner.id}) - sale_order.onchange_partner_id() - sale_order.write({'partner_invoice_id': partner.id}) - sale_order.onchange_partner_shipping_id() # fiscal position - sale_order['payment_term_id'] = self.sale_get_payment_term(partner) + # change the partner, and trigger the onchange + sale_order.write({'partner_id': partner.id}) + sale_order.onchange_partner_id() + sale_order.write({'partner_invoice_id': partner.id}) + sale_order.onchange_partner_shipping_id() # fiscal position + sale_order['payment_term_id'] = self.sale_get_payment_term(partner) - # check the pricelist : update it if the pricelist is not the 'forced' one - values = {} - if sale_order.pricelist_id: - if sale_order.pricelist_id.id != pricelist_id: - values['pricelist_id'] = pricelist_id - update_pricelist = True - - # if fiscal position, update the order lines taxes - if sale_order.fiscal_position_id: - sale_order._compute_tax_id() - - # if values, then make the SO update - if values: - sale_order.write(values) - - # check if the fiscal position has changed with the partner_id update - recent_fiscal_position = sale_order.fiscal_position_id.id - if flag_pricelist or recent_fiscal_position != fiscal_position: + # check the pricelist : update it if the pricelist is not the 'forced' one + values = {} + if sale_order.pricelist_id: + if sale_order.pricelist_id.id != pricelist_id: + values['pricelist_id'] = pricelist_id update_pricelist = True - if code and code != sale_order.pricelist_id.code: - code_pricelist = self.env['product.pricelist'].sudo().search([('code', '=', code)], limit=1) - if code_pricelist: - pricelist_id = code_pricelist.id - update_pricelist = True - elif code is not None and sale_order.pricelist_id.code: - # code is not None when user removes code and click on "Apply" - pricelist_id = partner.property_product_pricelist.id + # if fiscal position, update the order lines taxes + if sale_order.fiscal_position_id: + sale_order._compute_tax_id() + + # if values, then make the SO update + if values: + sale_order.write(values) + + # check if the fiscal position has changed with the partner_id update + recent_fiscal_position = sale_order.fiscal_position_id.id + if flag_pricelist or recent_fiscal_position != fiscal_position: update_pricelist = True - # update the pricelist - if update_pricelist: - request.session['website_sale_current_pl'] = pricelist_id - values = {'pricelist_id': pricelist_id} - sale_order.write(values) - for line in sale_order.order_line: - if line.exists(): - sale_order._cart_update(product_id=line.product_id.id, line_id=line.id, add_qty=0) + if code and code != sale_order.pricelist_id.code: + code_pricelist = self.env['product.pricelist'].sudo().search([('code', '=', code)], limit=1) + if code_pricelist: + pricelist_id = code_pricelist.id + update_pricelist = True + elif code is not None and sale_order.pricelist_id.code: + # code is not None when user removes code and click on "Apply" + pricelist_id = partner.property_product_pricelist.id + update_pricelist = True - else: - request.session['sale_order_id'] = None - return self.env['sale.order'] + # update the pricelist + if update_pricelist: + request.session['website_sale_current_pl'] = pricelist_id + values = {'pricelist_id': pricelist_id} + sale_order.write(values) + for line in sale_order.order_line: + if line.exists(): + sale_order._cart_update(product_id=line.product_id.id, line_id=line.id, add_qty=0) return sale_order