From 2cf3377fdbbd45b031baae5bbe1d5938fe33e70f Mon Sep 17 00:00:00 2001 From: Arnold Moyaux Date: Mon, 7 Oct 2019 09:14:52 +0000 Subject: [PATCH] [FIX] sale_stock: so line creation launch procurements twice Use case to reproduce: - Create a SO and confirm it - Add a new line with a consumable/storable product -> The delivery order contains the new lines but with the double of required quantity. Due to commit cb618e9a99ea3b86fdeed0295168a1e9fd7cddc3 that try to lauch procurement in bacth. Howerver The create from sale.order.line was not removed and the _action_launch_procurement were launched twice (in sale.order write + sale.order.line create). The fix could remove the create function from sale.order.line but the drawback is that everytime a sale.order.line is created/edited then it should pass through the sale.order 'write' method. That would create a lot of issue in the future compare to the small gain of performance for a correction. Task-2077129 closes odoo/odoo#38187 Signed-off-by: Arnold Moyaux --- addons/sale_stock/models/sale_order.py | 28 ++++++++++++---------- addons/sale_stock/tests/test_sale_stock.py | 8 +++++++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/addons/sale_stock/models/sale_order.py b/addons/sale_stock/models/sale_order.py index 42183c76c44..445533135b6 100644 --- a/addons/sale_stock/models/sale_order.py +++ b/addons/sale_stock/models/sale_order.py @@ -80,25 +80,17 @@ class SaleOrder(models.Model): if values.get('order_line') and self.state == 'sale': for order in self: to_log = {} - order_lines_to_run = self.env['sale.order.line'] for order_line in order.order_line: - if order_line not in pre_order_line_qty: - order_lines_to_run |= order_line - elif float_compare(order_line.product_uom_qty, pre_order_line_qty[order_line], order_line.product_uom.rounding) < 0: - to_log[order_line] = (order_line.product_uom_qty, pre_order_line_qty[order_line]) - elif float_compare(order_line.product_uom_qty, pre_order_line_qty[order_line], order_line.product_uom.rounding) > 0: - order_lines_to_run |= order_line + if float_compare(order_line.product_uom_qty, pre_order_line_qty.get(order_line, 0.0), order_line.product_uom.rounding) < 0: + to_log[order_line] = (order_line.product_uom_qty, pre_order_line_qty.get(order_line, 0.0)) if to_log: documents = self.env['stock.picking']._log_activity_get_documents(to_log, 'move_ids', 'UP') order._log_decrease_ordered_quantity(documents) - if order_lines_to_run: - order_lines_to_run._action_launch_stock_rule(pre_order_line_qty) return res def _action_confirm(self): - for order in self: - order.order_line._action_launch_stock_rule() - super(SaleOrder, self)._action_confirm() + self.order_line._action_launch_stock_rule() + return super(SaleOrder, self)._action_confirm() @api.depends('picking_ids') def _compute_picking_ids(self): @@ -337,6 +329,18 @@ class SaleOrderLine(models.Model): lines.filtered(lambda line: line.state == 'sale')._action_launch_stock_rule() return lines + def write(self, values): + lines = self.env['sale.order.line'] + if 'product_uom_qty' in values: + precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') + lines = self.filtered( + lambda r: r.state == 'sale' and not r.is_expense and float_compare(r.product_uom_qty, values['product_uom_qty'], precision_digits=precision) == -1) + previous_product_uom_qty = {line.id: line.product_uom_qty for line in lines} + res = super(SaleOrderLine, self).write(values) + if lines: + lines._action_launch_stock_rule(previous_product_uom_qty) + return res + @api.depends('order_id.state') def _compute_invoice_status(self): super(SaleOrderLine, self)._compute_invoice_status() diff --git a/addons/sale_stock/tests/test_sale_stock.py b/addons/sale_stock/tests/test_sale_stock.py index 580e207fcfa..073f1568c1a 100644 --- a/addons/sale_stock/tests/test_sale_stock.py +++ b/addons/sale_stock/tests/test_sale_stock.py @@ -328,6 +328,14 @@ class TestSaleStock(TestSale): elif backorder_move.product_id.id == item2.id: self.assertEqual(backorder_move.product_qty, 2) + # add a new sale order lines + self.so.write({ + 'order_line': [ + (0, 0, {'name': item1.name, 'product_id': item1.id, 'product_uom_qty': 1, 'product_uom': item1.uom_id.id, 'price_unit': item1.list_price}), + ] + }) + self.assertEqual(sum(backorder.move_lines.filtered(lambda m: m.product_id.id == item1.id).mapped('product_qty')), 2) + def test_05_create_picking_update_saleorderline(self): """ Same test than test_04 but only with enough products in stock so that the reservation is successful.