-
Notifications
You must be signed in to change notification settings - Fork 24
[NEW] spp_registry_name_suffix #879
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
Merged
gonzalesedwin1123
merged 12 commits into
17.0
from
new-module-for-adding-suffix-field-individual-registrant
Dec 16, 2025
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
542893b
[NEW] spp_registry_name_suffix
gonzalesedwin1123 181e72b
[UPD] spp_registry_name_suffix: add name suffix support for individuals
gonzalesedwin1123 98f41aa
[FIX] spp_registry_name_suffix: remove spp_registrant_import dependency
gonzalesedwin1123 b446d6e
[FIX] spp_registry_name_suffix: replace deprecated tt element with code
gonzalesedwin1123 2f4f81c
[FIX] spp_registry_name_suffix: add missing academic suffix data records
gonzalesedwin1123 238b623
[FIX] spp_registry_name_suffix: simplify tests to fix CI failures
gonzalesedwin1123 92c8ac9
[FIX] spp_registry_name_suffix: add placeholder name to satisfy check…
gonzalesedwin1123 df83d43
[FIX] spp_registry_name_suffix: add tests for name_get method to achi…
gonzalesedwin1123 a514c84
[FIX] Remove archive button in the suffix configuration UI
gonzalesedwin1123 462be1d
[UPD] spp_registry_name_suffix: support multiple suffixes per individual
gonzalesedwin1123 90ba115
[UPD] spp_registry_name_suffix: add exclusion groups for mutually exc…
gonzalesedwin1123 5dd04cd
[UPD] spp_registry_name_suffix: simplify exclusion to boolean is_gene…
gonzalesedwin1123 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| from . import models |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 --> | ||
gonzalesedwin1123 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| <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> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| from . import name_suffix | ||
| from . import res_partner |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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): | ||
gonzalesedwin1123 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| """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}" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| [build-system] | ||
| requires = ["whool"] | ||
| build-backend = "whool.buildapi" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.