Commit Graph

117 Commits

Author SHA1 Message Date
gsinghpal
d89546bec7 fix(shopfloor): Back button + logo frame shape
Two fixes from live testing of the 2026-05-24 redesign:

1. Job Workspace Back button routed to deprecated component.
   onBack() hardcoded tag: 'fp_shopfloor_landing' so tapping a card on
   the new plant kanban -> opening the workspace -> clicking Back
   dropped the user into the OLD per-step kanban (the legacy OWL
   component the data-record redirects don't reach because doAction
   bypasses the data layer).
   Fix: change the hardcoded tag to 'fp_plant_kanban'. Grep
   confirmed it's the only such reference in JS.

2. Logo frame shape — wider, shorter, logo bigger.
   140x140 square -> 280x110 rectangle. Better fit for horizontal
   company logos (mark + name + tagline laid out left-to-right).
   Uniform 18px padding on all sides so the image breathes evenly.
   Image area is ~244x74 (vs old ~104x104), so a typical horizontal
   logo renders ~50% wider. border-radius 28->22 for the flatter
   rect; letter-mark placeholder font 52->44 to fit the shorter
   frame.

Also augmented CLAUDE.md 'Legacy-action redirect' rule with a new
'grep JS for hardcoded doAction' clause — the XML-record redirect
trick only covers ir.actions.client data; OWL components with inline
this.action.doAction({tag: ...}) calls bypass the data layer entirely
and need a separate sweep.

Asset cache cleared (3 stale attachments).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 22:11:51 -04:00
gsinghpal
818dfa3882 fix(shopfloor): bigger logo frame on the tablet lock screen
User feedback after live testing: the 84px logo frame felt too small
and the image inside used only a fraction of the frame area.

Bumped the frame to 140px (1.67x) — image scales with the container
via the existing max-width/max-height: 100% rule. Proportional
adjustments to padding (14→18), border-radius (20→28), margin-bottom
(12→16), and the letter-mark placeholder font (32→52).

SCSS-only change. Asset cache cleared (3 stale attachments).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 22:06:17 -04:00
gsinghpal
772107d25b feat(shopfloor): tablet lock-screen redesign — frontend + manifest
LS-T2..T6 of the tablet lock-screen redesign (LS-T1 backend shipped
separately in c6137100).

Files:
  - _tablet_lock_tokens.scss  (new — design tokens, dark/light branches
                               via $o-webclient-color-scheme, registered
                               first in manifest per project rule 8)
  - tablet_lock.scss          (full rewrite — gradient bg, glassmorphic
                               tiles, 4 entrance keyframes, hover lift,
                               click press, clocked-in pulse,
                               prefers-reduced-motion gate)
  - tablet_lock.xml           (extended — logo + clock + prompt blocks
                               wrapping the existing tile loop; tile
                               inner shape updated for avatar gradient,
                               has_photo conditional, is_clocked_in
                               modifier)
  - tablet_lock.js            (extended — state.clockText / dateText /
                               company, setInterval(60s) clock tick,
                               _formatTime / _formatDate / tileStyle /
                               avatarClass helpers per project rule 20)
  - __manifest__.py           (19.0.31.0.0 -> 19.0.32.0.0, registered
                               new tokens SCSS BEFORE tablet_lock.scss)

Verified live on entech:
  - Module upgrade clean, registry loaded in 15.5s
  - 6 stale asset attachments cleared
  - Helpers in tablet_controller.py emit company payload + initials +
    gradients correctly (Garry Singh -> GS, EN Tech -> ET, uid=5 ->
    pink gradient)
  - res.company.logo present (has_logo: True)
  - All animations gated by prefers-reduced-motion per spec §6

CLAUDE.md updated with new Critical Rule 22 about Odoo 19 HTML fields
auto-wrapping plain-string writes — caught during Task 1 testing when
the original 'tagline equality' test failed because res.company.report
_header is an HTML field that wraps writes with <p> tags.

Closes the 6-task plan in
  docs/superpowers/plans/2026-05-24-tablet-lock-screen-redesign-plan.md
Spec: docs/superpowers/specs/2026-05-24-tablet-lock-screen-redesign-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 21:56:32 -04:00
gsinghpal
c61371005a feat(shopfloor): extend /fp/tablet/tiles payload with company block
LS-T1 of the tablet lock-screen redesign.

Adds 3 module-level helpers in tablet_controller.py:
  _initials_from(name)       — first/last initials for letter-mark fallback
  _avatar_gradient_for(uid)  — deterministic per-user color (8 gradients)
  _lock_company_payload(env) — company name + tagline + logo URL block

Endpoint /fp/tablet/tiles now returns:
  {ok, company:{id,name,tagline,logo_url,has_logo,initials},
   tiles:[{user_id, name, initials, avatar_url, has_photo,
           avatar_gradient, is_clocked_in, has_pin}, ...]}

Tagline reuses res.company.report_header (the existing invoice-letterhead
field) — no new model field. Falls back to 'Shop Floor Terminal' when
empty.

10 tests pass (initials edge cases, gradient determinism, payload shape).
The 'tagline matches input string' assertion was intentionally NOT added
— see new CLAUDE.md Critical Rule 22 about Odoo 19 HTML field
auto-wrapping that makes such an equality test brittle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 21:52:17 -04:00
gsinghpal
fd2b2908f3 fix(shopfloor): plant-view card sizing — match the mockup proportions
User feedback after live testing: cards were too cramped on the 9-column
board. Restoring the Variant C mockup proportions and letting the board
scroll horizontally on smaller viewports (user explicitly accepted
side-scrolling).

Changes:
  - .board grid: repeat(9, 1fr) → repeat(9, minmax(300px, 1fr))
    plus overflow-x: auto. Each column ~300px so the card has room to
    breathe. ~6 columns visible on 1920px desktop, ~4 on 1366px tablet,
    smooth horizontal scroll for the rest.
  - .col-scroll: gap 4→8, max-height eased so cards aren't packed.
  - .o_fp_plant_card: padding 8/10→12, gap 4→6, base font 11→12.
  - card-wo: 13→16 (matches mockup header size).
  - card-step: 12→14.
  - chips: padding 1/6→2/8, font 10→11, radius 10→12.
  - mini-timeline blocks: 8→16px tall (current step 11→22px), labels
    8→9px. Matches the mockup's punchy timeline strip.
  - progress bar: max-width 60→100, height 3→4.
  - operator pill / icon-row: bumped to match card scale.

No backend changes. SCSS-only. Asset cache cleared (3 attachments).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 21:20:01 -04:00
gsinghpal
eb1fd50add fix(shopfloor): legacy client actions redirect to fp_plant_kanban
The plant-view rollout left two legacy ir.actions.client data records
still claiming tag='fp_shopfloor_landing':
  - action_fp_plant_overview        (Plant Overview)
  - action_fp_shopfloor_tablet      (Shop Floor — Tablet Station)

The landing-action resolver dispatched the new view correctly when the
user clicked the Plating root menu, but bookmarks / breadcrumbs /
QR-scan landings / direct URLs still routed through these legacy
actions and loaded the per-step kanban (OWL component is still
registered for back-compat).

Flipping their tag to fp_plant_kanban means every entry point now
opens the new view. The legacy fp_shopfloor_landing OWL component
stays registered (no code removed) but no XMLID points at it
anymore — safe to delete in a future cleanup.

Also documented this as a durable convention in CLAUDE.md under
'Legacy-action redirect (general rule for OWL component swaps)'.

Verified on entech:
  - action 1129 (Shop Floor)     tag: fp_shopfloor_landing → fp_plant_kanban
  - action 1133 (Plant Overview) tag: fp_shopfloor_landing → fp_plant_kanban
  - 3 stale asset bundles cleared
  - Module re-upgraded clean, registry rebuilt in 15.7s

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 21:14:33 -04:00
gsinghpal
a60506a645 feat(shopfloor): Phase 5 — flip default to v2 plant view + docs
PV-Phase5 of the plant-view redesign. Final phase — flips the default
of x_fc_shopfloor_layout from 'legacy' to 'v2' and updates CLAUDE.md
with the new architecture rule.

Verified on entech:
  - HTTP 200 on /web/login
  - Shopfloor module loads cleanly with all 19 new frontend files
  - /fp/landing/plant_kanban returns the assembled payload with 9
    columns + denormalized cards
  - Card state distribution: 22 contract_review + 8 no_parts + 1 running
    (sample data only — dev system)
  - Asset bundle re-compiled (9 stale attachments cleared)
  - ir.config_parameter['fusion_plating_shopfloor.layout'] = 'v2' set

To switch back to legacy: Settings → Fusion Plating → Shop Floor
Layout, or UPDATE ir_config_parameter SET value='legacy' WHERE
key='fusion_plating_shopfloor.layout'.

CLAUDE.md gets a new ~80-line section documenting:
  - Why the redesign (per-step kanban produced duplicate cards)
  - 9-column layout + step-kind → area mapping (spec D3, D4, D5)
  - 13-state catalog + precedence dispatch in _compute_card_state
  - Backend single-endpoint payload shape (/fp/landing/plant_kanban)
  - Frontend OWL component tree + critical implementation gotchas
    (rule 20 OWL scope, rule 8 SCSS @import, dark-mode compile-time)
  - How to switch back to legacy

Closes the 20-task plan in
  docs/superpowers/plans/2026-05-23-shopfloor-plant-view-plan.md

Spec: docs/superpowers/specs/2026-05-23-shopfloor-plant-view-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:59:44 -04:00
gsinghpal
8b9b4d60ad feat(shopfloor): Phase 4 — plant-view kanban frontend (OWL + SCSS + XML)
PV-Phase4 of the plant-view redesign. 19 new files implementing the
6-component OWL tree plus design tokens.

Components (each = JS + XML + SCSS triple):
  - FpMiniTimeline    — 9-step bar consuming mini_timeline_json
  - FpPlantCard       — Variant C card; 13 state-* CSS classes; tap
                        opens fp_job_workspace
  - FpColumnHeader    — column label + count badge + 'You're here'
                        badge when paired
  - FpKpiTile         — clickable KPI button with urgent/warn/good
                        variants and active state
  - FpFilterChip      — toggleable chip
  - FpPlantKanban     — top-level orchestrator: 10s polling, mode
                        toggle, search + 6 filter chips, board with
                        9 fixed columns, localStorage filter persistence

SCSS:
  - _plant_tokens.scss (loads first, exposes $plant-* vars to every
    later file — required because Odoo 19 forbids @import in custom
    SCSS, manifest order IS the concat order)
  - Dark mode via $o-webclient-color-scheme compile-time branch

Manifest registers all assets in dependency order: tokens → component
SCSS → component XML → leaf JS → top-level JS. Mirrors the existing
project pattern.

Critical patterns honored:
  - Project rule 20 (no String/Number/parseInt in OWL templates):
    all coercion in JS, string literals in foreach arrays.
  - No t-out without markup() (none in this batch — all card text is
    pre-formatted by the controller).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:57:55 -04:00
gsinghpal
a90eace4d0 feat(shopfloor): Phase 3 — plant_kanban endpoint + dispatch
PV-Phase3 of the plant-view redesign.

- /fp/landing/plant_kanban JSONRPC endpoint returns {kpis, columns,
  cards} in one payload. One card per fp.job; cards denormalized so
  the OWL component doesn't fan out RPCs. Server-side filter handling
  for All / Mine / Running / Blocked / Overdue / FAIR. Within-column
  sort by (overdue, _SORT_PRIORITY[card_state], due_date).
- fusion_plating_shopfloor.action_fp_plant_kanban client action
  registered alongside the existing fp_shopfloor_landing action.
- fp_landing_data.xml resolver extended to read the layout flag and
  dispatch to v2 when x_fc_shopfloor_layout='v2' (default still legacy).

Card payload (23 fields): WO, customer, PN+rev, qty, PO, recipe, spec,
tags, current step + work centre, state chip, mini_timeline, operator,
icons (signoff / bake / tracking / etc.), progress.

State-chip mapping per spec §6.1 — one map keyed by card_state with
running-time elapsed, idle-hours, and operator-name interpolation.

Verified live — card payload sample on WO-30036 (contract_review state)
produces all expected keys + 9-element mini_timeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:51:36 -04:00
gsinghpal
63d692b322 feat(plating): Phase 1 — plant-view kanban data model foundation
PV-T1: fp.work.centre.area_kind Selection (9 floor columns)
PV-T2: fp.job.step.area_kind compute + _STEP_KIND_TO_AREA fallback
       (covers all 30+ step kinds in the project library, plus the
       spec D4 rule that de_mask folds into de_racking)
PV-T3: fp.job.step.last_activity_at + write hook + message_post
       override + fp.job.step.move.create() hook + _fp_is_idle helper
PV-T4: res.users.paired_work_centre_ids M2M (single-station for MVP,
       forward-compatible for Phase 2 multi-station picker)
PV-T5: res.config.settings.x_fc_shopfloor_layout feature flag backed
       by ir.config_parameter for the landing-action resolver

Migrations:
  fusion_plating 19.0.21.0.0      — backfill area_kind from kind
  fusion_plating_jobs 19.0.10.24.0 — backfill last_activity_at

Deployed + verified on entech:
  - 9/9 fp.work.centre rows have area_kind set
  - 400/400 fp.job.step rows have area_kind + last_activity_at
  - paired_work_centre_ids M2M relation table created
  - All 271 modules loaded cleanly, registry rebuilt in 27s

Part of the 2026-05-23 Shop Floor plant-view kanban redesign.
Plan: docs/superpowers/plans/2026-05-23-shopfloor-plant-view-plan.md
Spec: docs/superpowers/specs/2026-05-23-shopfloor-plant-view-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:43:15 -04:00
gsinghpal
1a3ca8704e feat(plating): session 2026-05-23 deploys — F1/F7/S22/S23 + UI fixes
Consolidated commit of session work already deployed to entech and
verified via the deep audit + the persona walk:

S22 — Signoff gate (fp.job.step.requires_signoff was 100% unenforced,
42/42 done steps had NULL signoff_user_id). Three-piece fix:
_fp_autosign_if_required (captures finisher on button_finish),
_fp_check_signoff_complete (raises UserError if NULL after autosign),
action_signoff (explicit supervisor pre-sign). Bypass:
fp_skip_signoff_gate=True.

S23 — Transition-form gate (same dormant-field shape as S22, caught
preventively before recipe authors flipped requires_transition_form
on). Model helpers on fp.job.step.move + controller gate in
move_controller (parts commit) + pre-reject in rack commit.

F7 — Chatter standardization: _fp_create_qc_check_if_needed,
_fp_fire_notification, _fp_create_delivery silent failures now also
post to job chatter instead of only logging to file.

UI fixes:
- Critical Rule 20 documented + applied: OWL templates only expose
  Math as a global. Calling String(d) inside t-on-click throws
  'v2 is not a function'. Fixed pin_pad.xml (string array instead of
  number array with String() coercion). Also swept parseInt/
  parseFloat in recipe_tree_editor + simple_recipe_editor.
- Notes panel HTML escape fix: chatter messages off /fp/workspace/load
  were rendered via t-out, escaping the HTML. Wrap with markup() in
  job_workspace.js refresh() before assigning to state.

Versions:
  fusion_plating         19.0.20.8.0 → 19.0.20.9.0
  fusion_plating_jobs    19.0.10.20.0 → 19.0.10.23.0
  fusion_plating_shopfloor 19.0.30.2.0 → 19.0.30.5.0

All deployed to entech (LXC 111) and verified live.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:37:17 -04:00
gsinghpal
27e12dd544 chore(shopfloor): register fp_rpc.js asset + bump to 19.0.30.2.0 (P6.3.6)
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Adds the Phase 6.3 fpRpc wrapper to the web.assets_backend bundle.
Placed before its consumers so the `import { fpRpc } from "./services/fp_rpc"`
calls in job_workspace, shopfloor_landing, manager_dashboard, and
hold_composer resolve.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:47:51 -04:00
gsinghpal
5f03080374 feat(shopfloor): switch action-path RPCs to fpRpc + wire plant_overview/move_card (P6.3.5)
JobWorkspace, ShopfloorLanding, ManagerDashboard, and the embedded
FpHoldComposer now call fpRpc() for write-path endpoints (start/finish
step, hold create, sign-off, milestone advance, work-centre move,
assign-worker, assign-tank, manager takeover). fpRpc auto-injects
tablet_tech_id from the tech_store so the server can rebind env via
env_for_tablet_tech() and credit the right user.

Read-path RPCs (workspace/load, landing/kanban, manager/overview,
manager/funnel, manager/approval_inbox, manager/at_risk, shopfloor/scan)
stay as plain rpc() — no audit benefit, no need for the extra plumbing.

Also wires tablet_tech_id into /fp/shopfloor/plant_overview/move_card
which I missed in P6.3.3 — surfaced when grepping JS for write callers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:47:20 -04:00
gsinghpal
efaf16dffb feat(shopfloor): propagate tablet_tech_id to shopfloor + manager action endpoints (P6.3.3 + P6.3.4)
10 endpoints in shopfloor_controller (log_chemistry, start_bake, end_bake,
start_wo, stop_wo, bump_qty_done, bump_qty_scrapped, log_thickness_reading,
quality_hold, mark_gate) and 3 in manager_controller (assign_worker,
assign_tank, take_over) now accept a `tablet_tech_id` kwarg. Each rebinds
env via env_for_tablet_tech() so writes carry the correct uid even when
the OS session belongs to the persistent tablet user.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:43:44 -04:00
gsinghpal
e4000374ca feat(fusion_plating_shopfloor): wire tablet_tech_id into workspace endpoints (P6.3.2)
hold, sign_off, advance_milestone each accept tablet_tech_id and
rebind env via env_for_tablet_tech. Writes (Hold.create, button_finish,
action_advance_next_milestone) now carry the tech-of-record's uid.
load endpoint is read-only and untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:37:58 -04:00
gsinghpal
fee4219703 feat(fusion_plating_shopfloor): fpRpc wrapper + env_for_tablet_tech helper (P6.3.1)
Client-side fpRpc() is a drop-in for rpc() that automatically injects
tablet_tech_id from the tech_store into every action call. Read-only
endpoints can keep using plain rpc().

Server-side env_for_tablet_tech(env, tablet_tech_id) returns an env
scoped via with_user() when the id is a valid active user; otherwise
returns the original env unchanged. Controllers call this at the top
of action methods so all subsequent writes carry the right uid.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:37:02 -04:00
gsinghpal
6ca9a58a8c chore(fusion_plating_shopfloor): bump 19.0.30.1.0 for Phase 6.2 — lock screen
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Frontend lock screen ships:
- tech_store + activity_tracker shared OWL services
- FpPinPad, FpIdleWarning, FpPinSetup components
- FpTabletLock outer wrapper
- Wired into Landing/Workspace/Manager + Hand-Off button in each header
- fp_tablet_pin_setup client action for Preferences self-service
2026-05-23 00:33:42 -04:00
gsinghpal
d86c120969 feat(fusion_plating_shopfloor): FpPinSetup client action for self-service PIN (P6.2.6)
Registers fp_tablet_pin_setup as an ir.actions.client tag. Triggered
from res.users preferences via action_open_tablet_pin_setup (added
to res_users.py in P6.1.1). Three-stage flow:

  loading → check if user has existing PIN via search_count
  old     → enter current PIN (skipped if first-time)
  new     → choose new PIN
  confirm → enter new PIN again
  done    → success toast + auto-close 1.5s later

Each stage reuses FpPinPad with a different onSubmit + title. On
mismatch / server error, resets to the first stage with a notification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:33:28 -04:00
gsinghpal
85609f99cd feat(fusion_plating_shopfloor): wire FpTabletLock + Hand-Off into Landing/Workspace/Manager (P6.2.5)
Three OWL client actions all wrap their root in <FpTabletLock>:

  ShopfloorLanding   wraps o_fp_landing
  JobWorkspace       wraps o_fp_ws
  ManagerDashboard   wraps o_fp_manager

Each adds FpTabletLock to static components, imports tech_store, and
gains a handOff() method that calls techStore.lock(). The Hand-Off
button (yellow, lock icon) lands next to the scan/QR controls in each
header — pressing it instantly returns the tablet to the tile grid
without waiting for the idle timer.

Component composition (per spec §6.5):
  FpTabletLock
    if isLocked → tile grid + FpPinPad
    else → existing client action (via <t t-slot="default"/>) + FpIdleWarning

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:32:52 -04:00
gsinghpal
29821bd541 feat(fusion_plating_shopfloor): FpTabletLock outer wrapper component (P6.2.4)
Top-level wrapper that renders lock screen (tile grid + PIN pad) when
no tech is signed in, and renders <t t-slot="default"/> otherwise.
Drives the auto-lock countdown via the activity_tracker service +
sends a /fp/tablet/ping heartbeat every 60s while a tech is signed in.

Tiles fetch from /fp/tablet/tiles using the localStorage station id
(set by ShopfloorLanding on QR pair / station picker selection).

State machine for the lock screen body:
  loadingTiles → tiles list → tile tapped → PinPad → unlock RPC
                                          ↑
                                          onPinCancel → back to tiles

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:29:24 -04:00
gsinghpal
1fdafd34d1 feat(fusion_plating_shopfloor): FpIdleWarning overlay (P6.2.3)
Fixed-position yellow-border overlay + countdown toast shown during
the last N (default 30) seconds before auto-lock. Pure props-driven —
secondsRemaining is the only input; parent (FpTabletLock) decides
when to mount and unmount. Box-shadow pulse animation runs CSS-only
so OWL doesn't need to re-render every tick.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:28:30 -04:00
gsinghpal
9584953467 feat(fusion_plating_shopfloor): FpPinPad numeric keypad component (P6.2.2)
Reusable 4-digit PIN pad. Auto-submits on the 4th digit via the
onSubmit prop. On wrong PIN, shake animation + dots clear + error
banner (caller controls the message via the returned {ok:false, error}).

Used by FpTabletLock (unlock flow) and FpPinSetup (set/change flow).

Dark-mode SCSS branch follows the same $o-webclient-color-scheme
pattern as the rest of the shopfloor components.

Also registers tech_store + activity_tracker services in the asset
bundle (assets/web.assets_backend) before the pin_pad files, since
the pin_pad/tablet_lock components consume them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:28:01 -04:00
gsinghpal
52097ca59b feat(fusion_plating_shopfloor): tech_store + activity_tracker OWL services (P6.2.1)
Two registry-level services:

tech_store    Shared reactive state holding currentTechId after a
              successful PIN unlock. Other components subscribe via
              useService("fp_shopfloor_tech_store") and read
              currentTechId to inject into action RPCs. setTech(id, name)
              on unlock; lock() on auto-lock / Hand-Off.

activity_tracker  Document-level event tracker for pointerdown / touchstart
              / keydown / visibilitychange. Mouse-move alone deliberately
              EXCLUDED — a tool resting on a tablet would otherwise keep
              the session alive indefinitely. Public API:
                bump(), getSecondsUntilLock(), getWarnThresholdSec()
              Reads thresholds from ir.config_parameter at start +
              every 5 min (so manager edits propagate within a shift).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:27:13 -04:00
gsinghpal
1d6184dd2f chore(fusion_plating_shopfloor): bump 19.0.30.0.0 for Phase 6.1 — PIN backend
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Backend foundation for the tablet PIN gate:
- res.users PIN fields + hash helpers (PBKDF2-SHA256, 200k iter, salted)
- 5 endpoints: /fp/tablet/{tiles,unlock,set_pin,reset_pin_for,ping}
- Per-user lockout (5 fails → 5 min, both configurable)
- Station roster + per-station idle override
- ir.config_parameter defaults
- Preferences Set/Change PIN button + Manager Reset button

Phase 6.2 (frontend lock screen) is next.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:17:37 -04:00
gsinghpal
88a473e7eb feat(fusion_plating_shopfloor): Preferences Set/Change PIN + Manager Reset button (P6.1.7)
Two view inheritances on res.users:

(a) Preferences form — adds a 'Tablet PIN' group with a 'Set / Change
    Tablet PIN' button that triggers action_open_tablet_pin_setup → the
    fp_tablet_pin_setup OWL client action (Phase 6.2). Shows PIN Last
    Set as read-only context.

(b) Standard res.users form — header button 'Reset Tablet PIN' visible
    only to the fusion_plating manager group; hidden when no PIN is set
    (via the set_date invisible field reference). Confirms before clearing.
    Calls the clear_tablet_pin method from the model.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:17:20 -04:00
gsinghpal
08ababc2c7 feat(fusion_plating_shopfloor): station roster + idle override + tablet config defaults (P6.1.6)
Adds two fields to fusion.plating.shopfloor.station:
- x_fc_authorised_user_ids (Many2many → res.users): restricts the
  tablet lock-screen tile grid to a specific roster per station.
  Empty = all operator-group users shown.
- x_fc_idle_lock_minutes (Integer, nullable): per-station override
  for the auto-lock idle threshold; null = use system parameter.

Plus data/fp_tablet_config_data.xml registers four ir.config_parameter
defaults (noupdate=1 — manager can override via Settings → Technical
→ Parameters):
  fp.shopfloor.tablet_idle_lock_minutes = 5
  fp.shopfloor.tablet_pin_fail_threshold = 5
  fp.shopfloor.tablet_pin_fail_lockout_minutes = 5
  fp.shopfloor.tablet_warn_seconds_before_lock = 30

Form view surfaces both new fields in a dedicated 'Tablet PIN Gate'
group.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:16:52 -04:00
gsinghpal
59ad77839a feat(fusion_plating_shopfloor): /fp/tablet/tiles + /fp/tablet/ping endpoints (P6.1.4-P6.1.5)
Tiles returns the lock-screen grid: operator-group users, sorted
clocked-in-first then alphabetical, with avatar URL + has_pin flag.
Honours station.x_fc_authorised_user_ids when non-empty (Phase 6.1.6
adds that field). Ping is a lightweight ack used by FpTabletLock as
a heartbeat — logs current_tech_id at DEBUG for forensic visibility.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:15:40 -04:00
gsinghpal
a594431eb6 feat(fusion_plating_shopfloor): /fp/tablet/unlock with per-user lockout (P6.1.3)
Verifies PIN, resets failure counter on success, increments + locks out
on 5 consecutive failures (configurable via ir.config_parameter
fp.shopfloor.tablet_pin_fail_threshold + tablet_pin_fail_lockout_minutes,
both defaulting to 5).

Returns informative payloads:
  ok=true            current_tech_id, current_tech_name
  needs_setup=true   user has no PIN yet
  locked_until       lockout in effect (rejects even correct PIN)
  attempts_remaining failed but not yet locked

Logs INFO on success, WARNING on failure (with running counter +
locked flag).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:15:01 -04:00
gsinghpal
58d02598da feat(fusion_plating_shopfloor): /fp/tablet/set_pin + /fp/tablet/reset_pin_for endpoints (P6.1.2)
set_pin is self-service: requires old PIN if a hash exists, validates
4-digit format. reset_pin_for is manager-only (enforced server-side
via has_group); clears the hash + posts to chatter.

Both endpoints log INFO on success and WARNING on access-control denials.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:14:18 -04:00
gsinghpal
395bd4949e feat(fusion_plating_shopfloor): res.users tablet PIN fields + hash helpers (P6.1.1)
PBKDF2-SHA256 + 16-byte salt + 200k iterations on res.users. Format
of the stored hash string is <salt_hex>$<digest_hex>. Field is
manager-readable only (groups=group_fusion_plating_manager); helpers
that need to read or write it use .sudo() internally so operator-level
callers can still set/verify their own PIN.

Adds set_tablet_pin / verify_tablet_pin / clear_tablet_pin model
methods + action_open_tablet_pin_setup that triggers the OWL setup
modal (Phase 6.2). Tests cover hash uniqueness, verify, clear with
chatter post, and the 4-digit format guard.

Tests verified on entech: -u fusion_plating_shopfloor --test-tags fp_tablet_pin

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:13:33 -04:00
gsinghpal
3ef67c6beb fix(fusion_plating_shopfloor): import fields in manager_controller
The Phase 4 endpoints (/fp/manager/funnel, approval_inbox, at_risk)
all use fields.Datetime.now() but the controller only imported http
+ request. Hitting the Workflow Funnel tab on Manager Desk threw:

  NameError: name 'fields' is not defined

Funnel auto-loads on dashboard mount → infinite spinner + 'Funnel:
Odoo Server Error' notification. Same bug would have hit at_risk
and approval_inbox on first navigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 23:01:44 -04:00
gsinghpal
2cdb2e3d0b chore(fusion_plating): bump versions for Phase 4 — Manager Desk refactor
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
fusion_plating            19.0.20.8.0  (bottleneck_score on fp.work.centre)
  fusion_plating_shopfloor  19.0.29.0.0  (3 new endpoints + 4-tab manager dashboard
                                          + 2 new KPI tiles)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:22:18 -04:00
gsinghpal
f00dda2abd feat(fusion_plating_shopfloor): Manager Desk 4-tab refactor (P4.5-P4.10)
Plan tasks P4.5 through P4.10 batched. Existing 3-column Plant Board
becomes one tab of four; adds Workflow Funnel (default), Approval
Inbox, and At-Risk siblings. Adds 2 new KPI tiles for Pending Cert +
At-Risk.

  WORKFLOW FUNNEL (default tab)
    Calls /fp/manager/funnel. Renders one row per fp.job.workflow.state
    with stage chip + count + top 5 WO cards. Tap a card → JobWorkspace.
    Bar chart bar behind each row scales with stage count.

  APPROVAL INBOX
    Calls /fp/manager/approval_inbox. Three strips: Holds to Release,
    Certs to Issue, Scrap to Review. Per-row open + Open Workspace
    buttons. Tab badge shows total pending count.

  PLANT BOARD (existing — relocated as one tab)
    The 3-column Needs Worker / In Progress / Team layout that already
    exists, wrapped in t-if="activeTab === 'plant_board'". No behaviour
    change — still uses /fp/manager/overview with 8s refresh.

  AT-RISK
    Calls /fp/manager/at_risk. 3 sub-panels: Trending Late (sorted by
    late_risk_ratio desc), Hold Reasons (read_group), Bottleneck heatmap
    (bottleneck_score from P4.1 with red/yellow/green bars).

  KPI STRIP (new conditional tiles)
    Pending Cert  — count from inbox.certs_to_issue, click to open Inbox tab.
    At-Risk       — count from at_risk.trending_late, click to open At-Risk.

Auto-refresh: 8s for /fp/manager/overview (existing); the active tab's
data also refreshes every 8s via refreshActiveTab().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:21:53 -04:00
gsinghpal
3b7b2477cf feat(fusion_plating_shopfloor): 3 new manager endpoints — funnel, inbox, at_risk (P4.2-P4.4)
Plan tasks P4.2 + P4.3 + P4.4 batched. Adds the backend data layer
for the Manager Desk's 3 new sibling tabs (Phase 4 tablet redesign).

  POST /fp/manager/funnel
      Workflow funnel: jobs grouped by fp.job.workflow.state. Returns
      stages[] with count + top 5 WO cards per stage. Drives the
      default tab on the refactored dashboard.

  POST /fp/manager/approval_inbox
      Four buckets: holds_to_release (state=on_hold|under_review),
      certs_to_issue (all_steps_terminal + draft cert), scrap_to_review
      (last 24h mark_for_scrap holds), override_requests (deferred —
      empty placeholder).

  POST /fp/manager/at_risk
      Three panels: trending_late (top 20 by late_risk_ratio desc),
      hold_reasons (read_group on hold_reason), bottleneck (top 10
      work centres by bottleneck_score from P4.1).

All endpoints respect optional facility_id scope. Cheap implementations
— no caching yet; performance can be added if entech load demands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:17:53 -04:00
gsinghpal
5d086c7f27 chore(fusion_plating_shopfloor): bump 19.0.28.0.0 for Phase 3 — Landing refactor
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Phase 3 ships:
- /fp/landing/kanban endpoint (P3.1)
- ShopfloorLanding OWL client action with Station/All-Plant toggle,
  KPI strip, search, kanban with DnD, QR scan, card-tap to Workspace (P3.2-P3.4)
- Menu rewire: 'Tablet Station' + 'Plant Overview' → single 'Workstation'
  entry; legacy actions retargeted to fp_shopfloor_landing for bookmark
  back-compat (P3.5)
- DEPRECATED markers on legacy /fp/shopfloor/tablet_overview, plant_overview,
  queue endpoints (P3.6 — pragmatic deviation: bodies kept intact for the
  still-registered legacy OWL components)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:12:06 -04:00
gsinghpal
3eba80bb31 docs(fusion_plating_shopfloor): deprecation markers on legacy endpoints (P3.6)
Plan task P3.6 — pragmatic deviation. The plan called for stubs that
internally route to /fp/landing/kanban + reshape; in practice the
legacy fp_shopfloor_tablet OWL component (still registered, just
unhooked from the menu) consumes a much richer payload (my_queue,
active_wo, baths, bake_windows, gates, holds, pending_qcs, stations)
than /fp/landing/kanban returns. Gutting tablet_overview to a stub
would break that legacy component.

Instead: add explicit DEPRECATED markers + INFO log lines on the three
endpoints (tablet_overview, plant_overview, queue). Bodies stay intact
so the legacy components keep working until Phase 5 cleanup retires
both endpoints AND the legacy OWL components together.

Note: /fp/shopfloor/plant_overview/move_card is NOT deprecated — the
new Landing component still uses it for drag-and-drop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:11:49 -04:00
gsinghpal
2a0d1862df feat(fusion_plating_shopfloor): rewire menus to Shop Floor Landing (P3.5)
Plan task P3.5. Single 'Workstation' menu item replaces both the
legacy 'Tablet Station' and 'Plant Overview' entries. The new
fp_shopfloor_landing component has a Station/All-Plant toggle so
one menu covers both old surfaces.

Old action records redirected for back-compat (so existing bookmarks
+ smart-button references keep working):

  action_fp_shopfloor_tablet  tag → fp_shopfloor_landing
  action_fp_plant_overview    tag → fp_shopfloor_landing
                              params → {'mode': 'all_plant'}

The legacy OWL components (fp_shopfloor_tablet, fp_plant_overview)
remain registered — no code removed, just no menu points at them.
Phase 5 cleanup will remove the OWL components after a release of
soak time on entech.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:10:36 -04:00
gsinghpal
7f70785b79 feat(fusion_plating_shopfloor): ShopfloorLanding client action (P3.2-P3.4)
Plan tasks P3.2 + P3.3 + P3.4 batched. Full ShopfloorLanding OWL
client action — replaces fp_shopfloor_tablet AND folds in
fp_plant_overview.

  Header strip          Title, station chip, station picker dropdown,
                        Station/All-Plant mode toggle, QR scan controls,
                        last-refresh indicator.
  KPI strip             4 tech-relevant tiles: Ready · Running ·
                        Bakes Due (warning) · Holds (red when > 0).
  Search                Live debounced (200ms) across WO# + customer +
                        part. ESC clears.
  Kanban board          Columns = work centres from /fp/landing/kanban.
                        Cards = FpKanbanCard (Phase 1 — P1.7).
                        Drag-and-drop reuses existing
                        /fp/shopfloor/plant_overview/move_card.
  Card tap              doAction → fp_job_workspace with
                        {job_id, focus_step_id}.
  QR scan               FP-STATION pairs, FP-JOB / FP-STEP jump to the
                        Workspace.

Mode + station_id persist in localStorage (LS_STATION_ID, LS_MODE).
Auto-refresh every 15s; suppressed during a drop and for 5s after.

Registers client action `fp_shopfloor_landing`. Menu rewire + endpoint
stubs land in P3.5 + P3.6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:09:09 -04:00
gsinghpal
9dcd00d9b2 feat(fusion_plating_shopfloor): /fp/landing/kanban endpoint
Plan task P3.1. New JSON-RPC endpoint for the Shop Floor Landing
client action (Phase 3). Two modes:

  station    — paired WC + Unassigned + next 1-2 WCs in recipe flow
  all_plant  — every active WC, recipe-flow order (replaces the data
               path for the standalone fp_plant_overview action)

Returns {columns: [{work_center_id, work_center_name, cards}], kpis:
{ready, running, bakes_due, holds}, stations: [...], facility_name,
server_time}. Card payload matches the KanbanCard OWL component
(P1.7) — same shape, no client-side adapter needed.

Light implementation — no urgency scoring or batch prefetch yet.
Both can be ported from plant_overview if performance demands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:06:40 -04:00
gsinghpal
5a28c7e90f chore(fusion_plating): bump versions for Phase 2 — cron + ACL + supporting computes
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
fusion_plating              19.0.20.7.0  (long_running on process node)
  fusion_plating_jobs         19.0.10.20.0 (late_risk_ratio, active_step_id, autopause cron)
  fusion_plating_shopfloor    19.0.27.1.0  (no code change; data-version bump for Phase 2)
  fusion_plating_certificates 19.0.7.9.0   (ACL lift — bumped in P2.6)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:04:26 -04:00
gsinghpal
3c2efae951 feat(fusion_plating): lift operator ACL for cert write + thickness create + override read
Plan task P2.6. Per the spec's "techs wear multiple hats" rule, lift
gates so technicians can do their work without permission walls:

  fp.certificate         operator: read → read+write
                         (flip draft→issued from tablet)
  fp.thickness.reading   operator: read → read+write+create
                         (capture Fischerscope readings from tablet)
  fp.job.node.override   operator: NEW read-only
                         (see opt-out badges on steps)

Supervisor-only operations (step Skip, hold Release, override
Re-include) remain enforced in workspace_controller, not ACL — so the
ACL stays minimal and the controller centralizes the gate logic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:04:05 -04:00
gsinghpal
a18ef6c405 feat(fusion_plating_shopfloor): JobWorkspace client action (header/steps/side/rail)
Plan tasks P1.12 through P1.15 batched. Full-screen OWL component
registered as fp_job_workspace. Layout:

  STICKY HEADER       WO #, customer, part, qty/done, deadline,
                      WorkflowChip, holds badge
  STICKY WORKFLOW BAR 9-stage dots (passed/current/pending) +
                      Next-action button driving advance_milestone
  STEP LIST           All steps with state icons; active step
                      auto-expanded with recipe chips (thickness/
                      dwell/bake/sign-off) + instructions + Start/
                      Finish buttons; blocked steps show GateViz;
                      override-excluded steps faded
  SIDE PANEL          Customer spec PDF link, attachments list,
                      chatter notes
  STICKY ACTION RAIL  Create Hold (HoldComposer modal), Add Note
                      (chatter via message_post), Issue Cert (when
                      draft cert exists), Next Milestone

Auto-refresh every 15s. Sign-off steps route Finish through
SignaturePad → /fp/workspace/sign_off.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:52:26 -04:00
gsinghpal
eae6a471e8 feat(fusion_plating_shopfloor): workspace_controller — 4 endpoints + tests
Plan tasks P1.8 through P1.11 batched into one commit (local tests not
run between them; entech is the verification env).

  POST /fp/workspace/load               — full payload for one fp.job
  POST /fp/workspace/hold               — quality.hold create with photo
  POST /fp/workspace/sign_off           — signature + finish step atomic
  POST /fp/workspace/advance_milestone  — fire next_milestone_action

Each endpoint logs INFO on success, EXCEPTION on failure, returns a
consistent {'ok': bool, 'error': str?} envelope. Hold endpoint isolates
photo-attach failures so they don't roll back the hold record.

Tests cover: payload shape, bad job_id, hold create with/without photo,
empty qty rejection, empty-signature rejection, sign-off finish, and
the no-milestone-action error path.

Verify on entech: -u fusion_plating_shopfloor --test-tags fp_shopfloor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:50:09 -04:00
gsinghpal
a61bd05a5c feat(fusion_plating_shopfloor): KanbanCard shared OWL service
Plan task P1.7. Final shared service — standard WO card used on Landing
kanban, Manager Plant Board, and Workflow Funnel. Embeds WorkflowChip,
shows progress bar, priority dot, blocker badge from step.blocker_kind.

Density prop ('compact' vs 'normal') swaps padding for funnel use.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:48:13 -04:00
gsinghpal
8109b3ec76 feat(fusion_plating_shopfloor): HoldComposer shared OWL service
Plan task P1.6. Modal hold-creation form: reason picker, qty split,
optional photo (camera input on mobile), description, mark-for-scrap
toggle. Calls /fp/workspace/hold (added in P1.9). Reason list kept
client-side, keep in sync with fusion.plating.quality.hold.hold_reason.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:47:29 -04:00
gsinghpal
9d78bc4317 feat(fusion_plating_shopfloor): SignaturePad shared OWL service
Plan task P1.5. Modal canvas signature capture using HTML pointer events
+ Odoo Dialog service. Returns image/png dataURI via onSubmit callback;
caller decides what to do with it (e.g. /fp/workspace/sign_off attaches
to fp.job.step).

Canvas stays light even in dark mode for signature legibility.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:46:46 -04:00
gsinghpal
5c3c979f77 feat(fusion_plating_shopfloor): GateViz shared OWL service
Plan task P1.4. "Can't start yet — Waiting on Step N: X" block reused
across JobWorkspace step rows and Manager Plant Board cards. Icon set
maps to blocker_kind (predecessor/contract_review/parts_not_received/
racking_required/manager_input). Optional Jump button propagates to
parent via onJump callback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:46:07 -04:00
gsinghpal
b52fe01d07 feat(fusion_plating_shopfloor): WorkflowChip shared OWL service + dark-mode SCSS
Plan task P1.3. Bootstraps the tests/ dir and adds the first of 5
shared OWL services. Pill renders fp.job.workflow.state with color
mapping + optional next-action hint.

Per CLAUDE.md "Dark Mode" rule: registered once in web.assets_backend;
Odoo 19 auto-compiles into both bright and dark bundles via the
\$o-webclient-color-scheme SCSS branch.

Version bumped to 19.0.27.0.0 (Phase 1 — Workspace foundation).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:45:33 -04:00
gsinghpal
091f98e1f9 changes 2026-05-18 22:33:23 -04:00
gsinghpal
145b424760 fix(seeds): noupdate=1 on remaining 3 user-editable seed files
Audit of all 86 data XML files in the fusion_plating module set
turned up 3 more files that lacked noupdate=1 protection — every
module upgrade would re-import them and silently overwrite user
customisations. Following the ENP-ALUM-BASIC recovery (a68bf2e),
locked these too:

1. fusion_tasks/data/ir_cron_data.xml — 4 ir.cron records
   (technician travel times, push notifications, late-arrival
   checks, location cleanup). Users may disable / re-schedule.

2. fusion_plating_shopfloor/data/fp_cron_data.xml — 1 ir.cron
   (Bake Window state updater). Same reasoning.

3. fusion_plating_bridge_maintenance/data/fp_maintenance_stage_data.xml
   — 3 maintenance.stage records (kanban columns: New / Active /
   Completed). Admin may rename, reorder, or add new stages.

Companion entech-side action (executed via SQL during the fix
session): 11 ir.model.data rows for these records were updated to
noupdate=true so the next module upgrade respects the new flag.

Files left explicitly noupdate=0 — verified safe:
- fusion_plating/data/fp_landing_data.xml — 1 ir.actions.server
  (system action, code-defined; re-import is harmless)
- fusion_plating_reports/data/fp_hide_default_reports.xml —
  re-asserts deletion of default Odoo report bindings; intentional
  to re-run on every upgrade

Final audit confirmed 0 user-editable noupdate=false records remain.
ir.model.inherit + report.paperformat rows still noupdate=false but
those are system metadata (Odoo manages) and Odoo's standard
paperformat pattern, both safe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:32:30 -04:00