Skip to content

[19.0][MIG] dms: Migration to 19.0#475

Open
dnplkndll wants to merge 178 commits into
OCA:19.0from
ledoent:19.0-mig-dms
Open

[19.0][MIG] dms: Migration to 19.0#475
dnplkndll wants to merge 178 commits into
OCA:19.0from
ledoent:19.0-mig-dms

Conversation

@dnplkndll
Copy link
Copy Markdown

@dnplkndll dnplkndll commented May 12, 2026

Migrates the dms module from 18.0 to 19.0 with preserved commit history per the OCA wiki (176 18.0 commits replayed onto 19.0, then [IMP] pre-commit auto fixes and [19.0][MIG] on top). All 64 tests pass locally with demo data; all 42 tests pass on OCA CI without demo. All CI checks green.

Re. @pedrobaeza's review on 2026-05-12: history is now preserved using
the wiki technical method (git format-patch --keep-subject --stdout origin/19.0..origin/18.0 -- dms | git am -3 --keep). The first 176
commits on this branch are verbatim 18.0 history (original authors,
dates, and subjects).

Scope

Scoped to only the dms module per @pedrobaeza's review feedback on #457 / #474. Follow-up PRs can migrate the other DMS modules separately.

Attribution

Builds on prior 19.0 work by:

Both prior PRs hit the same set of access-rule and test_starred test failures. This PR identifies the root cause (a 19.0 ORM behaviour change) and works around it.

Root cause: ir.rule + computed-field search methods in 19.0

Odoo 19.0 changed ir.rule._compute_domain() to use Domain.optimize(model) (basic level), where in 18.0 the search methods on computed fields ran during the same evaluation. At basic optimisation level, search= methods on non-stored computed fields are bypassed. The result: rules like

<field name="domain_force">[('permission_read', '=', user.id)]</field>

silently no-op, and every user sees every record. Confirmed by attaching a RuntimeError probe to _get_permission_domain — it was never raised during any test run.

Fix

Override _search() on dms.security.mixin to AND the existing access-group + inheritance domain directly into the search domain. SQL translation uses optimize_full, which DOES invoke search methods, so this restores the intended filter:

@api.model
def _search(self, domain, *args, **kwargs):
    if not self.env.su and not self.env.context.get("dms_skip_access_filter"):
        self = self.with_context(dms_skip_access_filter=True)
        dms_domain = Domain.OR([
            self._get_domain_by_access_groups("read"),
            self._get_domain_by_inheritance("read"),
        ])
        domain = Domain.AND([Domain(domain), dms_domain])
    return super()._search(domain, *args, **kwargs)

Plus _search_starred updated to handle both = and in operators (19.0's basic optimizer normalises ('starred', '=', True) to ('starred', 'in', {True})).

All 19.0 migration changes ([19.0][MIG] commit)

Per OCA's 19.0 migration wiki:

  • res.groups.category_idprivilege_id + new res.groups.privilege record (adopted from [19.0][MIG] Migrate DMS modules to 19.0 #474)
  • 2-tier group structure: dropped group_dms_viewer; group_dms_user implies base.group_user directly
  • res.users.groups_idgroup_ids in demo XMLs + test fixtures
  • auto_join=*bypass_search_access=* (10 fields across access_groups/directory/dms_file/storage)
  • _sql_constraintsmodels.Constraint (dms_category, access_groups, tag)
  • res.groups.usersuser_ids in compute dependencies
  • odoo.osv.expressionodoo.fields.Domain (all imports + call sites)
  • read_group_read_group with new aggregate-tuple return format (dms_security_mixin._get_domain_by_inheritance)
  • @route(type="json")@route(type="jsonrpc") in controllers
  • Translation modernisation per pylint_odoo 19.0 (W8161 prefer-env-translation, W8301 translation-not-lazy)
  • _search override + _search_starred operator handling — see Fix section above
  • View / JS cleanups adopted from [19.0][MIG] Migrate DMS modules to 19.0 #474 (OWL XPath fixes, store["ir.attachment"], removed deprecated <group expand="0"> and target="inline")
  • Demo-data test guards — tests requiring env.ref("dms.file_*_demo") / env.ref("base.partner_demo_portal") now skip via the new require_demo_xmlid helper that raises unittest.SkipTest (safe in both instance methods and setUpClass, since 19.0 default changed to with_demo=False on CI)
  • index=Trueindex="btree" on dms_file.attachment_id
  • pylint: disable=no-search-all on _get_ref_selection() (intentional)

Tests

Local lab — with demo (docker compose run odoo-19 -d dms_demo -i dms --with-demo --test-enable):

Module dms: loading demo
Module dms loaded in 1.79s, 3331 queries
0 failed, 0 error(s) of 64 tests

Local lab — without demo (simulates CI):

Module dms loaded in 0.94s, 2728 queries
0 failed, 0 error(s) of 42 tests

Pre-commit fully clean (ruff, prettier, pylint_odoo, README/requirements/manifest hooks). No DeprecationWarnings.

CI

✅ pre-commit · ✅ Detect unreleased dependencies · ✅ test with Odoo · ✅ test with OCB · ✅ runboat/build · ✅ codecov

Commits (OCA structure, history preserved per wiki)

[19.0][MIG] dms: Migration to 19.0
[IMP] dms: pre-commit auto fixes
... 176 commits replayed verbatim from origin/18.0 (original authors, dates,
    and subject lines retained) ...

This supersedes (in spirit, not via Closes:) #457 and the dms-only portion of #474.

/ocabot migration dms

@pedrobaeza
Copy link
Copy Markdown
Member

Thanks for the contribution.

Please preserve commit history following technical method explained in https://github.com/OCA/maintainer-tools/wiki/Migration-to-version-19.0.

If the jump is between several versions, you have to modify the source branch in the main command to accommodate it to this circumstance.

@dnplkndll dnplkndll force-pushed the 19.0-mig-dms branch 5 times, most recently from 05b4630 to 43752f4 Compare May 12, 2026 15:29
victoralmau and others added 25 commits May 12, 2026 15:52
When deleting an attachment, an attempt should be made to delete the linked file, causing an error if it is locked.
Do not show the Delete/Archive/Unarchive option on files if it is locked and you cannot unlock it.

Fixes OCA#381
Currently translated at 100.0% (354 of 354 strings)

Translation: dms-18.0/dms-18.0-dms
Translate-URL: https://translation.odoo-community.org/projects/dms-18-0/dms-18-0-dms/it/
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: dms-18.0/dms-18.0-dms
Translate-URL: https://translation.odoo-community.org/projects/dms-18-0/dms-18-0-dms/
Currently translated at 100.0% (359 of 359 strings)

Translation: dms-18.0/dms-18.0-dms
Translate-URL: https://translation.odoo-community.org/projects/dms-18-0/dms-18-0-dms/it/
Currently translated at 100.0% (359 of 359 strings)

Translation: dms-18.0/dms-18.0-dms
Translate-URL: https://translation.odoo-community.org/projects/dms-18-0/dms-18-0-dms/it/
… is applied correctly.

Before these changes, the domain was never applied to search by the parent, so all subfolders were being displayed instead of only the direct children of the selected one.

After making the changes, only a single level of folders is shown, without displaying all descendant folders.
Currently translated at 89.6% (322 of 359 strings)

Translation: dms-18.0/dms-18.0-dms
Translate-URL: https://translation.odoo-community.org/projects/dms-18-0/dms-18-0-dms/es/
The _check_access_dms_record method uses self.search(domain) to verify
write permissions. However, search() applies active_test=True by default,
which excludes archived records (active=False).

This means when a user tries to unarchive a file via toggle_active(),
the write permission check cannot find the archived record in the search
results, causing an AccessError even when the user has full write
permissions through DMS access groups.

Fix: add active_test=False context to include archived records in the
permission check search.
@dnplkndll
Copy link
Copy Markdown
Author

Thanks for the review @pedrobaeza — sorry I missed the technical method on the first round. I've now:

  1. Rebuilt the branch using the wiki's procedure exactly:

    git checkout -b 19.0-mig-dms origin/19.0
    git format-patch --keep-subject --stdout origin/19.0..origin/18.0 -- dms | git am -3 --keep
    pre-commit run -a
    git add -A && git commit -m "[IMP] dms: pre-commit auto fixes" --no-verify
    

    176 commits from origin/18.0 are now preserved verbatim on the branch (you can see them in git log --oneline origin/19.0..HEAD | tail -20 — original authors / dates / subject lines retained).

  2. Layered the [IMP] dms: pre-commit auto fixes and [19.0][MIG] dms: Migration to 19.0 commits on top.

  3. Force-pushed to ledoent:19.0-mig-dms (PR description updated). Tests still 0 failed / 0 errors of 64 (with demo) / 42 (without demo).

CI is re-running now.

- Bump manifest version to 19.0.1.0.0.
- Adopt 19.0 group privilege model: replace res.groups.category_id with
  privilege_id and the new res.groups.privilege record.
- Simplify to a 2-tier security structure (user / manager); group_dms_user
  now implies base.group_user directly. Removed group_dms_viewer.
- res.users.groups_id → group_ids (demo XML + tests).
- res.groups.users → user_ids in access_groups._compute_users dependency.
- auto_join=True/False → bypass_search_access=True/False on 10 fields
  across access_groups, directory, dms_file, storage.
- _sql_constraints → models.Constraint in dms_category, access_groups, tag.
- odoo.osv.expression → odoo.fields.Domain (all imports + AND/OR/Domain.TRUE
  /FALSE/NEGATIVE_OPERATORS aliases at module top).
- read_group → _read_group with the new aggregate-tuple return format in
  dms_security_mixin._get_domain_by_inheritance.
- @http.route(type='json') → type='jsonrpc' on the onboarding controller.
- Translation modernisation per pylint_odoo 19.0 (W8161 prefer-env-translation
  + W8301 translation-not-lazy): replace 'from odoo import _' with
  self.env._() and lazy positional/keyword formatting throughout controllers
  and models.
- DMS access filter restoration: override _search() on dms.security.mixin
  to AND the access-group + inheritance domain into all non-su searches.

  19.0 changed ir.rule._compute_domain() to use Domain.optimize (basic
  level) instead of optimize_full, which means 'search=' methods on
  computed-Boolean fields like permission_read are silently bypassed when
  rule domain_force is evaluated. Without this override the
  [('permission_read', '=', user.id)] global rules no-op and every user
  sees every record.
- _search_starred now handles both '=' and 'in' operators (19.0's basic
  optimizer normalises ('starred','=',True) to ('starred','in',{True}),
  which the old single-operator branch did not recognise).
- Demo-data test guards: tests referencing dms.file_*_demo /
  base.partner_demo_portal now skipTest() when the xmlid isn't found,
  since 19.0 defaults to with_demo=False on CI.
- index=True → index='btree' on dms_file.attachment_id.
- _get_ref_selection(): pylint: disable=no-search-all (intentional,
  enumerates all registered models for the reference selection).
- View / JS cleanups (adopted from OCA#474 by @HaithamSaqr): removed
  deprecated <group expand='0' string='Group By'> attributes; removed
  unsupported target='inline' on ir.actions.act_window; fixed OWL XPath
  '//div' → '.' in empty KanbanView/ListView Buttons templates; replaced
  store.Attachment with store['ir.attachment'] in attachment JS models.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.