From 0a87d08bd4857908dd48a9e34d30af8014d17ffa Mon Sep 17 00:00:00 2001 From: Carlos Roca Date: Tue, 27 Oct 2026 12:29:17 +0100 Subject: [PATCH 1/3] [FIX] web_company_color: avoid showing other company's colors The company scss link was added inside the methods whose result is stored by ormcache (`_generate_asset_links_cache` / `_generate_asset_links`). The cache key does not depend on the company, and the override changed the cached list in place with `+=`. Each request added its company scss to the shared list, so the colors shown were those of the last company added in that worker. Now the company scss is added in `_get_asset_links`, which is not cached, and a new list is returned without changing the cached one. --- web_company_color/models/ir_qweb.py | 48 ++++++----------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/web_company_color/models/ir_qweb.py b/web_company_color/models/ir_qweb.py index b9f389f004e3..bee28e831685 100644 --- a/web_company_color/models/ir_qweb.py +++ b/web_company_color/models/ir_qweb.py @@ -8,50 +8,20 @@ class QWeb(models.AbstractModel): _inherit = "ir.qweb" - def _generate_asset_links_cache( - self, - bundle, - css=True, - js=True, - assets_params=None, - rtl=False, - ): - res = super()._generate_asset_links_cache( - bundle, - css=css, - js=js, - assets_params=assets_params, - rtl=rtl, - ) - if bundle == "web_company_color.company_color_assets": - asset = AssetsBundleCompanyColor( - bundle, [], env=self.env, css=True, js=True - ) - res += [asset.get_company_color_asset_node()] - return res + def _get_asset_links(self, bundle, css=True, js=True, debug=None): + """Inject the active company scss. - def _generate_asset_links( - self, - bundle, - css=True, - js=True, - debug_assets=False, - assets_params=None, - rtl=False, - ): - res = super()._generate_asset_links( - bundle, - css=css, - js=js, - debug_assets=debug_assets, - assets_params=assets_params, - rtl=rtl, - ) + This must be done outside of the cached methods + (``_generate_asset_links_cache``), because their cache key does not + depend on the company and the cached list is shared by all requests. + """ + res = super()._get_asset_links(bundle, css=css, js=js, debug=debug) if bundle == "web_company_color.company_color_assets": asset = AssetsBundleCompanyColor( bundle, [], env=self.env, css=True, js=True ) - res += [asset.get_company_color_asset_node()] + # Build a new list to not alter the (possibly cached) one + res = res + [asset.get_company_color_asset_node()] return res def _get_asset_content(self, bundle, assets_params=None): From e7bf1d6bf988322d587442cf20c082550ccac9c6 Mon Sep 17 00:00:00 2001 From: Carlos Roca Date: Tue, 27 Oct 2026 12:35:16 +0100 Subject: [PATCH 2/3] [FIX] web_company_color: apply all configured colors correctly --- web_company_color/models/res_company.py | 60 +++++++++------------ web_company_color/tests/test_res_company.py | 2 +- web_company_color/view/res_company.xml | 1 + 3 files changed, 26 insertions(+), 37 deletions(-) diff --git a/web_company_color/models/res_company.py b/web_company_color/models/res_company.py index 3d40723bc5e4..2276b5ab8a93 100644 --- a/web_company_color/models/res_company.py +++ b/web_company_color/models/res_company.py @@ -29,41 +29,23 @@ def _get_scss_template(self): background-color: %(color_navbar_bg_hover)s !important; } } - - > ul { - > li { - > a, > label { - color: %(color_navbar_text)s !important; - - &:hover, &:focus, &:active, &:focus:active { - background-color: %(color_navbar_bg_hover)s !important; - } - } - } - } } - .o_menu_brand { + .o_main_navbar .o_menu_brand { + color: rgba(%(color_navbar_text)s, 0.9) !important; + &:hover, &:focus, &:active, &:focus:active { + background: none !important; color: %(color_navbar_text)s !important; - &:hover, &:focus, &:active, &:focus:active { - background-color: %(color_navbar_bg_hover)s !important; - } - } - - a[href], - a[tabindex], - .btn-link, - .o_external_button { - color: %(color_link_text)s; - .o_main_navbar { - color: none; - } } + } + a[href], + a[tabindex], + .btn-link, + .o_external_button { + color: %(color_link_text)s; + } a:hover, .btn-link:hover { color: %(color_link_text_hover)s; - .o_main_navbar { - color: none; - } } .btn-primary:not(.disabled), .ui-autocomplete .ui-menu-item > a.ui-state-active { @@ -89,12 +71,12 @@ def _get_scss_template(self): .o_form_view .oe_button_box .oe_stat_button > span .o_stat_value { color: %(color_link_text)s !important; } - .o_form_view .o_form_statusbar > .o_statusbar_status > - .o_arrow_button.btn-primary.disabled { + .o_form_view .o_form_statusbar .o_statusbar_status + .o_arrow_button.o_arrow_button_current { color: %(color_link_text)s !important; } .o_required_modifier{ - :focus-within { + &:focus-within { --o-input-border-color: %(color_button_bg)s !important; --o-caret-color: %(color_button_bg)s !important; } @@ -184,6 +166,8 @@ def write(self, values): def button_reset_colors(self): self.write({"company_colors": {}}) + # Reload like a regular save does, so the reset colors are applied + return {"type": "ir.actions.client", "tag": "reload_context"} def button_compute_color(self): self.ensure_one() @@ -215,12 +199,16 @@ def _scss_get_sanitized_values(self): # This allow extend company_colors and only sanitize selected fields # or add custom values values = dict(self.company_colors or {}) + # The SCSS is compiled alone, so Odoo SCSS variables + # (like $o-brand-odoo) are not available: use literal colors. + navbar_bg = values.get("color_navbar_bg") or "#71639e" values.update( { - "color_navbar_bg": (values.get("color_navbar_bg") or "$o-brand-odoo"), - "color_navbar_bg_hover": (values.get("color_navbar_bg_hover")), + "color_navbar_bg": navbar_bg, + "color_navbar_bg_hover": values.get("color_navbar_bg_hover") + or f"darken({navbar_bg}, 10%)", "color_navbar_border_bottom": values.get("color_navbar_border_bottom") - or f"darken({values.get('color_navbar_bg') or '$o-brand-odoo'}, 10%)", + or f"darken({navbar_bg}, 10%)", "color_navbar_text": (values.get("color_navbar_text") or "#FFF"), "color_button_bg": values.get("color_button_bg") or "#71639e", "color_button_bg_hover": values.get("color_button_bg_hover") @@ -229,7 +217,7 @@ def _scss_get_sanitized_values(self): "color_link_text": values.get("color_link_text") or "#71639e", "color_link_text_hover": values.get("color_link_text_hover") or "darken(#71639e, 10%)", - "color_submenu_text": values.get("color_link_text") or "#374151", + "color_submenu_text": values.get("color_submenu_text") or "#374151", } ) return values diff --git a/web_company_color/tests/test_res_company.py b/web_company_color/tests/test_res_company.py index 3963ba8f9646..18ca28a659fa 100644 --- a/web_company_color/tests/test_res_company.py +++ b/web_company_color/tests/test_res_company.py @@ -51,7 +51,7 @@ def test_scss_sanitized_values(self): values = company_id.sudo()._scss_get_sanitized_values() self.assertEqual( values["color_navbar_bg"], - "$o-brand-odoo", + "#71639e", "Invalid Navbar Background Color", ) company_id.sudo().write({"color_navbar_bg": "#DEAD00"}) diff --git a/web_company_color/view/res_company.xml b/web_company_color/view/res_company.xml index 26ffea8dd234..f2be2b6c5ea0 100644 --- a/web_company_color/view/res_company.xml +++ b/web_company_color/view/res_company.xml @@ -25,6 +25,7 @@ +