Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new method to validate moves in a separate transfer #72

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion shopfloor/models/stock_move.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from odoo import models
from odoo import _, models


class StockMove(models.Model):
Expand Down Expand Up @@ -36,3 +36,45 @@ def _action_done(self, cancel_backorder=False):
if picking.state == "done":
picking.action_done()
return moves

def extract_and_action_done(self):
"""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.
"""
moves = self.filtered(lambda m: m.state == "assigned")
sebalix marked this conversation as resolved.
Show resolved Hide resolved
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
1 change: 1 addition & 0 deletions shopfloor/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@
from . import test_zone_picking_unload_all
from . import test_zone_picking_unload_set_destination
from . import test_misc
from . import test_stock_split
112 changes: 92 additions & 20 deletions shopfloor/tests/test_stock_split.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def setUpClass(cls):
cls.pack_location = cls.warehouse.wh_pack_stock_loc_id
cls.ship_location = cls.warehouse.wh_output_stock_loc_id
cls.stock_location = cls.env.ref("stock.stock_location_stock")
# Create a product
# Create products
cls.product_a = (
cls.env["product.product"]
.sudo()
Expand All @@ -39,6 +39,30 @@ def setUpClass(cls):
}
)
)
cls.product_b = (
cls.env["product.product"]
.sudo()
.create(
{
"name": "Product B",
"type": "product",
"default_code": "B",
"barcode": "B",
"weight": 2,
}
)
)
cls.product_b_packaging = (
cls.env["product.packaging"]
.sudo()
.create(
{
"name": "Box",
"product_id": cls.product_b.id,
"barcode": "ProductBBox",
}
)
)
# Put product_a quantities in different packages to get several move lines
cls.package_1 = cls.env["stock.quant.package"].create({"name": "PACKAGE_1"})
cls.package_2 = cls.env["stock.quant.package"].create({"name": "PACKAGE_2"})
Expand All @@ -53,6 +77,8 @@ def setUpClass(cls):
cls._update_qty_in_location(
cls.stock_location, cls.product_a, 5, package=cls.package_3
)
# Put product_b quantities in stock
cls._update_qty_in_location(cls.stock_location, cls.product_b, 10)
# Create the pick/pack/ship transfer
cls.ship_move_a = cls.env["stock.move"].create(
{
Expand All @@ -68,12 +94,28 @@ def setUpClass(cls):
"state": "draft",
}
)
cls.ship_move_a._assign_picking()
cls.ship_move_a._action_confirm(merge=False)
cls.pack_move = cls.ship_move_a.move_orig_ids[0]
cls.pick_move = cls.pack_move.move_orig_ids[0]
cls.picking = cls.pick_move.picking_id
cls.packing = cls.pack_move.picking_id
cls.ship_move_b = cls.env["stock.move"].create(
{
"name": cls.product_b.display_name,
"product_id": cls.product_b.id,
"product_uom_qty": 4,
"product_uom": cls.product_b.uom_id.id,
"location_id": cls.ship_location.id,
"location_dest_id": cls.customer_location.id,
"warehouse_id": cls.warehouse.id,
"picking_type_id": cls.warehouse.out_type_id.id,
"procure_method": "make_to_order",
"state": "draft",
}
)
(cls.ship_move_a | cls.ship_move_b)._assign_picking()
(cls.ship_move_a | cls.ship_move_b)._action_confirm(merge=False)
cls.pack_move_a = cls.ship_move_a.move_orig_ids[0]
cls.pick_move_a = cls.pack_move_a.move_orig_ids[0]
cls.pack_move_b = cls.ship_move_b.move_orig_ids[0]
cls.pick_move_b = cls.pack_move_b.move_orig_ids[0]
cls.picking = cls.pick_move_a.picking_id
cls.packing = cls.pack_move_a.picking_id
cls.picking.action_assign()

@classmethod
Expand All @@ -90,27 +132,27 @@ def _update_qty_in_location(
)

def test_split_pickings_from_source_location(self):
dest_location = self.pick_move.location_dest_id.sudo().copy(
dest_location = self.pick_move_a.location_dest_id.sudo().copy(
{
"name": self.pick_move.location_dest_id.name + "_2",
"barcode": self.pick_move.location_dest_id.barcode + "_2",
"location_id": self.pick_move.location_dest_id.id,
"name": self.pick_move_a.location_dest_id.name + "_2",
"barcode": self.pick_move_a.location_dest_id.barcode + "_2",
"location_id": self.pick_move_a.location_dest_id.id,
}
)
# Pick goods from stock and move some of them to a different destination
self.assertEqual(self.pick_move.state, "assigned")
for i, move_line in enumerate(self.pick_move.move_line_ids):
self.assertEqual(self.pick_move_a.state, "assigned")
for i, move_line in enumerate(self.pick_move_a.move_line_ids):
move_line.qty_done = move_line.product_uom_qty
if i % 2:
move_line.location_dest_id = dest_location
self.pick_move.with_context(_sf_no_backorder=True)._action_done()
self.assertEqual(self.pick_move.state, "done")
self.pick_move_a.with_context(_sf_no_backorder=True)._action_done()
self.assertEqual(self.pick_move_a.state, "done")
# Pack step, we want to split move lines from common source location
self.assertEqual(self.pack_move.state, "assigned")
move_lines_to_process = self.pack_move.move_line_ids.filtered(
self.assertEqual(self.pack_move_a.state, "assigned")
move_lines_to_process = self.pack_move_a.move_line_ids.filtered(
lambda ml: ml.location_id == dest_location
)
self.assertEqual(len(self.pack_move.move_line_ids), 3)
self.assertEqual(len(self.pack_move_a.move_line_ids), 3)
self.assertEqual(len(self.packing.package_level_ids), 3)
self.assertEqual(len(move_lines_to_process), 1)
new_packing = move_lines_to_process._split_pickings_from_source_location()
Expand All @@ -120,9 +162,39 @@ def test_split_pickings_from_source_location(self):
self.assertTrue(new_packing != self.packing)
self.assertEqual(new_packing.backorder_id, self.packing)
self.assertEqual(
self.pick_move.move_dest_ids.picking_id, self.packing | new_packing
self.pick_move_a.move_dest_ids.picking_id, self.packing | new_packing
)
self.assertEqual(move_lines_to_process.state, "assigned")
self.assertEqual(
set(self.pack_move.move_line_ids.mapped("state")), {"assigned"}
set(self.pack_move_a.move_line_ids.mapped("state")), {"assigned"}
)

def test_extract_and_action_done_one_move(self):
self.assertFalse(self.picking.backorder_ids)
self.assertEqual(self.picking.state, "assigned")
for move_line in self.pick_move_b.move_line_ids:
move_line.qty_done = move_line.product_uom_qty
self.pick_move_b.extract_and_action_done()
new_picking = self.picking.backorder_ids
self.assertTrue(new_picking)
# Check move lines repartition
self.assertNotIn(self.pick_move_b, self.picking.move_lines)
self.assertEqual(new_picking.move_lines, self.pick_move_b)
# Check states
self.assertEqual(self.picking.state, "assigned")
self.assertEqual(self.pick_move_b.state, "done")
self.assertEqual(new_picking.state, "done")

def test_extract_and_action_done_several_moves(self):
self.assertFalse(self.picking.backorder_ids)
self.assertEqual(self.picking.state, "assigned")
for move_line in self.picking.move_line_ids:
move_line.qty_done = move_line.product_uom_qty
self.picking.move_lines.extract_and_action_done()
# No backorder as all moves of the picking have been validated
new_picking = self.picking.backorder_ids
self.assertFalse(new_picking)
# Check move lines repartition
self.assertEqual(len(self.picking.move_lines), 2)
# Check states
self.assertEqual(self.picking.state, "done")