From 3a2cf42dd9ea6f24e8e921a5cea5699ac97d35d6 Mon Sep 17 00:00:00 2001 From: Tom Blauwendraat Date: Sat, 29 Jul 2023 02:35:35 +0200 Subject: [PATCH 1/9] [ADD] new module: base_order_by_related --- base_order_by_related/README.rst | 0 base_order_by_related/__init__.py | 1 + base_order_by_related/__manifest__.py | 18 ++++ base_order_by_related/models/__init__.py | 1 + base_order_by_related/models/models.py | 89 ++++++++++++++++++ base_order_by_related/readme/CONTRIBUTORS.rst | 1 + base_order_by_related/readme/DESCRIPTION.rst | 1 + base_order_by_related/readme/USAGE.rst | 9 ++ base_order_by_related/tests/__init__.py | 1 + base_order_by_related/tests/fake_models.py | 20 ++++ .../tests/test_order_by_related.py | 91 +++++++++++++++++++ 11 files changed, 232 insertions(+) create mode 100644 base_order_by_related/README.rst create mode 100644 base_order_by_related/__init__.py create mode 100644 base_order_by_related/__manifest__.py create mode 100644 base_order_by_related/models/__init__.py create mode 100644 base_order_by_related/models/models.py create mode 100644 base_order_by_related/readme/CONTRIBUTORS.rst create mode 100644 base_order_by_related/readme/DESCRIPTION.rst create mode 100644 base_order_by_related/readme/USAGE.rst create mode 100644 base_order_by_related/tests/__init__.py create mode 100644 base_order_by_related/tests/fake_models.py create mode 100644 base_order_by_related/tests/test_order_by_related.py diff --git a/base_order_by_related/README.rst b/base_order_by_related/README.rst new file mode 100644 index 00000000000..e69de29bb2d diff --git a/base_order_by_related/__init__.py b/base_order_by_related/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/base_order_by_related/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/base_order_by_related/__manifest__.py b/base_order_by_related/__manifest__.py new file mode 100644 index 00000000000..5ce491964fb --- /dev/null +++ b/base_order_by_related/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright (C) 2023 Therp (). +# @author Tom Blauwendraat +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Base order by related", + "summary": "Order by non-stored related fields", + "version": "14.0.1.0.0", + "category": "Tools", + "website": "https://github.com/OCA/server-tools", + "author": "Therp BV, Odoo Community Association (OCA)", + "maintainers": ["thomaspaulb"], + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["base"], + "data": [], +} diff --git a/base_order_by_related/models/__init__.py b/base_order_by_related/models/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/base_order_by_related/models/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/base_order_by_related/models/models.py b/base_order_by_related/models/models.py new file mode 100644 index 00000000000..88ff99afe00 --- /dev/null +++ b/base_order_by_related/models/models.py @@ -0,0 +1,89 @@ +# Copyright (C) 2023 Therp (). +# @author Tom Blauwendraat +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging + +from odoo import api, models + +_logger = logging.getLogger(__name__) + + +class BaseModel(models.AbstractModel): + _inherit = "base" + + _order_by_related = [] + + @api.model + def _related_join_calc(self, alias, fname, query): + model, field = self, self._fields[fname] + while field.related: + # retrieve the parent model where field is inherited from + if field.related_field.model_name not in self.env: + continue + related_model = self.env[field.related_field.model_name] + related_fname = field.related[0] + related_fname2 = field.related[1] + + # JOIN related_model._table AS related_alias ON + # alias.related_fname = related_alias.id + related_alias = query.left_join( + alias, + related_fname, + related_model._table, + "id", + related_fname2, + ) + model, alias, field = related_model, related_alias, field.related_field + # handle the case where the field is translated + if field.translate is True: + return model._generate_translated_field(alias, related_fname2, query) + else: + return '"%s"."%s"' % (alias, related_fname2) + + @api.model + def _generate_order_by_inner( + self, alias, order_spec, query, reverse_direction=False, seen=None + ): + order_parts = order_spec.split(",") + order_fields = [p.strip().split(" ")[0].strip() for p in order_parts] + if not any(f in self._order_by_related for f in order_fields): + return super()._generate_order_by_inner( + alias, order_spec, query, reverse_direction=reverse_direction, seen=seen + ) + + if seen is None: + seen = set() + self._check_qorder(order_spec) + + order_by_elements = [] + for order_part in order_parts: + order_split = order_part.strip().split(" ") + order_field = order_split[0].strip() + if order_field not in self._order_by_related: + order_by_elements += super()._generate_order_by_inner( + alias, + order_part, + query, + reverse_direction=reverse_direction, + seen=seen, + ) + continue + + self._fields.get(order_field) + order_direction = ( + order_split[1].strip().upper() if len(order_split) == 2 else "" + ) + if reverse_direction: + order_direction = "ASC" if order_direction == "DESC" else "DESC" + qualified_name = self._related_join_calc(alias, order_field, query) + order_by_elements.append("%s %s" % (qualified_name, order_direction)) + return order_by_elements + + @api.model + def fields_get(self, allfields=None, attributes=None): + ret = super().fields_get(allfields=allfields, attributes=attributes) + for k in self._order_by_related: + if k in ret: + ret[k]["sortable"] = True + return ret diff --git a/base_order_by_related/readme/CONTRIBUTORS.rst b/base_order_by_related/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..36efafcf46a --- /dev/null +++ b/base_order_by_related/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Tom Blauwendraat diff --git a/base_order_by_related/readme/DESCRIPTION.rst b/base_order_by_related/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..37d24ef81e9 --- /dev/null +++ b/base_order_by_related/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module allows a search to order by a non-stored related field. diff --git a/base_order_by_related/readme/USAGE.rst b/base_order_by_related/readme/USAGE.rst new file mode 100644 index 00000000000..4e571b68427 --- /dev/null +++ b/base_order_by_related/readme/USAGE.rst @@ -0,0 +1,9 @@ +In any model where you have a non-stored related field, you can make it sortable:: + + class ResPartner(models.Model): + _inherit = "res.partner" + + country_name = fields.Char(related="country_id.name") + + # make some non-stored related fields sortable + _order_by_related = ["country_name"] diff --git a/base_order_by_related/tests/__init__.py b/base_order_by_related/tests/__init__.py new file mode 100644 index 00000000000..a4cb97ccf93 --- /dev/null +++ b/base_order_by_related/tests/__init__.py @@ -0,0 +1 @@ +from . import test_order_by_related diff --git a/base_order_by_related/tests/fake_models.py b/base_order_by_related/tests/fake_models.py new file mode 100644 index 00000000000..0d5232cfcb0 --- /dev/null +++ b/base_order_by_related/tests/fake_models.py @@ -0,0 +1,20 @@ +# Copyright (C) 2023 Therp (). +# @author Tom Blauwendraat +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class FakeCustomer(models.Model): + _name = "fake.customer" + _description = "fake model for customers" + + _order_by_related = ["country_name", "country_code"] + + name = fields.Char(required=True) + sortkey1 = fields.Integer() + sortkey2 = fields.Integer() + sortkey3 = fields.Integer() + country_id = fields.Many2one("res.country") + country_name = fields.Char(related="country_id.name") + country_code = fields.Char(related="country_id.code") diff --git a/base_order_by_related/tests/test_order_by_related.py b/base_order_by_related/tests/test_order_by_related.py new file mode 100644 index 00000000000..95f10902d77 --- /dev/null +++ b/base_order_by_related/tests/test_order_by_related.py @@ -0,0 +1,91 @@ +# Copyright (C) 2023 Therp (). +# @author Tom Blauwendraat +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from math import floor + +from odoo_test_helper import FakeModelLoader + +from odoo.tests.common import SavepointCase + + +class TestOrderByRelated(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + from .fake_models import FakeCustomer + + cls.loader.update_registry((FakeCustomer,)) + + # Create test data + cls.countries = [] + cls.countries.append( + cls.env["res.country"].create( + { + "name": "A-land", + "code": "Q1", + } + ) + ) + cls.countries.append( + cls.env["res.country"].create( + { + "name": "B-land", + "code": "Q2", + } + ) + ) + cls.customers = cls.env["fake.customer"] + for c in range(16): + # Customers with some weird keys to sort on + customer = cls.env["fake.customer"].create( + { + "name": "Customer %d" % (c,), + "sortkey1": floor(c / 8), # 0,0...0,1,1...1 + "country_id": cls.countries[floor(c / 8)].id, + "sortkey2": c, # 0,1,2,.......15 + "sortkey3": (c + 3) % 16, # 3,4,...15,0,1,2 + } + ) + cls.customers |= customer + + @classmethod + def tearDownClass(cls): + cls.loader.restore_registry() + super().tearDownClass() + + def test_1_sort_by_related(self): + """Test if we can now search by non-stored related fields""" + result = self.env["fake.customer"].search([], order="country_name asc") + self.assertEqual(result[8:15].mapped("country_id"), self.countries[1]) + result = self.env["fake.customer"].search([], order="country_name desc") + self.assertEqual(result[8:15].mapped("country_id"), self.countries[0]) + + def test_2_sortable(self): + """Test if the fields show as sortable""" + fields_get = self.env["fake.customer"].fields_get() + self.assertTrue(fields_get["country_code"]["sortable"]) + self.assertTrue(fields_get["country_name"]["sortable"]) + + def test_3_sort_by_two_related_fields(self): + self.env["fake.customer"].search( + [], order="country_code asc, country_name desc" + ) + + def test_4_sort_by_mix_of_fields(self): + customers = self.customers + # country_name bychance is also a translated field, so also test that. + result = self.env["fake.customer"].search( + [], order="country_name desc, sortkey2 asc" + ) + self.assertEqual(result[0], customers[8]) + result = self.env["fake.customer"].search( + [], order="sortkey2 asc, country_code asc" + ) + self.assertEqual(result[0], customers[0]) + result = self.env["fake.customer"].search( + [], order="sortkey1 desc, sortkey3 asc, country_code asc" + ) + self.assertEqual(result[0], customers[13]) From caed2a59cf279ca788aba083bb870bb8803e5310 Mon Sep 17 00:00:00 2001 From: Tom Blauwendraat Date: Mon, 7 Aug 2023 09:20:13 +0200 Subject: [PATCH 2/9] [IMP] support single level related fields --- base_order_by_related/models/models.py | 8 ++++++-- base_order_by_related/tests/fake_models.py | 3 ++- base_order_by_related/tests/test_order_by_related.py | 3 +++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/base_order_by_related/models/models.py b/base_order_by_related/models/models.py index 88ff99afe00..67fd82cc87f 100644 --- a/base_order_by_related/models/models.py +++ b/base_order_by_related/models/models.py @@ -22,8 +22,12 @@ def _related_join_calc(self, alias, fname, query): if field.related_field.model_name not in self.env: continue related_model = self.env[field.related_field.model_name] - related_fname = field.related[0] - related_fname2 = field.related[1] + if len(field.related) == 1: + related_fname = "id" + related_fname2 = field.related[0] + else: + related_fname = field.related[0] + related_fname2 = field.related[1] # JOIN related_model._table AS related_alias ON # alias.related_fname = related_alias.id diff --git a/base_order_by_related/tests/fake_models.py b/base_order_by_related/tests/fake_models.py index 0d5232cfcb0..121b163a899 100644 --- a/base_order_by_related/tests/fake_models.py +++ b/base_order_by_related/tests/fake_models.py @@ -9,7 +9,7 @@ class FakeCustomer(models.Model): _name = "fake.customer" _description = "fake model for customers" - _order_by_related = ["country_name", "country_code"] + _order_by_related = ["country_name", "country_code", "fake_sortkey3"] name = fields.Char(required=True) sortkey1 = fields.Integer() @@ -18,3 +18,4 @@ class FakeCustomer(models.Model): country_id = fields.Many2one("res.country") country_name = fields.Char(related="country_id.name") country_code = fields.Char(related="country_id.code") + fake_sortkey3 = fields.Integer(related="sortkey3") diff --git a/base_order_by_related/tests/test_order_by_related.py b/base_order_by_related/tests/test_order_by_related.py index 95f10902d77..c9ef32f3579 100644 --- a/base_order_by_related/tests/test_order_by_related.py +++ b/base_order_by_related/tests/test_order_by_related.py @@ -62,6 +62,9 @@ def test_1_sort_by_related(self): self.assertEqual(result[8:15].mapped("country_id"), self.countries[1]) result = self.env["fake.customer"].search([], order="country_name desc") self.assertEqual(result[8:15].mapped("country_id"), self.countries[0]) + # same-model related field + result = self.env["fake.customer"].search([], order="fake_sortkey3 asc") + self.assertEqual(result[0], self.customers[13]) def test_2_sortable(self): """Test if the fields show as sortable""" From d20962658d4713ee6806b021b043900f8d9c1b21 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 15 Feb 2024 10:33:11 +0000 Subject: [PATCH 3/9] [UPD] Update base_order_by_related.pot --- .../i18n/base_order_by_related.pot | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 base_order_by_related/i18n/base_order_by_related.pot diff --git a/base_order_by_related/i18n/base_order_by_related.pot b/base_order_by_related/i18n/base_order_by_related.pot new file mode 100644 index 00000000000..f992b58ad87 --- /dev/null +++ b/base_order_by_related/i18n/base_order_by_related.pot @@ -0,0 +1,19 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_order_by_related +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: base_order_by_related +#: model:ir.model,name:base_order_by_related.model_base +msgid "Base" +msgstr "" From 6bddcdfc03ae13462f2e824c96e8a4a17c05a786 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 15 Feb 2024 10:40:03 +0000 Subject: [PATCH 4/9] [BOT] post-merge updates --- base_order_by_related/README.rst | 97 ++++ .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 436 ++++++++++++++++++ 3 files changed, 533 insertions(+) create mode 100644 base_order_by_related/static/description/icon.png create mode 100644 base_order_by_related/static/description/index.html diff --git a/base_order_by_related/README.rst b/base_order_by_related/README.rst index e69de29bb2d..364f2cb39d0 100644 --- a/base_order_by_related/README.rst +++ b/base_order_by_related/README.rst @@ -0,0 +1,97 @@ +===================== +Base order by related +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:5a2f274bad5669f872068a0636e91112968f8870464e5b6bae453c5728d02506 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github + :target: https://github.com/OCA/server-tools/tree/14.0/base_order_by_related + :alt: OCA/server-tools +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-tools-14-0/server-tools-14-0-base_order_by_related + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=14.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows a search to order by a non-stored related field. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +In any model where you have a non-stored related field, you can make it sortable:: + + class ResPartner(models.Model): + _inherit = "res.partner" + + country_name = fields.Char(related="country_id.name") + + # make some non-stored related fields sortable + _order_by_related = ["country_name"] + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Therp BV + +Contributors +~~~~~~~~~~~~ + +* Tom Blauwendraat + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-thomaspaulb| image:: https://github.com/thomaspaulb.png?size=40px + :target: https://github.com/thomaspaulb + :alt: thomaspaulb + +Current `maintainer `__: + +|maintainer-thomaspaulb| + +This module is part of the `OCA/server-tools `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_order_by_related/static/description/icon.png b/base_order_by_related/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/base_order_by_related/static/description/index.html b/base_order_by_related/static/description/index.html new file mode 100644 index 00000000000..8d590252a7d --- /dev/null +++ b/base_order_by_related/static/description/index.html @@ -0,0 +1,436 @@ + + + + + +Base order by related + + + + + + From 3ab99ceda2979920b6918325720afb4484ff5815 Mon Sep 17 00:00:00 2001 From: mymage Date: Tue, 3 Dec 2024 09:42:23 +0000 Subject: [PATCH 5/9] Added translation using Weblate (Italian) --- base_order_by_related/i18n/it.po | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 base_order_by_related/i18n/it.po diff --git a/base_order_by_related/i18n/it.po b/base_order_by_related/i18n/it.po new file mode 100644 index 00000000000..cd13a9a0da2 --- /dev/null +++ b/base_order_by_related/i18n/it.po @@ -0,0 +1,20 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_order_by_related +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: base_order_by_related +#: model:ir.model,name:base_order_by_related.model_base +msgid "Base" +msgstr "" From 008905b7667503196ea9b02dd7cbc7b68466652c Mon Sep 17 00:00:00 2001 From: mymage Date: Thu, 16 Jan 2025 13:11:24 +0000 Subject: [PATCH 6/9] Translated using Weblate (Italian) Currently translated at 100.0% (1 of 1 strings) Translation: server-tools-14.0/server-tools-14.0-base_order_by_related Translate-URL: https://translation.odoo-community.org/projects/server-tools-14-0/server-tools-14-0-base_order_by_related/it/ --- base_order_by_related/i18n/it.po | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/base_order_by_related/i18n/it.po b/base_order_by_related/i18n/it.po index cd13a9a0da2..3fd17b1b01a 100644 --- a/base_order_by_related/i18n/it.po +++ b/base_order_by_related/i18n/it.po @@ -6,15 +6,17 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2025-01-16 16:06+0000\n" +"Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" #. module: base_order_by_related #: model:ir.model,name:base_order_by_related.model_base msgid "Base" -msgstr "" +msgstr "Base" From b07064fa1a93c20805af26d9231788f1f0e17ed3 Mon Sep 17 00:00:00 2001 From: Nikos Tsirintanis Date: Mon, 19 May 2025 14:25:34 +0200 Subject: [PATCH 7/9] [IMP] base_order_by_related: pre-commit stuff --- .../base_order_by_related/odoo/addons/base_order_by_related | 1 + setup/base_order_by_related/setup.py | 6 ++++++ 2 files changed, 7 insertions(+) create mode 120000 setup/base_order_by_related/odoo/addons/base_order_by_related create mode 100644 setup/base_order_by_related/setup.py diff --git a/setup/base_order_by_related/odoo/addons/base_order_by_related b/setup/base_order_by_related/odoo/addons/base_order_by_related new file mode 120000 index 00000000000..65c5934b757 --- /dev/null +++ b/setup/base_order_by_related/odoo/addons/base_order_by_related @@ -0,0 +1 @@ +../../../../base_order_by_related \ No newline at end of file diff --git a/setup/base_order_by_related/setup.py b/setup/base_order_by_related/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/base_order_by_related/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From ea2b92af4ee5bc021ea9672ccbecfb8e8dda3189 Mon Sep 17 00:00:00 2001 From: Nikos Tsirintanis Date: Mon, 19 May 2025 14:27:08 +0200 Subject: [PATCH 8/9] [MIG] base_order_by_related: Migration to 16.0 --- base_order_by_related/__manifest__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base_order_by_related/__manifest__.py b/base_order_by_related/__manifest__.py index 5ce491964fb..3698bbfa2d3 100644 --- a/base_order_by_related/__manifest__.py +++ b/base_order_by_related/__manifest__.py @@ -1,11 +1,11 @@ -# Copyright (C) 2023 Therp (). +# Copyright (C) 2025 Therp (). # @author Tom Blauwendraat # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Base order by related", "summary": "Order by non-stored related fields", - "version": "14.0.1.0.0", + "version": "16.0.1.0.0", "category": "Tools", "website": "https://github.com/OCA/server-tools", "author": "Therp BV, Odoo Community Association (OCA)", From d5859b40f141e0a87ac01ff424bb72404e6e53f7 Mon Sep 17 00:00:00 2001 From: Nikos Tsirintanis Date: Mon, 19 May 2025 16:10:57 +0200 Subject: [PATCH 9/9] fixup! [MIG] base_order_by_related: Migration to 16.0 --- base_order_by_related/README.rst | 10 +++++----- base_order_by_related/models/models.py | 4 ---- .../static/description/index.html | 17 ++++++++++------- .../tests/test_order_by_related.py | 4 ++-- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/base_order_by_related/README.rst b/base_order_by_related/README.rst index 364f2cb39d0..6ea60f6eb44 100644 --- a/base_order_by_related/README.rst +++ b/base_order_by_related/README.rst @@ -17,13 +17,13 @@ Base order by related :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github - :target: https://github.com/OCA/server-tools/tree/14.0/base_order_by_related + :target: https://github.com/OCA/server-tools/tree/16.0/base_order_by_related :alt: OCA/server-tools .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/server-tools-14-0/server-tools-14-0-base_order_by_related + :target: https://translation.odoo-community.org/projects/server-tools-16-0/server-tools-16-0-base_order_by_related :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=14.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=16.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -54,7 +54,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -92,6 +92,6 @@ Current `maintainer `__: |maintainer-thomaspaulb| -This module is part of the `OCA/server-tools `_ project on GitHub. +This module is part of the `OCA/server-tools `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_order_by_related/models/models.py b/base_order_by_related/models/models.py index 67fd82cc87f..e90a0c89ea7 100644 --- a/base_order_by_related/models/models.py +++ b/base_order_by_related/models/models.py @@ -39,10 +39,6 @@ def _related_join_calc(self, alias, fname, query): related_fname2, ) model, alias, field = related_model, related_alias, field.related_field - # handle the case where the field is translated - if field.translate is True: - return model._generate_translated_field(alias, related_fname2, query) - else: return '"%s"."%s"' % (alias, related_fname2) @api.model diff --git a/base_order_by_related/static/description/index.html b/base_order_by_related/static/description/index.html index 8d590252a7d..f128e1dff75 100644 --- a/base_order_by_related/static/description/index.html +++ b/base_order_by_related/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -368,7 +369,7 @@

Base order by related

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:5a2f274bad5669f872068a0636e91112968f8870464e5b6bae453c5728d02506 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/server-tools Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/server-tools Translate me on Weblate Try me on Runboat

This module allows a search to order by a non-stored related field.

Table of contents

@@ -401,7 +402,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -421,13 +422,15 @@

Contributors

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

Current maintainer:

thomaspaulb

-

This module is part of the OCA/server-tools project on GitHub.

+

This module is part of the OCA/server-tools project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/base_order_by_related/tests/test_order_by_related.py b/base_order_by_related/tests/test_order_by_related.py index c9ef32f3579..318054f0586 100644 --- a/base_order_by_related/tests/test_order_by_related.py +++ b/base_order_by_related/tests/test_order_by_related.py @@ -6,10 +6,10 @@ from odoo_test_helper import FakeModelLoader -from odoo.tests.common import SavepointCase +from odoo.tests.common import TransactionCase -class TestOrderByRelated(SavepointCase): +class TestOrderByRelated(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass()