[FIX] stock_vertical_lift: handles multiple move lines on pick

If there is two move lines for the same product in the vertical lift
(stored in2 differents trays for instance), the pick scenario was
failing when the user was processing the first line.

To circumvent this, instead of validating directly the move, we put the line
in its own stock move, then we put the stock move in its own transfer and
validate this one.

Methods used to do that have been copied from the `shopfloor` module,
they probably deserves their own module as they are quite generic.
This commit is contained in:
Sébastien Alix
2020-12-01 14:07:32 +01:00
committed by Hai Lang
parent a2476efdaa
commit ff4d9bbfad
6 changed files with 114 additions and 10 deletions

View File

@@ -3,7 +3,7 @@
{
"name": "Vertical Lift",
"summary": "Provides the core for integration with Vertical Lifts",
"version": "13.0.1.1.1",
"version": "13.0.1.1.2",
"category": "Stock",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "AGPL-3",

View File

@@ -7,7 +7,27 @@
<field name="product_id" ref="product_running_socks" />
<field name="product_uom_id" ref="uom.product_uom_unit" />
<field name="inventory_id" ref="stock_inventory_vertical_lift_0" />
<field name="product_qty">30.0</field>
<field name="product_qty">10.0</field>
<field
name="location_id"
ref="stock_location_vertical_lift_demo_tray_1b_x1y2"
/>
</record>
<record id="stock_inventory_vertical_lift_line_2" model="stock.inventory.line">
<field name="product_id" ref="product_running_socks" />
<field name="product_uom_id" ref="uom.product_uom_unit" />
<field name="inventory_id" ref="stock_inventory_vertical_lift_0" />
<field name="product_qty">10.0</field>
<field
name="location_id"
ref="stock_location_vertical_lift_demo_tray_1b_x2y2"
/>
</record>
<record id="stock_inventory_vertical_lift_line_3" model="stock.inventory.line">
<field name="product_id" ref="product_running_socks" />
<field name="product_uom_id" ref="uom.product_uom_unit" />
<field name="inventory_id" ref="stock_inventory_vertical_lift_0" />
<field name="product_qty">10.0</field>
<field
name="location_id"
ref="stock_location_vertical_lift_demo_tray_1b_x3y2"

View File

@@ -125,6 +125,14 @@ msgstr ""
msgid "Created by"
msgstr ""
#. module: stock_vertical_lift
#: code:addons/stock_vertical_lift/models/vertical_lift_operation_base.py:0
#, python-format
msgid ""
"Created from backorder <a href=# data-oe-model=stock.picking data-oe-"
"id=%d>%s</a>."
msgstr ""
#. module: stock_vertical_lift
#: model:ir.model.fields,field_description:stock_vertical_lift.field_vertical_lift_command__create_date
#: model:ir.model.fields,field_description:stock_vertical_lift.field_vertical_lift_operation_inventory__create_date

View File

@@ -11,6 +11,79 @@ from odoo.addons.base_sparse_field.models.fields import Serialized
_logger = logging.getLogger(__name__)
# The following methods have been copied from 'shopfloor' module (OCA/wms)
# TODO: we should move them in a generic module
def split_other_move_lines(move, move_lines):
"""Substract `move_lines` from `move.move_line_ids`, put the result
in a new move and returns it.
"""
other_move_lines = move.move_line_ids - move_lines
if other_move_lines or move.state == "partially_available":
qty_to_split = move.product_uom_qty - sum(move_lines.mapped("product_uom_qty"))
backorder_move_id = move._split(qty_to_split)
backorder_move = move.browse(backorder_move_id)
backorder_move.move_line_ids = other_move_lines
backorder_move._recompute_state()
backorder_move._action_assign()
move._recompute_state()
return backorder_move
return False
def extract_and_action_done(move):
"""Extract the moves in a separate transfer and validate them.
You can combine this method with `split_other_move_lines` method
to first extract some move lines in a separate move, then validate it
with this method.
"""
# Put remaining qty to process from partially available moves
# in their own move (which will be then 'confirmed')
partial_moves = move.filtered(lambda m: m.state == "partially_available")
for partial_move in partial_moves:
partial_move.split_other_move_lines(partial_move.move_line_ids)
# Process assigned moves
moves = move.filtered(lambda m: m.state == "assigned")
if not moves:
return False
for picking in moves.picking_id:
moves_todo = picking.move_lines & moves
if moves_todo == picking.move_lines:
# No need to create a new transfer if we are processing all moves
new_picking = picking
else:
new_picking = picking.copy(
{
"name": "/",
"move_lines": [],
"move_line_ids": [],
"backorder_id": picking.id,
}
)
new_picking.message_post(
body=_(
"Created from backorder "
"<a href=# data-oe-model=stock.picking data-oe-id=%d>%s</a>."
)
% (picking.id, picking.name)
)
moves_todo.write({"picking_id": new_picking.id})
moves_todo.package_level_id.write({"picking_id": new_picking.id})
moves_todo.move_line_ids.write({"picking_id": new_picking.id})
moves_todo.move_line_ids.package_level_id.write(
{"picking_id": new_picking.id}
)
new_picking.action_assign()
assert new_picking.state == "assigned"
new_picking.action_done()
return True
# /methods
class VerticalLiftOperationBase(models.AbstractModel):
"""Base model for shuttle operations (pick, put, inventory)"""
@@ -412,7 +485,9 @@ class VerticalLiftOperationTransfer(models.AbstractModel):
line = self.current_move_line_id
if line.state in ("assigned", "partially_available"):
line.qty_done = line.product_qty
line.move_id._action_done()
# if the move has other move lines, it is split to have only this move line
split_other_move_lines(line.move_id, line)
extract_and_action_done(line.move_id)
return True
def fetch_tray(self):

View File

@@ -154,10 +154,11 @@ class VerticalLiftCase(common.LocationTrayTypeCase):
inventory.action_start()
return inventory
def _test_button_release(self, move_line, expected_state):
# for the test, we'll consider our last line has been delivered
def _test_button_release(self, move_lines, expected_state):
# for the test, we'll consider all the lines has been delivered
for move_line in move_lines:
move_line.qty_done = move_line.product_qty
move_line.move_id._action_done()
move_lines.picking_id.action_done()
# release, no further operation in queue
operation = self.shuttle._operation_for_mode()
# the release button can be used only in the state... release

View File

@@ -13,7 +13,7 @@ class TestPick(VerticalLiftCase):
)
# we have a move line to pick created by demo picking
# stock_picking_out_demo_vertical_lift_1
cls.out_move_line = cls.picking_out.move_line_ids
cls.out_move_line = cls.picking_out.move_line_ids[0]
def test_switch_pick(self):
self.shuttle.switch_pick()
@@ -159,7 +159,7 @@ class TestPick(VerticalLiftCase):
def test_button_release(self):
self._open_screen("pick")
self._test_button_release(self.out_move_line, "noop")
self._test_button_release(self.picking_out.move_line_ids, "noop")
def test_process_current_pick(self):
operation = self._open_screen("pick")
@@ -183,7 +183,7 @@ class TestPick(VerticalLiftCase):
# fmt: off
'cells': [
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0],
]
# fmt: on
},