From f8c1927b5ba6aed72f8d116ad5e4de55a4129b77 Mon Sep 17 00:00:00 2001 From: clesgow Date: Thu, 7 Sep 2023 15:47:56 +0200 Subject: [PATCH] [FIX] mrp: compute the right producible qty with same components Steps to reproduce: - In Manufacturing, create a the following BoM - Product: P1 - Components: - 2 x P2 - 2 x P2 - Set the quantity in stock for P2 to 2 - Open the Overview from the BoM Issue: The 'Ready to Produce' column will indicate 1, as it checks line by line how much product there is in stock compared to what is required for this line. To avoid this, we just need to sum the quantities required by products. closes odoo/odoo#134890 X-original-commit: b8fda0bdb2238cba21a4541f4292da04003704cf Signed-off-by: William Henrotin (whe) Signed-off-by: Arnold Moyaux (arm) --- addons/mrp/report/mrp_report_bom_structure.py | 14 +++++++----- addons/mrp/tests/test_bom.py | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) 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