[PERF] pos_sale: memoize _compute_currency_rate of pos.order
Description:
Saving a new `res.config.settings` (for ex: checking "Use QR code on
ticket") can be extremely slow on database with a large number
of `pos.order`.
Analysis:
Saving a new `res.config.settings` creates a new instance of the config.
This will invoke a check on the python constraints calling
eventually `_check_currencies` of `pos.config`, which will invoke the
compute of `currency_id` setting the field as dirty.
The `_compute_currency_rate` of `pos.order` depends on the `currency_id`
of the current `pos.config` (via a related).
This means the compute will be called with *all* `pos.order` ever made.
As the compute itself makes a few calls to `_get_conversion_rate`, which
makes a query, it can become slow when the method is called frequently.
Solution:
Memoize the call to `_get_conversion_rate`, as similarly done
in `account.move.line` from d8d47f9ff8
to reduce the number queries necessary.
Benchmark:
The `create` request to `res.config.settings` on a database with over
240k `pos.order` took
| | Before | After |
|-------------|-----------|----------|
| Timing | 36.9 secs | 4.3 secs |
| Query count | 47k | 627 |
Reference:
opw-3632273
closes odoo/odoo#148136
X-original-commit: 1c6f7f23b2c0dbd009d8d56689c7a98792990f7f
Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
Signed-off-by: Piryns Victor (pivi) <pivi@odoo.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from markupsafe import Markup
|
||||
from functools import partial
|
||||
from functools import partial, lru_cache
|
||||
from itertools import groupby
|
||||
from collections import defaultdict
|
||||
|
||||
@@ -418,8 +418,18 @@ class PosOrder(models.Model):
|
||||
|
||||
@api.depends('date_order', 'company_id', 'currency_id', 'company_id.currency_id')
|
||||
def _compute_currency_rate(self):
|
||||
@lru_cache
|
||||
def get_rate(from_currency, to_currency, company, date):
|
||||
return self.env['res.currency']._get_conversion_rate(
|
||||
from_currency=from_currency,
|
||||
to_currency=to_currency,
|
||||
company=company,
|
||||
date=date,
|
||||
)
|
||||
for order in self:
|
||||
order.currency_rate = self.env['res.currency']._get_conversion_rate(order.company_id.currency_id, order.currency_id, order.company_id, order.date_order)
|
||||
# date_order is a datetime, but the rates are looked up on a date basis,
|
||||
# therefor converting the date_order to a date helps with sharing entries in the lru_cache
|
||||
order.currency_rate = get_rate(order.company_id.currency_id, order.currency_id, order.company_id, order.date_order.date())
|
||||
|
||||
@api.depends('lines.is_total_cost_computed')
|
||||
def _compute_is_total_cost_computed(self):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from functools import lru_cache
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.tools import float_compare, float_is_zero
|
||||
@@ -24,9 +25,19 @@ class PosOrder(models.Model):
|
||||
|
||||
@api.depends('date_order', 'company_id')
|
||||
def _compute_currency_rate(self):
|
||||
@lru_cache
|
||||
def get_rate(from_currency, to_currency, company, date):
|
||||
return self.env['res.currency']._get_conversion_rate(
|
||||
from_currency=from_currency,
|
||||
to_currency=to_currency,
|
||||
company=company,
|
||||
date=date,
|
||||
)
|
||||
for order in self:
|
||||
date_order = order.date_order or fields.Datetime.now()
|
||||
order.currency_rate = self.env['res.currency']._get_conversion_rate(order.company_id.currency_id, order.currency_id, order.company_id, date_order)
|
||||
# date_order is a datetime, but the rates are looked up on a date basis,
|
||||
# therefor converting the date_order to a date helps with sharing entries in the lru_cache
|
||||
order.currency_rate = get_rate(order.company_id.currency_id, order.currency_id, order.company_id, date_order.date())
|
||||
|
||||
def _prepare_invoice_vals(self):
|
||||
invoice_vals = super(PosOrder, self)._prepare_invoice_vals()
|
||||
|
||||
Reference in New Issue
Block a user