[FIX] stock: filter on 'closest' strategy

Steps to reproduce:
- Enable Storage locations
- Add two lots in stock:
  - lot_shelf_2 in WH/Stock/Shelf 2
  - lot_shelf_1 in WH/Stock/Shelf 1
- Enable the 'Closest Location' removal strategy on its product category
- Create a delivery using this product and mark it as todo

Issue:
lot_shelf_2 will be selected even though it should take the one from
Shelf 1.

When filtering on the location, we need to filter on the location name
instead of this is.
Also, when creating a new quant on a product using the 'closest'
location, the filter will create a traceback because it will try to
filter on a NewId.

closes odoo/odoo#140175

Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
clesgow
2023-10-31 08:24:42 +00:00
parent 9200d3a5b2
commit 34db3fd706
2 changed files with 23 additions and 11 deletions
+2 -2
View File
@@ -741,7 +741,7 @@ class StockQuant(models.Model):
if removal_strategy == 'lifo':
reverse = True
elif removal_strategy == 'closest':
key = lambda q: (q.location_id, -q.id)
key = lambda q: (q.location_id.complete_name, -q.id)
return key, reverse
def _get_gather_domain(self, product_id, location_id, lot_id=None, package_id=None, owner_id=None, strict=False):
@@ -770,7 +770,7 @@ class StockQuant(models.Model):
removal_strategy = self._get_removal_strategy(product_id, location_id)
domain = self._get_gather_domain(product_id, location_id, lot_id, package_id, owner_id, strict)
domain, order = self._get_removal_strategy_domain_order(domain, removal_strategy, qty)
if self:
if self.ids:
sort_key = self._get_removal_strategy_sort_key(removal_strategy)
res = self.filtered_domain(domain).sorted(key=sort_key[0], reverse=sort_key[1])
else:
+21 -9
View File
@@ -5,7 +5,7 @@ from datetime import datetime, timedelta
from unittest.mock import patch
from ast import literal_eval
from odoo import fields
from odoo import Command, fields
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.exceptions import ValidationError
from odoo.tests.common import Form, TransactionCase
@@ -625,6 +625,10 @@ class StockQuant(TransactionCase):
""" Check that the Closest location strategy correctly applies when you have multiple lot received
at different locations for a tracked product.
"""
# Enable multi-locations to be able to set an origin location for delivery
grp_multi_loc = self.env.ref('stock.group_stock_multi_locations')
self.env.user.write({'groups_id': [Command.link(grp_multi_loc.id)]})
closest_strategy = self.env['product.removal'].search([('method', '=', 'closest')])
self.stock_location.removal_strategy_id = closest_strategy
lot1 = self.env['stock.lot'].create({
@@ -638,14 +642,22 @@ class StockQuant(TransactionCase):
'company_id': self.env.company.id,
})
in_date = datetime.now()
# Add a product from lot1 in stock_location/subloc2
self.env['stock.quant']._update_available_quantity(self.product_serial, self.stock_subloc2, 1.0, lot_id=lot1, in_date=in_date)
# Add a product from lot2 in stock_location/subloc3
self.env['stock.quant']._update_available_quantity(self.product_serial, self.stock_subloc3, 1.0, lot_id=lot2, in_date=in_date)
# Require one unit of the product
quants = self.env['stock.quant']._get_reserve_quantity(self.product_serial, self.stock_location, 1)
# Default removal strategy is 'Closest location', so lot1 should be received as it was put in a closer location. (stock_location/subloc2 < stock_location/subloc3)
self.assertEqual(quants[0][0].lot_id.id, lot1.id)
# Add a product from lot1 in stock_location/subloc3
self.env['stock.quant']._update_available_quantity(self.product_serial, self.stock_subloc3, 1.0, lot_id=lot1, in_date=in_date)
# Add a product from lot2 in stock_location/subloc2
self.env['stock.quant']._update_available_quantity(self.product_serial, self.stock_subloc2, 1.0, lot_id=lot2, in_date=in_date)
# Require one unit of the product for a delivery
with Form(self.env['stock.picking']) as picking_form:
picking_form.picking_type_id = self.env.ref('stock.picking_type_out')
picking_form.location_id = self.stock_location
with picking_form.move_ids_without_package.new() as move_form:
move_form.product_id = self.product_serial
move_form.product_uom_qty = 1
picking = picking_form.save()
picking.action_confirm()
# Default removal strategy is 'Closest location', so lot2 should be received as it was put in a closer location. (stock_location/subloc2 < stock_location/subloc3)
self.assertEqual(picking.move_ids.lot_ids.id, lot2.id)
def test_closest_removal_strategy_untracked(self):
""" Check that the Closest location strategy correctly applies when you have multiple products received