Root cause: my @api.depends_context('fp_express_part_picker') decorator
on _compute_display_name was not honored by Odoo. Verified via odoo
shell — display_name returns the full 'PART (Rev X) — Name' regardless
of context. Reason: display_name is defined on the base Model class
and Odoo registers the field metadata (incl. _depends_context) when
the field is FIRST declared. Subclass redefinitions of the compute
method don't update _depends_context after the fact.
Workaround: don't rely on display_name context override. Instead,
overlay a custom span on top of the Many2OneField that shows JUST
the part_number_display value. CSS overlay uses:
- position: absolute / inset: 0
- background: $xpr-card (matches list row background)
- z-index: 2 over the picker
- pointer-events: none so clicks pass through to the picker
When the picker is focused (:focus-within parent), the overlay
hides so the user sees the autocomplete input value as they type.
When not focused, the overlay covers display_name with just the
part number.
Row 1 now reads 'ENG-1042 / B' — picker on the left (showing only
part_number_display), separator, revision on the right. Matches the
mockup pixel layout the user requested.
Customer feedback: rows 2 (description) and 3 (serials) in the Part
cell rendered as read-only spans. User wanted to edit directly.
New writable computed fields on fp.direct.order.line:
- part_name_editable: compute reads part_catalog_id.name, inverse
writes back to part.name on the linked catalog record
- serials_text: compute joins serial_ids names with commas; inverse
parses the typed string and find-or-creates fp.serial records,
updates the line's serial_ids M2M
Removed the redundant rev separator (display_name already includes
'(Rev X)' so showing it twice was clutter). Rev edits happen by
editing the part record directly via the OPEN button.
OWL widget templates updated:
- Row 2: <input> bound to part_name_editable, t-on-change saves
- Row 3: <input> bound to serials_text, t-on-change parses + saves
SCSS:
- Row 2 input: italic, transparent border, focus tints background yellow
- Row 3 input: small grey text, comma-separated friendly placeholder
- Both disabled-look when no part is picked
Both inputs trigger the inverse method on blur. The G4 sync chain
takes over from there to push line.line_description etc. back to
the part as before — so editing in the line keeps the part defaults
fresh for future orders.
Wasted-space audit revealed:
1. PO Block occupied a wide 2-col span but its inner inputs didn't
fill the available width (130px label column + narrow input area)
2. Customer Job # + Job Sorting placed in row 2 cols 3-4 next to the
tall PO block left empty vertical space below them
3. Row 2 col 3-4 was sparse because the PO block forced row 2 to be tall
Reorganized:
- PO Block now spans 2 grid ROWS (.row-span-2 class → grid-row: span 2)
- Customer Job # / Job Sorting flow into row 2 cols 3-4 (alongside PO top)
- Material/Process Tag / Lead Time flow into row 3 cols 3-4 (alongside
PO bottom) — filling the previously-empty space next to the PO block
- Row 4 (after PO ends): Payment Terms / Delivery Method / Pricelist /
Quote Validity — full 4-col width back
- Row 5: Blanket Sales Order + Invoice Strategy + conditional Deposit % /
Progress Initial % (only show when relevant invoice strategy picked)
Inside the PO block:
- Label column tightened 130px → 110px so the input takes more width
- Inputs + Many2One wrappers now have width: 100% propagated, so PO #
and Expected By inputs fill the available row width
- Upload button restyled with the accent colour (was the green default)
Net effect: same field count but tighter packing, no empty vertical
or horizontal space next to the PO block.
Root cause for column widths: Odoo 19's column_width_hook.js dynamically
sets inline widths on every cell at render time, overriding any CSS
width on td/th selectors. Confirmed by reading the hook source on
entech: 'A width can also be hardcoded in the arch (width="60px").'
Fix: set width='Npx' as an ARCH ATTRIBUTE on each <field> in the line
list:
- Part Number 230px, Line Job # 80px, Thickness 100px, Mask 55px,
Bake 120px, Qty 55px, Price 80px, Subtotal 90px, Action stack 60px
- Specification + Internal Notes get NO width → take remaining flex
space (responsive: layout adapts to viewport)
Root cause for missing checkbox: my SCSS underline-style override
selected ALL .o_field_widget input including type=checkbox, rendering
checkboxes as 30px-tall full-width transparent text inputs.
Fix: exclude type=checkbox/radio/file from the underline rule, and
add explicit rendering for type=checkbox (18px square, accent-coloured)
inside .o_fp_xpr_cell. The Blanket Sales Order checkbox + the inline
Block partial shipments checkbox are now both visible.
1. Blanket Sales Order — match legacy field shape. Renamed label from
'Blanket SO' to 'Blanket Sales Order' (matches legacy view), removed
the boolean_toggle widget (defaults to checkbox), and added the
sibling 'block_partial_shipments' field inline (only visible when
blanket is checked, with 'Block partial shipments' helper text).
2. Column widths — give roomier columns where data needs space, tighten
numeric columns. Part Number 230px, Specification min 220px,
Internal Notes min 140px, Qty 60px, Price 80px, Subtotal 90px,
Mask 55px, Bake 130px, Action stack 60px.
3. Stacked DWG / OPEN buttons — new OWL widget FpExpressActionBtns
(express_action_btns.js + .xml) renders both buttons vertically in
ONE column to save horizontal space. Widget binds to a new
action_btns_anchor field (related from part_catalog_id) on the
line. Each button shows tooltip + disabled state when no part is
picked; DWG triggers the native file picker, OPEN navigates to the
part record.
4. Field activation — clicking the cell anywhere now focuses the
input, not just clicking the label. Achieved via:
- cursor: text on .o_fp_xpr_cell
- cursor: pointer on labels
- min-height: 30px on all inputs (larger click target)
- width: 100% propagated through Many2One wrappers (.o-dropdown,
.o-autocomplete) so the input genuinely fills the cell
- box-sizing: border-box so widths are predictable
- Background tint on focus for visual feedback
A bad replacement in the previous commit left an extra '}' that
prematurely closed the .o_fp_xpr block, dumping all the legend bar /
PO status pill / part cell / bake pill styles OUTSIDE the namespace.
SCSS compile silently produced an unusable bundle and the form
rendered without any of the new visual treatment.
Brace balance now verified at 0.
NEW OWL widgets:
- FpExpressPartCell (static/src/js/express_part_cell.js + .xml) — multi-row
Part cell. Wraps Many2OneField for the part picker (row 1: part# / rev,
bold). Below it: row 2 part description (italic muted), row 3 serial #s
joined + '+ bulk' button that triggers the existing bulk-add wizard.
- FpExpressBakePill (static/src/js/express_bake_pill.js + .xml) — click-
to-edit Bake pill. Renders amber pill when set, italic muted 'no bake'
when empty. Click swaps to inline textarea + Save / Clear / Cancel.
NEW fields:
- fp.direct.order.line.part_number_display / part_revision_display /
part_name_display (related Char from fp.part.catalog) — fed to the
Part cell widget so it can render multi-row without RPC.
- fp.direct.order.wizard.tooling_charge (Monetary) — surfaced in the
Totals card on the Express form.
- fp.direct.order.wizard.po_status (computed Selection
received/pending/missing) — drives the PO Block status badge.
- sale.order.x_fc_tooling_charge (Monetary) — receives wizard.tooling_charge
at confirm.
View updates (fp_express_order_views.xml):
- PO block header now shows the PO status pill (green Received,
amber Pending, red Missing)
- Order Lines legend bar (Mask / Bake pill / DWG / OPEN explainers)
- Part Number column uses widget='fp_express_part_cell' — single cell
with 3 internal rows
- Bake column uses widget='fp_express_bake_pill' — interactive pill
- Totals card now has Subtotal / Tooling Charge / Total Lines / Total
Quantity / Grand Total + currency pill
SCSS adds:
- Multi-row part cell styles (internal borders, bold/italic/muted rows)
- Bake pill (has-bake amber, no-bake italic muted) + inline editor
- Legend bar (section background, gap-spaced explainer chips)
- PO status pill colour scheme
- Bulk button styling
Wizard's action_create_order now carries tooling_charge to the SO at
confirm so it persists on the resulting sale.order.
Previous rebuild used Odoo's <group col='4'> which renders as an HTML
table — colspan+nesting broke into a vertical stack. Replaced entirely
with raw <div> + CSS Grid (display: grid; grid-template-columns:
repeat(4, 1fr)) so the header layout matches the mockup exactly:
- Row 1: Customer (span 2) + Shipping Address (span 2)
- Row 2: PO block (span 2, accent-bordered card with PO#/PDF/Pending
toggle/Expected date stacked + chase warning) + Customer Job # + Job Sorting
- Row 3: Material/Process Tag + Lead Time (inline X to Y) + Payment
Terms + Delivery Method
- Row 4: Blanket SO + Currency/Pricelist + Quote Validity + Invoice Strategy
Footer also rebuilt as CSS Grid (1fr 320px) — Notes/Terms cards
stacked in the left column, Totals card with Grand Total + currency
pill in the right column. Each card has a title + subtitle + body
matching the mockup's card chrome.
SCSS overrides Odoo's default field chrome inside .o_fp_xpr_cell so
inputs render with the mockup's underline style (no Bootstrap form-
control border, just a 1px bottom-border that thickens on focus).
Restructures the Express form to align with the brainstorming mockup:
Header (4-column grid via <group col='4'>):
- Row 1: Customer (colspan=2) + Shipping Address (colspan=2)
- Row 2: Consolidated PO Block (colspan=2 with PO#/PDF/Pending toggle/
Expected date stacked + chase warning inline) + Customer Job # + Job Sorting
- Row 3: Material/Process Tag + Lead Time (X to Y inline) + Payment Terms + Delivery Method
- Row 4: Blanket SO + Currency/Pricelist + Quote Validity + Invoice Strategy
Lines: 13 inline columns including the Express-specific Line Job #,
masking toggle, bake text, plus per-line action buttons (DWG, OPEN,
+ bulk) wired to the Phase B helpers.
Footer: side-by-side cards — Notes + Terms stacked in the left card,
Totals card on the right with Total Lines / Total Qty / Grand Total
+ currency pill.
SCSS adds:
- PO block: accent-bordered card-within-card
- Lines: tight spreadsheet borders, hover row highlight
- Bake column: amber pill style, italic 'no bake' for empty
- Customer Line Job #: bold, uppercase, narrow column
- Inline action buttons: small uppercase bordered chips
- Footer cards with prominent Grand Total + currency pill
OWL multi-row Part cell (FpExpressPartCell) and click-to-edit Bake
pill (FpExpressBakePill) are still deferred — they need real OWL
components, separate pass.
C1: product.pricelist._compute_display_name override gated by the
'fp_express_currency_picker' context flag (set on the Express form's
pricelist_id field). When active, prefixes the dropdown label with
the currency code: 'CAD — Public Pricelist (CAD)'. Elsewhere the
standard display name is unchanged.
C3: SCSS tokens + base styles for the Express form. Tokens use the
compile-time @if $o-webclient-color-scheme branch per the project's
'Dark Mode' rule — same SCSS compiles into both bundles with different
hex values. Token vars wrapped in CSS custom properties so downstream
modules can override for per-shop branding without recompiling.
Base styles: spreadsheet-feel table borders, bake-cell inset-pill,
customer line ref bold/uppercase, accent section markers.
Reported 2026-05-20: the Template dropdown in the Part > Process
Composer's 'Add Variant from Template' row truncated long recipe
names to 4 characters ("Cher" instead of "Chemical Conversion …").
The hard-coded max-width: 280px was set before the curated template
catalog grew names like "Chemical Conversion — Iridite Type II Cl 3"
and "ENP-STEEL-BASIC — Standard Heavy Phos".
Fix: replace the rigid max-width with a flex sizing that gives the
dropdown room to grow:
- min-width: 360px (full common recipe name fits)
- flex: 1 1 360px (grows to fill available space)
- max-width: 560px (cap so it doesn't push the buttons off-screen)
Same flex pattern applied to the Variant label input (slightly
narrower min/max).
Also: pulled the entech-side version of fp_part_process_composer.xml
back into the local repo — local was stale (one 'Add Variant' button;
entech had the dual 'Add — Tree' / 'Add — Simple' buttons that
landed in an out-of-band edit).
Module: fusion_plating_configurator 19.0.21.5.0 → 19.0.21.5.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reverting the previous wizard-width attempt. The
`.modal-dialog:has(.o_fp_direct_order_wizard)` selector combined
with the fixed width override produced broken layout (modal no
longer rendering correctly).
Better path for widening this wizard is still TBD — the built-in
maximize icon in the modal header already lets users go full-
screen as a workaround until a safe width override lands.
fusion_plating_configurator → 19.0.13.5.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User complaint: the direct-order wizard's line table was crammed —
"Primary Treatment" showed as "Primary T..." and "Serial Number"
as "Serial Nu..." at the default Odoo modal width (~992px).
Added a dedicated stylesheet that targets the wizard via a new
o_fp_direct_order_wizard class on the form element. The modal
dialog containing the wizard now opens at min(1600px, 95vw) —
wide enough for the 10+ columns (Part, Primary Treatment, Process,
Thickness, Serial Number, Qty, Unit Price, Subtotal, Part Deadline,
WO Group) to fit without truncation on typical desktop displays,
while still adapting to narrower screens.
Also nudged per-cell horizontal padding from Bootstrap's default
to 10px left/right so the columns have a bit more breathing room
inside the wider table.
fusion_plating_configurator → 19.0.13.4.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two separate issues were stacking up on the breadcrumb trail:
1. The composer was launching the tree editor with the name
"Process Composer — …" — identical to its own label. The
breadcrumb trail ended up showing "Process Composer / Process
Composer" because both pages claimed the same name. Renamed the
tree-editor instance to "Process Editor — …" so the two pages
read distinctly.
2. Every "Back to part" click pushed a new entry onto the
breadcrumb stack instead of resetting. After one round-trip the
trail looked like "… / Composer / Editor / Part"; after two it
was "… / Composer / Editor / Part / Composer / Editor / Part".
Added clearBreadcrumbs: true to both back paths (composer's
backToPart and tree-editor's onBackToList) so a RETURN action
actually resets the stack.
fusion_plating → 19.0.6.2.0
fusion_plating_configurator → 19.0.12.4.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Icon + label now share an inline-flex row with align-items: center,
so both sit on the button's vertical midline regardless of line-
height inheritance.
- Dedicated gap (10px) replaces the me-2 utility so the _hint block's
.fa { margin-bottom: 16px } can't bleed in and push the icon off.
- Icon colour forced to #ffffff to match the button's white label —
contrast against btn-primary green is now clean.
fusion_plating_configurator → 19.0.12.3.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Icon: fa-edit → fa-sitemap (pencil suggests inline editing; the
button actually navigates to a separate tree editor — sitemap
matches the intent).
- Icon spacing: swap the fragile leading-space-in-span for the
Bootstrap me-2 utility so the icon-to-text gap is consistent.
- Label: "Open Tree Editor" → "Open Process Editor" to match the
page title ("Process Composer") and the menu vocabulary the rest
of the product uses.
fusion_plating_configurator → 19.0.12.2.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Process Composer was rendering a white card background on dark-mode
tenants because the SCSS relied on var(--bs-body-bg, #ffffff) — the
Bootstrap CSS variable doesn't flip reliably in Odoo 19's backend,
and the hardcoded fallback kicked in.
Rewrote with the shopfloor token pattern from CLAUDE.md: branch on
$o-webclient-color-scheme == dark at compile time, expose via CSS
custom properties (--fp-composer-card / -border / -panel / -text /
-muted), drop every --bs-* fallback for layout colours.
Cleared the ir_attachment asset cache on entech so both the backend
and web_dark bundles recompile cleanly.
fusion_plating_configurator → 19.0.12.1.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add fp_part_composer_controller with 3 JSON-RPC endpoints:
/fp/part/composer/state, /fp/part/composer/templates,
/fp/part/composer/load_template (deep-clones a shared template
into a part-owned tree inside a cr.savepoint, sets
fp.part.catalog.default_process_id atomically)
- _clone_subtree copies name/sequence/opt_in_out/treatment_uom plus
description/notes/icon/color/timing/behaviour/work_center/process_type
and stamps part_catalog_id + cloned_from_id on every node
- Add fp_part_process_composer OWL client action (JS + XML + SCSS):
picks template from dropdown, clones, hands off to existing
fp_recipe_tree_editor via context={recipe_id, part_id}
- Add Process tab on part form with readonly default_process_id
field and Compose button calling action_open_part_composer
- Register new assets in web.assets_backend, bump configurator
version to 19.0.11.0.0
The Quote Configurator form devoted nearly half its width to a sticky
3D viewer + drawing PDF preview. That panel meant the actual fields
(geometry, dimensions, pricing) had to fight for real estate. Replaced
the inline previews with two affordances that take zero layout space:
1. New '3D Model' smart button at the top of the form, next to the
existing 'Drawings' button. Click to open the existing
fp_3d_viewer_open client action — same fullscreen modal the
'Full Screen' button used to launch from the side panel.
2. Inline 'Preview' link (eye icon) sits next to the 3D Model and
Drawing fields in the Customer & Part group. Click to open the
same modal preview as the smart button. Two paths to the same
content — power users grab the field-adjacent link mid-edit;
visual-thinkers grab the smart button up top.
Layout collapses to a single full-width column. The .o_fp_cfg_layout
wrapper is kept (display:block) so we have a stable hook in case a
side panel returns later for a different purpose. Old SCSS dance with
:has() selectors to fake-collapse the grid is gone.
Bumped fusion_plating_configurator to 19.0.3.0.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>