From a11033d42c8da8b87658a92c6ab74bae3d286632 Mon Sep 17 00:00:00 2001 From: "Hubert Van de Walle (huvw)" Date: Wed, 2 Nov 2022 15:31:23 +0000 Subject: [PATCH] [FIX] mrp: division by 0 when computing the production capacity Steps to reproduce ================== - Create a BOM - Add a line with a product of type product - Set the quantity to 0 - Save and click on overview -> ServerError: Division by 0 Cause of the issue ================== Lines with a quantity of 0 should be excluded from the computation opw-3053167 closes odoo/odoo#104980 X-original-commit: b0f5170252ed73d31543b8d1dcf114ae6f0b65bc Signed-off-by: Adrien Widart Signed-off-by: Hubert Van De Walle --- addons/mrp/report/mrp_report_bom_structure.py | 7 ++- addons/mrp/tests/test_bom.py | 46 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/addons/mrp/report/mrp_report_bom_structure.py b/addons/mrp/report/mrp_report_bom_structure.py index 5ae25e689e7..f5717d0d242 100644 --- a/addons/mrp/report/mrp_report_bom_structure.py +++ b/addons/mrp/report/mrp_report_bom_structure.py @@ -3,7 +3,7 @@ import json from odoo import api, fields, models, _ -from odoo.tools import float_compare, float_round, format_date +from odoo.tools import float_compare, float_round, format_date, float_is_zero from datetime import timedelta class ReportBomStructure(models.AbstractModel): @@ -23,7 +23,10 @@ class ReportBomStructure(models.AbstractModel): @api.model def _compute_current_production_capacity(self, bom_data): # Get the maximum amount producible product of the selected bom given each component's stock levels. - stockable_components = filter(lambda c: c['product'].detailed_type == 'product', bom_data.get('components', [])) + stockable_components = filter( + lambda c: c['product'].detailed_type == 'product' + and not float_is_zero(c['base_bom_line_qty'], precision_digits=c['uom'].rounding), + bom_data.get('components', [])) producibles = [float_round(comp['quantity_available'] / comp['base_bom_line_qty'], precision_digits=0, rounding_method='DOWN') for comp in stockable_components] return min(producibles) * bom_data['bom']['product_qty'] if producibles else 0 diff --git a/addons/mrp/tests/test_bom.py b/addons/mrp/tests/test_bom.py index 317fe8c05f1..88db820b79a 100644 --- a/addons/mrp/tests/test_bom.py +++ b/addons/mrp/tests/test_bom.py @@ -980,6 +980,52 @@ class TestBoM(TestMrpCommon): self.assertAlmostEqual(report_values['lines']['bom_cost'], 2.92) + def test_bom_report_capacity_with_quantity_of_0(self): + uom_unit = self.env.ref('uom.product_uom_unit') + location = self.env.ref('stock.stock_location_stock') + + target = self.env['product.product'].create({ + 'name': 'Target', + 'type': 'product', + }) + + product_one = self.env['product.product'].create({ + 'name': 'Component one', + 'type': 'product', + }) + self.env['stock.quant']._update_available_quantity(product_one, location, 3.0) + + product_two = self.env['product.product'].create({ + 'name': 'Component two', + 'type': 'product', + }) + self.env['stock.quant']._update_available_quantity(product_two, location, 4.0) + + bom = self.env['mrp.bom'].create({ + 'product_tmpl_id': target.product_tmpl_id.id, + 'product_uom_id': self.uom_unit.id, + 'product_qty': 1.0, + 'type': 'phantom', + 'bom_line_ids': [ + Command.create({ + 'product_id': product_one.id, + 'product_qty': 0, + 'product_uom_id': uom_unit.id, + }), + Command.create({ + 'product_id': product_two.id, + 'product_qty': 1, + 'product_uom_id': uom_unit.id, + }) + ] + }) + + report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom.id) + + # The first product shouldn't affect the producible quantity because the target needs none of it + # So with 4 of the second product available, we can produce 4 items + self.assertEqual(report_values["lines"]["producible_qty"], 4) + def test_validate_no_bom_line_with_same_product(self): """ Cannot set a BOM line on a BOM with the same product as the BOM itself