From 1f1a95282dc61d63ee4933f5c5e42588e4bc3476 Mon Sep 17 00:00:00 2001 From: clesgow Date: Thu, 23 Nov 2023 14:17:43 +0000 Subject: [PATCH] [FIX] stock: avoid recomputing the schedule_date too early Steps to reproduce: - Inventory -> Delivery -> New Planned transfer - Add two lines with two different products and save - Set different scheduled dates for each move - Set the earliest move quantity_done to the demand - Validate and create a backorder Issue: The done picking scheduled date will be changed to the latest move (that is moved to the backorder). This is due to a recompute of the picking's scheduled_date *before* the remaining moves are assigned to the backorder. Note: The order on the `stock.move.line` had to be removed, as it forced a recompute of the original picking *before* the assignation of the remaining moves to the backorder. What happens is : - Updating the move will check its move lines - To follow the SML order, it will need their pickings - To follow the picking order, it will need their scheduled date - Their scheduled dates can be out of date (since we already put some moves to `done`) - This will lead to a recompute of the original picking's scheduled date Instead, what we do is adapt the changes from odoo/odoo#79069, moving the order from the model to the reports where it's used. opw-3346598 closes odoo/odoo#147330 X-original-commit: 92092420548cb68db03ac139c23608fc1aa3a7cd Related: odoo/enterprise#53320 Signed-off-by: Arnold Moyaux (arm) Signed-off-by: Quentin Wolfs (quwo) --- addons/stock/models/stock_move_line.py | 2 +- addons/stock/models/stock_picking.py | 9 ++-- .../report/report_stockpicking_operations.xml | 2 +- addons/stock/tests/test_move.py | 46 ++++++++++++++++++- addons/stock/views/stock_move_views.xml | 4 +- 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index d87890838f3..45011c3daae 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -14,7 +14,7 @@ class StockMoveLine(models.Model): _name = "stock.move.line" _description = "Product Moves (Stock Move Line)" _rec_name = "product_id" - _order = "result_package_id desc, location_id asc, location_dest_id asc, picking_id asc, id" + _order = "result_package_id desc, id" picking_id = fields.Many2one( 'stock.picking', 'Transfer', auto_join=True, diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 4de6afb608b..8f49f30f9e0 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -1261,14 +1261,13 @@ class Picking(models.Model): 'move_line_ids': [], 'backorder_id': picking.id }) + moves_to_backorder.write({'picking_id': backorder_picking.id, 'picked': False}) + moves_to_backorder.move_line_ids.package_level_id.write({'picking_id': backorder_picking.id}) + moves_to_backorder.mapped('move_line_ids').write({'picking_id': backorder_picking.id}) + backorders |= backorder_picking picking.message_post( body=_('The backorder %s has been created.', backorder_picking._get_html_link()) ) - moves_to_backorder.write({'picking_id': backorder_picking.id, 'picked': False}) - moves_to_backorder.move_line_ids.package_level_id.write({'picking_id': backorder_picking.id}) - # moves_to_backorder._do_unreserve() - moves_to_backorder.mapped('move_line_ids').write({'picking_id': backorder_picking.id}) - backorders |= backorder_picking if backorder_picking.picking_type_id.reservation_method == 'at_confirm': bo_to_assign |= backorder_picking if bo_to_assign: diff --git a/addons/stock/report/report_stockpicking_operations.xml b/addons/stock/report/report_stockpicking_operations.xml index b245908cf64..969283596a9 100644 --- a/addons/stock/report/report_stockpicking_operations.xml +++ b/addons/stock/report/report_stockpicking_operations.xml @@ -109,7 +109,7 @@ - + Customizable Desk
Description on transfer diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index 86727cb656d..3216139135b 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import Command +from dateutil.relativedelta import relativedelta + +from odoo import Command, fields from odoo.exceptions import UserError from odoo.tests import Form, new_test_user from odoo.tests.common import TransactionCase +from odoo.addons.mail.tests.common import mail_new_test_user class StockMove(TransactionCase): @@ -60,6 +63,14 @@ class StockMove(TransactionCase): 'type': 'consu', 'categ_id': cls.env.ref('product.product_category_all').id, }) + cls.user_stock_user = mail_new_test_user( + cls.env, + name='Stock user', + login='stock_user', + email='s.u@example.com', + notification_type='inbox', + groups='stock.group_stock_user', + ) def gather_relevant(self, product_id, location_id, lot_id=None, package_id=None, owner_id=None, strict=False): quants = self.env['stock.quant']._gather(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict) @@ -6221,3 +6232,36 @@ class StockMove(TransactionCase): self.assertRecordValues(receipt.move_ids.move_line_ids[-1], [ {'location_dest_id': child_location.id, 'product_id': self.product.id, 'quantity': 2}, ]) + + def test_scheduled_date_after_backorder(self): + today = fields.Datetime.today() + with Form(self.env['stock.picking']) as picking_form: + picking_form.picking_type_id = self.env.ref('stock.picking_type_out') + with picking_form.move_ids_without_package.new() as move: + move.product_id = self.product + move.product_uom_qty = 1 + move.date = today + relativedelta(day=5) + with picking_form.move_ids_without_package.new() as move: + move.product_id = self.product_consu + move.product_uom_qty = 1 + move.date = today + relativedelta(day=10) + picking = picking_form.save() + + # Set different scheduled dates for each move + move_product = picking.move_ids.filtered(lambda m: m.product_id == self.product) + move_product.date = today + relativedelta(day=5) + move_consu = picking.move_ids.filtered(lambda m: m.product_id == self.product_consu) + move_consu.date = today + relativedelta(day=10) + self.assertEqual(picking.scheduled_date, today + relativedelta(day=5)) + picking.action_confirm() + + # Complete one move and create a backorder with the remaining move + move_product.quantity = 1 + move_consu.quantity = 0 + backorder_wizard_dict = picking.button_validate() + backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save() + backorder_wizard.with_user(self.user_stock_user).process() + backorder = self.env['stock.picking'].search([('backorder_id', '=', picking.id)]) + + self.assertEqual(picking.scheduled_date, today + relativedelta(day=5)) + self.assertEqual(backorder.scheduled_date, today + relativedelta(day=10)) diff --git a/addons/stock/views/stock_move_views.xml b/addons/stock/views/stock_move_views.xml index 33b5760d6c0..786dbfdd066 100644 --- a/addons/stock/views/stock_move_views.xml +++ b/addons/stock/views/stock_move_views.xml @@ -186,7 +186,7 @@ stock.move.line 1000 - + @@ -241,7 +241,7 @@ stock.move.line 1000 - +