Commit Graph

106 Commits

Author SHA1 Message Date
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
gsinghpal
d891002c84 feat(promote-customer-spec): Phase E — final removal of coating + treatment
DELETED entirely (model + view + ACL + data file + menu):
- fp.coating.config (configurator)
- fp.treatment (configurator + seeded data)
- fp.coating.thickness (configurator) — replaced by fp.recipe.thickness in Phase A
- fp.customer.price.list (configurator) — coating-keyed, no replacement

Field deletions:
- sale.order.x_fc_coating_config_id
- sale.order.line.x_fc_coating_config_id + x_fc_treatment_ids
- account.move.line.x_fc_coating_config_id
- fp.part.catalog.x_fc_default_coating_config_id + x_fc_default_treatment_ids
- fp.job.coating_config_id
- fp.pricing.rule.coating_config_id
- fp.quality.point.coating_config_ids
- fp.direct.order.line.coating_config_id + treatment_ids
- fp.sale.description.template.coating_config_id

Refactored:
- fp.quote.configurator.coating_config_id → recipe_id (now points at
  fusion.plating.process.node, the actual recipe). All compute, onchange,
  and matcher logic updated to use recipe directly. Quality inherit
  extends matcher with spec-tier scoring.
- fp.job._fp_create_certificates now reads spec from job.customer_spec_id
  and formats spec_reference as "code Rev rev". Same for thickness
  source — bake fields read from recipe_root (Phase A).
- fp.job.step.button_finish bake-window auto-spawn reads bake settings
  from recipe_root instead of coating.
- fp.certificate auto-fill spec_min_mils/max_mils from recipe (Phase A
  thickness fields) instead of coating.
- jobs/sale_order.py: job creation reads x_fc_customer_spec_id from
  line, drops coating refs and the legacy header-coating fallback.
- Wizards drop coating + treatment fields and refs.
- Configurator views drop x_fc_coating_config_id + x_fc_treatment_ids
  fields entirely. Quality inherits re-anchor on stable fields
  (x_fc_part_catalog_id, x_fc_internal_description, default_process_id,
  process_variant_id, substrate_material) so they keep working.
- Reports drop coating fallback elifs; print recipe / spec.
- Tablet payload drops coating_config_id from job.read fields.

Skipped (deferred to backlog):
- fusion_plating_bridge_mrp — module is uninstalled per Sub 11; source
  files retain coating refs but no runtime impact.
- fusion_plating_portal — circular dep (portal → quality → certs →
  portal). Customer-facing portal coating picker stays for now;
  promote-spec polish is a separate sub-project.

Verification: grep for "coating_config_id|fp.coating.config|
fp.treatment|fp.coating.thickness" in live (non-bridge_mrp,
non-portal, non-script, non-test) Python/XML/CSV returns 3 hits,
all in module / class docstrings explaining Phase E history.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 02:00:41 -04:00
gsinghpal
e0eacc2530 feat(promote-customer-spec): Phase D — reports + tablet payload include spec
Reports updated to print Specification (with revision via display_name):
- report_fp_sale.xml — header sections show "SPECIFICATION" instead
  of "COATING CONFIG", reads doc.x_fc_customer_spec_id (added on
  sale.order via quality inherit, computed from line.customer_spec_id)
- report_fp_wo_sticker.xml — propagates _spec alongside _coating
- fusion_plating_reports/report_fp_job_traveller.xml — header row
  now shows Specification (falls back to coating)
- fusion_plating_jobs/report_fp_job_traveller.xml — same fall-back
- fusion_plating_jobs/report_fp_job_sticker.xml — _spec added

sale.order.x_fc_customer_spec_id added as a stored compute on
sale.order (in quality) so reports can render order-level spec.
Mirrors the line's first spec; updates on line edit.

Tablet payload (shopfloor_controller.py):
- spec_label added to the job payload dict
- defensive 'customer_spec_id' in job._fields check (shopfloor doesn't
  depend on quality — circular if added)

Portal: deferred (same circular-dep issue, more substantial UI rewrite
needed; Phase E backlog item).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 01:30:05 -04:00
gsinghpal
01a46e33e2 fix(process-tree): breadcrumb pile-up + dead "No MO selected" banner
Two issues on the Process Tree client action:

1. Back to Work Order kept growing breadcrumbs (WO -> Tree -> WO ->
   Tree -> ...) because onBack used action.doAction() which PUSHES
   a new act_window onto the stack instead of popping. Fixed by
   trying action.restore() first (pops the Tree off the stack and
   returns to the parent WO/Step controller). Falls through to
   explicit doAction only when there's no parent in the stack
   (direct URL access).

2. The empty-state banner referenced productionId, a dead variable
   from the bridge_mrp era when the tree was tied to mrp.production.
   Since the component now uses jobId (fp.job context key), the
   "No manufacturing order selected" message ALWAYS fired regardless
   of whether a job was loaded. Fixed by using jobId and updating
   the message to "No work order selected".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 09:05:27 -04:00
gsinghpal
dcbe8305d0 ui(process-tree): back to Work Order + pulsing green for done steps
Two improvements to the Process Tree visualization opened from the
Work Order's Process Tree header button:

  1. Back button returns to the Work Order (job form) instead of
     Plant Overview. fp.job.action_open_process_tree now passes
     back_job_id in the client-action context; process_tree.js
     reads it via a new backJobId getter, updates the button label
     to "Back to Work Order", and routes onBack to fp.job form.
     The Plant Overview fallback stays for callers that don't pass
     either back_step_id or back_job_id.

  2. Completed operation/step cards now have a green fill (#1e8449)
     and a subtle pulsing glow (box-shadow animation, 2.6s alternate)
     so finished work pops against still-pending dark cards. Hover
     pauses the animation so the click target is steady. Reuses the
     same green the workflow-state slice already used.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:13:46 -04:00
gsinghpal
9794a98de9 feat(jobs): Sub 13 sequential step enforcement + Sub 12e v3 wizard
Two coherent feature drops shipping together because their fp_job_step
edits overlap. Both target operator workflow correctness.

## Sub 13 — Sequential step enforcement (recipe + per-step)

Background:
  Investigation on WH/JOB/00339 showed operators starting Incoming
  Inspection while Contract Review was still in_progress. Audit:
  98.7% of recipe operations system-wide had requires_predecessor_done
  = false (the legacy per-step opt-in defaults off, recipe authors
  rarely tick the box).

Architecture:
  Recipe-level toggle + per-step opt-out (Option A from /investigate).
  * fusion.plating.process.node.enforce_sequential — Boolean on the
    recipe root. Default True. When True, every operation under this
    recipe waits for earlier-sequence steps to finish before it can
    start.
  * fusion.plating.process.node.parallel_start — Boolean on operation
    nodes. When True, this step bypasses the sequential gate (e.g.
    paperwork or QA review that runs alongside production).
  * Mirrored on fp.step.template (parallel_start) so library steps
    carry the flag into snapshots.
  * fp.job.enforce_sequential — related from recipe_id. Snapshotted
    at job creation so a recipe author flipping the recipe's flag
    AFTER job generation does NOT change behaviour mid-run.
  * fp.job.step.parallel_start — related from recipe_node_id.
  * Decision matrix (encapsulated in
    fp.job.step._fp_should_block_predecessors):
        recipe.enforce_sequential | step.parallel_start | step.req_pred_done | block?
        --------------------------|---------------------|--------------------|------
                 True             |       False         |        any         |  YES
                 True             |       True          |        any         |   no
                 False            |        any          |       True         |  YES
                 False            |        any          |       False        |   no
  * Manager bypass via context fp_skip_predecessor_check=True (existing).

Runtime gates:
  * fp.job.step.button_start — calls _fp_should_block_predecessors;
    raises UserError naming the blocking earlier step(s).
  * fp.job.step.can_start — computed Boolean for view-side disable.
  * Move wizard predecessor check
    (fusion_plating_shopfloor/controllers/move_controller.py) — uses
    the same helper so tablet + backend behave identically.

UI surface:
  * Recipe form (fp_process_node_views.xml) — enforce_sequential
    toggle on recipe root, parallel_start checkbox on operations.
  * Step template form — parallel_start checkbox.
  * Simple Recipe Editor (inline library form) — Parallel Start
    checkbox + legacy flag demoted with muted styling + supervisor
    group gate.
  * Recipe Tree Editor (properties panel) — both flags exposed,
    only-show on the right node_type.
  * Controllers updated to allowlist + payload the new fields.

Migration:
  fusion_plating/migrations/19.0.18.12.0/post-migrate.py — sets
  enforce_sequential = TRUE on every existing recipe-root node.
  Idempotent. User confirmed dev-stage data, so retroactive flip
  is safe (no production jobs to disrupt).

Tests:
  TestSequentialEnforcement (10 tests) covering:
    * sequential mode blocks out-of-order start
    * first step always startable
    * predecessor finish/skip unlocks next
    * parallel_start opts out of gate
    * free-flow mode bypasses gate
    * legacy requires_predecessor_done still honoured in free-flow
    * manager bypass via context
    * can_start compute reflects state correctly
    * library template parallel_start snapshots into recipe-node

## Sub 12e — Record Inputs Wizard v3 (card layout, dark-mode aware)

Background:
  v2 wizard was a 17-column wide editable table. Operators got lost
  finding which value column applied to their row's type, horizontal
  scroll required on tablets, composite types crammed into one row.

New layout:
  * Each measurement renders as a stacked card (CSS Grid + display
    transformation on the existing list widget — preserves inline
    editing, no JS rewrite).
  * Card header: prompt name (large, bold) + type/unit pills.
  * Card body: ONLY the value widget for this row's type
    (number / boolean / date / text / photo / multi-point / panel).
  * Composite types (multi-point thickness 5x reading + avg, bath
    panel 4 fields) get inline sub-grid inside the card.
  * Empty state ("no measurement prompts") with friendly CTA.

Dark mode:
  * SCSS branches at compile time on $o-webclient-color-scheme
    (per fusion-plating/CLAUDE.md note).
  * Tokens: 7 surface colours + 4 ink levels with light/dark hex
    pairs, all behind var(--fp-*) custom properties for per-deploy
    override.
  * Registered in BOTH web.assets_backend AND web.assets_web_dark
    so each bundle compiles its own palette.

Tablet polish:
  @media (max-width: 900px) — collapse meta below prompt + bump
  numeric input min-height to 56px.

Defensive:
  * v2 view kept in the XML file (instant rollback by changing one
    view_id ref).
  * `:has(.o_invisible_modifier)` rule drops empty cells out of the
    grid so Odoo's invisible="..." doesn't punch holes in layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 21:24:12 -04:00
gsinghpal
13e300d90e changes 2026-04-28 19:39:37 -04:00
gsinghpal
3641b78a66 feat(phase2): Configuration grouped into 7 themed folders
Collapses the flat ~36-entry Configuration list into 7 navigable
folders + Settings (sibling, stays at top of Configuration). Existing
menu IDs unchanged so bookmarks + cross-module data refs still work
— only parent-id moves.

New folder menus (defined in fusion_plating core):
  menu_fp_config_shop_setup       Shop Setup
  menu_fp_config_recipes_steps    Recipes & Steps
  menu_fp_config_materials_tanks  Materials & Tanks
  menu_fp_config_workforce        Workforce
  menu_fp_config_quality_docs     Quality & Documents
  menu_fp_config_pricing_billing  Pricing & Billing
  menu_fp_config_reference_data   Reference Data

Routing per item (sources updated in their owning module):
  Shop Setup       Facilities, Work Centers, Work Centres, Process
                   Categories, Process Types, Bake Ovens, Shopfloor
                   Stations, Vehicles
  Recipes & Steps  Step Library, QC Checklist Templates, Quality Points
  Materials & Tanks  Bath Parameters, Replenishment Rules, Chemicals,
                     Rack Tags, Calibration Equipment, Calibration Events
  Workforce        Operator Certifications, Shop Roles, Training Types,
                   Quality Teams
  Quality & Documents  Customer Specs, Approved Vendor List, Quality
                       Tags, Quality Reasons, Quality Stages, N299
                       Levels, Notification Templates, Notification Log
  Pricing & Billing  Invoice Strategy Defaults, Account Holds
  Reference Data   Value Sets, Value Rotations
  (Settings remains as a sibling at top of Configuration, manager-gated)

Versions bumped: fusion_plating, fusion_plating_quality, _safety,
_shopfloor, _logistics, _culture, _invoicing, _notifications, _nuclear.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:45:21 -04:00
gsinghpal
7d3b8f132a fix(sub12c+): close 3 known gaps — rack travel ticket, cert statement, CoC actuals
Gap 1 — Rack Travel Ticket PDF (Sub 12b's Save+Print 404):
  + report_fp_rack_travel.xml in fusion_plating_reports — A5 landscape
    single page, big rack name, Code 128 of FP-RACK:<name>, tag chips,
    contained part-batches table.
  + ir.actions.report bound to fusion.plating.rack so it appears in
    the rack form's Print menu too.
  + Sub 12b's rack_parts_dialog.js Save+Print URL fixed to use the
    standard /report/pdf/<xmlid>/<id> route.

Gap 2 — Per-customer cert statement:
  + res.company.x_fc_default_cert_statement (company-level fallback).
  + res.partner.x_fc_cert_statement (per-customer override).
  + Surfaced on the partner form under the existing Cert + Document
    Routing block.
  + Chronological CoC body resolves: customer override → company
    default → hardcoded AS9100/ISO 9001 boilerplate. Three-tier
    fallback so existing certs without overrides keep working.

Gap 3 — Chronological CoC 'Actual' column:
  + Build a captured_values_by_input dict from the move's
    transition_input_value_ids (Sub 12b captures these on every
    Move Parts commit).
  + Render typed Actual: text → as-is, number → with target unit,
    boolean → PASS/FAIL, date → formatted, attachment → '[Attachment]'
    placeholder.
  + Falls back to prompts from the destination step's step_input list
    when no values were captured (still useful as audit-of-what-was-
    asked even if blank).

Version bumps:
  fusion_plating → 19.0.10.3.0
  fusion_plating_reports → 19.0.10.1.0
  fusion_plating_certificates → 19.0.5.3.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:55:48 -04:00
gsinghpal
11dbbf578e feat(sub12b): plant overview Racks pane (Task 16)
Controller: extend /fp/shopfloor/plant_overview return payload to
include 'racks' array (filtered to loaded/in_use/awaiting_unrack
states). Each entry has tag chips, part count, current node
breadcrumb, current step + tank code, and a precomputed
next_step_id (next sequence in the job's recipe — operator
overrides at runtime in the Move Rack dialog).

JS: state.racks populated from payload. New openMoveRackDialog()
method spawns FpMoveRackDialog. Notification when rack has no
successor (last step of job).

XML: top section above the existing work-centre columns. Renders
rack rows with tags, part count, breadcrumb, and primary MOVE RACK
button per row. Visible only when state.racks.length > 0.

SCSS: minimal styling for the racks pane (extends move_dialogs.scss
to keep all Sub 12b styles in one file).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:19:05 -04:00
gsinghpal
902f3e8398 feat(sub12b): wire Move Parts + Stop Timer dialogs into tablet (Task 15)
ShopfloorTablet component:
- Imports the 3 new OWL dialogs.
- useService('dialog') for spawning.
- Listens for 'fp-resolve-rack' window CustomEvent fired from inside
  FpMovePartsDialog → spawns FpRackPartsDialog inline.
- New methods: openMovePartsDialog(from, to) + openStopTimerDialog(id).
  Refresh tablet after commit/reconcile so the UI reflects new state.

Listener cleanup on unmount.

Note: the actual buttons that call these methods are added to the
existing tablet XML in a follow-up step — for now they are wired but
not surfaced. Operators get them after Task 16 + smoke test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:16:15 -04:00
gsinghpal
11bc0ca742 feat(sub12b): shared SCSS for Move/Rack/Timer dialogs (Task 14)
3-column grid layout for field rows (label / input / hint).
Compliance prompts + Blockers blocks have their own backgrounds.
Soft blockers amber + left border, hard blockers red + left border —
matches the spec's protocol.

Token pattern + dark-mode @if branch (CLAUDE.md rule: Odoo 19 doesn't
flip dark mode via runtime DOM class; we branch at SCSS compile time
on $o-webclient-color-scheme).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:15:12 -04:00