[REF] stock: cache the get_warehouse of stock.location

To avoid multiple search of the get_warehouse for the same location
and extra SQL request (it happens a lot for complicate flow, e.g.
mrp_mps, replenishment report).
Translate it into a standard compute to use the cache of
the ORM for no-store compute field (`warehouse_id`) and put
some depends to be always correct (even if `warehouse_id` shouldn't
change in the same request).

task-2439019
This commit is contained in:
Rémy Voet (ryv)
2021-03-30 09:27:05 +00:00
parent 974c4398b4
commit 64caa930b3
9 changed files with 32 additions and 23 deletions
+5 -5
View File
@@ -509,7 +509,7 @@ class MrpProduction(models.Model):
@api.depends('product_uom_qty', 'date_planned_start')
def _compute_forecasted_issue(self):
for order in self:
warehouse = order.location_dest_id.get_warehouse()
warehouse = order.location_dest_id.warehouse_id
order.forecasted_issue = False
if order.product_id:
virtual_available = order.product_id.with_context(warehouse=warehouse.id, to_date=order.date_planned_start).virtual_available
@@ -631,7 +631,7 @@ class MrpProduction(models.Model):
def _onchange_location(self):
source_location = self.location_src_id
self.move_raw_ids.update({
'warehouse_id': source_location.get_warehouse().id,
'warehouse_id': source_location.warehouse_id.id,
'location_id': source_location.id,
})
@@ -641,7 +641,7 @@ class MrpProduction(models.Model):
update_value_list = []
for move in self.move_finished_ids:
update_value_list += [(1, move.id, ({
'warehouse_id': destination_location.get_warehouse().id,
'warehouse_id': destination_location.warehouse_id.id,
'location_dest_id': destination_location.id,
}))]
self.move_finished_ids = update_value_list
@@ -834,7 +834,7 @@ class MrpProduction(models.Model):
'location_dest_id': self.location_dest_id.id,
'company_id': self.company_id.id,
'production_id': self.id,
'warehouse_id': self.location_dest_id.get_warehouse().id,
'warehouse_id': self.location_dest_id.warehouse_id.id,
'origin': self.name,
'group_id': self.procurement_group_id.id,
'propagate_cancel': self.propagate_cancel,
@@ -895,7 +895,7 @@ class MrpProduction(models.Model):
'procure_method': 'make_to_stock',
'origin': self.name,
'state': 'draft',
'warehouse_id': source_location.get_warehouse().id,
'warehouse_id': source_location.warehouse_id.id,
'group_id': self.procurement_group_id.id,
'propagate_cancel': self.propagate_cancel,
}
+2 -2
View File
@@ -257,7 +257,7 @@ class MrpUnbuild(models.Model):
'procure_method': 'make_to_stock',
'location_dest_id': location_dest_id.id,
'location_id': location_id.id,
'warehouse_id': location_dest_id.get_warehouse().id,
'warehouse_id': location_dest_id.warehouse_id.id,
'unbuild_id': self.id,
'company_id': move.company_id.id,
})
@@ -266,7 +266,7 @@ class MrpUnbuild(models.Model):
product_prod_location = product.with_company(self.company_id).property_stock_production
location_id = bom_line_id and product_prod_location or self.location_id
location_dest_id = bom_line_id and self.location_dest_id or product_prod_location
warehouse = location_dest_id.get_warehouse()
warehouse = location_dest_id.warehouse_id
return self.env['stock.move'].create({
'name': self.name,
'date': self.create_date,
+1 -1
View File
@@ -67,5 +67,5 @@ class ProductProduct(models.Model):
uom = self.env['uom.uom'].browse(group['product_uom'][0])
product_qty = uom._compute_quantity(group['product_qty'], product.uom_id, round=False)
qty_by_product_location[(product.id, location.id)] += product_qty
qty_by_product_wh[(product.id, location.get_warehouse().id)] += product_qty
qty_by_product_wh[(product.id, location.warehouse_id.id)] += product_qty
return qty_by_product_location, qty_by_product_wh
+1 -1
View File
@@ -574,7 +574,7 @@ class Product(models.Model):
seen_rules = self.env['stock.rule']
rule = self.env['procurement.group']._get_rule(self, location, {
'route_ids': route_ids,
'warehouse_id': location.get_warehouse()
'warehouse_id': location.warehouse_id
})
if not rule:
return seen_rules
+15 -6
View File
@@ -6,6 +6,7 @@ from datetime import timedelta
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.osv import expression
from collections import OrderedDict
class Location(models.Model):
@@ -65,6 +66,8 @@ class Location(models.Model):
cyclic_inventory_frequency = fields.Integer("Inventory Frequency (Days)", default=0, help=" When different than 0, inventory adjustments for products stored at this location will be created automatically at the defined frequency.")
last_inventory_date = fields.Datetime("Last Effective Inventory", readonly=True, help="Date of the last inventory at this location.")
next_inventory_date = fields.Date("Next Expected Inventory", compute="_compute_next_inventory_date", store=True, help="Date for next planned inventory based on cyclic schedule.")
warehouse_view_ids = fields.One2many('stock.warehouse', 'view_location_id', readonly=True)
warehouse_id = fields.Many2one('stock.warehouse', compute='_compute_warehouse_id')
_sql_constraints = [('barcode_company_uniq', 'unique (barcode,company_id)', 'The barcode for a location must be unique per company !'),
('inventory_freq_nonneg', 'check(cyclic_inventory_frequency >= 0)', 'The inventory frequency (days) for a location must be non-negative')]
@@ -95,6 +98,18 @@ class Location(models.Model):
else:
location.next_inventory_date = False
@api.depends('location_id.warehouse_id', 'warehouse_view_ids')
def _compute_warehouse_id(self):
warehouses = self.env['stock.warehouse'].search([('view_location_id', 'parent_of', self.ids)])
view_by_wh = OrderedDict((wh.view_location_id.id, wh.id) for wh in warehouses)
self.warehouse_id = False
for loc in self:
path = set(int(loc_id) for loc_id in loc.parent_path.split('/')[:-1])
for view_location_id in view_by_wh:
if view_location_id in path:
loc.warehouse_id = view_by_wh[view_location_id]
break
@api.onchange('usage')
def _onchange_usage(self):
if self.usage not in ('internal', 'inventory'):
@@ -177,12 +192,6 @@ class Location(models.Model):
current_location = current_location.location_id
return putaway_location
@api.returns('stock.warehouse', lambda value: value.id)
def get_warehouse(self):
""" Returns warehouse id of warehouse that contains location """
domain = [('view_location_id', 'parent_of', self.ids)]
return self.env['stock.warehouse'].search(domain, limit=1)
def should_bypass_reservation(self):
self.ensure_one()
return self.usage in ('supplier', 'customer', 'inventory', 'production') or self.scrap_location or (self.usage == 'transit' and not self.company_id)
+4 -4
View File
@@ -409,7 +409,7 @@ class StockMove(models.Model):
move.forecast_availability = move.product_qty
product_moves = (self - not_product_moves)
warehouse_by_location = {loc: loc.get_warehouse() for loc in product_moves.location_id}
warehouse_by_location = {loc: loc.warehouse_id for loc in product_moves.location_id}
outgoing_unreserved_moves_per_warehouse = defaultdict(lambda: self.env['stock.move'])
for move in product_moves:
@@ -670,9 +670,9 @@ class StockMove(models.Model):
'move_to_match_ids': self.ids,
}
if self.picking_type_id.code == 'outgoing':
warehouse = self.location_id.get_warehouse()
warehouse = self.location_id.warehouse_id
else:
warehouse = self.location_dest_id.get_warehouse()
warehouse = self.location_dest_id.warehouse_id
if warehouse:
action['context']['warehouse'] = warehouse.id
@@ -883,7 +883,7 @@ class StockMove(models.Model):
def _get_forecast_availability_incoming(self):
self.ensure_one()
warehouse = self.location_dest_id.get_warehouse()
warehouse = self.location_dest_id.warehouse_id
self.forecast_availability = self.product_id.with_context(warehouse=warehouse.id, to_date=self.date).virtual_available
if self.state == 'draft':
self.forecast_availability += self.product_uom_qty
+1 -1
View File
@@ -176,7 +176,7 @@ class StockWarehouseOrderpoint(models.Model):
@api.onchange('location_id')
def _onchange_location_id(self):
warehouse = self.location_id.get_warehouse().id
warehouse = self.location_id.warehouse_id.id
if warehouse:
self.warehouse_id = warehouse
+1 -1
View File
@@ -380,7 +380,7 @@ class PickingType(models.Model):
locations_company = locations_by_company[values['company_id']]
# TODO : choice only location child of warehouse.lot_stock_id
inter_location = random.choice(locations_company)
values['warehouse_id'] = inter_location.get_warehouse().id
values['warehouse_id'] = inter_location.warehouse_id.id
if values['code'] == 'internal':
values['default_location_src_id'] = inter_location.id
values['default_location_dest_id'] = random.choice(locations_company - inter_location).id
+2 -2
View File
@@ -96,7 +96,7 @@ class ReportStockRule(models.AbstractModel):
ordered_locations = self.env['stock.location']
locations = all_locations.filtered(lambda l: l.usage in ('supplier', 'production'))
for warehouse_id in warehouses:
all_warehouse_locations = all_locations.filtered(lambda l: l.get_warehouse() == warehouse_id)
all_warehouse_locations = all_locations.filtered(lambda l: l.warehouse_id == warehouse_id)
starting_rules = [d for d in rules_and_loc if d['source'] not in all_warehouse_locations]
if starting_rules:
start_locations = self.env['stock.location'].concat(*([r['destination'] for r in starting_rules]))
@@ -116,7 +116,7 @@ class ReportStockRule(models.AbstractModel):
def _sort_locations_by_warehouse(self, rules_and_loc, used_rules, start_locations, ordered_locations, warehouse_id):
""" We order locations by putting first the locations that are not the destination of others and do it recursively.
"""
start_locations = start_locations.filtered(lambda l: l.get_warehouse() == warehouse_id)
start_locations = start_locations.filtered(lambda l: l.warehouse_id == warehouse_id)
ordered_locations |= start_locations
rules_start = []
for rule in rules_and_loc: