From 6f6aa6e90ae2dbf33924a824bf15925e59e13c83 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 26 May 2026 21:27:13 -0400 Subject: [PATCH] feat(fusion_login_audit): settings model + page section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four x_fc_* fields on res.config.settings backed by ir.config_parameter: retention_days (default 365, 0 = forever), alert_threshold (5), alert_window_min (15), alert_enabled (True). New "Login Audit" block on the General Settings page (gated by base.group_system on the block, NOT on the inherited view record per CLAUDE.md rule #11). CLAUDE.md gotchas added during this task: #5 Boolean config_parameter fields don't round-trip "False" as a string — IrConfigParameter.set_param deletes the row on falsy. Test with assertFalse, never assertEqual(..., "False"). #6 ir.ui.view uses group_ids (Odoo 19 rename mirrored from res.users). Setting groups_id on an ir.ui.view record raises ValueError at install. (The XML attribute groups="..." on inner nodes is unrelated and still works.) Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 1 + fusion_login_audit/__manifest__.py | 3 +- fusion_login_audit/models/__init__.py | 1 + .../models/res_config_settings.py | 31 ++++++++++++++++ fusion_login_audit/tests/test_login_audit.py | 18 ++++++++++ .../views/res_config_settings_views.xml | 36 +++++++++++++++++++ 6 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 fusion_login_audit/models/res_config_settings.py create mode 100644 fusion_login_audit/views/res_config_settings_views.xml diff --git a/CLAUDE.md b/CLAUDE.md index 6f5c331a..3ef13c0c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,6 +12,7 @@ 3. **Backend OWL**: Use standalone `rpc()` from `@web/core/network/rpc`. NOT `useService("rpc")`. `static props = []` not `{}`. 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. **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 ``, `