Skip to content
Merged
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
1 change: 1 addition & 0 deletions spp_registry_name_suffix/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
28 changes: 28 additions & 0 deletions spp_registry_name_suffix/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
{
"name": "OpenSPP Registry Name Suffix",
"summary": "Adds a configurable suffix field (Jr., Sr., III, etc.) to Individual registrant names in OpenSPP.",
"category": "OpenSPP",
"version": "17.0.1.4.1",
"sequence": 1,
"author": "OpenSPP.org",
"website": "https://github.com/OpenSPP/openspp-modules",
"license": "LGPL-3",
"development_status": "Beta",
"maintainers": ["jeremi", "gonzalesedwin1123"],
"depends": [
"g2p_registry_individual",
],
"data": [
"security/ir.model.access.csv",
"views/name_suffix_views.xml",
"views/res_partner_views.xml",
"data/name_suffix_data.xml",
],
"assets": {},
"demo": [],
"images": [],
"application": False,
"installable": True,
"auto_install": False,
}
171 changes: 171 additions & 0 deletions spp_registry_name_suffix/data/name_suffix_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">

<!-- Generational Suffixes (mutually exclusive - only one can be used) -->
<record id="suffix_jr" model="spp.name.suffix">
<field name="name">Jr.</field>
<field name="code">JR</field>
<field name="sequence">10</field>
<field name="is_generational" eval="True" />
<field name="description">Junior - typically used for a son named after his father</field>
</record>

<record id="suffix_sr" model="spp.name.suffix">
<field name="name">Sr.</field>
<field name="code">SR</field>
<field name="sequence">20</field>
<field name="is_generational" eval="True" />
<field name="description">Senior - typically used for a father when a son has the same name</field>
</record>

<record id="suffix_jra" model="spp.name.suffix">
<field name="name">Jra.</field>
<field name="code">JRA</field>
<field name="sequence">25</field>
<field name="is_generational" eval="True" />
<field name="description">JRA</field>
</record>

<record id="suffix_i" model="spp.name.suffix">
<field name="name">I</field>
<field name="code">I</field>
<field name="sequence">30</field>
<field name="is_generational" eval="True" />
<field name="description">The First</field>
</record>

<record id="suffix_ii" model="spp.name.suffix">
<field name="name">II</field>
<field name="code">II</field>
<field name="sequence">40</field>
<field name="is_generational" eval="True" />
<field name="description">The Second</field>
</record>

<record id="suffix_iii" model="spp.name.suffix">
<field name="name">III</field>
<field name="code">III</field>
<field name="sequence">50</field>
<field name="is_generational" eval="True" />
<field name="description">The Third</field>
</record>

<record id="suffix_iv" model="spp.name.suffix">
<field name="name">IV</field>
<field name="code">IV</field>
<field name="sequence">60</field>
<field name="is_generational" eval="True" />
<field name="description">The Fourth</field>
</record>

<record id="suffix_v" model="spp.name.suffix">
<field name="name">V</field>
<field name="code">V</field>
<field name="sequence">70</field>
<field name="is_generational" eval="True" />
<field name="description">The Fifth</field>
</record>

<record id="suffix_vi" model="spp.name.suffix">
<field name="name">VI</field>
<field name="code">VI</field>
<field name="sequence">71</field>
<field name="is_generational" eval="True" />
<field name="description">The Sixth</field>
</record>

<record id="suffix_vii" model="spp.name.suffix">
<field name="name">VII</field>
<field name="code">VII</field>
<field name="sequence">72</field>
<field name="is_generational" eval="True" />
<field name="description">The Seventh</field>
</record>

<record id="suffix_viii" model="spp.name.suffix">
<field name="name">VIII</field>
<field name="code">VIII</field>
<field name="sequence">73</field>
<field name="is_generational" eval="True" />
<field name="description">The Eighth</field>
</record>

<record id="suffix_ix" model="spp.name.suffix">
<field name="name">IX</field>
<field name="code">IX</field>
<field name="sequence">74</field>
<field name="is_generational" eval="True" />
<field name="description">The Ninth</field>
</record>

<record id="suffix_x" model="spp.name.suffix">
<field name="name">X</field>
<field name="code">X</field>
<field name="sequence">75</field>
<field name="is_generational" eval="True" />
<field name="description">The Tenth</field>
</record>

<record id="suffix_xi" model="spp.name.suffix">
<field name="name">XI</field>
<field name="code">XI</field>
<field name="sequence">76</field>
<field name="is_generational" eval="True" />
<field name="description">The Eleventh</field>
</record>

<record id="suffix_xii" model="spp.name.suffix">
<field name="name">XII</field>
<field name="code">XII</field>
<field name="sequence">77</field>
<field name="is_generational" eval="True" />
<field name="description">The Twelfth</field>
</record>

<record id="suffix_xiii" model="spp.name.suffix">
<field name="name">XIII</field>
<field name="code">XIII</field>
<field name="sequence">78</field>
<field name="is_generational" eval="True" />
<field name="description">The Thirteenth</field>
</record>

<record id="suffix_xiv" model="spp.name.suffix">
<field name="name">XIV</field>
<field name="code">XIV</field>
<field name="sequence">79</field>
<field name="is_generational" eval="True" />
<field name="description">The Fourteenth</field>
</record>

<record id="suffix_xv" model="spp.name.suffix">
<field name="name">XV</field>
<field name="code">XV</field>
<field name="sequence">80</field>
<field name="is_generational" eval="True" />
<field name="description">The Fifteenth</field>
</record>

<!-- Academic/Professional Suffixes -->
<record id="suffix_phd" model="spp.name.suffix">
<field name="name">PhD</field>
<field name="code">PHD</field>
<field name="sequence">100</field>
<field name="description">Doctor of Philosophy</field>
</record>

<record id="suffix_md" model="spp.name.suffix">
<field name="name">MD</field>
<field name="code">MD</field>
<field name="sequence">110</field>
<field name="description">Doctor of Medicine</field>
</record>

<record id="suffix_esq" model="spp.name.suffix">
<field name="name">Esq.</field>
<field name="code">ESQ</field>
<field name="sequence">120</field>
<field name="description">Esquire - typically used for attorneys</field>
</record>

</odoo>
2 changes: 2 additions & 0 deletions spp_registry_name_suffix/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import name_suffix
from . import res_partner
62 changes: 62 additions & 0 deletions spp_registry_name_suffix/models/name_suffix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from odoo import fields, models


class SPPNameSuffix(models.Model):
_name = "spp.name.suffix"
_description = "Name Suffix"
_order = "sequence, name"

name = fields.Char(
string="Suffix",
required=True,
help="The suffix value (e.g., Jr., Sr., III, PhD)",
)
code = fields.Char(
string="Code",
required=True,
help="Short code for the suffix",
)
sequence = fields.Integer(
string="Sequence",
default=10,
help="Used to order suffixes in dropdown lists",
)
active = fields.Boolean(
string="Active",
default=True,
help="If unchecked, the suffix will not be available for selection",
)
description = fields.Text(
string="Description",
help="Additional description or usage notes for this suffix",
)
is_generational = fields.Boolean(
string="Generational Suffix",
default=False,
help="Check this for generational suffixes (Jr., Sr., I, II, III, etc.). "
"Only one generational suffix can be used per individual.",
)

_sql_constraints = [
(
"name_uniq",
"unique(name)",
"Suffix name must be unique!",
),
(
"code_uniq",
"unique(code)",
"Suffix code must be unique!",
),
]

def name_get(self):
"""Display suffix name with code if different."""
result = []
for record in self:
if record.code and record.code != record.name:
name = f"{record.name} ({record.code})"
else:
name = record.name
result.append((record.id, name))
return result
44 changes: 44 additions & 0 deletions spp_registry_name_suffix/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError


class ResPartner(models.Model):
_inherit = "res.partner"

suffix_ids = fields.Many2many(
comodel_name="spp.name.suffix",
relation="res_partner_name_suffix_rel",
column1="partner_id",
column2="suffix_id",
string="Suffixes",
help="Name suffixes",
)

@api.constrains("suffix_ids")
def _check_generational_suffix_conflict(self):
"""Validate that only one generational suffix is selected."""
for record in self:
if not record.suffix_ids:
continue
generational_suffixes = record.suffix_ids.filtered(lambda s: s.is_generational)
if len(generational_suffixes) > 1:
suffix_names = ", ".join(generational_suffixes.mapped("name"))
raise ValidationError(
_(
"Only one generational suffix can be used at a time. "
"The following are generational suffixes: %(suffixes)s",
suffixes=suffix_names,
)
)

@api.onchange("is_group", "family_name", "given_name", "addl_name", "suffix_ids")
def name_change(self):
"""Extend name change to include suffixes for individuals."""
super().name_change()
if not self.is_group and self.suffix_ids and self.name:
# Join all suffixes in sequence order, separated by comma
suffixes_str = ", ".join(self.suffix_ids.sorted("sequence").mapped(lambda s: s.name.upper()))
suffix_part = f", {suffixes_str}"
# Only append suffixes if not already present (avoid double-append)
if not self.name.endswith(suffix_part):
self.name = f"{self.name}{suffix_part}"
3 changes: 3 additions & 0 deletions spp_registry_name_suffix/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
59 changes: 59 additions & 0 deletions spp_registry_name_suffix/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# OpenSPP Registry Name Suffix

The `spp_registry_name_suffix` module adds a configurable suffix field to Individual registrant names in OpenSPP, enabling proper recording of name suffixes such as Jr., Sr., III, IV, PhD, MD, etc.

## Purpose

This module enhances individual registrant data by:

* **Providing configurable suffixes**: Administrators can manage available suffixes through the Registry Configuration menu.
* **Adding suffix support**: Record name suffixes using a standardized Many2one field reference.
* **Extending name generation**: Automatically includes the suffix in the generated full name.
* **Maintaining data integrity**: The suffix is stored as a reference to a configurable suffix record.

## Features

### Suffix Configuration
A new "Name Suffixes" menu is available under Registry > Configuration, allowing administrators to:
- Create, edit, and archive name suffixes
- Define suffix codes for data integration
- Set display order using sequence numbers
- Add descriptions for suffix usage guidance

### Pre-configured Suffixes
The module comes with commonly used suffixes:
- **Generational**: Jr., Sr., I, II, III, IV, V
- **Academic/Professional**: PhD, MD, Esq.

### Individual Registrant Integration
The suffix field appears on the Individual registrant form after the "Additional Name" field. It uses a dropdown selection with the following features:
- Quick search by suffix name or code
- No inline creation (to maintain data quality)
- Optional display in the registrant list view

### Automatic Name Generation
The suffix is automatically appended to the registrant's name when using the form. The module extends the `name_change` method from `g2p_registry_individual` to include the suffix in the generated name format:
`FAMILY_NAME, GIVEN_NAME ADDL_NAME, SUFFIX`

For example: "SMITH, JOHN MICHAEL, JR."

## Dependencies

This module depends on:
- **g2p_registry_individual**: Provides the individual registrant views, model, and the base `name_change` method.

## Configuration

1. Navigate to Registry > Configuration > Name Suffixes
2. Create additional suffixes as needed for your implementation
3. Set the sequence to control display order in dropdowns

## Usage

1. Navigate to an Individual registrant form
2. Select a suffix from the "Suffix" dropdown field
3. The full name will automatically update to include the suffix

## References

- OpenG2P Registry Individual: https://github.com/OpenSPP/openg2p-registry/tree/17.0-develop-openspp/g2p_registry_individual
4 changes: 4 additions & 0 deletions spp_registry_name_suffix/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink

spp_name_suffix_registrar,SPP Name Suffix Registrar Access,spp_registry_name_suffix.model_spp_name_suffix,g2p_registry_base.group_g2p_registrar,1,1,1,1
spp_name_suffix_admin,SPP Name Suffix Admin Access,spp_registry_name_suffix.model_spp_name_suffix,g2p_registry_base.group_g2p_admin,1,1,1,1
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading