From 0494e6763f3cdb325b0e5bf6f46934548cf36067 Mon Sep 17 00:00:00 2001 From: fw-bot Date: Thu, 13 Feb 2020 14:01:49 +0000 Subject: [PATCH] [FIX] stock: immediate transfer Create an immediate transfer for a receipt, add a move, set a quantity done and due to rev[0], an initial demand is set, then _autoconfirm_picking is called and action_confirm of picking calls _action_assign if the location source bypasses the reservation. Set again an inferior qty_done, the initial demand is also updated due to rev[0] and somehow the system tries to write on a now unlinked move line. fixes - never reserve an immediate transfer - never update the initial demand if the move is reserved to fix the existing databases. - adapt _compute_state so that immediate transfer moves considered reserved so that they're always "ready" - adapt the test that was working on an immediate transfer picking and setting the initial demand while it's not possible through the interface, the user can only set the done quantity. [0] 8303b1a closes odoo/odoo#45317 X-original-commit: 357e0a862744f1bc23a9643a1822d2ee4a2eb7a2 Signed-off-by: Simon Lejeune (sle) --- addons/stock/models/stock_move_line.py | 3 ++- addons/stock/models/stock_picking.py | 8 +++++--- addons/stock/report/report_stock_quantity.py | 4 ++-- addons/stock/tests/test_move.py | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index defd0045295..b4ab7d3273d 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -347,7 +347,8 @@ class StockMoveLine(models.Model): # done stock move should have its `quantity_done` equals to its `product_uom_qty`, and # this is what move's `action_done` will do. So, we replicate the behavior here. if updates or 'qty_done' in vals: - moves = self.filtered(lambda ml: ml.move_id.state == 'done' or ml.move_id.picking_id and ml.move_id.picking_id.immediate_transfer).mapped('move_id') + moves = self.filtered(lambda ml: ml.move_id.state == 'done').mapped('move_id') + moves |= self.filtered(lambda ml: ml.move_id.state not in ('done', 'cancel') and ml.move_id.picking_id.immediate_transfer and not ml.product_uom_qty).mapped('move_id') for move in moves: move.product_uom_qty = move.quantity_done next_moves._do_unreserve() diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 9878c5f1763..4878a2e93ed 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -427,7 +427,7 @@ class Picking(models.Model): ] }) - @api.depends('move_type', 'move_lines.state', 'move_lines.picking_id') + @api.depends('move_type', 'immediate_transfer', 'move_lines.state', 'move_lines.picking_id') def _compute_state(self): ''' State of a picking depends on the state of its related stock.move - Draft: only used for "planned pickings" @@ -452,7 +452,9 @@ class Picking(models.Model): picking.state = 'done' else: relevant_move_state = picking.move_lines._get_relevant_state_among_moves() - if relevant_move_state == 'partially_available': + if picking.immediate_transfer and relevant_move_state not in ('draft', 'cancel', 'done'): + picking.state = 'assigned' + elif relevant_move_state == 'partially_available': picking.state = 'assigned' else: picking.state = relevant_move_state @@ -656,7 +658,7 @@ class Picking(models.Model): .filtered(lambda move: move.state == 'draft')\ ._action_confirm() # call `_action_assign` on every confirmed move which location_id bypasses the reservation - self.filtered(lambda picking: picking.location_id.usage in ('supplier', 'inventory', 'production') and picking.state == 'confirmed')\ + self.filtered(lambda picking: not picking.immediate_transfer and picking.location_id.usage in ('supplier', 'inventory', 'production') and picking.state == 'confirmed')\ .mapped('move_lines')._action_assign() return True diff --git a/addons/stock/report/report_stock_quantity.py b/addons/stock/report/report_stock_quantity.py index e5baf12d524..ebaf173980f 100644 --- a/addons/stock/report/report_stock_quantity.py +++ b/addons/stock/report/report_stock_quantity.py @@ -88,8 +88,8 @@ SELECT ELSE date::date - interval '1 day' END, '1 day'::interval)::date date, CASE - WHEN (whs.id IS NOT NULL AND whd.id IS NULL) OR ls.usage = 'transit' AND m.state = 'done' THEN product_qty - WHEN (whs.id IS NULL AND whd.id IS NOT NULL) OR ld.usage = 'transit' AND m.state = 'done' THEN -product_qty + WHEN ((whs.id IS NOT NULL AND whd.id IS NULL) OR ls.usage = 'transit') AND m.state = 'done' THEN product_qty + WHEN ((whs.id IS NULL AND whd.id IS NOT NULL) OR ld.usage = 'transit') AND m.state = 'done' THEN -product_qty WHEN (whs.id IS NOT NULL AND whd.id IS NULL) OR ls.usage = 'transit' THEN -product_qty WHEN (whs.id IS NULL AND whd.id IS NOT NULL) OR ld.usage = 'transit' THEN product_qty END AS product_qty, diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index 282533016f5..2ea2047baf0 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -4277,12 +4277,12 @@ class StockMove(SavepointCase): 'location_dest_id': self.stock_location.id, 'product_id': self.product.id, 'product_uom': self.uom_unit.id, - 'product_uom_qty': 10.0, + 'quantity_done': 10.0, 'picking_id': picking.id, }) picking._autoconfirm_picking() self.assertEqual(picking.state, 'assigned') - move1.product_uom_qty = 12 + move1.quantity_done = 12 self.assertEqual(picking.state, 'assigned') def test_initial_demand_4(self):