Commit Graph

18 Commits

Author SHA1 Message Date
gsinghpal
091f98e1f9 changes 2026-05-18 22:33:23 -04:00
gsinghpal
d9bdbd8e18 feat(portal): reusable list-search JS + fp_portal_list_controls macro
Adds the shared infrastructure for real-time multi-keyword search on
portal list pages:

- static/src/js/fp_portal_list_search.js — vanilla-JS IIFE that wires
  every input.o_fp_list_search to the container at the selector in
  its data-fp-target. On every keystroke, walks the container's
  direct children and toggles display: none based on whether each
  row's textContent contains all whitespace-tokenised keywords. Also
  wires .o_fp_sort_select dropdowns on every page EXCEPT Account
  Summary (scoped by .o_fp_account_summary closest-ancestor check) so
  the existing fp_portal_account_summary.js handler isn't doubled up.

- views/fp_portal_macros.xml — new t-call macro
  fusion_plating_portal.fp_portal_list_controls that renders the
  filter pills + search input + sort dropdown strip in one block.
  Callers pass filters, sorts, active_filter, active_sort, search,
  url, extra_qs, target, result_total, clipped via t-set.

- __manifest__.py — registers the new JS in web.assets_frontend
  (after fp_portal_account_summary.js). Version bumps 19.0.4.0.0 ->
  19.0.4.1.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 00:06:02 -04:00
gsinghpal
cdc47554ed fix(portal): account summary sort dropdown — drop inline JS for CSP safety
The inline 'onchange=\"window.location.href = this.value\"' attribute on
the sort <select> is the only inline-JS handler in the project's QWeb
templates. Under a strict Content-Security-Policy (script-src 'self')
the handler silently fails, leaving the sort dropdown dead. Replace
with a tiny vanilla-JS file (fp_portal_account_summary.js) that attaches
the listener via class selector .o_fp_sort_select inside the Account
Summary page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 14:23:01 -04:00
gsinghpal
77b84ac11b feat(portal): Account Summary template (3 tabs, filter, search, sort, pager)
Tabs: Invoices / Credit Memos / Statements (V1 placeholder).
Page header carries the Open Balance pill. Per-tab filter pills
(Open/Closed/All), search box (name OR ref), sort dropdown
(newest/oldest/largest/smallest), 10-per-page pager.

Empty states: 'No results for X' for failed searches, 'No records
in this tab' for empty result sets, and the dedicated Statements
'coming soon' card. Statements tab hides the filter/search/sort
strip — nothing to filter yet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 14:19:33 -04:00
gsinghpal
fe4cceeffa chore(portal): bump 19.0.4.0.0 + register sidebar SCSS + JS
fp_portal_shell.xml was already registered in Task 3 commit
(d17cada). This commit adds the two missing asset entries:
fp_portal_sidebar.scss in web.assets_frontend, after
fp_portal_dashboard.scss; fp_portal_sidebar.js after fp_rfq_form.js.
Version bumps 19.0.3.7.0 -> 19.0.4.0.0 (sidebar is a chrome change,
minor bump).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 13:50:30 -04:00
gsinghpal
d17cadabf0 feat(portal): sidebar shell template + portal.portal_layout inherit
fp_portal_shell wraps every /my/* page (FP custom + Odoo default)
in a sticky-sidebar shell with no per-template edits. Sidebar markup
is a separate fp_portal_sidebar template that reads fp_sidebar_items
+ fp_partner_display_name from the page context.

Approach D ($0 re-emit) used instead of plan's unbalanced-xpath approach:
position="replace" on //div[@id='wrap'] with $0 inside <main> causes
Odoo's Python inheritance engine to re-emit the original #wrap node
(verified in tools/template_inheritance.py lines 162-169). Every
xpath block is well-formed XML.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 13:39:17 -04:00
gsinghpal
2802fcf738 feat(portal): fix configurator 500, hide manual measurements, upgrade job card
1. Configurator step 2/3 500 fix: fp.coating.config was retired
   (Sub-11) but the controller still queried it -> KeyError. Swapped
   to fusion.plating.process.type (the real coating taxonomy on entech:
   Hard Chrome, EN Low Phos, Type I Anodize, etc). Step 2 template
   dropped dead refs (coat.process_type_id / spec_reference / thickness_*
   / certification_level), now shows code + process_family + description.
   Pricing helper relaxed: filters out rules keyed to the dead model
   and silently returns {'available': False} -> template shows 'Quote
   will be priced by EN Plating' instead of fake numbers.

2. Configurator step 1: manual measurements hidden per customer
   feedback. Length/Width/Height/Surface Area are kept as hidden 0s so
   the rest of the flow doesn't error; backend trimesh still auto-calcs
   surface area silently when STL is uploaded. Single file input split
   into two: separate Drawing (PDF) + 3D Model (STL/STP/STEP/IGES)
   uploads so customer can send both. Multi-upload session shape:
   attachment_ids list. Submit handler re-keys ALL uploads onto the
   new quote_request.

3. Job card upgraded: new fp_portal_job_card macro shared by dashboard
   + jobs list. Renders wrap div containing main anchor (whole card
   clickable -> detail page) + sibling actions footer (4 doc download
   quick-buttons: SO / WO / CoC / Packing + Repeat Order form).
   Forms-inside-anchor is invalid HTML so the footer lives as a
   sibling, not a child. Card now shows part name+number and ship-to
   address pulled inline from job.x_fc_job_id.sale_order_id chain.
   Same data also added to detail-page hero for consistency.

Version bump: 19.0.3.6.0 -> 19.0.3.7.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 12:34:06 -04:00
gsinghpal
6cad69cb86 feat(portal): customer PO/uploads + WO Detail PDF + hover-underline fix
1. From-You group now surfaces ANY ir.attachment attached to the
   linked sale.order (sudo'd) so customer-uploaded PO + drawings
   appear automatically. Each shows file name + upload date + size,
   downloads via /web/content/<id>?download=true. Falls through to
   the Sales Order Confirmation entry as before.

2. New 'Work Order' document group between Specifications and Quality,
   surfacing the EN Plating WO Detail PDF via new route
   /my/jobs/<id>/wo_detail. Sudo'd render of report_fp_job_wo_detail_
   template so the template can read backend fp.job + recipe nodes.
   Placeholder rendered when there's no linked backend job yet.

3. Hover underline gone: Bootstrap Reboot puts
   text-decoration: underline on a:hover for every anchor, which read
   as buggy on our flat chips / pill buttons / dashboard cards. Added
   a catch-all selector list in fp_portal_buttons.scss that pins
   text-decoration: none across hover/focus/active for every brand
   element. Hover signal lives in color + shadow only.

Version bump: 19.0.3.5.0 -> 19.0.3.6.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 12:06:41 -04:00
gsinghpal
49013c64fb feat(portal): pulse animation, repeat-order button, 5-panel dashboard
1. Pulse animation on the active step indicator:
   - New @keyframes fp-pulse-teal / fp-pulse-amber in stepper.scss
   - Applied to .o_fp_step_active / _warn and .o_fp_timeline_active
     .o_fp_timeline_dot so dashboard stepper + detail-page timeline
     breathe in sync. 1.8s ease-in-out, ring grows 4px -> 9px and
     fades 20% -> 6% opacity. Two color variants so QC (warn) keeps
     its amber meaning.
   - prefers-reduced-motion: reduce kills the animation for users
     who opted out.

2. Repeat Order button on /my/jobs/<id> detail page:
   - New POST /my/jobs/<id>/repeat route that creates a draft
     fusion.plating.quote.request seeded with the user's contact +
     the job's quantity, posts a chatter link back to the original
     job, redirects to the new RFQ for review/submit.
   - Button placed in the detail footer next to 'Back to all jobs',
     CSRF-protected via the form's csrf_token hidden field.

3. Dashboard expanded from 3 secondary panels to 5 (Recent Quote
   Requests + Recent Purchase Orders added) so every previously-
   designed customer page is reachable from /my/home.
   - Auto-fit grid: 3+2 / 2+2+1 / single column depending on width.
   - Every panel header gets a 'View all ->' link to its list page
     (Quote Requests / POs / Certs / Deliveries / Invoices).
   - Empty-state for Quote Requests gets an inline 'Get a quote ->'
     CTA so first-time customers know where to start.

Version bump: 19.0.3.4.0 -> 19.0.3.5.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 03:56:53 -04:00
gsinghpal
28220f0732 fix(portal): 5 hotfixes - /my route, button sizing, clickable cards, state sync, SO doc
1. /my now serves the FP dashboard (stock Odoo home was leaking
   through because parent route declared ['/my', '/my/home'] but my
   override only listed /my/home).
2. Button padding bumped to .5rem 1rem + font 1rem so o_fp_btn matches
   Odoo's standard Bootstrap button rhythm. Ghost button drops its
   custom padding override.
3. .o_fp_job_card on /my/home + /my/jobs is now an <a> wrapping the
   whole card area — full row is the click target, not just the WO
   number. Inner <a> on job.name dropped to avoid nested anchors;
   focus-visible outline added for keyboard nav.
4. fp.job.write() now mirrors state -> fp.portal.job.state via new
   _FP_JOB_STATE_TO_PORTAL_STATE map (confirmed->received,
   in_progress->in_progress, done->ready_to_ship). Fixes the bug where
   completed backend jobs left the portal stuck on 'in_progress'.
   'on_hold' and 'cancelled' intentionally not mirrored — manager
   choice what to surface.
5. Sales Order Confirmation now surfaces in the 'From You' group on
   the job detail page, pulled via job.x_fc_job_id.sale_order_id ->
   /report/pdf/sale.report_saleorder/<id>. Falls back to the upload
   placeholder when no SO is linked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 03:13:00 -04:00
gsinghpal
edcc325483 chore(portal): bump 19.0.3.3.0 - Phase 4 cosmetic sweep
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 02:57:40 -04:00
gsinghpal
488243cd75 chore(portal): bump 19.0.3.2.0 + register timeline SCSS
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 02:51:49 -04:00
gsinghpal
06df9745a0 chore(portal): bump 19.0.3.1.0 + register Phase 2 SCSS/data
Adds 4 Phase 2 SCSS partials (badges/cards/stepper/dashboard) plus
the macros XML data file. Macros load before any template that
t-calls them per Odoo's strict-sequential XML loader.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 02:43:46 -04:00
gsinghpal
83c2b42aad chore(portal): bump 19.0.3.0.0 + register Phase 1 SCSS
Tokens partial loaded first; buttons SCSS loaded next; legacy
catch-all stays last. Per CLAUDE.md rule 8 every SCSS file is a
separate entry (no @import allowed in Odoo 19 custom SCSS).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 02:37:25 -04:00
gsinghpal
655b767127 fix(portal): override stock /my/home with FP rich dashboard
The custom dashboard at fusion_plating_portal was rendering a 6-card
view at /my/home, but a method-name mismatch left the parent
portal.CustomerPortal.home() route active instead. Rename the
override to home() so Python MRO does the override naturally, and
add CLAUDE.md Critical Rule 16 documenting the gotcha so future
controller-override work doesn't trip on it.

Version bump: 19.0.2.2.0 -> 19.0.2.3.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 02:35:52 -04:00
gsinghpal
cd2584d6ee ui(rename): "Plating Job" -> "Work Order" / display "WO # 01368"
Standardise user-facing terminology across 5 modules (27 files):
  - display_name compute: 'Work Order # 01368' -> 'WO # 01368'
  - _description on 5 models: Plating Job{," Step"," Step Time Log"," Margin Report"," Recipe Node Override"} -> Work Order equivalents
  - field labels (string=...) on 13 Many2one / One2many fields
    across fp.batch, fp.thickness_reading, fp.quality.hold,
    fp.job_consumption, fp.portal.job, fp.certificate, fp.delivery,
    fp.quality.check, fp.racking.inspection, res.partner, sale.order
  - XML view labels: action names, list/form/search strings,
    portal template names, dashboard tile titles

What's deliberately preserved:
  - DB model name 'fp.job' (technical identifier — used by
    sale_order.x_fc_plating_job_ids and all comodel refs)
  - Module name 'fusion_plating_jobs' (directory / import path)
  - Settings -> Apps display label 'Fusion Plating Jobs' (module
    identity for Odoo's app picker)
  - 'Use Native Plating Jobs' migration toggle (internal mechanism
    flag, not user-facing terminology)

Verified on entech: WH/JOB/01368 now displays as 'WO # 01368'
everywhere humans look (form header, breadcrumbs, M2O dropdowns,
error messages, smart-button titles).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:22:09 -04:00
gsinghpal
eed4dc8a78 fix(plating): chatter HTML rendering + workflow stage banner UX
Two fixes from a single SO walkthrough screenshot:

**1. "Current stage" banner**
- Was placed `inside sheet` so it rendered at the BOTTOM of the form
  where users miss it. Moved to `before form/header` (same xpath
  pattern as the Account Hold banner) — now it's the first thing
  visible above the SO header.
- Was still showing "Shipped — awaiting invoice" after the invoice
  was posted because `_compute_workflow_stage` only advanced to
  `complete` when shipped + ALL paid; an unpaid posted invoice left
  the SO stuck on `shipped`. Added an `invoicing` branch: shipped +
  has_posted_invoice → invoicing. Banner invisible-list now also
  includes `invoicing` and `paid`, so the banner only shows for
  in-progress steps.

**2. Chatter messages rendering raw HTML tags as text**
Odoo 19 escapes any string passed to `message_post(body=...)`
unless wrapped in `markupsafe.Markup`. We had ~10 places posting
HTML (`<a href>`, `<b>`, `<br/>`, `<code>`, `<pre>`) that all
showed up as `&lt;a href=...&gt;` literal text in the chatter.

Wrapped each one with `Markup(_(...))` so the tags render. Files
touched:

- fusion_plating_bridge_mrp/models/sale_order.py
  (auto-MO failure code block, "Draft MO created" link,
   "Job assigned to <b>" message)
- fusion_plating_bridge_mrp/models/mrp_production.py
  ("Recipe steps" pre/br block on each WO)
- fusion_plating_bridge_mrp/models/fp_proficiency.py
  (operator promotion announcement)
- fusion_plating_configurator/models/fp_quote_configurator.py
  (SO link, 3D model attached, drawing attached, save to catalog)
- fusion_plating_configurator/models/fp_part_catalog.py
  (3D/drawing change tracking + propagation to linked quotes)
- fusion_plating_portal/models/fp_quote_request.py
  (RFQ → SO link)
- fusion_plating_quality/models/fp_quality_hold.py
  (hold status change)
- fusion_plating_shopfloor/controllers/manager_controller.py
  (worker / tank / manager-takeover assignments)

Verified on entech: SO S00038 stage now reads `invoicing` (banner
hidden), and a freshly posted message shows `<a href>` and `<b>`
as actual link + bold instead of escaped text.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 08:36:00 -04:00
gsinghpal
7c7ef06057 folder rename 2026-04-16 20:53:53 -04:00