Skip to content

Commit 462be1d

Browse files
[UPD] spp_registry_name_suffix: support multiple suffixes per individual
Change suffix field from Many2one to Many2many to allow selecting multiple suffixes (e.g., 'Jr., PhD'). Suffixes are displayed in sequence order. Updated views to use many2many_tags widget and added comprehensive tests for multiple suffix scenarios.
1 parent a514c84 commit 462be1d

File tree

4 files changed

+159
-37
lines changed

4 files changed

+159
-37
lines changed

spp_registry_name_suffix/data/name_suffix_data.xml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616
<field name="description">Senior - typically used for a father when a son has the same name</field>
1717
</record>
1818

19+
<record id="suffix_jra" model="spp.name.suffix">
20+
<field name="name">Jra.</field>
21+
<field name="code">JRA</field>
22+
<field name="sequence">25</field>
23+
<field name="description">JRA </field>
24+
</record>
25+
1926
<record id="suffix_i" model="spp.name.suffix">
2027
<field name="name">I</field>
2128
<field name="code">I</field>
@@ -51,6 +58,76 @@
5158
<field name="description">The Fifth</field>
5259
</record>
5360

61+
<record id="suffix_vi" model="spp.name.suffix">
62+
<field name="name">VI</field>
63+
<field name="code">VI</field>
64+
<field name="sequence">71</field>
65+
<field name="description">The Sixth</field>
66+
</record>
67+
68+
<record id="suffix_vii" model="spp.name.suffix">
69+
<field name="name">VII</field>
70+
<field name="code">VII</field>
71+
<field name="sequence">72</field>
72+
<field name="description">The Seventh</field>
73+
</record>
74+
75+
<record id="suffix_viii" model="spp.name.suffix">
76+
<field name="name">VIII</field>
77+
<field name="code">VIII</field>
78+
<field name="sequence">73</field>
79+
<field name="description">The Eighth</field>
80+
</record>
81+
82+
<record id="suffix_ix" model="spp.name.suffix">
83+
<field name="name">IX</field>
84+
<field name="code">IX</field>
85+
<field name="sequence">74</field>
86+
<field name="description">The Ninth</field>
87+
</record>
88+
89+
<record id="suffix_x" model="spp.name.suffix">
90+
<field name="name">X</field>
91+
<field name="code">X</field>
92+
<field name="sequence">75</field>
93+
<field name="description">The Tenth</field>
94+
</record>
95+
96+
<record id="suffix_xi" model="spp.name.suffix">
97+
<field name="name">XI</field>
98+
<field name="code">XI</field>
99+
<field name="sequence">76</field>
100+
<field name="description">The Eleventh</field>
101+
</record>
102+
103+
<record id="suffix_xii" model="spp.name.suffix">
104+
<field name="name">XII</field>
105+
<field name="code">XII</field>
106+
<field name="sequence">77</field>
107+
<field name="description">The Twelfth</field>
108+
</record>
109+
110+
<record id="suffix_xiii" model="spp.name.suffix">
111+
<field name="name">XIII</field>
112+
<field name="code">XIII</field>
113+
<field name="sequence">78</field>
114+
<field name="description">The Thirteenth</field>
115+
</record>
116+
117+
<record id="suffix_xiv" model="spp.name.suffix">
118+
<field name="name">XIV</field>
119+
<field name="code">XIV</field>
120+
<field name="sequence">79</field>
121+
<field name="description">The Fourteenth</field>
122+
</record>
123+
124+
<record id="suffix_xv" model="spp.name.suffix">
125+
<field name="name">XV</field>
126+
<field name="code">XV</field>
127+
<field name="sequence">80</field>
128+
<field name="description">The Fifteenth</field>
129+
</record>
130+
54131
<!-- Academic/Professional Suffixes -->
55132
<record id="suffix_phd" model="spp.name.suffix">
56133
<field name="name">PhD</field>

spp_registry_name_suffix/models/res_partner.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,23 @@
44
class ResPartner(models.Model):
55
_inherit = "res.partner"
66

7-
suffix_id = fields.Many2one(
7+
suffix_ids = fields.Many2many(
88
comodel_name="spp.name.suffix",
9-
string="Suffix",
10-
ondelete="restrict",
11-
help="Name suffix such as Jr., Sr., III, IV, PhD, MD, etc.",
9+
relation="res_partner_name_suffix_rel",
10+
column1="partner_id",
11+
column2="suffix_id",
12+
string="Suffixes",
13+
help="Name suffixes such as Jr., Sr., III, IV, PhD, MD, etc.",
1214
)
1315

14-
@api.onchange("is_group", "family_name", "given_name", "addl_name", "suffix_id")
16+
@api.onchange("is_group", "family_name", "given_name", "addl_name", "suffix_ids")
1517
def name_change(self):
16-
"""Extend name change to include suffix for individuals."""
18+
"""Extend name change to include suffixes for individuals."""
1719
super().name_change()
18-
if not self.is_group and self.suffix_id and self.name:
19-
suffix_upper = self.suffix_id.name.upper()
20-
suffix_str = f", {suffix_upper}"
21-
# Only append suffix if not already present (avoid double-append)
22-
if not self.name.endswith(suffix_str):
23-
self.name = f"{self.name}{suffix_str}"
20+
if not self.is_group and self.suffix_ids and self.name:
21+
# Join all suffixes in sequence order, separated by comma
22+
suffixes_str = ", ".join(self.suffix_ids.sorted("sequence").mapped(lambda s: s.name.upper()))
23+
suffix_part = f", {suffixes_str}"
24+
# Only append suffixes if not already present (avoid double-append)
25+
if not self.name.endswith(suffix_part):
26+
self.name = f"{self.name}{suffix_part}"

spp_registry_name_suffix/tests/test_name_suffix.py

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ def test_02_suffix_data_loaded(self):
3636
self.assertEqual(self.suffix_phd.name, "PhD")
3737
self.assertEqual(self.suffix_phd.code, "PHD")
3838

39-
def test_03_name_with_suffix(self):
40-
"""Test that suffix is appended to the computed name."""
39+
def test_03_name_with_single_suffix(self):
40+
"""Test that a single suffix is appended to the computed name."""
4141
individual = self.env["res.partner"].create(
4242
{
4343
"name": "Temp", # Required by res_partner_check_name constraint
4444
"family_name": "Doe",
4545
"given_name": "John",
46-
"suffix_id": self.suffix_jr.id,
46+
"suffix_ids": [(6, 0, [self.suffix_jr.id])],
4747
"is_registrant": True,
4848
"is_group": False,
4949
}
@@ -74,32 +74,52 @@ def test_04_name_without_suffix(self):
7474
"Name should not have trailing comma when no suffix",
7575
)
7676

77-
def test_05_name_with_all_fields(self):
78-
"""Test name with all fields including addl_name and suffix."""
77+
def test_05_name_with_multiple_suffixes(self):
78+
"""Test name with multiple suffixes (e.g., Jr. and PhD)."""
7979
individual = self.env["res.partner"].create(
8080
{
8181
"name": "Temp", # Required by res_partner_check_name constraint
8282
"family_name": "Smith",
8383
"given_name": "Robert",
84-
"addl_name": "James",
85-
"suffix_id": self.suffix_phd.id,
84+
"suffix_ids": [(6, 0, [self.suffix_jr.id, self.suffix_phd.id])],
8685
"is_registrant": True,
8786
"is_group": False,
8887
}
8988
)
9089
individual.name_change()
90+
# Jr. has sequence 10, PhD has sequence 100, so Jr. comes first
9191
self.assertEqual(
9292
individual.name,
93-
"SMITH, ROBERT JAMES, PHD",
94-
"Name should include all parts including suffix",
93+
"SMITH, ROBERT, JR., PHD",
94+
"Name should include multiple suffixes in sequence order",
9595
)
9696

97-
def test_06_group_name_unaffected(self):
97+
def test_06_name_with_all_fields_and_multiple_suffixes(self):
98+
"""Test name with all fields including addl_name and multiple suffixes."""
99+
individual = self.env["res.partner"].create(
100+
{
101+
"name": "Temp", # Required by res_partner_check_name constraint
102+
"family_name": "Williams",
103+
"given_name": "James",
104+
"addl_name": "Edward",
105+
"suffix_ids": [(6, 0, [self.suffix_jr.id, self.suffix_phd.id])],
106+
"is_registrant": True,
107+
"is_group": False,
108+
}
109+
)
110+
individual.name_change()
111+
self.assertEqual(
112+
individual.name,
113+
"WILLIAMS, JAMES EDWARD, JR., PHD",
114+
"Name should include all parts including multiple suffixes",
115+
)
116+
117+
def test_07_group_name_unaffected(self):
98118
"""Test that group name is not affected by suffix logic."""
99119
group = self.env["res.partner"].create(
100120
{
101121
"name": "Test Group",
102-
"suffix_id": self.suffix_jr.id,
122+
"suffix_ids": [(6, 0, [self.suffix_jr.id])],
103123
"is_registrant": True,
104124
"is_group": True,
105125
}
@@ -112,8 +132,8 @@ def test_06_group_name_unaffected(self):
112132
"Group name should not include suffix",
113133
)
114134

115-
def test_07_suffix_update_triggers_name_change(self):
116-
"""Test that updating suffix and calling name_change updates name."""
135+
def test_08_suffix_update_triggers_name_change(self):
136+
"""Test that updating suffixes and calling name_change updates name."""
117137
individual = self.env["res.partner"].create(
118138
{
119139
"name": "Temp", # Required by res_partner_check_name constraint
@@ -128,38 +148,59 @@ def test_07_suffix_update_triggers_name_change(self):
128148
self.assertEqual(individual.name, "JOHNSON, MICHAEL")
129149

130150
# Add suffix and call name_change again
131-
individual.suffix_id = self.suffix_phd.id
151+
individual.suffix_ids = [(6, 0, [self.suffix_phd.id])]
132152
individual.name_change()
133153
self.assertEqual(
134154
individual.name,
135155
"JOHNSON, MICHAEL, PHD",
136156
"Name should update when suffix is added",
137157
)
138158

139-
def test_08_suffix_removal(self):
140-
"""Test that removing suffix updates the name correctly."""
159+
def test_09_suffix_removal(self):
160+
"""Test that removing suffixes updates the name correctly."""
141161
individual = self.env["res.partner"].create(
142162
{
143163
"name": "Temp", # Required by res_partner_check_name constraint
144164
"family_name": "Williams",
145165
"given_name": "Sarah",
146-
"suffix_id": self.suffix_jr.id,
166+
"suffix_ids": [(6, 0, [self.suffix_jr.id])],
147167
"is_registrant": True,
148168
"is_group": False,
149169
}
150170
)
151171
individual.name_change()
152172
self.assertEqual(individual.name, "WILLIAMS, SARAH, JR.")
153173

154-
individual.suffix_id = False
174+
individual.suffix_ids = [(5, 0, 0)] # Clear all suffixes
155175
individual.name_change()
156176
self.assertEqual(
157177
individual.name,
158178
"WILLIAMS, SARAH",
159-
"Name should update when suffix is removed",
179+
"Name should update when suffixes are removed",
180+
)
181+
182+
def test_10_suffix_sequence_ordering(self):
183+
"""Test that suffixes are ordered by sequence field."""
184+
# PhD has sequence 100, Jr. has sequence 10
185+
# Even if we add PhD first, Jr. should appear first in the name
186+
individual = self.env["res.partner"].create(
187+
{
188+
"name": "Temp",
189+
"family_name": "Brown",
190+
"given_name": "David",
191+
"suffix_ids": [(6, 0, [self.suffix_phd.id, self.suffix_jr.id])],
192+
"is_registrant": True,
193+
"is_group": False,
194+
}
195+
)
196+
individual.name_change()
197+
self.assertEqual(
198+
individual.name,
199+
"BROWN, DAVID, JR., PHD",
200+
"Suffixes should be ordered by sequence regardless of selection order",
160201
)
161202

162-
def test_09_name_get_with_different_code(self):
203+
def test_11_name_get_with_different_code(self):
163204
"""Test name_get when code differs from name."""
164205
# suffix_jr has name="Jr." and code="JR" (different)
165206
result = self.suffix_jr.name_get()
@@ -171,7 +212,7 @@ def test_09_name_get_with_different_code(self):
171212
"name_get should show name with code in parentheses",
172213
)
173214

174-
def test_10_name_get_with_same_code(self):
215+
def test_12_name_get_with_same_code(self):
175216
"""Test name_get when code equals name."""
176217
# Create a suffix where name and code are the same
177218
suffix_same = self.env["spp.name.suffix"].create(
@@ -189,7 +230,7 @@ def test_10_name_get_with_same_code(self):
189230
"name_get should show only name when code equals name",
190231
)
191232

192-
def test_11_name_get_multiple_records(self):
233+
def test_13_name_get_multiple_records(self):
193234
"""Test name_get with multiple records."""
194235
# Get multiple suffixes at once
195236
suffixes = self.suffix_jr | self.suffix_phd

spp_registry_name_suffix/views/res_partner_views.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
<field name="arch" type="xml">
1111
<xpath expr="//field[@name='addl_name']" position="after">
1212
<field
13-
name="suffix_id"
14-
placeholder="Select Suffix"
13+
name="suffix_ids"
14+
widget="many2many_tags"
15+
placeholder="Select Suffixes"
1516
options="{'no_create': True, 'no_open': True}"
1617
/>
1718
</xpath>
@@ -25,7 +26,7 @@
2526
<field name="inherit_id" ref="g2p_registry_individual.view_individuals_list_tree" />
2627
<field name="arch" type="xml">
2728
<xpath expr="//field[@name='name']" position="after">
28-
<field name="suffix_id" optional="hide" />
29+
<field name="suffix_ids" widget="many2many_tags" optional="hide" />
2930
</xpath>
3031
</field>
3132
</record>

0 commit comments

Comments
 (0)