Skip to content

Commit 152f1cf

Browse files
committed
fix(spp_registry): format individual name on create and write
The name_change onchange only runs in the UI. When creating or updating individuals via XML-RPC, API, or code, the display name was not formatted as "FAMILY_NAME, GIVEN_NAME ADDL_NAME" (uppercase). Extract name formatting into _format_individual_name() helper and call it from create (injects into vals before super) and write (applies after super only when name fields are in vals). Groups are not affected.
1 parent f738582 commit 152f1cf

1 file changed

Lines changed: 43 additions & 15 deletions

File tree

spp_registry/models/individual.py

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,28 @@ class SPPIndividual(models.Model):
4747
# Membership fields
4848
individual_membership_ids = fields.One2many("spp.group.membership", "individual", "Membership to Groups")
4949

50+
# Fields that trigger name recomputation
51+
_name_fields = {"family_name", "given_name", "addl_name"}
52+
53+
@api.model
54+
def _format_individual_name(self, family_name, given_name, addl_name):
55+
"""Compute display name from individual name parts.
56+
57+
Format: "FAMILY_NAME, GIVEN_NAME ADDL_NAME" (uppercase).
58+
Used by onchange (UI), create, and write to ensure consistent naming.
59+
"""
60+
name_vals = [
61+
f"{family_name}," if family_name and (given_name or addl_name) else f"{family_name}" if family_name else "",
62+
given_name,
63+
addl_name,
64+
]
65+
return " ".join(filter(None, name_vals)).upper()
66+
5067
@api.onchange("is_group", "family_name", "given_name", "addl_name")
5168
def name_change(self):
52-
vals = {}
5369
if not self.is_group:
54-
name_vals = [
55-
f"{self.family_name},"
56-
if self.family_name and (self.given_name or self.addl_name)
57-
else f"{self.family_name}"
58-
if self.family_name
59-
else "",
60-
self.given_name,
61-
self.addl_name,
62-
]
63-
64-
name = " ".join(filter(None, name_vals))
65-
vals.update({"name": name.upper()})
66-
self.update(vals)
70+
name = self._format_individual_name(self.family_name, self.given_name, self.addl_name)
71+
self.update({"name": name})
6772

6873
@api.depends("birthdate")
6974
def _compute_calc_age(self):
@@ -129,8 +134,23 @@ def _recompute_parent_groups(self, records):
129134
self.env.add_to_compute(field, groups)
130135

131136
def write(self, vals):
132-
"""Override to invalidate group metrics when demographics change."""
137+
"""Override to recompute name and invalidate group metrics."""
138+
# Recompute name if any name field changed (only for non-group individuals)
139+
name_updates = {}
140+
if self._name_fields & vals.keys() and not self.env.context.get("skip_name_format"):
141+
for rec in self.filtered(lambda r: not r.is_group):
142+
name_updates[rec.id] = self._format_individual_name(
143+
vals.get("family_name", rec.family_name),
144+
vals.get("given_name", rec.given_name),
145+
vals.get("addl_name", rec.addl_name),
146+
)
147+
133148
res = super().write(vals)
149+
150+
# Apply computed names after super to avoid interfering with the main write
151+
if name_updates:
152+
for rec_id, name in name_updates.items():
153+
super(SPPIndividual, self.browse(rec_id).with_context(skip_name_format=True)).write({"name": name})
134154
self._recompute_parent_groups(self)
135155

136156
# Fields that affect group-level metrics
@@ -177,6 +197,14 @@ def _invalidate_parent_group_metrics(self, individuals):
177197

178198
@api.model_create_multi
179199
def create(self, vals_list):
200+
# Compute name from parts before create (injects into vals, no extra write)
201+
for vals in vals_list:
202+
if not vals.get("is_group") and self._name_fields & vals.keys():
203+
vals["name"] = self._format_individual_name(
204+
vals.get("family_name", ""),
205+
vals.get("given_name", ""),
206+
vals.get("addl_name", ""),
207+
)
180208
res = super().create(vals_list)
181209
self._recompute_parent_groups(res)
182210
return res

0 commit comments

Comments
 (0)