From a60506a6453011201fb3f86ed67e77c100d2092f Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sat, 23 May 2026 20:59:44 -0400 Subject: [PATCH] =?UTF-8?q?feat(shopfloor):=20Phase=205=20=E2=80=94=20flip?= =?UTF-8?q?=20default=20to=20v2=20plant=20view=20+=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- fusion_plating/CLAUDE.md | 101 ++++++++++++++++++ .../models/res_config_settings.py | 2 +- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/fusion_plating/CLAUDE.md b/fusion_plating/CLAUDE.md index 8cce0a39..b2053271 100644 --- a/fusion_plating/CLAUDE.md +++ b/fusion_plating/CLAUDE.md @@ -420,6 +420,107 @@ Plan: [docs/superpowers/plans/2026-05-22-shopfloor-tablet-redesign-plan.md](docs - Don't add `web.assets_web_dark` entries to the manifest — Odoo 19 auto-compiles `web.assets_backend` SCSS into both bundles - Don't bypass `_fp_should_block_predecessors()` when computing step blockers — keep `blocker_kind=predecessor` logic in sync with `can_start` +## Shop Floor — Plant View kanban (2026-05-23 redesign) + +**Default Shop Floor surface** for new installs (gated by feature flag +`ir.config_parameter['fusion_plating_shopfloor.layout']`, values `legacy` +or `v2`). Legacy per-step kanban (`fp_shopfloor_landing`) remains +accessible by flipping the flag back to `legacy` in Settings → Fusion +Plating. + +**Why redesign:** the per-step kanban produced one card per recipe step +per column, so a 14-step recipe spawned 9+ cards for ONE job across the +board. With 17 active jobs the board showed 100+ duplicate cards across +narrow columns. The new design is **one card per `fp.job`** at the +**department level** — recipe step count no longer drives layout width. + +**Spec:** `docs/superpowers/specs/2026-05-23-shopfloor-plant-view-design.md` +**Plan:** `docs/superpowers/plans/2026-05-23-shopfloor-plant-view-plan.md` + +### Layout — 9 fixed columns in process sequence + +`Receiving → Masking → Blasting → Racking → Plating → Baking → +De-Racking → Final inspection → Shipping` + +Columns are first-class — they always render in this exact order, never +reorder, never collapse when empty. Driven by `fp.work.centre.area_kind` +Selection (added 2026-05-23). Each `fp.job.step.area_kind` is computed +(stored) from `work_centre.area_kind` with a fallback to a step-kind +dispatch table (`_STEP_KIND_TO_AREA` in `fusion_plating_jobs/models/fp_job_step.py`). + +**Spec D3:** all wet-line steps (Soak Clean, Electroclean, Acid Dip, +Etch, Desmut, Zincate, Rinse, E-Nickel, Chrome, Anodize, Black Oxide, +Drying) roll up into the **Plating** column. The tank chip on the card +distinguishes them. + +**Spec D4:** De-Masking folds into De-Racking (no separate column). + +**Spec D5:** Contract Review (paperwork) cards live in Receiving with a +purple "📋 QA-005" chip — they're admin gates, not physical work. + +### Card state catalog — 13 mutually-exclusive states + +`fp.job.card_state` is a stored Char computed in `_compute_card_state` +(see `fusion_plating_jobs/models/fp_job.py`). Explicit precedence +dispatch matching spec §6.2 — first match wins: + +`no_parts → on_hold → awaiting_signoff → awaiting_qc → bake_due → +predecessor_locked → idle_warning → done → contract_review → +running_mine/running → ready_mine/ready` + +Each state has a distinct background tint + left-border color + chip + +mini-timeline marker color. See `_plant_card.scss` for the mapping. The +"mine" variants (`ready_mine`, `running_mine`) light up only when the +active step's work centre is in `res.users.paired_work_centre_ids` (the +M2M holds one row in MVP, mirrors the existing single-station picker). + +### Backend — single endpoint, denormalized payload + +`/fp/landing/plant_kanban` (controller in +`fusion_plating_shopfloor/controllers/plant_kanban.py`) returns +`{ok, mode, paired_station, kpis, columns, cards}` in one JSONRPC call. +Frontend has zero per-card RPCs — every card field comes pre-formatted +from the controller's `_render_card`. State-chip text (with elapsed +times, operator names, hours-idle) is interpolated server-side. + +### Frontend — OWL component tree + +``` +FpPlantKanban (client action 'fp_plant_kanban') +└── FpTabletLock (PIN gate wrapper) + ├── PlantHeader (KPIs + filter chips + mode toggle + station picker) + └── Board (9 × Column) + ├── FpColumnHeader (with 'You're here' badge for paired column) + └── FpPlantCard[] (each with FpMiniTimeline) +``` + +Polls every 10s. Filter state persists in localStorage. All 13 card +states styled via `.state-` CSS modifier classes on a single +shared `.o_fp_plant_card` base. The mini-timeline renders 9 colored +dots driven by `fp.job.mini_timeline_json` (Python emits the array +shape — frontend just maps state → CSS class). + +### Critical implementation gotchas (project rules applied) + +- **OWL templates only expose `Math` as a JS global** (Rule 20). All + coercion (String, Number, parseInt) MUST happen in JS — `tag_chip_class()` + / `progress_style` etc. live in plant_card.js, not in the XML. +- **SCSS @import is forbidden** (Rule 8). `_plant_tokens.scss` loads + FIRST in the manifest's `web.assets_backend`; subsequent component + partials get the `$plant-*` vars via the concatenated bundle. +- **Dark mode** via `$o-webclient-color-scheme == dark` compile-time + branch in `_plant_tokens.scss` (NOT runtime class selectors). + +### How to switch back to legacy + +```sql +UPDATE ir_config_parameter SET value = 'legacy' + WHERE key = 'fusion_plating_shopfloor.layout'; +``` + +Or use Settings → Fusion Plating → Shop Floor Layout. Both surfaces +write the same `ir.config_parameter` key. + ## Deployment ### odoo-entech (LXC 111 on pve-worker5) diff --git a/fusion_plating/fusion_plating_shopfloor/models/res_config_settings.py b/fusion_plating/fusion_plating_shopfloor/models/res_config_settings.py index bc83dfa0..5ba99be3 100644 --- a/fusion_plating/fusion_plating_shopfloor/models/res_config_settings.py +++ b/fusion_plating/fusion_plating_shopfloor/models/res_config_settings.py @@ -23,7 +23,7 @@ class ResConfigSettings(models.TransientModel): ('v2', 'Plant View (one card per job, 9 columns)'), ], string='Shop Floor Layout', - default='legacy', + default='v2', config_parameter='fusion_plating_shopfloor.layout', help='Switches the Shop Floor client action between the legacy ' 'per-step kanban and the v2 plant view. Defaults to legacy '