Skip to content

[18.0][FIX] base_user_role: don't trigger constraint res_users_notification_type#419

Open
StefanRijnhart wants to merge 1 commit intoOCA:18.0from
StefanRijnhart:18.0-base_user_role-fix-res_users_notification_type
Open

[18.0][FIX] base_user_role: don't trigger constraint res_users_notification_type#419
StefanRijnhart wants to merge 1 commit intoOCA:18.0from
StefanRijnhart:18.0-base_user_role-fix-res_users_notification_type

Conversation

@StefanRijnhart
Copy link
Member

@StefanRijnhart StefanRijnhart commented Feb 10, 2026

How to reproduce

Having the website module installed, and a user with some roles and notification type set to inbox, delete the roles from the user and save.

Expected result

Roles are removed from the user.

Actual result

ERROR: new row for relation "res_users" violates check constraint "res_users_notification_type"

Analysis

Notification_type inbox is not allowed when the user is no longer has the share flag (which is set for users without group base.group_user). This is implemened as a database constraint. The constraint is triggered by the intermittent flush caused by website's _check_one_user_type code constraint on res.users which gets called earlier than the recompute of notification_type.

Fixes

  File "/home/odoo/src/oca-server-backend/base_user_role/tests/test_user_role.py", line 312, in test_notification_type_reset
    user.write(
  File "/home/odoo/odoo/18.0/odoo/addons/auth_totp_mail/models/res_users.py", line 11, in write
    res = super().write(vals)
          ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/addons/auth_signup/models/res_users.py", line 362, in write
    return super().write(vals)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/addons/mail/models/discuss/res_users.py", line 17, in write
    res = super().write(vals)
          ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/addons/mail/models/res_users.py", line 108, in write
    write_res = super(Users, self).write(vals)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/addons/resource/models/res_users.py", line 17, in write
    rslt = super().write(vals)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/src/oca-server-backend/base_user_role/models/user.py", line 60, in write
    res = super().write(vals)
          ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 1920, in write
    res = super(UsersView, self).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 1609, in write
    return super(UsersImplied, self).write(values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 759, in write
    res = super(Users, self).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4812, in write
    field.write(self, value)
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 4552, in write
    self.write_batch([(records, value)])
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 4573, in write_batch
    self.write_real(records_commands_list, create)
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 4769, in write_real
    flush()
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 4720, in flush
    comodel.browse(to_delete).unlink()
  File "/home/odoo/src/oca-server-backend/base_user_role/models/role.py", line 180, in unlink
    users.set_groups_from_roles(force=True)
  File "/home/odoo/src/oca-server-backend/base_user_role/models/user.py", line 121, in set_groups_from_roles
    super(ResUsers, user).write(vals)
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 1920, in write
    res = super(UsersView, self).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 1611, in write
    res = super(UsersImplied, self.with_context(no_add_implied_groups=True)).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 759, in write
    res = super(Users, self).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4834, in write
    real_recs._validate_fields(vals, inverse_fields)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 1631, in _validate_fields
    check(self)
  File "/home/odoo/odoo/18.0/odoo/addons/website/models/res_users.py", line 105, in _check_one_user_type
    internal_users = self.env.ref('base.group_user').users & self
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 3102, in __get__
    return super().__get__(records, owner)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 1274, in __get__
    recs._fetch_field(self)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4119, in _fetch_field
    self.fetch(fnames)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4157, in fetch
    fetched = self._fetch_query(query, fields_to_fetch)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4268, in _fetch_query
    field.read(fetched)
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 5063, in read
    for id1, id2 in records.env.execute_query(query.select(sql_id1, sql_id2)):
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/api.py", line 992, in execute_query
    self.flush_query(query)
  File "/home/odoo/odoo/18.0/odoo/odoo/api.py", line 984, in flush_query
    self[model_name].flush_model(field_names)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 6773, in flush_model
    self._flush(fnames)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 6851, in _flush
    model.browse(some_ids)._write_multi(vals_list)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4937, in _write_multi
    self.env.execute_query(SQL(
  File "/home/odoo/odoo/18.0/odoo/odoo/api.py", line 993, in execute_query
    self.cr.execute(query)
  File "/home/odoo/odoo/18.0/odoo/odoo/sql_db.py", line 364, in execute
    res = self._obj.execute(query, params)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
psycopg2.errors.CheckViolation: new row for relation "res_users" violates check constraint "res_users_notification_type"
DETAIL:  Failing row contains (81, 1, 151, t, 2026-02-10 15:41:40.105622, user_test_roles, null, null, 1, 84, <p data-o-mail-quote="1">--<br data-o-mail-quote="1">USER TEST (..., t, 2026-02-10 15:41:40.105622, null, f, inbox, null, null, null, null).

Also fixes tagged being applied to individual test methods, where it is not effective.

@OCA-git-bot
Copy link
Contributor

Hi @jcdrubay, @novawish, @sebalix,
some modules you are maintaining are being modified, check this out!

@StefanRijnhart StefanRijnhart force-pushed the 18.0-base_user_role-fix-res_users_notification_type branch 3 times, most recently from 3572087 to 453f5c3 Compare February 10, 2026 16:19
…_type

Deleting all roles from a user with notification type 'inbox' may trigger

```
ERROR: new row for relation "res_users" violates check constraint "res_users_notification_type"
```

because notification_type `inbox` is not allowed when the user is no longer has
the share flag (which is set for users without group base.group_user).

The issue is only triggered due to intermittent flushes, such as the one caused
by website's `_check_one_user_type` code constraint on res.users.

Fixes

```
  File "/home/odoo/src/oca-server-backend/base_user_role/tests/test_user_role.py", line 312, in test_notification_type_reset
    user.write(
  File "/home/odoo/odoo/18.0/odoo/addons/auth_totp_mail/models/res_users.py", line 11, in write
    res = super().write(vals)
          ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/addons/auth_signup/models/res_users.py", line 362, in write
    return super().write(vals)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/addons/mail/models/discuss/res_users.py", line 17, in write
    res = super().write(vals)
          ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/addons/mail/models/res_users.py", line 108, in write
    write_res = super(Users, self).write(vals)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/addons/resource/models/res_users.py", line 17, in write
    rslt = super().write(vals)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/src/oca-server-backend/base_user_role/models/user.py", line 60, in write
    res = super().write(vals)
          ^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 1920, in write
    res = super(UsersView, self).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 1609, in write
    return super(UsersImplied, self).write(values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 759, in write
    res = super(Users, self).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4812, in write
    field.write(self, value)
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 4552, in write
    self.write_batch([(records, value)])
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 4573, in write_batch
    self.write_real(records_commands_list, create)
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 4769, in write_real
    flush()
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 4720, in flush
    comodel.browse(to_delete).unlink()
  File "/home/odoo/src/oca-server-backend/base_user_role/models/role.py", line 180, in unlink
    users.set_groups_from_roles(force=True)
  File "/home/odoo/src/oca-server-backend/base_user_role/models/user.py", line 121, in set_groups_from_roles
    super(ResUsers, user).write(vals)
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 1920, in write
    res = super(UsersView, self).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 1611, in write
    res = super(UsersImplied, self.with_context(no_add_implied_groups=True)).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/addons/base/models/res_users.py", line 759, in write
    res = super(Users, self).write(values)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4834, in write
    real_recs._validate_fields(vals, inverse_fields)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 1631, in _validate_fields
    check(self)
  File "/home/odoo/odoo/18.0/odoo/addons/website/models/res_users.py", line 105, in _check_one_user_type
    internal_users = self.env.ref('base.group_user').users & self
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 3102, in __get__
    return super().__get__(records, owner)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 1274, in __get__
    recs._fetch_field(self)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4119, in _fetch_field
    self.fetch(fnames)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4157, in fetch
    fetched = self._fetch_query(query, fields_to_fetch)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4268, in _fetch_query
    field.read(fetched)
  File "/home/odoo/odoo/18.0/odoo/odoo/fields.py", line 5063, in read
    for id1, id2 in records.env.execute_query(query.select(sql_id1, sql_id2)):
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/odoo/odoo/18.0/odoo/odoo/api.py", line 992, in execute_query
    self.flush_query(query)
  File "/home/odoo/odoo/18.0/odoo/odoo/api.py", line 984, in flush_query
    self[model_name].flush_model(field_names)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 6773, in flush_model
    self._flush(fnames)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 6851, in _flush
    model.browse(some_ids)._write_multi(vals_list)
  File "/home/odoo/odoo/18.0/odoo/odoo/models.py", line 4937, in _write_multi
    self.env.execute_query(SQL(
  File "/home/odoo/odoo/18.0/odoo/odoo/api.py", line 993, in execute_query
    self.cr.execute(query)
  File "/home/odoo/odoo/18.0/odoo/odoo/sql_db.py", line 364, in execute
    res = self._obj.execute(query, params)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
psycopg2.errors.CheckViolation: new row for relation "res_users" violates check constraint "res_users_notification_type"
DETAIL:  Failing row contains (81, 1, 151, t, 2026-02-10 15:41:40.105622, user_test_roles, null, null, 1, 84, <p data-o-mail-quote="1">--<br data-o-mail-quote="1">USER TEST (..., t, 2026-02-10 15:41:40.105622, null, f, inbox, null, null, null, null).
```
@StefanRijnhart StefanRijnhart force-pushed the 18.0-base_user_role-fix-res_users_notification_type branch from 453f5c3 to 5189eeb Compare February 10, 2026 16:20
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