From 2a16f80d8d42ec4e91fae6657dd30fdc25d29d32 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sat, 30 May 2026 14:48:29 -0400 Subject: [PATCH] feat(fusion_clock): kiosk app + Kiosk Operator role, full-screen PWA, app-integrated permissions - PWA manifest on the NFC kiosk page so it installs as a full-screen home-screen app (Chrome "Install" / Safari "Add to Home Screen"). - Dedicated "Kiosk Operator" permission + gated "Fusion Clock Kiosk" top-level app (act_url -> /fusion_clock/kiosk/nfc). Kiosk controllers accept Manager OR Kiosk Operator; all kiosk data ops already run sudo. - Fix 403: read the company kiosk location via sudo on page-load and tap (Kiosk Operator has no fusion.clock.location ACL). - Odoo 19 permissions UX: ir.module.category + res.groups.privilege so User/Team Lead/Manager and Kiosk Operator appear as application-access dropdowns on the user form (no developer mode). Short group display names. - Docs: note res.groups.privilege as the Odoo 19 category_id replacement. Deployed live to entech (odoo-entech / LXC 111 on pve-worker5). v19.0.3.6.0. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 2 +- fusion_clock/__manifest__.py | 2 +- fusion_clock/controllers/clock_kiosk.py | 14 ++++-- fusion_clock/controllers/clock_nfc_kiosk.py | 53 +++++++++++++++++++-- fusion_clock/security/security.xml | 47 ++++++++++++++++-- fusion_clock/views/clock_menus.xml | 16 +++++++ fusion_clock/views/kiosk_nfc_templates.xml | 7 +++ 7 files changed, 127 insertions(+), 14 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 3d6588f4..bedaf02a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ 4. **HTTP routes**: `type="jsonrpc"` — NOT `type="json"` (deprecated). 5. **res.config.settings**: Only boolean/integer/float/char/selection/many2one/datetime. NO Date fields. **`config_parameter=` Boolean fields don't round-trip `False` as a string.** Odoo's `set_values()` calls `IrConfigParameter.set_param(key, value)`, and `set_param` deletes the row when `value` is falsy (False / None / empty). So writing `False` to a Boolean config field means the param no longer exists in `ir_config_parameter`; a subsequent `get_param(key)` returns the *default* (Python `False`), not `'False'`. Test like `self.assertFalse(ICP.get_param('...'))` — never `assertEqual(..., 'False')`. (Integer/Float/Char go through `repr(value)` / strip, so they DO persist as strings — `'90'`, `'0'`, etc.) Source: `odoo/addons/base/models/res_config.py::set_values` and `ir_config_parameter.py::set_param`. -6. **res.groups**: NO `users` field, NO `category_id` field. +6. **res.groups**: NO `users` field, NO `category_id` field. **The Odoo 19 replacement for `category_id` is `res.groups.privilege`.** To make a module's groups appear as application-access dropdowns on the user form (Settings → Users → *Application Accesses*) instead of only in developer mode: define an `ir.module.category`, a `res.groups.privilege` (with `category_id` → that category), and set each group's `privilege_id` → that privilege. Groups under one privilege that form an `implied_ids` chain render as a single role dropdown; a standalone group in its own privilege renders as a separate row under the same category header. Verified in `fusion_clock/security/security.xml`; mirrors `fusion_plating`/`fusion_tasks`. **res.users**: field was renamed `groups_id` → `group_ids` (also `all_group_ids` for implied). The plural form is gone; using `groups_id` raises `ValueError: Invalid field 'groups_id' in 'res.users'`. **`ir.ui.view`**: same rename — view-level visibility gating uses `group_ids`, not `groups_id`. A record like `` on an `ir.ui.view` raises `ValueError: Invalid field 'groups_id' in 'ir.ui.view'` at module install. (The XML *attribute* `groups="base.group_system"` on form elements like ``, `