Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[14.0][ADD] - field_search_panel #158

Closed
wants to merge 1 commit into from
Closed
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
87 changes: 87 additions & 0 deletions field_search_panel/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
==================
Field Search panel
==================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:c60e5709a00cbdd54be84471698f7944bf28a905f6311d21b583ba95ec4253aa
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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%2Fodoo--pim-lightgray.png?logo=github
:target: https://github.com/OCA/odoo-pim/tree/14.0/field_search_panel
:alt: OCA/odoo-pim
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/odoo-pim-14-0/odoo-pim-14-0-field_search_panel
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/odoo-pim&target_branch=14.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module allows the user to define the field that will appear in the search panel of a model at run time.

It also allows the user to use boolean field in the search panel.

**Table of contents**

.. contents::
:local:

Usage
=====

If you want a model search view to have a dynamic search panel, this model need to inherit from 'search.panel.mixin'.

You are not obliged to define a search panel in the xml view, but if you do so the fields that were defined in the xml view will be used to build the search panel in combination with the fields that will be define at run time. The fields define in the xml view won't be removable at run time.

To define the field you want to be display at run time *Settings* > *Search panel fields* than select the fields you want to be display at run time. Be careful, select fields of model that inherit from 'search.panel.mixin' or they won't be display.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/odoo-pim/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 <https://github.com/OCA/odoo-pim/issues/new?body=module:%20field_search_panel%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
~~~~~~~

* ACSONE SA/NV

Contributors
~~~~~~~~~~~~

* Steven Sermeus <sermeus.steven.isj@gmail.com>

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.

This module is part of the `OCA/odoo-pim <https://github.com/OCA/odoo-pim/tree/14.0/field_search_panel>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions field_search_panel/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
13 changes: 13 additions & 0 deletions field_search_panel/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2023 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Field Search panel",
"category": "Generic Modules/Others",
"website": "https://github.com/OCA/odoo-pim",
"version": "14.0.1.0.0",
"data": [
"views/res_config_settings.xml",
],
"license": "AGPL-3",
"author": "ACSONE SA/NV, Odoo Community Association (OCA)",
}
2 changes: 2 additions & 0 deletions field_search_panel/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import search_panel_mixin
from . import res_config_settings
41 changes: 41 additions & 0 deletions field_search_panel/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from odoo import api, fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
searchpanel_field_ids = fields.Many2many(
comodel_name="ir.model.fields",
relation="searchpanel_field_rel",
column1="searchpanel_id",
column2="field_id",
string="Search Panel Fields",
domain=[("ttype", "in", ("selection", "many2one", "boolean"))],
)

@api.model
def _get_search_panel_field_ids(self):
param = self.env["ir.config_parameter"].sudo()
search_panel_field_ids = param.get_param(
"field_selection.searchpanel_field_ids"
)
if search_panel_field_ids and not search_panel_field_ids == "[]":
search_panel_field_ids = search_panel_field_ids[1:-1]
return [int(x) for x in search_panel_field_ids.split(",")]
return []

@api.model
def get_values(self):
res = super().get_values()
search_panel_field_ids = self._get_search_panel_field_ids()
if search_panel_field_ids:
res.update(searchpanel_field_ids=[[6, 0, search_panel_field_ids]])
return res

@api.model
def set_values(self):
res = super().set_values()
IrConfigParameter = self.env["ir.config_parameter"].sudo()
IrConfigParameter.set_param(
"field_selection.searchpanel_field_ids", self.searchpanel_field_ids.ids
)
return res
150 changes: 150 additions & 0 deletions field_search_panel/models/search_panel_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
from lxml import etree

from odoo import _, api, models
from odoo.osv.expression import AND


class SearchpanelMixin(models.AbstractModel):
_name = "search.panel.mixin"
_description = "Mixin Search Panel"

@api.model
def fields_view_get(
self, view_id=None, view_type="form", toolbar=False, submenu=False
):
result = super().fields_view_get(
view_id=view_id,
view_type=view_type,
toolbar=toolbar,
submenu=submenu,
)
if view_type == "search":
result["arch"] = self._set_dynamic_search_panel(result["arch"])
return result

@api.model
def _set_dynamic_search_panel(self, arch):

search_panel_field_ids = self.env[
"res.config.settings"
]._get_search_panel_field_ids()

fields = self.env["ir.model.fields"].search(
[
("id", "in", search_panel_field_ids),
("model", "=", self._name),
]
)

if not fields:
return arch

eview = etree.fromstring(arch)

search_panels = eview.xpath("//searchpanel")

if len(search_panels) == 0:
search_panel = etree.Element("searchpanel")
else:
search_panel = search_panels[0]

for field in fields:
efield = etree.Element("field", name=field.name)
search_panel.insert(0, efield)

eview.insert(0, search_panel)

return etree.tostring(eview, pretty_print=True)

@api.model
def web_search_read(
self,
domain=None,
fields=None,
offset=0,
limit=None,
order=None,
):
"""
Due to the search panel implementation, we can't use False as a boolean value.
So we use "True" and "False" as string values and we convert them to boolean.
"""
new_domain = []
for leaf in domain:
if len(leaf) < 3:
new_domain.append(leaf)
continue
field, operator, value = leaf
field = self._fields.get(field, None)
if field and field.type == "boolean" and not isinstance(value, bool):
value = value == "True"
leaf = (field.name, operator, value)
new_domain.append(leaf)
return super().web_search_read(
domain=new_domain,
fields=fields,
offset=offset,
limit=limit,
order=order,
)

@api.model
def _search_panel_boolean(self, field_name, **kwargs):
field = self._fields[field_name]
domain = self._build_doamin_search_panel(kwargs)
# Expression gonna parse the domain and return a query object
result = self.read_group(domain, [field_name], [field_name])
distinct_values = [x[field_name] for x in result]
selection = self._get_selection(field, field_name)
return {
"parent_field": False,
"values": self._define_panel_values_labels(
distinct_values, selection, field
),
}

@api.model
def _build_doamin_search_panel(self, kwargs):
domain = AND(
[
kwargs.get("search_domain", []),
kwargs.get("model_domain", []),
kwargs.get("category_domain", []),
kwargs.get("filter_domain", []),
]
)

return domain

@api.model
def _define_panel_values_labels(self, distinct_values, values_label, field):
panel_values_label = []
for value, label in values_label:
if value in distinct_values:
if field.type == "boolean":
id_value = str(value)
else:
id_value = value
panel_values_label.append(
{
"id": id_value,
"display_name": label,
}
)
return panel_values_label

@api.model
def search_panel_select_range(self, field_name, **kwargs):
field = self._fields[field_name]
if field.type in ("many2one", "selection"):
return super().search_panel_select_range(field_name, **kwargs)

return self._search_panel_boolean(field_name, **kwargs)

@api.model
def _get_selection(self, field, field_name):
if field.type == "selection":
selection = self.fields_get([field_name])[field_name]["selection"]
elif field.type == "boolean":
selection = [(True, _("Yes")), (False, _("No"))]
return selection
1 change: 1 addition & 0 deletions field_search_panel/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Steven Sermeus <sermeus.steven.isj@gmail.com>
3 changes: 3 additions & 0 deletions field_search_panel/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This module allows the user to define the field that will appear in the search panel of a model at run time.

It also allows the user to use boolean field in the search panel.
Empty file.
5 changes: 5 additions & 0 deletions field_search_panel/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
If you want a model search view to have a dynamic search panel, this model need to inherit from 'search.panel.mixin'.

You are not obliged to define a search panel in the xml view, but if you do so the fields that were defined in the xml view will be used to build the search panel in combination with the fields that will be define at run time. The fields define in the xml view won't be removable at run time.

To define the field you want to be display at run time *Settings* > *Search panel fields* than select the fields you want to be display at run time. Be careful, select fields of model that inherit from 'search.panel.mixin' or they won't be display.
Loading