Files
Odoo-Modules/CLAUDE.md
gsinghpal afc01ec1d9 fix(shopfloor): proper dark-mode via \$o-webclient-color-scheme branch
Dug deeper after the user reported shop-floor pages staying white in
dark mode. Traced through Odoo 19 source:

  _dependencies/web_enterprise/static/src/
    webclient/color_scheme/color_scheme_service.js  <- reads cookie
    scss/primary_variables.scss       \$o-webclient-color-scheme: bright
    scss/primary_variables.dark.scss  \$o-webclient-color-scheme: dark

Odoo compiles TWO separate CSS bundles:
  web.assets_backend       -> compiled with \$...scheme: bright
  web.assets_web_dark      -> compiled with \$...scheme: dark
    (the .dark.scss files are layered in front of the light ones)

Our shop-floor SCSS is in web.assets_backend, which means it gets
compiled into BOTH bundles. But the previous CSS-variable fallback
chain (var(--fp-page-bg, var(--bs-tertiary-bg, #hex))) baked the
SAME hex fallback into both bundles, so cards stayed white in dark.

Odoo's own code doesn't redefine --bs-* CSS custom properties at
runtime either — it just bakes the dark palette straight into the
dark bundle via SCSS \$-variables during compile.

Fix: _fp_shopfloor_tokens.scss now branches at compile time:

    \$o-webclient-color-scheme: bright !default;

    \$_fp-page-hex: #f3f4f6;  // light defaults
    \$_fp-card-hex: #ffffff;
    ...
    @if \$o-webclient-color-scheme == dark {
        \$_fp-page-hex: #1a1d21 !global;
        \$_fp-card-hex: #22262d !global;
        ...
    }

    \$fp-page: var(--fp-page-bg, \$_fp-page-hex);
    \$fp-card: var(--fp-card-bg, \$_fp-card-hex);

The CSS-custom-property fallback stays so deployments can still skin
via --fp-* without touching SCSS; the underlying hex changes between
bundles.

Verified via odoo-shell:
  LIGHT bundle: .o_fp_plant_overview { background-color: var(...#f3f4f6) }
                .o_fp_po_card         { background-color: var(...#ffffff);
                                         border: ... #d8dadd }
  DARK bundle:  .o_fp_plant_overview { background-color: var(...#1a1d21) }
                .o_fp_po_card         { background-color: var(...#22262d);
                                         border: ... #343942 }

Two separate bundle URLs generated:
  /web/assets/a593157/web.assets_backend.min.css
  /web/assets/a9dba7d/web.assets_web_dark.min.css

=== CLAUDE.md ===
Replaced the previous (incorrect) .o_dark_mode override advice with
a proper "Branch on \$o-webclient-color-scheme at SCSS compile time"
section, including the bundle names and the verify-via-odoo-shell
snippet. Future redesigns now have a single, correct pattern to
follow.

Version bumped 19.0.4.0.0 -> 19.0.5.0.0 to force asset hash change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:30:14 -04:00

5.1 KiB

Odoo Modules — Claude Code Instructions

Project

27 custom Odoo 19 modules for Fusion Central (Westin Healthcare + NEXA Systems).

Critical Rules — Odoo 19

  1. NEVER code from memory — Always read a reference file from Docker first:
    docker exec odoo-dev-app cat /usr/lib/python3/dist-packages/odoo/addons/<module>/static/src/<path>
    
  2. Frontend JS: Use Interaction class from @web/public/interaction, registered via registry.category("public.interactions"). NOT IIFE/DOMContentLoaded.
  3. Backend OWL: Use standalone rpc() from @web/core/network/rpc. NOT useService("rpc"). static props = [] not {}.
  4. HTTP routes: type="jsonrpc" — NOT type="json" (deprecated).
  5. res.config.settings: Only boolean/integer/float/char/selection/many2one/datetime. NO Date fields.
  6. res.groups: NO users field, NO category_id field.
  7. Search views: NO group expand="0" syntax.
  8. SCSS imports: @import "./partial" is FORBIDDEN in Odoo 19 custom SCSS. It prints a warning and silently falls back to the old cached bundle. Register every SCSS file (including _partial.scss tokens) as a separate entry in web.assets_backend. Put tokens first; Odoo concatenates bundle files so SCSS variables/mixins from the first file are visible to every later file.

Card Styling — Copy Odoo's Kanban Pattern

Don't rely on var(--bs-border-color) or var(--bs-body-bg) for card surfaces — they drift between themes/addons and often render invisible. Odoo's own kanban (.o_kanban_record) uses explicit hex values:

background-color: white;
border: 1px solid #d8dadd;

For custom OWL dashboards / client actions use the same approach:

  • Define a _tokens.scss partial with explicit hex values wrapped in a CSS custom property:
    $fp-card:   var(--fp-card-bg, #ffffff);
    $fp-border: var(--fp-border-color, #d8dadd);
    
  • Reference those tokens everywhere (never var(--bs-border-color) directly)
  • Three-layer contrast: page (grayest) → container/column (mid) → card (brightest). That's what makes cards pop.
  • Reference implementation: fusion_plating_shopfloor/static/src/scss/_fp_shopfloor_tokens.scss.

Dark Mode — Branch on $o-webclient-color-scheme at SCSS Compile Time

Odoo 19 does NOT flip dark mode via a runtime DOM class. It compiles TWO asset bundles:

  • web.assets_backend — compiled with $o-webclient-color-scheme: bright
  • web.assets_web_dark — compiled with $o-webclient-color-scheme: dark (dark variant primary variables loaded first)

Your SCSS file is compiled into BOTH bundles. To make the dark bundle have different colors, branch at compile time using the SCSS variable Odoo sets:

$o-webclient-color-scheme: bright !default;

$_my-page-hex: #f3f4f6;
$_my-card-hex: #ffffff;

@if $o-webclient-color-scheme == dark {
    $_my-page-hex: #1a1d21 !global;
    $_my-card-hex: #22262d !global;
}

$my-page: var(--my-page-bg, $_my-page-hex);
$my-card: var(--my-card-bg, $_my-card-hex);

Do NOT use .o_dark_mode class selectors, [data-bs-theme="dark"], or @media (prefers-color-scheme: dark) — none of those fire reliably in Odoo 19. The user toggles dark mode via the user profile, which sets a color_scheme cookie and reloads the page; Odoo then serves the dark bundle. Your SCSS @if handles the rest at compile time.

Verify by inspecting the attachments — you should see two files with different URLs for the two bundles:

env['ir.qweb']._get_asset_bundle('web.assets_backend').css()     # light
env['ir.qweb']._get_asset_bundle('web.assets_web_dark').css()    # dark

Asset Bundle Cache Busting

Odoo content-hashes the compiled bundle URL (/web/assets/<hash>/...). When CSS changes but the hash doesn't update, the browser serves the old bundle. Fixes in order of escalation:

  1. Bump the module version in __manifest__.py
  2. DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%'; then restart odoo
  3. Call env['ir.qweb']._get_asset_bundle('web.assets_backend').css() in odoo-shell to force regeneration
  4. Hard-refresh browser with cache clear (DevTools → right-click refresh → Empty Cache and Hard Reload); on mobile clear website data

Naming

  • New fields: x_fc_* prefix
  • Legacy fields: x_studio_*
  • Canadian English for all user-facing text
  • Currency: $ sign with Monetary fields + currency_id

Cursor-Managed Modules

  • fusion_clock is currently being modified in Cursor — always read files fresh before editing, don't assume you know the current state

Workflow

  • Local dev: docker exec odoo-dev-app odoo -d fusion-dev -u <module> --stop-after-init
  • Local URL: http://localhost:8069
  • Test before deploying. Edit existing files — don't create unnecessary new ones.

Supabase Knowledge Base

Before starting unfamiliar work, check Supabase for context:

PGPASSWORD='a09e12e0995dc29446631fa458f3d4b3' psql -h 100.74.28.73 -p 5433 -U postgres -d postgres
  • fusionapps.decisions — past architecture decisions
  • fusionapps.issues — known issues and fixes
  • fusionapps.code_snippets — reference code
  • fusionapps.quick_commands — deployment and admin commands