From 978cd5953e4804d4a3c217ebded8c6cad0d06295 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sun, 24 May 2026 15:00:37 -0400 Subject: [PATCH] docs(plating): update Shop-floor attribution section for Phase G Tablet PIN session redesign Phase G removed all tablet_tech_id plumbing. CLAUDE.md still documented the old session-pool + kwarg flow which would mislead future-Claude. Updated to describe the new per-tech-session attribution + kiosk re-auth flow, plus the gotcha about keeping ir.config_parameter['fp.tablet.kiosk_password'] in sync with the actual user-record password. Co-Authored-By: Claude Opus 4.7 (1M context) --- fusion_plating/CLAUDE.md | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/fusion_plating/CLAUDE.md b/fusion_plating/CLAUDE.md index 02b16a2f..44d62c08 100644 --- a/fusion_plating/CLAUDE.md +++ b/fusion_plating/CLAUDE.md @@ -166,18 +166,33 @@ These modules have **source code in this repo** but are **intentionally NOT inst | `fusion_plating_culture` | `state=uninstalled`, dir removed from entech disk | Soft people-ops feature (peer kudos / "Fundamental of the Week"); zero data entered; not a client priority. Top-level "Culture" menu confused operators. | Ask the client whether they want it before reinstalling. If yes: re-sync folder + `-i fusion_plating_culture` + seed a value set. | | `fusion_plating_sensors` | deleted entirely (not in repo anymore) | Duplicated `fusion_plating_iot`'s scope but with no working alerting logic. Its valuables (sensor_type taxonomy, dashboard, location flexibility) were ported into `fusion_iot/fusion_plating_iot/`. | N/A — gone. Any new sensor work goes in `fusion_iot/fusion_plating_iot/`. | -## Shop-floor action endpoints — credit the correct tech via `tablet_tech_id` -The tablet sits on a long-lived "shopfloor service" Odoo session shared by many techs. The actual tech-of-record is established via the PIN unlock (Phase 6); their id lives in the OWL `fp_shopfloor_tech_store` service and is sent as `tablet_tech_id` on every action RPC. +## Shop-floor action endpoints — attribution is automatic via `request.env.user` -When writing a NEW shop-floor controller endpoint that **writes** (creates a record, calls a `button_*` method, posts to chatter): -1. Add `tablet_tech_id=None` as a kwarg on the route handler. -2. At the top, call: `env = env_for_tablet_tech(request.env, tablet_tech_id)` (from `fusion_plating_shopfloor/controllers/_tablet_audit.py`). -3. Use `env` (not `request.env`) for all subsequent writes. `env.with_user(...)` is applied internally so `create_uid` / `write_uid` / chatter authorship carry the right uid. -4. Read-only endpoints (load / kanban / funnel / overview) don't need this — leave them as `request.env`. +As of `fusion_plating_shopfloor 19.0.33.1.0` (2026-05-24 Tablet PIN session redesign, Phase G cleanup), tablet writes are attributed via **real per-tech Odoo sessions**, not via a `tablet_tech_id` kwarg. -On the client side: use `fpRpc()` from `services/fp_rpc.js` (drop-in for `rpc()`) for action calls. It auto-injects `tablet_tech_id`. Read calls can keep using plain `rpc()`. +**How it works now:** +- The tablet browser holds a session as the kiosk user (xmlid `fusion_plating_shopfloor.user_fp_tablet_kiosk`, id 141 on entech) when nobody is unlocked. +- PIN unlock POSTs to `/fp/tablet/unlock_session`, which calls `request.session.authenticate(type='fp_tablet_pin', login, pin)`. The custom `_check_credentials` override on `res.users` validates the PIN hash + `all_group_ids` shop-branch membership and mints a real session AS the tech. Browser cookie swaps. +- Subsequent writes use `request.env.user` (= the tech) automatically. `create_uid` / `write_uid` / chatter authorship are correct with zero plumbing. +- Lock-back (`/fp/tablet/lock_session`) destroys the tech's session and re-auths the browser as the kiosk via the password stored in `ir.config_parameter['fp.tablet.kiosk_password']`. -If `tablet_tech_id` is missing or invalid, `env_for_tablet_tech` falls back to the session uid — old callers and pre-Phase-6.3 endpoints continue working. +**When writing a NEW shop-floor controller endpoint that writes:** +1. Use `env = request.env` directly. No `tablet_tech_id` kwarg, no `env_for_tablet_tech` helper. +2. Read-only endpoints — same thing, `request.env` is fine. + +**Gone post-Phase-G** — do NOT re-introduce: +- `tablet_tech_id` kwarg on any HTTP route +- `env_for_tablet_tech(...)` helper (the `_tablet_audit.py` file is deleted) +- `fp_shopfloor_tech_store` OWL service (the `services/tech_store.js` file is deleted) +- Legacy `/fp/tablet/unlock` route (the new one is `/fp/tablet/unlock_session`) +- `fp.shopfloor.tablet_session_mode` feature flag (`session_swap` is the only flow; flag was for the 1-week overlap window during rollout — now retired) + +**Kiosk password lives in TWO places — keep them in sync:** +The kiosk user's actual `res.users.password` AND `ir.config_parameter['fp.tablet.kiosk_password']` must match. The lock_session endpoint reads ICP to re-auth as kiosk after the tech session is destroyed. If they diverge (e.g. someone resets the password on the user form without updating ICP), lock-back fails and the endpoint returns `needs_kiosk_relogin=True` — the tablet then needs a manual login. Two valid states: +- **Both set to the same value** — kiosk password is plaintext-readable in DB but lock-back works automatically. +- **ICP key deleted entirely** — `DELETE FROM ir_config_parameter WHERE key = 'fp.tablet.kiosk_password';` — accepts manual re-login after every lock event in exchange for no plaintext in DB or backups. + +**Audit log** (`fp.tablet.session.event`): append-only model with Owner-only read ACL + Python `write`/`unlink` overrides (only the force-lock cron + retention crons bypass via context flags `fp_tablet_audit_admin_write` / `fp_tablet_audit_admin_purge`). Captures every unlock / failed_unlock / manual_lock / idle_lock / ceiling_lock / force_lock / admin_reset event with sha256(session sid), ip, user-agent, acting_uid, duration. View under Plating → Configuration → Tablet Audit Log (Owner-only menu). Per-user 7-day count smart button on `res.users` form. ## Removing menus/records — Odoo does NOT auto-delete orphans Deleting a `` (or any ``) from a data XML file does NOT remove the corresponding database row. The XML loader only updates records it sees; orphans persist in `ir.ui.menu` / `ir.model.data` until you delete them explicitly. Symptom: the menu still appears in the UI after `-u`. Fix — add a `` directive in a data file with `noupdate="0"`: