diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py index df23497e58a9be14fef1197c2f6c078c870ad86f..e5da1f90299492c393ca36a9207139ee96e40d63 100644 --- a/addons/stock_picking_batch/models/stock_picking_batch.py +++ b/addons/stock_picking_batch/models/stock_picking_batch.py @@ -185,14 +185,24 @@ class StockPickingBatch(models.Model): if any(picking.state not in ('assigned', 'confirmed') for picking in pickings): raise UserError(_('Some transfers are still waiting for goods. Please check or force their availability before setting this batch to done.')) + empty_pickings = set() for picking in pickings: + if all(float_is_zero(line.qty_done, precision_rounding=line.product_uom_id.rounding) for line in picking.move_line_ids if line.state not in ('done', 'cancel')): + empty_pickings.add(picking.id) picking.message_post( body="<b>%s:</b> %s <a href=#id=%s&view_type=form&model=stock.picking.batch>%s</a>" % ( _("Transferred by"), _("Batch Transfer"), picking.batch_id.id, picking.batch_id.name)) - return pickings.button_validate() + + if len(empty_pickings) == len(pickings): + return pickings.button_validate() + else: + res = pickings.with_context(skip_immediate=True).button_validate() + if empty_pickings and res.get('context'): + res['context']['pickings_to_detach'] = list(empty_pickings) + return res def action_assign(self): self.ensure_one() diff --git a/addons/stock_picking_batch/tests/test_batch_picking.py b/addons/stock_picking_batch/tests/test_batch_picking.py index ecf50379002914b9a7c456cb5283ade0e97cf57d..38af9971fd14aba9f1b79451cfe8a3635051946f 100644 --- a/addons/stock_picking_batch/tests/test_batch_picking.py +++ b/addons/stock_picking_batch/tests/test_batch_picking.py @@ -286,10 +286,10 @@ class TestBatchPicking(TransactionCase): self.assertFalse(sum(quant_B.mapped('quantity'))) def test_batch_with_immediate_transfer_and_backorder_wizard_with_manual_operations(self): - """ Test a simple batch picking with only one quantity fully available. - The user set the quantity done only for the partially available picking. - The test should run the immediate transfer for the first picking and then - the backorder wizard for the second picking. + """ When validating a batch picking where some pickings have no quantities done + some + do, then avoid immediate transfers wizard and remove pickings with no quantities done + from the batch picking. This will make it so users can validate a partially done batch + picking in this case. """ self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 5.0) self.env['stock.quant']._update_available_quantity(self.productB, self.stock_location, 10.0) @@ -304,27 +304,17 @@ class TestBatchPicking(TransactionCase): self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be ready') self.picking_client_1.move_lines.quantity_done = 5 - # There should be a wizard asking to process picking without quantity done - immediate_transfer_wizard_dict = self.batch.action_done() - self.assertTrue(immediate_transfer_wizard_dict) - immediate_transfer_wizard = Form(self.env[(immediate_transfer_wizard_dict.get('res_model'))].with_context(immediate_transfer_wizard_dict['context'])).save() - self.assertEqual(len(immediate_transfer_wizard.pick_ids), 1) - back_order_wizard_dict = immediate_transfer_wizard.process() + # There should be a wizard asking to make a backorder + back_order_wizard_dict = self.batch.action_done() self.assertTrue(back_order_wizard_dict) + self.assertEqual(back_order_wizard_dict.get('res_model'), 'stock.backorder.confirmation') 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), 1) + self.assertEqual(len(back_order_wizard.pick_ids), 2) back_order_wizard.process() self.assertEqual(self.picking_client_1.state, 'done', 'Picking 1 should be done') self.assertEqual(self.picking_client_1.move_lines.product_uom_qty, 5, 'initial demand should be 5 after picking split') - self.assertTrue(self.env['stock.picking'].search([('backorder_id', '=', self.picking_client_1.id)]), 'no back order created') - - quant_A = self.env['stock.quant']._gather(self.productA, self.stock_location) - quant_B = self.env['stock.quant']._gather(self.productB, self.stock_location) - - # ensure that quantity for picking has been moved - self.assertFalse(sum(quant_A.mapped('quantity'))) - self.assertFalse(sum(quant_B.mapped('quantity'))) + self.assertFalse(self.picking_client_2.batch_id, 'The picking should be removed from the batch') def test_put_in_pack(self): self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 10.0) diff --git a/addons/stock_picking_batch/wizard/__init__.py b/addons/stock_picking_batch/wizard/__init__.py index cfb88076d8392da60b275711dd279ec7f017b2df..044d36b943b7950b6c0514c2fd68fd8a8ae7159c 100644 --- a/addons/stock_picking_batch/wizard/__init__.py +++ b/addons/stock_picking_batch/wizard/__init__.py @@ -3,3 +3,4 @@ from . import stock_picking_to_batch from . import stock_package_destination +from . import stock_backorder_confirmation diff --git a/addons/stock_picking_batch/wizard/stock_backorder_confirmation.py b/addons/stock_picking_batch/wizard/stock_backorder_confirmation.py new file mode 100644 index 0000000000000000000000000000000000000000..ba587e08ce6c7ea597285e4734259dcb9ff77165 --- /dev/null +++ b/addons/stock_picking_batch/wizard/stock_backorder_confirmation.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models + + +class StockBackorderConfirmation(models.TransientModel): + _inherit = 'stock.backorder.confirmation' + + def process(self): + res = super().process() + if self.env.context.get('pickings_to_detach'): + self.env['stock.picking'].browse(self.env.context['pickings_to_detach']).batch_id = False + return res + + def process_cancel_backorder(self): + res = super().process_cancel_backorder() + if self.env.context.get('pickings_to_detach'): + self.env['stock.picking'].browse(self.env.context['pickings_to_detach']).batch_id = False + return res