Skip to content

Commit a8c9b05

Browse files
committed
fix(change_request): replace head-replacement toggle with an info notice (#871)
Drop the 'Replace current Head of Household' boolean. When the new member is given the Head role and the group already has a head, the form now shows a warning that applying will make this member the head and remove the role from the current head; the replacement then happens automatically on apply (the CR still passes through approval first).
1 parent 1612822 commit a8c9b05

4 files changed

Lines changed: 20 additions & 68 deletions

File tree

spp_change_request_v2/details/add_member.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ class SPPCRDetailAddMember(models.Model):
138138

139139
# ──────────────────────────────────────────────────────────────────────
140140
# Head-of-household replacement (OP#871 QA round 1)
141-
# When the target group already has a head, making this new member the head
142-
# is an explicit, confirmed action rather than a silent auto-demotion.
141+
# When the target group already has a head and this new member is given the
142+
# Head role, an info banner warns that applying will replace the current
143+
# head. The replacement then happens automatically on apply.
143144
# ──────────────────────────────────────────────────────────────────────
144145
group_has_head = fields.Boolean(
145146
compute="_compute_current_head",
@@ -149,11 +150,6 @@ class SPPCRDetailAddMember(models.Model):
149150
compute="_compute_current_head",
150151
string="Current Head of Household",
151152
)
152-
replace_existing_head = fields.Boolean(
153-
string="Replace current Head of Household",
154-
help="When set, applying this change request removes the Head role from "
155-
"the group's current head and assigns it to this new member.",
156-
)
157153
selected_role_is_head = fields.Boolean(
158154
compute="_compute_selected_role_is_head",
159155
string="Selected Role Is Head",

spp_change_request_v2/strategies/add_member.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,6 @@ def _validate(self, detail):
9292
)
9393
)
9494

95-
# Replacing an existing head must be explicitly confirmed.
96-
if self._is_head_role(detail.membership_type_id) and detail.group_has_head and not detail.replace_existing_head:
97-
head_suffix = f" ({detail.current_head_name})" if detail.current_head_name else ""
98-
raise UserError(
99-
_(
100-
"This group already has a Head of Household%s. Enable "
101-
"'Replace current Head of Household' to make this new member the head."
102-
)
103-
% head_suffix
104-
)
105-
10695
# ──────────────────────────────────────────────────────────────────────
10796
# Individual creation
10897
# ──────────────────────────────────────────────────────────────────────
@@ -208,8 +197,9 @@ def _demote_existing_head_if_needed(self, detail, group):
208197
picking the Head role. "Demote" unlinks the ``head`` code from the
209198
existing membership's ``membership_type_ids``; other roles are kept.
210199
"""
211-
# Only when the new member is being made head AND the user confirmed.
212-
if not (self._is_head_role(detail.membership_type_id) and detail.replace_existing_head):
200+
# Only when the new member is being made head. Demotion is automatic on
201+
# apply; the form warns the user beforehand via the info banner.
202+
if not self._is_head_role(detail.membership_type_id):
213203
return
214204

215205
head_code = self._head_code()

spp_change_request_v2/tests/test_add_member_strategy.py

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,11 @@ def test_adding_head_demotes_existing_head(self):
161161
)
162162
self.assertIn(self.head_kind, old_membership.membership_type_ids)
163163

164-
# Add new member as head, confirming the replacement.
164+
# Add new member as headreplacement happens automatically on apply.
165165
cr = self._make_cr(
166166
given_name="New",
167167
family_name="Head",
168168
membership_type_id=self.head_kind.id,
169-
replace_existing_head=True,
170169
)
171170
cr.approval_state = "approved"
172171
cr.action_apply()
@@ -179,31 +178,8 @@ def test_adding_head_demotes_existing_head(self):
179178
# Old head's membership had `head` removed.
180179
self.assertNotIn(self.head_kind, old_membership.membership_type_ids)
181180

182-
def test_head_replacement_requires_confirmation(self):
183-
"""Making the new member head while the group already has one is blocked
184-
until 'Replace current Head of Household' is enabled (OP#871 QA round 1)."""
185-
if not self.head_kind:
186-
self.skipTest("head membership-type code not present in the vocabulary")
187-
old_head = self.partner_model.create({"name": "Seated Head", "is_registrant": True, "is_group": False})
188-
self.membership_model.create(
189-
{
190-
"group": self.group.id,
191-
"individual": old_head.id,
192-
"start_date": "2020-01-01",
193-
"membership_type_ids": [Command.link(self.head_kind.id)],
194-
}
195-
)
196-
# Head role picked but replacement NOT confirmed → blocked on apply.
197-
cr = self._make_cr(given_name="No", family_name="Confirm", membership_type_id=self.head_kind.id)
198-
self.assertTrue(cr.get_detail().group_has_head)
199-
cr.approval_state = "approved"
200-
with self.assertRaises(UserError) as cm:
201-
cr.action_apply()
202-
self.assertIn("already has a head of household", str(cm.exception).lower())
203-
204-
def test_replace_toggle_ignored_when_role_not_head(self):
205-
"""A stale replace toggle must not make a non-head member the head, nor
206-
demote the existing head, when the picked role isn't Head (OP#871)."""
181+
def test_non_head_role_leaves_existing_head(self):
182+
"""Adding a non-head member must not touch the group's existing head."""
207183
if not self.head_kind or not self.member_kind:
208184
self.skipTest("head/member membership-type codes not present")
209185
old_head = self.partner_model.create({"name": "Keep Head", "is_registrant": True, "is_group": False})
@@ -215,16 +191,13 @@ def test_replace_toggle_ignored_when_role_not_head(self):
215191
"membership_type_ids": [Command.link(self.head_kind.id)],
216192
}
217193
)
218-
cr = self._make_cr(
219-
given_name="Plain",
220-
family_name="Member",
221-
membership_type_id=self.member_kind.id,
222-
replace_existing_head=True, # stale toggle, role is not head
223-
)
224-
self.assertFalse(cr.get_detail().selected_role_is_head)
194+
cr = self._make_cr(given_name="Plain", family_name="Member", membership_type_id=self.member_kind.id)
195+
detail = cr.get_detail()
196+
self.assertTrue(detail.group_has_head)
197+
self.assertFalse(detail.selected_role_is_head) # drives the info banner visibility
225198
cr.approval_state = "approved"
226199
cr.action_apply()
227-
new_member = cr.get_detail().created_individual_id
200+
new_member = detail.created_individual_id
228201
new_membership = self.membership_model.search(
229202
[("group", "=", self.group.id), ("individual", "=", new_member.id)]
230203
)

spp_change_request_v2/views/detail_add_member_views.xml

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -175,33 +175,26 @@
175175
>Head</em> before applying.
176176
</div>
177177

178-
<!-- Head-of-household replacement (OP#871 QA round 1):
179-
only surfaced when the group already has a head. -->
178+
<!-- Head-of-household replacement notice (OP#871 QA round 1):
179+
shown only when Role is Head and the group already has one. -->
180180
<field name="group_has_head" invisible="1" />
181181
<field name="selected_role_is_head" invisible="1" />
182182
<div
183-
class="alert alert-info"
183+
class="alert alert-warning"
184184
role="alert"
185185
invisible="not group_has_head or not selected_role_is_head"
186186
>
187-
<i class="fa fa-info-circle me-2" />
187+
<i class="fa fa-exclamation-triangle me-2" />
188188
This group already has a Head of Household
189189
(<field
190190
name="current_head_name"
191191
readonly="1"
192192
nolabel="1"
193193
class="d-inline"
194194
/>).
195-
Enable <strong
196-
>Replace current Head of Household</strong> to make
197-
this new member the head instead — the current head loses the Head
198-
role when this change request is applied.
195+
Applying this change request will make this new member the Head and
196+
remove the Head role from the current head.
199197
</div>
200-
<group
201-
invisible="not group_has_head or not selected_role_is_head"
202-
>
203-
<field name="replace_existing_head" />
204-
</group>
205198

206199
<separator string="Existing members (read-only)" />
207200
<field

0 commit comments

Comments
 (0)