From 3747f36802e1f3ea3327f96119fc8c6982d9067d Mon Sep 17 00:00:00 2001 From: arbaes Date: Wed, 10 Oct 2018 09:02:39 +0000 Subject: [PATCH 1/3] [IMP] stock: Doctring update and useless kwargs deleted - The docstring for the method `create_backorder(self)` was updated to a more convenient one. - The kwargs `backorder_moves` was remove since it was useless. --- addons/stock/models/stock_picking.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 310f7b6bef5..85d15f0d1c6 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -806,10 +806,11 @@ class Picking(models.Model): precision_rounding=move.product_uom.rounding) == 1 ) - @api.multi - def _create_backorder(self, backorder_moves=[]): - """ Move all non-done lines into a new backorder picking. - """ + def _create_backorder(self): + + """ This method is called when the user chose to create a backorder. It will create a new +        picking, the backorder, and move the stock.moves that are not `done` or `cancel` into it. +        """ backorders = self.env['stock.picking'] for picking in self: moves_to_backorder = picking.move_lines.filtered(lambda x: x.state not in ('done', 'cancel')) From 9764f04a3c33ca1d69dc5bf75b1eb2b02767ef6a Mon Sep 17 00:00:00 2001 From: arbaes Date: Wed, 10 Oct 2018 13:33:50 +0000 Subject: [PATCH 2/3] [IMP] stock: backorder created only when needed Before this commit, when the user chose to not make a backorder, a backorder was created then immediatly canceled. This behaviour is now changed as in such a case the backorder is simply not created anymore --- addons/purchase_stock/models/stock.py | 4 ++-- addons/stock/models/stock_inventory.py | 2 +- addons/stock/models/stock_move.py | 6 ++++-- addons/stock/models/stock_move_line.py | 2 +- addons/stock/models/stock_picking.py | 2 +- addons/stock/wizard/stock_backorder_confirmation.py | 7 +------ addons/stock_account/models/stock.py | 4 ++-- 7 files changed, 12 insertions(+), 15 deletions(-) diff --git a/addons/purchase_stock/models/stock.py b/addons/purchase_stock/models/stock.py index 81536d55169..385899aa194 100644 --- a/addons/purchase_stock/models/stock.py +++ b/addons/purchase_stock/models/stock.py @@ -82,8 +82,8 @@ class StockMove(models.Model): super(StockMove, self)._clean_merged() self.write({'created_purchase_line_id': False}) - def _action_done(self): - res = super(StockMove, self)._action_done() + def _action_done(self, cancel_backorder=False): + res = super(StockMove, self)._action_done(cancel_backorder=cancel_backorder) self.mapped('purchase_line_id').sudo()._update_received_qty() return res diff --git a/addons/stock/models/stock_inventory.py b/addons/stock/models/stock_inventory.py index 1e66ccffe20..a763adee13c 100644 --- a/addons/stock/models/stock_inventory.py +++ b/addons/stock/models/stock_inventory.py @@ -180,7 +180,7 @@ class Inventory(models.Model): else: self._action_done() - def _action_done(self): + def _action_done(self, cancel_backorder=False): negative = next((line for line in self.mapped('line_ids') if line.product_qty < 0 and line.product_qty != line.theoretical_qty), False) if negative: raise UserError(_('You cannot set a negative product quantity in an inventory line:\n\t%s - qty: %s') % (negative.product_id.name, negative.product_qty)) diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 29433c13091..9fc83d6b7d0 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -1084,7 +1084,7 @@ class StockMove(models.Model): def _unreserve_initial_demand(self, new_move): pass - def _action_done(self): + def _action_done(self, cancel_backorder=False): self.filtered(lambda move: move.state == 'draft')._action_confirm() # MRP allows scrapping draft moves moves = self.exists().filtered(lambda x: x.state not in ('done', 'cancel')) moves_todo = self.env['stock.move'] @@ -1124,6 +1124,8 @@ class StockMove(models.Model): except UserError: pass move._unreserve_initial_demand(new_move) + if cancel_backorder: + self.env['stock.move'].browse(new_move)._action_cancel() moves_todo.mapped('move_line_ids')._action_done() # Check the consistency of the result packages; there should be an unique location across # the contained quants. @@ -1140,7 +1142,7 @@ class StockMove(models.Model): if all(move_todo.scrapped for move_todo in moves_todo): return moves_todo - if picking: + if picking and not cancel_backorder: picking._create_backorder() return moves_todo diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index ccd2aea5a85..711a921dee9 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -351,7 +351,7 @@ class StockMoveLine(models.Model): moves._recompute_state() return res - def _action_done(self): + def _action_done(self, cancel_backorder=False): """ This method is called during a move's `action_done`. It'll actually move a quant from the source location to the destination location, and unreserve if needed in the source location. diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 85d15f0d1c6..93187e523bc 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -622,7 +622,7 @@ class Picking(models.Model): new_move._action_confirm() todo_moves |= new_move #'qty_done': ops.qty_done}) - todo_moves._action_done() + todo_moves._action_done(cancel_backorder=self.env.context.get('cancel_backorder')) self.write({'date_done': fields.Datetime.now()}) return True diff --git a/addons/stock/wizard/stock_backorder_confirmation.py b/addons/stock/wizard/stock_backorder_confirmation.py index d0c30a2ffc0..8b0b70ccea3 100644 --- a/addons/stock/wizard/stock_backorder_confirmation.py +++ b/addons/stock/wizard/stock_backorder_confirmation.py @@ -20,12 +20,7 @@ class StockBackorderConfirmation(models.TransientModel): if float_compare(move.product_uom_qty, move.quantity_done, move.product_uom.rounding) > 0: moves_to_log[move] = (move.quantity_done, move.product_uom_qty) pick_id._log_less_quantities_than_expected(moves_to_log) - self.pick_ids.action_done() - if cancel_backorder: - for pick_id in self.pick_ids: - backorder_pick = self.env['stock.picking'].search([('backorder_id', '=', pick_id.id)]) - backorder_pick.action_cancel() - pick_id.message_post(body=_("Back order %s cancelled.") % (backorder_pick.name)) + self.pick_ids.with_context({'cancel_backorder': cancel_backorder}).action_done() def process(self): self._process() diff --git a/addons/stock_account/models/stock.py b/addons/stock_account/models/stock.py index f13f8316977..e8a645aeca1 100644 --- a/addons/stock_account/models/stock.py +++ b/addons/stock_account/models/stock.py @@ -348,9 +348,9 @@ class StockMove(models.Model): 'price_unit': price_unit if self._is_dropshipped() else -price_unit, }) - def _action_done(self): + def _action_done(self, cancel_backorder=False): self.product_price_update_before_done() - res = super(StockMove, self)._action_done() + res = super(StockMove, self)._action_done(cancel_backorder=cancel_backorder) for move in res: # Apply restrictions on the stock move to be able to make # consistent accounting entries. From 35a27f51511d05a9fb93c6b86cf7c5c6b0ef4c99 Mon Sep 17 00:00:00 2001 From: arbaes Date: Tue, 16 Oct 2018 10:45:23 +0000 Subject: [PATCH 3/3] [IMP] stock: Doctring update and useless kwargs deleted - The docstring for the method `create_backorder(self)` was updated to a more convenient one. - The kwargs `backorder_moves` was remove since it was useless. --- addons/stock/tests/test_stock_flow.py | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/addons/stock/tests/test_stock_flow.py b/addons/stock/tests/test_stock_flow.py index 592d0138515..29afb5aa4c2 100644 --- a/addons/stock/tests/test_stock_flow.py +++ b/addons/stock/tests/test_stock_flow.py @@ -1791,3 +1791,55 @@ class TestStockFlow(TestStockCommon): self.assertEquals(move_mto_alone.state, "draft") self.assertEquals(move_with_ancestors.state, "waiting") self.assertEquals(other_move.state, "confirmed") + + def test_80_partial_picking_without_backorder(self): + """ This test will create a picking with an initial demand for a product + then process a lesser quantity than the expected quantity to be processed. + When the wizard ask for a backorder, the 'NO BACKORDER' option will be selected + and no backorder should be created afterwards + """ + + picking = self.PickingObj.create({ + 'partner_id': self.partner_delta_id, + 'picking_type_id': self.picking_type_in, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location}) + move_a = self.MoveObj.create({ + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 10, + 'product_uom': self.productA.uom_id.id, + 'picking_id': picking.id, + 'location_id': self.supplier_location, + 'location_dest_id': self.stock_location}) + + picking.action_confirm() + + # Only 4 items are processed + move_a.move_line_ids.qty_done = 4 + backorder_wizard = self.env['stock.backorder.confirmation'].create({'pick_ids': [(4, picking.id)]}) + backorder_wizard.process_cancel_backorder() + + # Checking that no backorders were attached to the picking + self.assertFalse(picking.backorder_id) + + # Checking that the original move is still in the same picking + self.assertEquals(move_a.picking_id.id, picking.id) + + move_lines = picking.move_lines + move_done = move_lines.browse(move_a.id) + move_canceled = move_lines - move_done + + # Checking that the original move was set to done + self.assertEquals(move_done.product_uom_qty, 4) + self.assertEquals(move_done.state, 'done') + + # Checking that the new move created was canceled + self.assertEquals(move_canceled.product_uom_qty, 6) + self.assertEquals(move_canceled.state, 'cancel') + + # Checking that the canceled move is in the original picking + self.assertIn(move_canceled.id, picking.move_lines.mapped('id')) + + +