Skip to content
Draft
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
3 changes: 3 additions & 0 deletions spp_registry_search/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.

from . import models
45 changes: 45 additions & 0 deletions spp_registry_search/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.


{
"name": "OpenSPP Registry Search",
"category": "OpenSPP/OpenSPP",
"version": "17.0.1.0.0",
"sequence": 1,
"author": "OpenSPP.org",
"website": "https://github.com/OpenSPP/openspp-modules",
"license": "LGPL-3",
"development_status": "Beta",
"maintainers": ["jeremi", "gonzalesedwin1123", "emjay0921"],
"depends": [
"base",
"g2p_registry_base",
"spp_base_common",
"g2p_registry_individual",
"g2p_registry_group",
],
"excludes": [],
"external_dependencies": {},
"data": [
"security/ir.model.access.csv",
"data/partner_search_field_data.xml",
"data/partner_search_filter_data.xml",
"views/partner_search_field_view.xml",
"views/partner_search_filter_view.xml",
"views/partner_custom_search_view.xml",
],
"assets": {
"web.assets_backend": [
"spp_registry_search/static/src/js/partner_search_view.js",
"spp_registry_search/static/src/js/partner_search_widget.js",
"spp_registry_search/static/src/xml/partner_search_view.xml",
"spp_registry_search/static/src/xml/partner_search_widget.xml",
],
},
"demo": [],
"images": [],
"application": False,
"installable": True,
"auto_install": False,
"summary": "Provides advanced search capabilities for the OpenSPP Registry. Features include configurable search fields, dynamic field filtering by registrant type (Individual/Group), and an intuitive search interface with real-time results.",
}
30 changes: 30 additions & 0 deletions spp_registry_search/data/partner_search_field_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Part of OpenSPP. See LICENSE file for full copyright and licensing details.
-->
<odoo noupdate="0">
<!-- Default searchable registry fields configuration -->
<record id="registry_search_field_name" model="spp.partner.search.field">
<field name="name">Name</field>
<field name="field_id" ref="base.field_res_partner__name" />
<field name="target_type">both</field>
<field name="sequence">10</field>
<field name="active" eval="True" />
</record>

<record id="registry_search_field_email" model="spp.partner.search.field">
<field name="name">Email</field>
<field name="field_id" ref="base.field_res_partner__email" />
<field name="target_type">both</field>
<field name="sequence">20</field>
<field name="active" eval="True" />
</record>

<record id="registry_search_field_phone" model="spp.partner.search.field">
<field name="name">Phone</field>
<field name="field_id" ref="base.field_res_partner__phone" />
<field name="target_type">both</field>
<field name="sequence">30</field>
<field name="active" eval="True" />
</record>
</odoo>
30 changes: 30 additions & 0 deletions spp_registry_search/data/partner_search_filter_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo noupdate="0">
<!-- Demo Search Filters -->
<record id="registry_search_filter_female" model="spp.partner.search.filter">
<field name="name">Female Registrants</field>
<field name="sequence">10</field>
<field name="target_type">individual</field>
<field name="domain">[('gender', '=', 'Female')]</field>
<field name="description">Show only female individuals</field>
<field name="active" eval="True" />
</record>

<record id="registry_search_filter_male" model="spp.partner.search.filter">
<field name="name">Male Registrants</field>
<field name="sequence">20</field>
<field name="target_type">individual</field>
<field name="domain">[('gender', '=', 'Male')]</field>
<field name="description">Show only male individuals</field>
<field name="active" eval="True" />
</record>

<record id="registry_search_filter_archived" model="spp.partner.search.filter">
<field name="name">Archived Registrants</field>
<field name="sequence">90</field>
<field name="target_type">both</field>
<field name="domain">[('active', '=', False)]</field>
<field name="description">Show only archived registrants</field>
<field name="active" eval="True" />
</record>
</odoo>
5 changes: 5 additions & 0 deletions spp_registry_search/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.

from . import partner_search_field
from . import partner_search_filter
from . import res_partner
99 changes: 99 additions & 0 deletions spp_registry_search/models/partner_search_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.

import logging

from odoo import api, fields, models

_logger = logging.getLogger(__name__)


class PartnerSearchField(models.Model):
"""Configuration model for managing searchable partner fields"""

_name = "spp.partner.search.field"
_description = "Partner Search Field Configuration"
_order = "sequence, name"

name = fields.Char(
string="Field Label",
required=True,
help="Display name for the field in the dropdown",
)
field_id = fields.Many2one(
"ir.model.fields",
string="Field",
domain="[('model', '=', 'res.partner')]",
help="Partner field to be searchable",
)
field_name = fields.Char(
string="Field Name",
related="field_id.name",
store=True,
readonly=True,
)
field_type = fields.Selection(
string="Field Type",
related="field_id.ttype",
store=True,
readonly=True,
)
target_type = fields.Selection(
[
("individual", "Individual"),
("group", "Group"),
("both", "Both"),
],
string="Target Type",
default="both",
required=True,
help="Specify if this field is for Individuals, Groups, or Both",
)
active = fields.Boolean(
default=True,
help="If unchecked, this field will not appear in the search dropdown",
)
sequence = fields.Integer(
default=10,
help="Order in which fields appear in the dropdown",
)
company_id = fields.Many2one(
"res.company",
string="Company",
default=lambda self: self.env.company,
required=False,
)

_sql_constraints = [
(
"unique_field_per_company",
"unique(field_id, company_id)",
"This field is already configured for this company!",
),
]

@api.constrains("field_id")
def _check_field_type(self):
"""Ensure only searchable field types are selected"""
searchable_types = [
"char",
"text",
"selection",
"many2one",
"many2many",
"integer",
"float",
"date",
"datetime",
"boolean",
]
for record in self:
if record.field_type not in searchable_types:
raise models.ValidationError(f"Field type '{record.field_type}' is not supported for searching.")

def name_get(self):
"""Custom name display"""
result = []
for record in self:
name = f"{record.name} ({record.field_name})"
result.append((record.id, name))
return result
64 changes: 64 additions & 0 deletions spp_registry_search/models/partner_search_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.

import logging

from odoo import api, fields, models
from odoo.tools.safe_eval import safe_eval

_logger = logging.getLogger(__name__)


class SPPPartnerSearchFilter(models.Model):
_name = "spp.partner.search.filter"
_description = "Partner Search Filter Configuration"
_order = "sequence, name"

name = fields.Char(string="Filter Name", required=True, translate=True)
sequence = fields.Integer(default=10, help="Order of filter in dropdown")
active = fields.Boolean(default=True)
domain = fields.Text(
string="Domain",
required=True,
default="[]",
help="Domain filter in Python format, e.g., [('gender', '=', 'Female')]",
)
target_type = fields.Selection(
[
("individual", "Individual"),
("group", "Group"),
("both", "Both"),
],
string="Target Type",
required=True,
default="both",
help="Specify whether this filter applies to individuals, groups, or both",
)
description = fields.Text(string="Description", translate=True)
company_id = fields.Many2one(
"res.company",
string="Company",
default=lambda self: self.env.company,
)

@api.constrains("domain")
def _check_domain(self):
"""Validate that the domain is a valid Python expression"""
for record in self:
try:
domain = safe_eval(record.domain or "[]")
if not isinstance(domain, list):
raise ValueError("Domain must be a list")
except Exception as e:
from odoo.exceptions import ValidationError

raise ValidationError(f"Invalid domain: {e}") from e

def name_get(self):
"""Custom name display"""
result = []
for record in self:
name = record.name
if record.description:
name = f"{name} - {record.description}"
result.append((record.id, name))
return result
Loading
Loading