Skip to content

Commit 23b31b4

Browse files
committed
[IMP] stock_release_channel: Allow to sleep and reassign pickings
In some cases, we don't want to use an open channel to deliver pickings anymore. But the internal transfers may have been done. In that case, we should not unrelease done pickings but just removing the channel and triggering an assignation (to put those transfers in another open channel).
1 parent d328d6e commit 23b31b4

File tree

8 files changed

+143
-2
lines changed

8 files changed

+143
-2
lines changed

stock_release_channel/README.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ button is used, in addition to the state change, the system looks for pending
8787
transfers requiring a release and try to assign them to a channel in the
8888
"Open" or "Locked" state.
8989

90+
You can also use the "Sleep and Reassign" action on channels that have transfers
91+
in progress. This is particularly useful if you don't want to use the current
92+
channel and want to reassign pickings to another(s) channel(s). Before using that
93+
action, you should check that channels for those pickings are open (as the transfers
94+
could not be assigned if there is no corresponding channel found).
95+
9096
Bug Tracker
9197
===========
9298

stock_release_channel/models/stock_picking.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Copyright 2020 Camptocamp
22
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
3-
43
from odoo import _, exceptions, fields, models
54
from odoo.osv import expression
65

stock_release_channel/models/stock_release_channel.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ class StockReleaseChannel(models.Model):
225225
compute="_compute_is_action_wake_up_allowed",
226226
help="Technical field to check if the " "action 'Wake Up' is allowed.",
227227
)
228+
is_action_safe_sleep_allowed = fields.Boolean(
229+
compute="_compute_is_action_safe_sleep_allowed",
230+
help="Technical field to check if the action 'Safe Sleep' is allowed.",
231+
)
228232
is_release_allowed = fields.Boolean(
229233
compute="_compute_is_release_allowed",
230234
search="_search_is_release_allowed",
@@ -270,6 +274,13 @@ def _compute_is_release_allowed(self):
270274
for rec in self:
271275
rec.is_release_allowed = rec.state == "open" and not rec.release_forbidden
272276

277+
@api.depends("state")
278+
def _compute_is_action_safe_sleep_allowed(self):
279+
for rec in self:
280+
rec.is_action_safe_sleep_allowed = bool(
281+
rec.state in ["locked", "open"] and rec.open_picking_ids
282+
)
283+
273284
def _compute_show_last_picking_done(self):
274285
for rec in self:
275286
rec.show_last_picking_done = (
@@ -873,15 +884,21 @@ def action_unlock(self):
873884
self.write({"state": "open"})
874885

875886
def action_sleep(self):
887+
# TODO: Add safe argument in function arguments in further version to
888+
# avoid context call
889+
safe_sleep = self.env.context.get("release_channel_safe_sleep", False)
876890
self._check_is_action_sleep_allowed()
877891
pickings_to_unassign = self.env["stock.picking"].search(
878892
self._get_picking_to_unassign_domain()
879893
)
880894
pickings_to_unassign.write({"release_channel_id": False})
881-
pickings_to_unassign.unrelease()
895+
pickings_to_unassign.unrelease(safe_unrelease=safe_sleep)
882896
self.write({"state": "asleep"})
883897
pickings_to_unassign._delay_assign_release_channel()
884898

899+
def action_safe_sleep(self):
900+
self.with_context(release_channel_safe_sleep=True).action_sleep()
901+
885902
def action_wake_up(self):
886903
self._check_is_action_wake_up_allowed()
887904
for rec in self:

stock_release_channel/readme/USAGE.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,9 @@ A asleep channel can be waken up by using the "Wake up" button. When the "Wake u
2626
button is used, in addition to the state change, the system looks for pending
2727
transfers requiring a release and try to assign them to a channel in the
2828
"Open" or "Locked" state.
29+
30+
You can also use the "Sleep and Reassign" action on channels that have transfers
31+
in progress. This is particularly useful if you don't want to use the current
32+
channel and want to reassign pickings to another(s) channel(s). Before using that
33+
action, you should check that channels for those pickings are open (as the transfers
34+
could not be assigned if there is no corresponding channel found).

stock_release_channel/static/description/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,11 @@ <h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
436436
button is used, in addition to the state change, the system looks for pending
437437
transfers requiring a release and try to assign them to a channel in the
438438
“Open” or “Locked” state.</p>
439+
<p>You can also use the “Sleep and Reassign” action on channels that have transfers
440+
in progress. This is particularly useful if you don’t want to use the current
441+
channel and want to reassign pickings to another(s) channel(s). Before using that
442+
action, you should check that channels for those pickings are open (as the transfers
443+
could not be assigned if there is no corresponding channel found).</p>
439444
</div>
440445
<div class="section" id="bug-tracker">
441446
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>

stock_release_channel/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
test_release_channel,
77
test_release_channel_lifecycle,
88
test_release_channel_partner,
9+
test_release_channel_safe_sleep,
910
)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Copyright 2025 ACSONE SA/NV (https://acsone.eu)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
3+
4+
5+
from .common import ReleaseChannelCase
6+
7+
8+
class TestReleaseChannelCancel(ReleaseChannelCase):
9+
def test_release_channel_cancel(self):
10+
"""
11+
Create a new channel with a priority filter
12+
Release the move with that picking priority
13+
14+
The created channel is assigned to the move picking
15+
16+
Call the unassign on the channel and check the
17+
picking is unassigned
18+
19+
Set the channel to 'asleep' state
20+
Try to assign the picking
21+
22+
The default channel should be set
23+
"""
24+
self.env.company.recompute_channel_on_pickings_at_release = True
25+
channel = self._create_channel(
26+
name="Test Domain",
27+
sequence=1,
28+
rule_domain=[("priority", "=", "1")],
29+
)
30+
move = self._create_single_move(self.product1, 10)
31+
move.picking_id.priority = "1"
32+
move.release_available_to_promise()
33+
self.assertEqual(move.picking_id.release_channel_id, channel)
34+
35+
channel.action_safe_sleep()
36+
self.assertFalse(move.picking_id.release_channel_id)
37+
38+
move.release_available_to_promise()
39+
self.assertEqual(move.picking_id.release_channel_id, self.default_channel)
40+
41+
def test_release_channel_cancel_after_picking(self):
42+
"""
43+
Create a new channel with a priority filter
44+
Release the move with that picking priority
45+
46+
The created channel is assigned to the move picking
47+
48+
Transfer the picking from stock location
49+
50+
Call the unassign on the channel and check the
51+
picking is unassigned
52+
53+
Set the channel to 'asleep' state
54+
Try to assign the picking
55+
56+
The default channel should be set
57+
58+
Transfer the outgoing picking
59+
60+
Try to unassign it. It should be impossible
61+
62+
"""
63+
self.env.company.recompute_channel_on_pickings_at_release = True
64+
channel = self._create_channel(
65+
name="Test Domain",
66+
sequence=1,
67+
rule_domain=[("priority", "=", "1")],
68+
)
69+
self._update_qty_in_location(self.wh.lot_stock_id, self.product1, 10.0)
70+
move = self._create_single_move(self.product1, 10)
71+
move.warehouse_id = self.wh
72+
move.procure_method = "make_to_order"
73+
move.rule_id = self.wh.delivery_route_id.rule_ids.filtered(
74+
lambda rule: rule.location_dest_id == move.location_dest_id
75+
)
76+
move.route_ids = move.rule_id.route_id
77+
move.picking_id.priority = "1"
78+
move.need_release = True
79+
move.invalidate_cache(["ordered_available_to_promise_qty"])
80+
move.release_available_to_promise()
81+
self.assertEqual(move.picking_id.release_channel_id, channel)
82+
83+
self.assertTrue(move.move_orig_ids)
84+
85+
move.move_orig_ids.quantity_done = 10.0
86+
move.move_orig_ids._action_done()
87+
88+
channel.action_safe_sleep()
89+
self.assertFalse(move.picking_id.release_channel_id)
90+
91+
move.release_available_to_promise()
92+
self.assertEqual(move.picking_id.release_channel_id, self.default_channel)
93+
94+
move.quantity_done = 10.0
95+
move._action_done()
96+
self.assertEqual("done", move.state)

stock_release_channel/views/stock_release_channel_views.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<field name="is_action_unlock_allowed" invisible="1" />
1212
<field name="is_action_sleep_allowed" invisible="1" />
1313
<field name="is_action_wake_up_allowed" invisible="1" />
14+
<field name="is_action_safe_sleep_allowed" invisible="1" />
1415
<button
1516
name="action_lock"
1617
string="Lock"
@@ -43,6 +44,16 @@
4344
icon="fa-bolt"
4445
attrs="{'invisible': [('is_action_wake_up_allowed', '=', False)]}"
4546
/>
47+
<button
48+
name="action_safe_sleep"
49+
string="Sleep and Reassign"
50+
type="object"
51+
class="oe_stat_button"
52+
icon="fa-random"
53+
confirm="Are you sure you want to make this channel fall asleep and reassign pickings? You maybe need to check if new channel to catch these pickings is open before doing this."
54+
help="Click here to make this channel sleep and reassign current pickings"
55+
attrs="{'invisible': [('is_action_safe_sleep_allowed', '=', False)]}"
56+
/>
4657
<field
4758
name="state"
4859
widget="statusbar"

0 commit comments

Comments
 (0)