diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index d98f5778a6b..19825276ec3 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -180,26 +180,41 @@ class StockMoveLine(models.Model): vals['company_id'] = self.env['stock.move'].browse(vals['move_id']).company_id.id elif vals.get('picking_id'): vals['company_id'] = self.env['stock.picking'].browse(vals['picking_id']).company_id.id - # If the move line is directly create on the picking view. - # If this picking is already done we should generate an - # associated done move. - if 'picking_id' in vals and not vals.get('move_id'): - picking = self.env['stock.picking'].browse(vals['picking_id']) - if picking.state == 'done': - product = self.env['product.product'].browse(vals['product_id']) - new_move = self.env['stock.move'].create({ - 'name': _('New Move:') + product.display_name, - 'product_id': product.id, - 'product_uom_qty': 'qty_done' in vals and vals['qty_done'] or 0, - 'product_uom': vals['product_uom_id'], - 'location_id': 'location_id' in vals and vals['location_id'] or picking.location_id.id, - 'location_dest_id': 'location_dest_id' in vals and vals['location_dest_id'] or picking.location_dest_id.id, - 'state': 'done', - 'additional': True, - 'picking_id': picking.id, - }) - vals['move_id'] = new_move.id - mls = super(StockMoveLine, self).create(vals_list) + + mls = super().create(vals_list) + + def create_move(move_line): + new_move = self.env['stock.move'].create({ + 'name': _('New Move:') + move_line.product_id.display_name, + 'product_id': move_line.product_id.id, + 'product_uom_qty': move_line.qty_done, + 'product_uom': move_line.product_uom_id.id, + 'description_picking': move_line.description_picking, + 'location_id': move_line.picking_id.location_id.id, + 'location_dest_id': move_line.picking_id.location_dest_id.id, + 'picking_id': move_line.picking_id.id, + 'state': move_line.picking_id.state, + 'picking_type_id': move_line.picking_id.picking_type_id.id, + 'restrict_partner_id': move_line.picking_id.owner_id.id, + 'company_id': move_line.picking_id.company_id.id, + }) + move_line.move_id = new_move.id + + # If the move line is directly create on the picking view. + # If this picking is already done we should generate an + # associated done move. + for move_line in mls: + if move_line.move_id or not move_line.picking_id: + continue + if move_line.picking_id.state != 'done': + moves = move_line.picking_id.move_lines.filtered(lambda x: x.product_id == move_line.product_id) + moves = sorted(moves, key=lambda m: m.quantity_done < m.product_qty, reverse=True) + if moves: + move_line.move_id = moves[0].id + else: + create_move(move_line) + else: + create_move(move_line) for ml, vals in zip(mls, vals_list): if ml.move_id and \ diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 4645ce7a9af..e932bf0c217 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -742,28 +742,6 @@ class Picking(models.Model): if picking.owner_id: picking.move_lines.write({'restrict_partner_id': picking.owner_id.id}) picking.move_line_ids.write({'owner_id': picking.owner_id.id}) - for move_line in picking.move_line_ids.filtered(lambda x: not x.move_id): - moves = picking.move_lines.filtered(lambda x: x.product_id == move_line.product_id) - moves = sorted(moves, key=lambda m: m.quantity_done < m.product_qty, reverse=True) - if moves: - move_line.move_id = moves[0].id - else: - new_move = self.env['stock.move'].create({ - 'name': _('New Move:') + move_line.product_id.display_name, - 'product_id': move_line.product_id.id, - 'product_uom_qty': move_line.qty_done, - 'product_uom': move_line.product_uom_id.id, - 'description_picking': move_line.description_picking, - 'location_id': picking.location_id.id, - 'location_dest_id': picking.location_dest_id.id, - 'picking_id': picking.id, - 'picking_type_id': picking.picking_type_id.id, - 'restrict_partner_id': picking.owner_id.id, - 'company_id': picking.company_id.id, - }) - move_line.move_id = new_move.id - new_move._action_confirm() - todo_moves |= new_move todo_moves._action_done(cancel_backorder=self.env.context.get('cancel_backorder')) self.write({'date_done': fields.Datetime.now(), 'priority': '0'}) diff --git a/addons/stock/tests/test_move2.py b/addons/stock/tests/test_move2.py index e41dabb488a..d2e251cb1b7 100644 --- a/addons/stock/tests/test_move2.py +++ b/addons/stock/tests/test_move2.py @@ -2042,6 +2042,55 @@ class TestSinglePicking(TestStockCommon): self.assertEqual(receipt.location_dest_id.id, stock_location.id) self.assertEqual(receipt.move_line_ids.location_dest_id.id, shelf_location.id) + def test_cancel_plan_transfer(self): + """ Test canceling plan transfer """ + # Create picking with stock move. + picking = self.env['stock.picking'].create({ + 'location_id': self.pack_location, + 'location_dest_id': self.customer_location, + 'picking_type_id': self.picking_type_out, + 'move_lines': [(0, 0, { + 'name': self.productA.name, + 'product_id': self.productA.id, + 'product_uom_qty': 10, + 'product_uom': self.productA.uom_id.id, + 'location_id': self.pack_location, + 'location_dest_id': self.customer_location, + })] + }) + # Confirm the outgoing picking, state should be changed. + picking.action_confirm() + self.assertEqual(picking.state, 'confirmed', "Picking should be in a confirmed state.") + + # Picking in a confirmed state and try to cancel it. + picking.action_cancel() + self.assertEqual(picking.state, 'cancel', "Picking should be in a cancel state.") + + def test_immediate_transfer(self): + """ Test picking should be in ready state if immediate transfer and SML is created via view + + Test picking cancelation with immediate transfer and done quantity""" + # create picking with stock move line + picking = self.env['stock.picking'].create({ + 'location_id': self.pack_location, + 'location_dest_id': self.customer_location, + 'picking_type_id': self.picking_type_out, + 'immediate_transfer': True, + 'move_line_ids': [(0, 0, { + 'product_id': self.productA.id, + 'qty_done': 10, + 'product_uom_id': self.productA.uom_id.id, + 'location_id': self.pack_location, + 'location_dest_id': self.customer_location, + })] + }) + + self.assertEqual(picking.state, 'assigned', "Picking should not be in a draft state.") + self.assertEqual(len(picking.move_lines), 1, "Picking should have stock move.") + picking.action_cancel() + self.assertEqual(picking.move_lines.state, 'cancel', "Stock move should be in a cancel state.") + self.assertEqual(picking.state, 'cancel', "Picking should be in a cancel state.") + + class TestStockUOM(TestStockCommon): def setUp(self): super(TestStockUOM, self).setUp()