diff --git a/addons/mrp/report/mrp_report_bom_structure.py b/addons/mrp/report/mrp_report_bom_structure.py index f2aec352530..22fcd576eba 100644 --- a/addons/mrp/report/mrp_report_bom_structure.py +++ b/addons/mrp/report/mrp_report_bom_structure.py @@ -5,6 +5,7 @@ import json from odoo import api, fields, models, _ from odoo.tools import float_compare, float_round, format_date, float_is_zero from datetime import timedelta +from collections import defaultdict class ReportBomStructure(models.AbstractModel): _name = 'report.mrp.report_bom_structure' @@ -23,11 +24,14 @@ 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' - 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] + components_qty_to_produce = defaultdict(lambda: 0) + components_qty_available = {} + for comp in bom_data.get('components', []): + if comp['product'].type != 'product' or float_is_zero(comp['base_bom_line_qty'], precision_digits=comp['uom'].rounding): + continue + components_qty_to_produce[comp['product_id']] += comp['base_bom_line_qty'] + components_qty_available[comp['product_id']] = comp['quantity_available'] + producibles = [float_round(components_qty_available[p_id] / qty, precision_digits=0, rounding_method='DOWN') for p_id, qty in components_qty_to_produce.items()] return min(producibles) * bom_data['bom']['product_qty'] if producibles else 0 @api.model diff --git a/addons/mrp/tests/test_bom.py b/addons/mrp/tests/test_bom.py index c93ab780c9a..d9edf2f9876 100644 --- a/addons/mrp/tests/test_bom.py +++ b/addons/mrp/tests/test_bom.py @@ -1018,6 +1018,28 @@ class TestBoM(TestMrpCommon): # So with 4 of the second product available, we can produce 4 items self.assertEqual(report_values["lines"]["producible_qty"], 4) + def test_bom_report_capacity_with_duplicate_components(self): + location = self.env.ref('stock.stock_location_stock') + self.env['stock.quant']._update_available_quantity(self.product_2, location, 2.0) + bom = self.env['mrp.bom'].create({ + 'product_tmpl_id': self.product_3.product_tmpl_id.id, + 'product_qty': 1, + 'bom_line_ids': [ + Command.create({ + 'product_id': self.product_2.id, + 'product_qty': 2, + }), + Command.create({ + 'product_id': self.product_2.id, + 'product_qty': 2, + }) + ] + }) + + report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom.id) + # Total quantity of components is 4, so shouldn't be able to produce a single one. + self.assertEqual(report_values['lines']['producible_qty'], 0) + 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