Skip to content

fix(spp_user_roles): prevent validation error when assigning groups to a new role#177

Open
anthonymarkQA wants to merge 4 commits into19.0from
fix/user-role-assignment-issue
Open

fix(spp_user_roles): prevent validation error when assigning groups to a new role#177
anthonymarkQA wants to merge 4 commits into19.0from
fix/user-role-assignment-issue

Conversation

@anthonymarkQA
Copy link
Copy Markdown
Contributor

Clicking "Add a line" in the Groups tab triggered inline creation of a
new res.groups record. Since res.groups.name is required and left blank,
Odoo threw a validation error and blocked the save entirely.

Two changes:

  • role.xml: replace implied_ids field with an inner list using create="0"
    so "Add a line" opens a search dialog to select existing groups instead
    of creating an inline row
  • role.py: override create() to extract implied_ids from vals and write it
    directly to group_id after creation, mirroring the existing write()
    workaround in base_user_role for the same Odoo _inherits cache-clearing bug

Why is this change needed?

Users unable to create a role and assign a group in one save. previously users must create an empty role first then save, then add a group into it. which is inneficient

How was the change implemented?

How was the change implemented?

1. spp_user_roles/views/role.xml
Replaced the implied_ids field override with one that includes an explicit
inner <list create="0">. Setting create="0" on the inner list tells Odoo
to replace the "Add a line" inline row with an "Add" button that opens a
search/select dialog. This ensures only existing res.groups records can be
linked to a role — no blank inline records are ever created.

2. spp_user_roles/models/role.py
Added a create() override that mirrors the existing write() workaround
already present in base_user_role. The res.users.role model uses Odoo's
_inherits delegation to res.groups, which means fields like implied_ids
belong to the parent res.groups record. On create, passing implied_ids
through the _inherits mechanism triggers an Odoo cache-clearing bug
(documented in the upstream write() override) that causes the value to be
dropped. The fix extracts implied_ids from vals before calling
super().create(), lets the role and its associated group_id be created
first, then writes implied_ids directly to group_id — bypassing the bug.

New unit tests

Unit tests executed by the author

How to test manually

Related links

https://projects.acn.fr/projects/acn-eng/work_packages/979/activity

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a workaround for an Odoo cache-clearing bug by overriding the create method in the ResUsersRoleCustomSPP model and updates the implied_ids field display in the XML view. Feedback includes a recommendation to narrow the scope of the create override to specifically target implied_ids to prevent interference with standard mechanisms, and a correction for a likely invalid field name (full_name) in the view definition.

Comment thread spp_user_roles/views/role.xml Outdated
domain="[('role_id', '=', False)]"
>
<list create="0">
<field name="full_name" string="Group" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The field full_name does not exist in the standard Odoo res.groups model. Unless it is added by a custom module not shown in this context, this will cause a traceback when loading the view. You should likely use name or display_name instead.

Suggested change
<field name="full_name" string="Group" />
<field name="name" string="Group" />

Comment on lines +21 to +34
groups_vals_list = []
group_fields = set(self.env["res.groups"]._fields) - {"name"}
for vals in vals_list:
group_vals = {}
for field in group_fields:
if field in vals:
group_vals[field] = vals.pop(field)
groups_vals_list.append(group_vals)

new_records = super().create(vals_list)

for record, group_vals in zip(new_records, groups_vals_list):
if group_vals:
record.group_id.write(group_vals)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation of the create override is broader than necessary. By popping all fields belonging to res.groups (except name), you risk interfering with the standard Odoo _inherits mechanism for fields that don't suffer from the cache-clearing bug. It also makes the creation fragile if other modules add required fields to res.groups. It is recommended to target only the problematic fields, specifically implied_ids, as mentioned in the PR description and mirroring the write workaround in base_user_role.

Suggested change
groups_vals_list = []
group_fields = set(self.env["res.groups"]._fields) - {"name"}
for vals in vals_list:
group_vals = {}
for field in group_fields:
if field in vals:
group_vals[field] = vals.pop(field)
groups_vals_list.append(group_vals)
new_records = super().create(vals_list)
for record, group_vals in zip(new_records, groups_vals_list):
if group_vals:
record.group_id.write(group_vals)
implied_ids_list = [vals.pop("implied_ids", None) for vals in vals_list]
new_records = super().create(vals_list)
for record, implied_ids in zip(new_records, implied_ids_list):
if implied_ids:
record.group_id.write({"implied_ids": implied_ids})

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.47%. Comparing base (6e859bb) to head (980b34f).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             19.0     #177      +/-   ##
==========================================
- Coverage   71.61%   71.47%   -0.14%     
==========================================
  Files         933      932       -1     
  Lines       55357    54830     -527     
==========================================
- Hits        39643    39191     -452     
+ Misses      15714    15639      -75     
Flag Coverage Δ
spp_analytics 93.13% <ø> (ø)
spp_api_v2 80.10% <ø> (ø)
spp_api_v2_change_request 66.85% <ø> (ø)
spp_api_v2_cycles 71.12% <ø> (ø)
spp_api_v2_data 64.41% <ø> (ø)
spp_api_v2_entitlements 70.19% <ø> (ø)
spp_api_v2_gis 71.52% <ø> (ø)
spp_api_v2_products 66.27% <ø> (ø)
spp_api_v2_service_points 70.94% <ø> (ø)
spp_api_v2_simulation 71.12% <ø> (ø)
spp_api_v2_vocabulary 57.26% <ø> (ø)
spp_approval 50.29% <ø> (ø)
spp_area 80.07% <ø> (ø)
spp_area_hdx 81.43% <ø> (ø)
spp_audit 72.60% <ø> (+0.06%) ⬆️
spp_base_common 90.26% <ø> (ø)
spp_case_cel 89.01% <ø> (ø)
spp_case_demo 94.34% <ø> (ø)
spp_programs 64.51% <ø> (+0.02%) ⬆️
spp_security 66.66% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.
see 11 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

emjay0921 added 3 commits May 4, 2026 11:15
CI's ruff (B905) flagged `zip(new_records, groups_vals_list)` for
omitting the explicit `strict=` parameter. The two iterables are built
side-by-side in the same loop above the call, so they're guaranteed
equal length — make it explicit with `strict=True` to satisfy the
linter and turn an undetectable mismatch into a clear runtime error
if the invariant ever breaks.
OCA xml-view-dangerous-replace-low-priority hook flagged the
position="replace" used to add a domain and an embedded list to the
`implied_ids` field on the role form. Replace is reserved as a last
resort; the same effect can be achieved with position="attributes"
(for the new domain) plus position="inside" (to embed the list).

Functionally identical for OP#979 — the field still restricts the
group dropdown to free groups and the inline list still has create
disabled, but the inheritance is now safer for downstream views.
Copy link
Copy Markdown
Contributor

@emjay0921 emjay0921 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI fully green after the two follow-ups (zip(strict=True) for ruff B905 and attributes + inside instead of position=replace for the OCA xml-view-dangerous-replace check). Functionality identical to the original fix — group dropdown restricted to free groups, inline create disabled to prevent OP#979's empty-row-creates-blank-group trap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants