From d0f0621c8680ca7cb7a9ff1e60996cedd0e4179a Mon Sep 17 00:00:00 2001 From: clesgow Date: Wed, 8 Mar 2023 14:43:31 +0100 Subject: [PATCH] [IMP] mrp: Add byproducts to MO Overview Adds the `By-Products` section in the MO Overview as done in the BoM Overview. This allows to correctly factor in the cost share of the production's byproducts. Part of task-3251506 Part-of: odoo/odoo#114536 --- addons/mrp/report/mrp_report_mo_overview.py | 62 +++++++++++++++++-- addons/mrp/report/mrp_report_mo_overview.xml | 34 ++++++++++ .../components/mo_overview/mrp_mo_overview.js | 5 +- .../mo_overview/mrp_mo_overview.xml | 1 + .../mrp_mo_overview_byproducts_block.js | 31 ++++++++++ .../mrp_mo_overview_byproducts_block.xml | 29 +++++++++ .../mrp_mo_overview_components_block.js | 10 +++ .../mrp_mo_overview_components_block.xml | 6 ++ 8 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 addons/mrp/static/src/components/mo_overview_byproducts_block/mrp_mo_overview_byproducts_block.js create mode 100644 addons/mrp/static/src/components/mo_overview_byproducts_block/mrp_mo_overview_byproducts_block.xml diff --git a/addons/mrp/report/mrp_report_mo_overview.py b/addons/mrp/report/mrp_report_mo_overview.py index f58d1762875..3c2cee7a39c 100644 --- a/addons/mrp/report/mrp_report_mo_overview.py +++ b/addons/mrp/report/mrp_report_mo_overview.py @@ -54,12 +54,16 @@ class ReportMoOverview(models.AbstractModel): production = self.env['mrp.production'].browse(production_id) components = self._get_components_data(production, level=1, current_index='') operations = self._get_operations_data(production, level=1, current_index='') - summary = self._get_mo_summary(production, components, operations) + initial_mo_cost = sum(component.get('summary', {}).get('mo_cost', 0.0) for component in components)\ + + operations.get('summary', {}).get('mo_cost', 0.0) + byproducts_cost_portion, byproducts = self._get_byproducts_data(production, initial_mo_cost, level=1, current_index='') + summary = self._get_mo_summary(production, components, initial_mo_cost, byproducts_cost_portion) return { 'id': production.id, 'summary': summary, 'components': components, 'operations': operations, + 'byproducts': byproducts, 'extras': self._get_report_extra_lines(summary), } @@ -73,10 +77,10 @@ class ReportMoOverview(models.AbstractModel): 'unit_product_cost': unit_product_cost, } - def _get_mo_summary(self, production, components, operations): + def _get_mo_summary(self, production, components, current_mo_cost, byproducts_cost_portion): product = production.product_id company = production.company_id or self.env.company - mo_cost = sum(component.get('summary', {}).get('mo_cost', 0.0) for component in components) + byproducts_cost_share = float_round(1 - byproducts_cost_portion, precision_rounding=0.0001) return { 'level': 0, 'model': production._name, @@ -93,7 +97,7 @@ class ReportMoOverview(models.AbstractModel): 'quantity_on_hand': product.uom_id._compute_quantity(product.qty_available, production.product_uom_id) if product.type == 'product' else False, 'quantity_reserved': 0.0, 'receipt': self._check_planned_start(production.date_deadline, self._get_replenishment_receipt(production, components)), - 'mo_cost': company.currency_id.round(mo_cost + operations.get('summary', {}).get('mo_cost', 0.0)), + 'mo_cost': company.currency_id.round(current_mo_cost * byproducts_cost_share), 'product_cost': company.currency_id.round(product.standard_price * production.product_uom_qty), 'currency_id': company.currency_id.id, 'currency': company.currency_id, @@ -187,6 +191,48 @@ class ReportMoOverview(models.AbstractModel): 'details': operations, } + def _get_byproducts_data(self, production, current_mo_cost, level=0, current_index=False): + currency = (production.company_id or self.env.company).currency_id + byproducts = [] + byproducts_cost_portion = 0 + total_mo_cost = 0 + total_product_cost = 0 + for index, move_bp in enumerate(production.move_byproduct_ids): + product = move_bp.product_id + cost_share = move_bp.cost_share / 100 + byproducts_cost_portion += cost_share + mo_cost = current_mo_cost * cost_share + product_cost = product.standard_price * move_bp.product_uom._compute_quantity(move_bp.product_uom_qty, product.uom_id) + total_mo_cost += mo_cost + total_product_cost += product_cost + byproducts.append({ + 'level': level, + 'index': f"{current_index}B{index}", + 'model': product._name, + 'id': product.id, + 'name': product.display_name, + 'quantity': move_bp.product_uom_qty, + 'uom_name': move_bp.product_uom.display_name, + 'uom_precision': self._get_uom_precision(move_bp.product_uom.rounding), + 'mo_cost': currency.round(mo_cost), + 'mo_cost_decorator': self._get_comparison_decorator(product_cost, mo_cost, currency.rounding), + 'product_cost': currency.round(product_cost), + 'currency_id': currency.id, + 'currency': currency, + }) + + return byproducts_cost_portion, { + 'summary': { + 'index': f"{current_index}B", + 'mo_cost': currency.round(total_mo_cost), + 'mo_cost_decorator': self._get_comparison_decorator(total_product_cost, total_mo_cost, currency.rounding), + 'product_cost': currency.round(total_product_cost), + 'currency_id': currency.id, + 'currency': currency, + }, + 'details': byproducts, + } + def _get_components_data(self, production, replenish_data=False, level=0, current_index=False): if not replenish_data: replenish_data = { @@ -315,7 +361,13 @@ class ReportMoOverview(models.AbstractModel): if doc_in._name == 'mrp.production': replenishment['components'] = self._get_components_data(doc_in, replenish_data, level + 2, replenishment_index) replenishment['operations'] = self._get_operations_data(doc_in, level + 2, replenishment_index) - replenishment['summary']['mo_cost'] = currency.round(sum(component.get('summary', {}).get('mo_cost', 0.0) for component in replenishment['components']) + replenishment['operations'].get('summary', {}).get('mo_cost', 0.0)) + initial_mo_cost = sum(component.get('summary', {}).get('mo_cost', 0.0) for component in replenishment['components'])\ + + replenishment['operations'].get('summary', {}).get('mo_cost', 0.0) + + byproducts_cost_portion, byproducts = self._get_byproducts_data(doc_in, initial_mo_cost, level + 2, replenishment_index) + byproducts_cost_share = float_round(1 - byproducts_cost_portion, precision_rounding=0.0001) + replenishment['byproducts'] = byproducts + replenishment['summary']['mo_cost'] = initial_mo_cost * byproducts_cost_share replenishment['summary']['receipt'] = self._check_planned_start(production.date_start, self._get_replenishment_receipt(doc_in, replenishment.get('components', []))) replenishments.append(replenishment) forecast_line['already_used'] = True diff --git a/addons/mrp/report/mrp_report_mo_overview.xml b/addons/mrp/report/mrp_report_mo_overview.xml index 4341b2320c1..db83e321388 100644 --- a/addons/mrp/report/mrp_report_mo_overview.xml +++ b/addons/mrp/report/mrp_report_mo_overview.xml @@ -35,6 +35,7 @@ + @@ -99,6 +100,7 @@ + @@ -107,6 +109,10 @@ + + + + + + diff --git a/addons/mrp/static/src/components/mo_overview/mrp_mo_overview.js b/addons/mrp/static/src/components/mo_overview/mrp_mo_overview.js index ce66e70e6ad..1a25c3bd67a 100644 --- a/addons/mrp/static/src/components/mo_overview/mrp_mo_overview.js +++ b/addons/mrp/static/src/components/mo_overview/mrp_mo_overview.js @@ -50,10 +50,13 @@ export class MoOverview extends Component { } this.state.showOptions.uom = reportValues.context.show_uom; this.context = reportValues.context; + // Main MO's operations & byproducts are always unfolded by default. if (reportValues.data?.operations?.summary?.index) { - // Main MO's operations are always unfolded by default. this.unfoldedIds.add(reportValues.data.operations.summary.index); } + if (reportValues.data?.byproducts?.summary?.index) { + this.unfoldedIds.add(reportValues.data.byproducts.summary.index); + } } //---- Handlers ---- diff --git a/addons/mrp/static/src/components/mo_overview/mrp_mo_overview.xml b/addons/mrp/static/src/components/mo_overview/mrp_mo_overview.xml index 53445e4c003..d74454b3ccd 100644 --- a/addons/mrp/static/src/components/mo_overview/mrp_mo_overview.xml +++ b/addons/mrp/static/src/components/mo_overview/mrp_mo_overview.xml @@ -34,6 +34,7 @@ diff --git a/addons/mrp/static/src/components/mo_overview_byproducts_block/mrp_mo_overview_byproducts_block.js b/addons/mrp/static/src/components/mo_overview_byproducts_block/mrp_mo_overview_byproducts_block.js new file mode 100644 index 00000000000..773a18fe721 --- /dev/null +++ b/addons/mrp/static/src/components/mo_overview_byproducts_block/mrp_mo_overview_byproducts_block.js @@ -0,0 +1,31 @@ +/** @odoo-module **/ + +import { MoOverviewOperationsBlock } from "../mo_overview_operations_block/mrp_mo_overview_operations_block"; +import { MoOverviewLine } from "../mo_overview_line/mrp_mo_overview_line"; + +export class MoOverviewByproductsBlock extends MoOverviewOperationsBlock { + static template = "mrp.MoOverviewByproductsBlock"; + + //---- Getters ---- + + get hasByproducts() { + return this.props?.byproducts?.length > 0; + } + + get level() { + return this.hasByproducts ? this.props.byproducts[0].level - 1 : 0; + } +} + +MoOverviewByproductsBlock.components = { + MoOverviewLine, +}; +MoOverviewByproductsBlock.props = { + // Keep all props except "operations" + ...(({ operations, ...props}) => props)(MoOverviewOperationsBlock.props), + byproducts: Array, +}; +MoOverviewByproductsBlock.props.summary.shape = { + ...MoOverviewByproductsBlock.props.summary.shape, + product_cost: { type: Number, optional: true }, +}; diff --git a/addons/mrp/static/src/components/mo_overview_byproducts_block/mrp_mo_overview_byproducts_block.xml b/addons/mrp/static/src/components/mo_overview_byproducts_block/mrp_mo_overview_byproducts_block.xml new file mode 100644 index 00000000000..16c95154d51 --- /dev/null +++ b/addons/mrp/static/src/components/mo_overview_byproducts_block/mrp_mo_overview_byproducts_block.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/mrp/static/src/components/mo_overview_components_block/mrp_mo_overview_components_block.js b/addons/mrp/static/src/components/mo_overview_components_block/mrp_mo_overview_components_block.js index c5301c196c0..23bf639b512 100644 --- a/addons/mrp/static/src/components/mo_overview_components_block/mrp_mo_overview_components_block.js +++ b/addons/mrp/static/src/components/mo_overview_components_block/mrp_mo_overview_components_block.js @@ -4,6 +4,7 @@ import { Component, onWillUpdateProps, useState } from "@odoo/owl"; import { useBus } from "@web/core/utils/hooks"; import { MoOverviewLine } from "../mo_overview_line/mrp_mo_overview_line"; import { MoOverviewOperationsBlock } from "../mo_overview_operations_block/mrp_mo_overview_operations_block"; +import { MoOverviewByproductsBlock } from "../mo_overview_byproducts_block/mrp_mo_overview_byproducts_block"; export class MoOverviewComponentsBlock extends Component { static template = "mrp.MoOverviewComponentsBlock"; @@ -81,6 +82,7 @@ export class MoOverviewComponentsBlock extends Component { MoOverviewComponentsBlock.components = { MoOverviewLine, MoOverviewOperationsBlock, + MoOverviewByproductsBlock, MoOverviewComponentsBlock, }; MoOverviewComponentsBlock.props = { @@ -94,6 +96,14 @@ MoOverviewComponentsBlock.props = { }, optional: true, }, + byproducts: { + type: Object, + shape: { + summary: Object, + details: Array, + }, + optional: true, + }, showOptions: { type: Object, shape: { diff --git a/addons/mrp/static/src/components/mo_overview_components_block/mrp_mo_overview_components_block.xml b/addons/mrp/static/src/components/mo_overview_components_block/mrp_mo_overview_components_block.xml index e8ac1874861..b371dae2653 100644 --- a/addons/mrp/static/src/components/mo_overview_components_block/mrp_mo_overview_components_block.xml +++ b/addons/mrp/static/src/components/mo_overview_components_block/mrp_mo_overview_components_block.xml @@ -22,6 +22,7 @@ unfoldAll="state.unfoldAll" components="replenishment.components" operations="replenishment.operations" + byproducts="replenishment.byproducts" showOptions="props.showOptions"/> @@ -31,6 +32,11 @@ summary="props.operations.summary" operations="props.operations.details" showOptions="props.showOptions"/> +