mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] stock_move_auto_assign: Auto reassign on move cancelation
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from odoo import _, models
|
||||
from odoo.tools import float_compare
|
||||
|
||||
from odoo.addons.queue_job.job import identity_exact
|
||||
|
||||
@@ -13,10 +14,29 @@ class StockMove(models.Model):
|
||||
|
||||
def _action_done(self, cancel_backorder=False):
|
||||
done_moves = super()._action_done(cancel_backorder=cancel_backorder)
|
||||
done_moves._prepare_auto_assign()
|
||||
done_moves._prepare_auto_assign(location_field="move_line_ids.location_dest_id")
|
||||
return done_moves
|
||||
|
||||
def _prepare_auto_assign(self):
|
||||
def _action_cancel(self):
|
||||
moves_with_reservation_to_cancel = self.filtered(
|
||||
lambda m: m.state not in ("done", "cancel")
|
||||
and float_compare(
|
||||
m.reserved_availability, 0, precision_rounding=m.product_uom.rounding
|
||||
)
|
||||
> 0
|
||||
)
|
||||
res = super()._action_cancel()
|
||||
moves_with_reservation_canceled = (
|
||||
self.filtered(lambda m: m.state == "cancel")
|
||||
& moves_with_reservation_to_cancel
|
||||
)
|
||||
if moves_with_reservation_canceled:
|
||||
moves_with_reservation_canceled._prepare_auto_assign(
|
||||
location_field="location_id"
|
||||
)
|
||||
return res
|
||||
|
||||
def _prepare_auto_assign(self, location_field):
|
||||
product_locs = defaultdict(set)
|
||||
for move in self:
|
||||
# select internal locations where we moved goods not for the
|
||||
@@ -26,7 +46,7 @@ class StockMove(models.Model):
|
||||
product = move.product_id
|
||||
if product.type != "product":
|
||||
continue
|
||||
locations = move.mapped("move_line_ids.location_dest_id").filtered(
|
||||
locations = move.mapped(location_field).filtered(
|
||||
lambda l: l.usage == "internal"
|
||||
)
|
||||
product_locs[product.id].update(locations.ids)
|
||||
|
||||
@@ -43,6 +43,35 @@ class TestStockMoveAutoAssign(StockMoveAutoAssignCase):
|
||||
self.assertEqual(delay_args, (self.shelf1_loc | self.shelf2_loc,))
|
||||
self.assertDictEqual(delay_kwargs, {})
|
||||
|
||||
def test_move_canceled_with_reservation_enqueue_job(self):
|
||||
"""A canceled move with reservations enqueue a new job to assign other moves"""
|
||||
move = self._create_move(self.product, self.out_type, qty=100)
|
||||
# put stock in Stock/Shelf 1, the move has a source location in Stock
|
||||
self._update_qty_in_location(self.shelf1_loc, self.product, 100)
|
||||
move._action_assign()
|
||||
with mock_with_delay() as (delayable_cls, delayable):
|
||||
move._action_cancel()
|
||||
# .with_delay() has been called once
|
||||
self.assertEqual(delayable_cls.call_count, 1)
|
||||
delay_args, delay_kwargs = delayable_cls.call_args
|
||||
# .with_delay() is called on self.product
|
||||
self.assertEqual(delay_args, (self.product,))
|
||||
# .with_delay() with the following options
|
||||
self.assertEqual(delay_kwargs.get("identity_key"), identity_exact)
|
||||
# check what's passed to the job method 'moves_auto_assign'
|
||||
self.assertEqual(delayable.moves_auto_assign.call_count, 1)
|
||||
delay_args, delay_kwargs = delayable.moves_auto_assign.call_args
|
||||
self.assertEqual(delay_args, (self.out_type.default_location_src_id,))
|
||||
self.assertDictEqual(delay_kwargs, {})
|
||||
|
||||
def test_move_canceled_without_reservation_no_job(self):
|
||||
move = self._create_move(self.product, self.out_type, qty=100)
|
||||
move._action_assign()
|
||||
with mock_with_delay() as (delayable_cls, delayable):
|
||||
move._action_cancel()
|
||||
# .with_delay() has not been called
|
||||
self.assertEqual(delayable_cls.call_count, 0)
|
||||
|
||||
def test_move_done_service_no_job(self):
|
||||
"""Service products do not enqueue job"""
|
||||
self.product.type = "service"
|
||||
|
||||
Reference in New Issue
Block a user