Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions server_environment/models/server_env_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ def _compute_server_env(self):
else:
record._compute_server_env_from_default(field_name, options)

def _search_server_env(self, field_name, operator, value):
# env-computed fields are not stored, so we can't search them in SQL.
# Load all records and filter them in memory instead. These config
# models hold very few records, so the full scan is acceptable.
all_records = self.search([]) # pylint: disable=no-search-all

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
all_records = self.search([]) # pylint: disable=no-search-all
all_records = self.with_context(active_test=False).search([]) # pylint: disable=no-search-all

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I don't think we need to search archived records as well. Do you have any reason?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think it would be better to include active=False support, since this is intended to be a generic search method.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Odoo standard generic search only find the active records, no?

matched = all_records.filtered_domain([(field_name, operator, value)])
return [("id", "in", matched.ids)]

def _inverse_server_env(self, field_name):
options = self._server_env_fields[field_name]
default_field = self._server_env_default_fieldname(field_name)
Expand Down Expand Up @@ -358,6 +366,16 @@ def _server_env_transform_field_to_read_from_env(self, field):
)
setattr(type(self), inverse_method_name, inverse_method)
field.inverse = inverse_method_name

search_method_name = f"_search_server_env_{field.name}"
search_method = _partialmethod(
type(self)._search_server_env,
field.name,
__name__=search_method_name,
)
setattr(type(self), search_method_name, search_method)
field.search = search_method_name

field.store = False
field.required = False
field.copy = False
Expand Down
33 changes: 33 additions & 0 deletions server_environment/tests/test_server_environment_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,36 @@ def test_load_config(self):
AssertionError, "can't write on readonly field 'password'"
):
f.password = "newpass"

def _setup_external_service(self):
from .models import ExternalService

add_to_registry(self.registry, ExternalService)
self.registry._setup_models__(self.env.cr, ["external.service"])
self.registry.init_models(
self.env.cr, ["external.service"], {"models_to_check": True}
)

def test_search_env_field(self):
"""Env-computed fields can be used in a search domain.

Regression test: since Odoo 19 the domain engine requires a
non-stored field to declare a ``search`` method, otherwise
searching on it raises ``ValueError: Cannot convert ... because
it is not stored``.
"""
self._setup_external_service()
model = self.env["external.service"]
ftp1 = model.create({"name": "ftp1", "description": "Description ftp1"})
ftp2 = model.create({"name": "ftp2", "description": "Description ftp2"})
ftp1.invalidate_recordset()
ftp2.invalidate_recordset()
with self.load_config(public=CONFIG):
# host is an env-computed (non-stored) field
self.assertEqual(ftp1.host, "sftp.example.com")
self.assertEqual(ftp2.host, "sftp2.example.com")

self.assertEqual(model.search([("host", "=", "sftp.example.com")]), ftp1)
self.assertEqual(model.search([("host", "!=", "sftp.example.com")]), ftp2)
self.assertEqual(model.search([("host", "like", "sftp")]), ftp1 + ftp2)
self.assertFalse(model.search([("host", "=", "nope.example.com")]))
Loading