From d43feb008b1b00b3b30457e2b344d5385597f73d Mon Sep 17 00:00:00 2001
From: William Henrotin <whe@odoo.com>
Date: Thu, 19 Aug 2021 12:39:24 +0000
Subject: [PATCH] [FIX] stock_picking_batch: remove empty pickings

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.

This is an adaptation of [1] (which is already deployed in 15.0)

[1] eb0ebc077afed24e8f5c2212f2a216bb1b8e6936

OPW-2711585

closes odoo/odoo#81844

Signed-off-by: Tiffany Chang <tic@odoo.com>
Co-authored-by: William Henrotin (whe) <whe@odoo.com>
---
 addons/stock/models/stock_picking.py          |  2 +-
 .../models/stock_picking_batch.py             | 10 ++++---
 .../tests/test_batch_picking.py               | 26 +++++++------------
 addons/stock_picking_batch/wizard/__init__.py |  1 +
 .../wizard/stock_backorder_confirmation.py    | 20 ++++++++++++++
 5 files changed, 38 insertions(+), 21 deletions(-)
 create mode 100644 addons/stock_picking_batch/wizard/stock_backorder_confirmation.py

diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 5b61eba3d3fc..1bb5da96cdbd 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -947,7 +947,7 @@ class Picking(models.Model):
             'view_id': view.id,
             'target': 'new',
             'res_id': wiz.id,
-            'context': self.env.context,
+            'context': dict(self.env.context),
         }
 
     def action_toggle_is_locked(self):
diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py
index e8316cffcc61..d3edc5e0824f 100644
--- a/addons/stock_picking_batch/models/stock_picking_batch.py
+++ b/addons/stock_picking_batch/models/stock_picking_batch.py
@@ -83,7 +83,7 @@ class StockPickingBatch(models.Model):
                 picking_to_backorder |= picking
             else:
                 picking.action_done()
-        if picking_without_qty_done:
+        if len(picking_without_qty_done) == len(pickings):
             view = self.env.ref('stock.view_immediate_transfer')
             wiz = self.env['stock.immediate.transfer'].create({
                 'pick_ids': [(4, p.id) for p in picking_without_qty_done],
@@ -100,8 +100,12 @@ class StockPickingBatch(models.Model):
                 'res_id': wiz.id,
                 'context': self.env.context,
             }
-        if picking_to_backorder:
-            return picking_to_backorder.action_generate_backorder_wizard()
+        if picking_to_backorder or picking_without_qty_done:
+            res = picking_to_backorder.action_generate_backorder_wizard()
+            if picking_without_qty_done and 'context' in res:
+                res['context']['pickings_to_detach'] = picking_without_qty_done.ids
+            return res
+
         # Change the state only if there is no other action (= wizard) waiting.
         self.write({'state': 'done'})
         return True
diff --git a/addons/stock_picking_batch/tests/test_batch_picking.py b/addons/stock_picking_batch/tests/test_batch_picking.py
index 0c477f88dc07..ae96f6941b28 100644
--- a/addons/stock_picking_batch/tests/test_batch_picking.py
+++ b/addons/stock_picking_batch/tests/test_batch_picking.py
@@ -188,10 +188,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)
@@ -202,24 +202,16 @@ 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.done()
-        self.assertTrue(immediate_transfer_wizard_dict)
-        immediate_transfer_wizard = self.env[(immediate_transfer_wizard_dict.get('res_model'))].browse(immediate_transfer_wizard_dict.get('res_id'))
-        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.done()
         self.assertTrue(back_order_wizard_dict)
+        self.assertEqual(back_order_wizard_dict.get('res_model'), 'stock.backorder.confirmation')
         back_order_wizard = self.env[(back_order_wizard_dict.get('res_model'))].browse(back_order_wizard_dict.get('res_id'))
+        back_order_wizard = back_order_wizard.with_context(back_order_wizard_dict.get('context'))
         self.assertEqual(len(back_order_wizard.pick_ids), 1)
         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')
diff --git a/addons/stock_picking_batch/wizard/__init__.py b/addons/stock_picking_batch/wizard/__init__.py
index 92e3d6e014e1..294c4323c494 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_immediate_transfer
+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 000000000000..ba587e08ce6c
--- /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
-- 
GitLab