From e3b43545519bb17843709b682ae504e18aeae71e Mon Sep 17 00:00:00 2001 From: times-odoo Date: Fri, 8 May 2026 15:23:06 +0530 Subject: [PATCH 1/2] [IMP] mrp_bom_overview: clean forecast view with consolidated status column The BOM overview forecast view is simplified by removing visual redundancy and consolidating availability information into the Status column. Changes introduced via patch on BomOverviewLine and inheritance of report.mrp.report_bom_structure: - Remove the standalone BOM name header section as it duplicates the breadcrumb information already visible in the page header - Remove the Availability column to reduce redundancy and consolidate all stock information into the Status column - Display quantity as integer to avoid unnecessary decimal places on whole-number quantities - Ensure 'Ready To Produce' tag is only shown when producible quantity is greater than zero - Always render 'Ready To Produce' tag in green for visual consistency regardless of other conditions - Each component now independently displays its availability state as a colored tag: green for available, dark for estimated, orange for expected, and red for not available - When components are missing, top-level BOM line shows estimated production date instead of 'No Ready To Produce' - All status tags are clickable and navigate to the respective product forecast report task-6204743 --- mrp_bom_overview_forecast/__init__.py | 1 + mrp_bom_overview_forecast/__manifest__.py | 14 +++++++ mrp_bom_overview_forecast/models/__init__.py | 1 + .../models/mrp_report_bom_structure.py | 15 +++++++ .../static/src/bom_overview.xml | 41 +++++++++++++++++++ .../static/src/bom_overview_line.js | 35 ++++++++++++++++ 6 files changed, 107 insertions(+) create mode 100644 mrp_bom_overview_forecast/__init__.py create mode 100644 mrp_bom_overview_forecast/__manifest__.py create mode 100644 mrp_bom_overview_forecast/models/__init__.py create mode 100644 mrp_bom_overview_forecast/models/mrp_report_bom_structure.py create mode 100644 mrp_bom_overview_forecast/static/src/bom_overview.xml create mode 100644 mrp_bom_overview_forecast/static/src/bom_overview_line.js diff --git a/mrp_bom_overview_forecast/__init__.py b/mrp_bom_overview_forecast/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/mrp_bom_overview_forecast/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/mrp_bom_overview_forecast/__manifest__.py b/mrp_bom_overview_forecast/__manifest__.py new file mode 100644 index 00000000000..dcf98e45391 --- /dev/null +++ b/mrp_bom_overview_forecast/__manifest__.py @@ -0,0 +1,14 @@ +{ + "name": "bom_overview", + "version": "1.0", + "depends": ["mrp", "purchase"], + "author": "times", + "category": "Tutorials", + "license": "LGPL-3", + 'installable': True, + "assets": { + "web.assets_backend": [ + "mrp_bom_overview_forecast/static/src/**/*", + ], + }, +} diff --git a/mrp_bom_overview_forecast/models/__init__.py b/mrp_bom_overview_forecast/models/__init__.py new file mode 100644 index 00000000000..d5f0e0470e2 --- /dev/null +++ b/mrp_bom_overview_forecast/models/__init__.py @@ -0,0 +1 @@ +from . import mrp_report_bom_structure diff --git a/mrp_bom_overview_forecast/models/mrp_report_bom_structure.py b/mrp_bom_overview_forecast/models/mrp_report_bom_structure.py new file mode 100644 index 00000000000..ea851bb3ba6 --- /dev/null +++ b/mrp_bom_overview_forecast/models/mrp_report_bom_structure.py @@ -0,0 +1,15 @@ +from odoo import _, models + + +class ReportMrpReport_Bom_Structure(models.AbstractModel): + _inherit = 'report.mrp.report_bom_structure' + + def _get_bom_data(self, *args, **kwargs): + result = super()._get_bom_data(*args, **kwargs) + if result.get('level') == 0: + qty = int(result.get('producible_qty') or 0) + if qty > 0: + result["status"] = _("%(qty)s Ready To Produce", qty=qty) + else: + result["status"] = _("No Ready To Produce") + return result diff --git a/mrp_bom_overview_forecast/static/src/bom_overview.xml b/mrp_bom_overview_forecast/static/src/bom_overview.xml new file mode 100644 index 00000000000..2f019241b62 --- /dev/null +++ b/mrp_bom_overview_forecast/static/src/bom_overview.xml @@ -0,0 +1,41 @@ + + + + + + + o_mrp_bom_report_page py-3 py-lg-2 px-0 overflow-auto border-bottom bg-view + + + + + + +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + props.currentWarehouseId + + + +
diff --git a/mrp_bom_overview_forecast/static/src/bom_overview_line.js b/mrp_bom_overview_forecast/static/src/bom_overview_line.js new file mode 100644 index 00000000000..3e54f58d2e9 --- /dev/null +++ b/mrp_bom_overview_forecast/static/src/bom_overview_line.js @@ -0,0 +1,35 @@ +import { patch } from "@web/core/utils/patch"; +import { BomOverviewLine } from "@mrp/components/bom_overview_line/mrp_bom_overview_line"; + +patch(BomOverviewLine.prototype, { + + get statusData() { + if (this.data.hasOwnProperty('components_available') && this.data.status && this.data.status !== "No Ready To Produce") { + return this.data.status; + } + if (this.data.status === "No Ready To Produce" && this.data.availability_display) { + return this.data.availability_display; + } + if (this.data.availability_display) { + return this.data.availability_display; + } + + return "Not Available"; + }, + + get statusBackgroundClass() { + if (!this.statusData) { + return "text-bg-danger"; + } + if (this.statusData === "Available" || this.statusData.includes("Ready To Produce")) { + return "text-bg-success"; + } + if (this.statusData.includes("Expected")) { + return "text-bg-warning"; + } + if (this.statusData.includes("Estimated")) { + return "text-bg-dark"; + } + return "text-bg-danger"; + }, +}); From 05cbf49e8254dfdd1808afea01e4a197c22b4397 Mon Sep 17 00:00:00 2001 From: times-odoo Date: Wed, 27 May 2026 10:22:42 +0530 Subject: [PATCH 2/2] [IMP] mrp_bom_overview_forecast: optimize BoM structure line status and formatting Refactored the BoM overview structure logic to stabilize status calculations and fix fragile XPath targets. Rationale: The previous implementation relied on parsing text strings (like "No Ready To Produce") within JavaScript getters to compute background styling classes, which is error-prone and breaks localization. Moving the raw quantity value (`producible_qty_int`) from the abstract model to the frontend allows precise, integer-based conditional styling. Additionally, XPath expressions were rewritten using robust name-matching syntax instead of positional or class-reliant queries that break across minor framework variations. Technical choices: - Updated 'mrp.report.bom.structure' to explicitly inject the integer 'producible_qty_int' into the rendered data payload. - Patched 'BomOverviewLine' prototype to handle fallback integer parsing for 'producible_qty' gracefully. - Replaced string-matching dependencies in 'statusBackgroundClass' with a switch-case statement driven by standard 'availability_state' keys. - Rewrote QWeb inherited templates to utilize structured attribute anchors like 'name="th_mrp_bom_h"' and 'name="bom_cost"' for cleaner extensions. task-6204743 --- .gitignore | 5 +++ mrp_bom_overview_forecast/__manifest__.py | 3 +- .../static/src/bom_overview.xml | 12 +++--- .../static/src/bom_overview_line.js | 40 +++++++++++-------- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index b6e47617de1..0422e30486a 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,8 @@ dmypy.json # Pyre type checker .pyre/ + +/vanilla_js +/health +/library +/hr_loan diff --git a/mrp_bom_overview_forecast/__manifest__.py b/mrp_bom_overview_forecast/__manifest__.py index dcf98e45391..9bd80afb001 100644 --- a/mrp_bom_overview_forecast/__manifest__.py +++ b/mrp_bom_overview_forecast/__manifest__.py @@ -1,11 +1,12 @@ { - "name": "bom_overview", + "name": "mrp_bom_overview_forecast", "version": "1.0", "depends": ["mrp", "purchase"], "author": "times", "category": "Tutorials", "license": "LGPL-3", 'installable': True, + 'auto_install': True, "assets": { "web.assets_backend": [ "mrp_bom_overview_forecast/static/src/**/*", diff --git a/mrp_bom_overview_forecast/static/src/bom_overview.xml b/mrp_bom_overview_forecast/static/src/bom_overview.xml index 2f019241b62..82eff50ac14 100644 --- a/mrp_bom_overview_forecast/static/src/bom_overview.xml +++ b/mrp_bom_overview_forecast/static/src/bom_overview.xml @@ -9,27 +9,27 @@ - +
- +
- - + + - + - + diff --git a/mrp_bom_overview_forecast/static/src/bom_overview_line.js b/mrp_bom_overview_forecast/static/src/bom_overview_line.js index 3e54f58d2e9..2f3dbcebdea 100644 --- a/mrp_bom_overview_forecast/static/src/bom_overview_line.js +++ b/mrp_bom_overview_forecast/static/src/bom_overview_line.js @@ -4,11 +4,14 @@ import { BomOverviewLine } from "@mrp/components/bom_overview_line/mrp_bom_overv patch(BomOverviewLine.prototype, { get statusData() { - if (this.data.hasOwnProperty('components_available') && this.data.status && this.data.status !== "No Ready To Produce") { - return this.data.status; - } - if (this.data.status === "No Ready To Produce" && this.data.availability_display) { - return this.data.availability_display; + if (this.data.hasOwnProperty('components_available')) { + const qty = parseInt(this.data.producible_qty) || 0; + if (qty > 0) { + return this.data.status; + } + if (qty == 0 && this.data.availability_display) { + return this.data.availability_display; + } } if (this.data.availability_display) { return this.data.availability_display; @@ -18,18 +21,23 @@ patch(BomOverviewLine.prototype, { }, get statusBackgroundClass() { - if (!this.statusData) { - return "text-bg-danger"; - } - if (this.statusData === "Available" || this.statusData.includes("Ready To Produce")) { - return "text-bg-success"; + if (this.data.hasOwnProperty('components_available')) { + const qty = parseInt(this.data.producible_qty) || 0; + if (qty > 0) { + return "text-bg-success"; + } } - if (this.statusData.includes("Expected")) { - return "text-bg-warning"; - } - if (this.statusData.includes("Estimated")) { - return "text-bg-dark"; + + const state = this.data.availability_state; + switch (state) { + case "available": + return "text-bg-success"; + case "expected": + return "text-bg-warning"; + case "estimated": + return "text-bg-dark"; + default: + return "text-bg-danger"; } - return "text-bg-danger"; }, });