diff --git a/addons/delivery/tests/test_packing_delivery.py b/addons/delivery/tests/test_packing_delivery.py
index c40cdb2d500..e4710c705e8 100644
--- a/addons/delivery/tests/test_packing_delivery.py
+++ b/addons/delivery/tests/test_packing_delivery.py
@@ -65,7 +65,7 @@ class TestPacking(TestPackingCommon):
'location_dest_id': self.customer_location.id
})
picking_ship.action_confirm()
- pack_action = picking_ship.put_in_pack()
+ pack_action = picking_ship.action_put_in_pack()
pack_action_ctx = pack_action['context']
pack_action_model = pack_action['res_model']
diff --git a/addons/delivery/wizard/choose_delivery_package.py b/addons/delivery/wizard/choose_delivery_package.py
index 1932b798c11..83026e5e3d6 100644
--- a/addons/delivery/wizard/choose_delivery_package.py
+++ b/addons/delivery/wizard/choose_delivery_package.py
@@ -46,7 +46,7 @@ class ChooseDeliveryPackage(models.TransientModel):
}
return {'warning': warning_mess}
- def put_in_pack(self):
+ def action_put_in_pack(self):
picking_move_lines = self.picking_id.move_line_ids
if not self.picking_id.picking_type_id.show_reserved:
picking_move_lines = self.picking_id.move_line_nosuggest_ids
diff --git a/addons/delivery/wizard/choose_delivery_package_views.xml b/addons/delivery/wizard/choose_delivery_package_views.xml
index 5f39d08d81a..5346ca84103 100644
--- a/addons/delivery/wizard/choose_delivery_package_views.xml
+++ b/addons/delivery/wizard/choose_delivery_package_views.xml
@@ -16,7 +16,7 @@
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 9c266ce95c3..f76d0aa2ea9 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -1280,7 +1280,7 @@ class Picking(models.Model):
else:
return {}
- def _put_in_pack(self, move_line_ids):
+ def _put_in_pack(self, move_line_ids, create_package_level=True):
package = False
for pick in self:
move_lines_to_pack = self.env['stock.move.line']
@@ -1312,20 +1312,21 @@ class Picking(models.Model):
ml.write(vals)
new_move_line.write({'product_uom_qty': done_to_keep})
move_lines_to_pack |= new_move_line
- package_level = self.env['stock.package_level'].create({
- 'package_id': package.id,
- 'picking_id': pick.id,
- 'location_id': False,
- 'location_dest_id': move_line_ids.mapped('location_dest_id').id,
- 'move_line_ids': [(6, 0, move_lines_to_pack.ids)],
- 'company_id': pick.company_id.id,
- })
+ if create_package_level:
+ package_level = self.env['stock.package_level'].create({
+ 'package_id': package.id,
+ 'picking_id': pick.id,
+ 'location_id': False,
+ 'location_dest_id': move_line_ids.mapped('location_dest_id').id,
+ 'move_line_ids': [(6, 0, move_lines_to_pack.ids)],
+ 'company_id': pick.company_id.id,
+ })
move_lines_to_pack.write({
'result_package_id': package.id,
})
return package
- def put_in_pack(self):
+ def action_put_in_pack(self):
self.ensure_one()
if self.state not in ('done', 'cancel'):
picking_move_lines = self.move_line_ids
diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py
index 65dd48a1c75..97dc10346fb 100644
--- a/addons/stock/tests/test_move.py
+++ b/addons/stock/tests/test_move.py
@@ -4381,13 +4381,13 @@ class StockMove(SavepointCase):
picking.action_assign()
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product, self.stock_location), 0)
move1.quantity_done = 1
- picking.put_in_pack()
+ picking.action_put_in_pack()
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product, self.stock_location), 0)
self.assertEqual(len(picking.move_line_ids), 2)
unpacked_ml = picking.move_line_ids.filtered(lambda ml: not ml.result_package_id)
self.assertEqual(unpacked_ml.product_qty, 1)
unpacked_ml.qty_done = 1
- picking.put_in_pack()
+ picking.action_put_in_pack()
self.assertEqual(len(picking.move_line_ids), 2)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product, self.stock_location), 0)
picking.button_validate()
@@ -4432,7 +4432,7 @@ class StockMove(SavepointCase):
picking.action_assign()
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product, self.stock_location), 0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, self.stock_location), 0)
- picking.put_in_pack()
+ picking.action_put_in_pack()
self.assertEqual(len(picking.move_line_ids), 2)
self.assertEqual(picking.move_line_ids[0].qty_done, 1, "Stock move line should have 1 quantity as a done quantity.")
self.assertEqual(picking.move_line_ids[1].qty_done, 2, "Stock move line should have 2 quantity as a done quantity.")
@@ -4482,9 +4482,9 @@ class StockMove(SavepointCase):
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product, self.stock_location), 0)
self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, self.stock_location), 0)
move1.quantity_done = 1
- picking.put_in_pack()
+ picking.action_put_in_pack()
move2.quantity_done = 2
- picking.put_in_pack()
+ picking.action_put_in_pack()
self.assertEqual(len(picking.move_line_ids), 2)
line1_result_package = picking.move_line_ids[0].result_package_id
line2_result_package = picking.move_line_ids[1].result_package_id
diff --git a/addons/stock/tests/test_packing.py b/addons/stock/tests/test_packing.py
index acdce51ef56..89ef70a0b1a 100644
--- a/addons/stock/tests/test_packing.py
+++ b/addons/stock/tests/test_packing.py
@@ -79,12 +79,12 @@ class TestPacking(TestPackingCommon):
pick_picking.move_line_ids.filtered(lambda ml: ml.product_id == self.productA).qty_done = 1.0
pick_picking.move_line_ids.filtered(lambda ml: ml.product_id == self.productB).qty_done = 2.0
- first_pack = pick_picking.put_in_pack()
+ first_pack = pick_picking.action_put_in_pack()
self.assertEqual(len(pick_picking.package_level_ids), 1, 'Put some products in pack should create a package_level')
self.assertEqual(pick_picking.package_level_ids[0].state, 'new', 'A new pack should be in state "new"')
pick_picking.move_line_ids.filtered(lambda ml: ml.product_id == self.productA and ml.qty_done == 0.0).qty_done = 4.0
pick_picking.move_line_ids.filtered(lambda ml: ml.product_id == self.productB and ml.qty_done == 0.0).qty_done = 3.0
- second_pack = pick_picking.put_in_pack()
+ second_pack = pick_picking.action_put_in_pack()
self.assertEqual(len(pick_picking.move_ids_without_package), 0)
self.assertEqual(len(packing_picking.move_ids_without_package), 2)
pick_picking.button_validate()
@@ -235,7 +235,7 @@ class TestPacking(TestPackingCommon):
picking.action_confirm()
picking.action_assign()
picking.move_line_ids.filtered(lambda ml: ml.product_id == self.productA).qty_done = 5.0
- picking.put_in_pack()
+ picking.action_put_in_pack()
pack1 = self.env['stock.quant.package'].search([])[-1]
picking.write({
'move_line_ids': [(0, 0, {
@@ -261,7 +261,7 @@ class TestPacking(TestPackingCommon):
'state': 'confirmed',
})]
})
- wizard_values = picking.put_in_pack()
+ wizard_values = picking.action_put_in_pack()
wizard = self.env[(wizard_values.get('res_model'))].browse(wizard_values.get('res_id'))
wizard.location_dest_id = shelf2_location.id
wizard.action_done()
@@ -424,7 +424,7 @@ class TestPacking(TestPackingCommon):
with receipt_form.move_line_ids_without_package.edit(1) as move_line:
move_line.qty_done = 1
receipt = receipt_form.save()
- receipt.put_in_pack()
+ receipt.action_put_in_pack()
receipt.button_validate()
receipt_package = receipt.package_level_ids_details[0]
@@ -563,7 +563,7 @@ class TestPacking(TestPackingCommon):
with receipt_form.move_line_ids_without_package.edit(1) as move_line:
move_line.qty_done = 1
receipt = receipt_form.save()
- receipt.put_in_pack()
+ receipt.action_put_in_pack()
receipt.button_validate()
receipt_package = receipt.package_level_ids_details[0]
@@ -665,4 +665,4 @@ class TestPacking(TestPackingCommon):
pick_picking.action_assign()
pick_picking.move_line_ids.qty_done = 3
- first_pack = pick_picking.put_in_pack()
+ first_pack = pick_picking.action_put_in_pack()
diff --git a/addons/stock/tests/test_stock_flow.py b/addons/stock/tests/test_stock_flow.py
index e5e301d723b..58bd6a3d16f 100644
--- a/addons/stock/tests/test_stock_flow.py
+++ b/addons/stock/tests/test_stock_flow.py
@@ -1328,7 +1328,7 @@ class TestStockFlow(TestStockCommon):
# Set the quantity done on the pack operation
move_in.move_line_ids.qty_done = 3.0
# Put in a pack
- picking_in.put_in_pack()
+ picking_in.action_put_in_pack()
# Get the new package
picking_in_package = move_in.move_line_ids.result_package_id
# Validate picking
diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml
index 83100224c6e..b04462e3dfd 100644
--- a/addons/stock/views/stock_picking_views.xml
+++ b/addons/stock/views/stock_picking_views.xml
@@ -333,7 +333,7 @@
-
+
@@ -344,7 +344,7 @@
attrs="{'readonly': ['|', '|', ('show_operations', '=', False), ('state', '=', 'cancel'), '&', ('state', '=', 'done'), ('is_locked', '=', True)]}"
context="{'tree_view_ref': 'stock.view_stock_move_line_detailed_operation_tree', 'default_picking_id': id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id, 'default_company_id': company_id}"/>
-
+
@@ -420,7 +420,7 @@
-
+
diff --git a/addons/stock/wizard/stock_package_destination.py b/addons/stock/wizard/stock_package_destination.py
index 910dfe6d21b..e4abde19db1 100644
--- a/addons/stock/wizard/stock_package_destination.py
+++ b/addons/stock/wizard/stock_package_destination.py
@@ -24,7 +24,6 @@ class ChooseDestinationLocation(models.TransientModel):
destination.filtered_location = destination.move_line_ids.mapped('location_dest_id')
def action_done(self):
- # set the same location on each move line and pass again in _put_in_pack
- for line in self.move_line_ids:
- line.location_dest_id = self.location_dest_id
- return self.picking_id.put_in_pack()
+ # set the same location on each move line and pass again in action_put_in_pack
+ self.move_line_ids.location_dest_id = self.location_dest_id
+ return self.picking_id.action_put_in_pack()
diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py
index 696c67eabc5..df23497e58a 100644
--- a/addons/stock_picking_batch/models/stock_picking_batch.py
+++ b/addons/stock_picking_batch/models/stock_picking_batch.py
@@ -3,7 +3,7 @@
from odoo import api, fields, models, _
from odoo.exceptions import UserError
-
+from odoo.tools.float_utils import float_compare, float_is_zero, float_round
class StockPickingBatch(models.Model):
_inherit = ['mail.thread', 'mail.activity.mixin']
@@ -198,6 +198,30 @@ class StockPickingBatch(models.Model):
self.ensure_one()
self.picking_ids.action_assign()
+ def action_put_in_pack(self):
+ """ Action to put move lines with 'Done' quantities into a new pack
+ This method follows same logic to stock.picking.
+ """
+ self.ensure_one()
+ if self.state not in ('done', 'cancel'):
+ picking_move_lines = self.move_line_ids
+
+ move_line_ids = picking_move_lines.filtered(lambda ml:
+ float_compare(ml.qty_done, 0.0, precision_rounding=ml.product_uom_id.rounding) > 0
+ and not ml.result_package_id
+ )
+ if not move_line_ids:
+ move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.product_uom_qty, 0.0,
+ precision_rounding=ml.product_uom_id.rounding) > 0 and float_compare(ml.qty_done, 0.0,
+ precision_rounding=ml.product_uom_id.rounding) == 0)
+ if move_line_ids:
+ res = self.picking_ids[0]._pre_put_in_pack_hook(move_line_ids)
+ if not res:
+ res = self.picking_ids[0]._put_in_pack(move_line_ids, False)
+ return res
+ else:
+ raise UserError(_("Please add 'Done' quantities to the batch picking to create a new pack."))
+
# -------------------------------------------------------------------------
# Miscellaneous
# -------------------------------------------------------------------------
diff --git a/addons/stock_picking_batch/tests/test_batch_picking.py b/addons/stock_picking_batch/tests/test_batch_picking.py
index c7352699439..ecf50379002 100644
--- a/addons/stock_picking_batch/tests/test_batch_picking.py
+++ b/addons/stock_picking_batch/tests/test_batch_picking.py
@@ -325,3 +325,43 @@ class TestBatchPicking(TransactionCase):
# ensure that quantity for picking has been moved
self.assertFalse(sum(quant_A.mapped('quantity')))
self.assertFalse(sum(quant_B.mapped('quantity')))
+
+ def test_put_in_pack(self):
+ self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 10.0)
+ self.env['stock.quant']._update_available_quantity(self.productB, self.stock_location, 10.0)
+
+ # Confirm batch, pickings should not be automatically assigned.
+ self.batch.action_confirm()
+ self.assertEqual(self.picking_client_1.state, 'confirmed', 'Picking 1 should be confirmed')
+ self.assertEqual(self.picking_client_2.state, 'confirmed', 'Picking 2 should be confirmed')
+ # Ask to assign, so pickings should be assigned now.
+ self.batch.action_assign()
+ self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be ready')
+ self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be ready')
+
+ # only do part of pickings + assign different destinations + try to pack (should get wizard to correct destination)
+ self.batch.move_line_ids.qty_done = 5
+ self.batch.move_line_ids[0].location_dest_id = self.stock_location.id
+ wizard_values = self.batch.action_put_in_pack()
+ wizard = self.env[(wizard_values.get('res_model'))].browse(wizard_values.get('res_id'))
+ wizard.location_dest_id = self.customer_location.id
+ package = wizard.action_done()
+
+ # a new package is made and done quantities should be in same package
+ self.assertTrue(package)
+ done_qty_move_lines = self.batch.move_line_ids.filtered(lambda ml: ml.qty_done == 5)
+ self.assertEqual(done_qty_move_lines[0].result_package_id.id, package.id)
+ self.assertEqual(done_qty_move_lines[1].result_package_id.id, package.id)
+
+ # not done quantities should be split into separate lines
+ self.assertEqual(len(self.batch.move_line_ids), 4)
+
+ # confirm w/ backorder
+ back_order_wizard_dict = self.batch.action_done()
+ self.assertTrue(back_order_wizard_dict)
+ back_order_wizard = Form(self.env[(back_order_wizard_dict.get('res_model'))].with_context(back_order_wizard_dict['context'])).save()
+ self.assertEqual(len(back_order_wizard.pick_ids), 2)
+ back_order_wizard.process()
+
+ # final package location should be correctly set based on wizard
+ self.assertEqual(package.location_id.id, self.customer_location.id)
diff --git a/addons/stock_picking_batch/views/stock_picking_batch_views.xml b/addons/stock_picking_batch/views/stock_picking_batch_views.xml
index 97378a93a2c..d1eec150b9f 100644
--- a/addons/stock_picking_batch/views/stock_picking_batch_views.xml
+++ b/addons/stock_picking_batch/views/stock_picking_batch_views.xml
@@ -111,6 +111,7 @@
+
diff --git a/addons/stock_picking_batch/wizard/__init__.py b/addons/stock_picking_batch/wizard/__init__.py
index 063ece3795c..cfb88076d83 100644
--- a/addons/stock_picking_batch/wizard/__init__.py
+++ b/addons/stock_picking_batch/wizard/__init__.py
@@ -2,3 +2,4 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import stock_picking_to_batch
+from . import stock_package_destination
diff --git a/addons/stock_picking_batch/wizard/stock_package_destination.py b/addons/stock_picking_batch/wizard/stock_package_destination.py
new file mode 100644
index 00000000000..05b60cf0ad8
--- /dev/null
+++ b/addons/stock_picking_batch/wizard/stock_package_destination.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, models
+
+
+class ChooseDestinationLocation(models.TransientModel):
+ _inherit = "stock.package.destination"
+
+ def _compute_move_line_ids(self):
+ destination_without_batch = self.env['stock.package.destination']
+ for destination in self:
+ if not destination.picking_id.batch_id:
+ destination_without_batch |= destination
+ continue
+ destination.move_line_ids = destination.picking_id.batch_id.move_line_ids.filtered(lambda l: l.qty_done > 0 and not l.result_package_id)
+ super(ChooseDestinationLocation, destination_without_batch)._compute_move_line_ids()
+
+ def action_done(self):
+ if self.picking_id.batch_id:
+ # set the same location on each move line and pass again in action_put_in_pack
+ self.move_line_ids.location_dest_id = self.location_dest_id
+ return self.picking_id.batch_id.action_put_in_pack()
+ else:
+ return super().action_done()