Skip to content

Commit 85083f0

Browse files
authored
Update the property logic to use payload (#110)
* Update the property logic to use payload * Update benefits payload * move benefits data * Amend the payload to include income * Amend additional benefit ordering * Default to none * Add refactoring comment
1 parent 716e53e commit 85083f0

File tree

10 files changed

+168
-265
lines changed

10 files changed

+168
-265
lines changed

app/means_test/api.py

+75-61
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,10 @@
11
from app.api import cla_backend
22
from flask import session
33
from app.means_test.forms.income import IncomeForm
4-
from app.means_test.forms.property import PropertiesPayload
4+
from app.means_test.forms.benefits import BenefitsForm, AdditionalBenefitsForm
5+
from app.means_test.forms.property import MultiplePropertiesForm
56
from app.means_test.money_interval import MoneyInterval
67
from tests.unit_tests.means_test.payload.test_cases import EligibilityData
7-
from app.means_test.data import BenefitsData, AdditionalBenefitData
8-
9-
10-
def deep_update(original, updates):
11-
"""
12-
Recursively updates a nested dictionary with values from another dictionary.
13-
Only updates keys present in the `updates` dictionary.
14-
"""
15-
for key, value in updates.items():
16-
if (
17-
isinstance(value, dict)
18-
and key in original
19-
and isinstance(original[key], dict)
20-
):
21-
deep_update(original[key], value) # Recursive call for nested dict
22-
else:
23-
original[key] = value
248

259

2610
def update_means_test(payload):
@@ -47,15 +31,7 @@ def is_eligible(reference):
4731

4832
def get_means_test_payload(eligibility_data: EligibilityData) -> dict:
4933
about = eligibility_data.forms.get("about-you", {})
50-
51-
income_form = eligibility_data.forms.get("income", {})
5234
savings_form = eligibility_data.forms.get("savings", {})
53-
property_form = eligibility_data.forms.get("property", {})
54-
benefits = BenefitsData(**eligibility_data.forms.get("benefits", {})).to_payload()
55-
56-
additional_benefits = AdditionalBenefitData(
57-
**eligibility_data.forms.get("additional-benefits", {})
58-
).to_payload()
5935

6036
has_partner = eligibility_data.forms.get("about-you", {}).get(
6137
"has_partner", False
@@ -65,41 +41,51 @@ def get_means_test_payload(eligibility_data: EligibilityData) -> dict:
6541
is_partner_employed = about.get("is_partner_employed", None)
6642
is_partner_self_employed = about.get("is_partner_self_employed", None)
6743

68-
income_data: dict[str, dict] = IncomeForm(**income_form).get_payload(
44+
# The below data code needs refactoring to only take in eligibility_data
45+
benefits_data = BenefitsForm.get_payload(eligibility_data.forms.get("benefits", {}))
46+
additional_benefits_data = AdditionalBenefitsForm.get_payload(
47+
eligibility_data.forms.get("additional-benefits", {})
48+
)
49+
income_data = IncomeForm(**eligibility_data.forms.get("income", {})).get_payload(
6950
employed=is_employed,
7051
self_employed=is_self_employed,
7152
partner_employed=is_partner_employed,
7253
partner_self_employed=is_partner_self_employed,
7354
)
74-
75-
you_income = income_data.get("you", {}).get("income", {})
76-
you_income.update(
77-
{
78-
"benefits": additional_benefits["benefits"],
79-
"child_benefits": benefits["child_benefits"],
80-
}
81-
)
82-
partner_income = income_data.get("partner", {}).get("income", {})
83-
partner_income.update(
84-
{
85-
"benefits": additional_benefits["benefits"],
86-
"child_benefits": benefits["child_benefits"],
87-
}
55+
property_data = MultiplePropertiesForm.get_payload(
56+
eligibility_data.forms.get("property", {})
8857
)
8958

90-
# Remove rent field from property set and setup payload
91-
if eligibility_data.forms.get("about-you", {}).get("own_property"):
92-
property_payload = PropertiesPayload(property_form)
93-
for property_item in property_payload.get("property_set", []):
94-
property_item.pop("rent", None)
59+
# Sums rent to the other income field for you
60+
other_income = MoneyInterval(
61+
property_data.get("you").get("income", {}).get("other_income", 0)
62+
) + income_data.get("you").get("income", {}).get("other_income", 0)
9563

9664
payload = {
9765
"category": eligibility_data.category,
9866
"your_problem_notes": "",
9967
"notes": "",
100-
"property_set": [],
68+
"property_set": property_data.get("property_set"),
10169
"you": {
102-
"income": you_income,
70+
"income": {
71+
"earnings": income_data.get("you", {})
72+
.get("income", {})
73+
.get("earnings"),
74+
"self_employment_drawings": income_data.get("you", {})
75+
.get("income", {})
76+
.get("self_employment_drawings"),
77+
"tax_credits": income_data.get("you", {})
78+
.get("income", {})
79+
.get("tax_credits"),
80+
"maintenance_received": income_data.get("you", {})
81+
.get("income", {})
82+
.get("maintenance_received"),
83+
"pension": income_data.get("you", {}).get("income", {}).get("pension"),
84+
"other_income": other_income,
85+
"self_employed": is_self_employed,
86+
"benefits": additional_benefits_data.get("benefits"),
87+
"child_benefits": benefits_data.get("child_benefits"),
88+
},
10389
"savings": {
10490
"bank_balance": savings_form.get("savings", 0),
10591
"investment_balance": savings_form.get("investments", 0),
@@ -121,10 +107,7 @@ def get_means_test_payload(eligibility_data: EligibilityData) -> dict:
121107
"per_interval_value": None,
122108
"interval_period": "per_month",
123109
},
124-
"mortgage": {
125-
"per_interval_value": None,
126-
"interval_period": "per_month",
127-
},
110+
"mortgage": property_data.get("deductions", {}).get("mortgage", {}),
128111
"rent": {
129112
"per_interval_value": None,
130113
"interval_period": "per_month",
@@ -133,8 +116,43 @@ def get_means_test_payload(eligibility_data: EligibilityData) -> dict:
133116
},
134117
},
135118
"partner": {
136-
"income": partner_income,
137-
# Question: Should partner savings be included in the payload, assuming they are always 0.
119+
"income": {
120+
"earnings": income_data.get("partner", {})
121+
.get("income", {})
122+
.get("earnings"),
123+
"self_employment_drawings": income_data.get("partner", {})
124+
.get("income", {})
125+
.get("self_employment_drawings"),
126+
"tax_credits": income_data.get("partner", {})
127+
.get("income", {})
128+
.get("tax_credits"),
129+
"maintenance_received": income_data.get("partner", {})
130+
.get("income", {})
131+
.get("maintenance_received"),
132+
"pension": income_data.get("partner", {})
133+
.get("income", {})
134+
.get("pension"),
135+
"other_income": income_data.get("partner", {})
136+
.get("income", {})
137+
.get("other_income"),
138+
"self_employed": "0",
139+
"benefits": {
140+
"per_interval_value": 0,
141+
"per_interval_value_pounds": None,
142+
"interval_period": "per_month",
143+
},
144+
"child_benefits": {
145+
"per_interval_value": 0,
146+
"per_interval_value_pounds": None,
147+
"interval_period": "per_month",
148+
},
149+
},
150+
"savings": {
151+
"bank_balance": None,
152+
"investment_balance": None,
153+
"asset_balance": None,
154+
"credit_balance": None,
155+
},
138156
"deductions": {
139157
"income_tax": income_data.get("partner", {})
140158
.get("deductions", {})
@@ -169,16 +187,12 @@ def get_means_test_payload(eligibility_data: EligibilityData) -> dict:
169187
else 0,
170188
"is_you_or_your_partner_over_60": about.get("aged_60_or_over", False),
171189
"has_partner": has_partner,
172-
"on_passported_benefits": benefits["on_passported_benefits"],
173-
"on_nass_benefits": additional_benefits["on_nass_benefits"],
174-
"specific_benefits": benefits["specific_benefits"],
190+
"on_passported_benefits": benefits_data["on_passported_benefits"],
191+
"on_nass_benefits": additional_benefits_data["on_nass_benefits"],
192+
"specific_benefits": benefits_data["specific_benefits"],
175193
"disregards": [],
176194
}
177195

178-
# Add in the property payload
179-
if eligibility_data.forms.get("about-you", {}).get("own_property"):
180-
deep_update(payload, property_payload)
181-
182196
if not has_partner:
183197
del payload["partner"]
184198

app/means_test/data.py

-68
This file was deleted.

app/means_test/forms/benefits.py

+77-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,51 @@
1111
ValidateIf,
1212
ValidateIfType,
1313
)
14-
from app.means_test.data import BenefitsData
1514
from app.means_test import YES, NO
1615

16+
from dataclasses import dataclass, field
17+
18+
19+
@dataclass
20+
class BenefitsData:
21+
BENEFITS_CHOICES = [
22+
("child_benefit", _("Child Benefit")),
23+
("pension_credit", _("Guarantee Credit")),
24+
("income_support", _("Income Support")),
25+
("job_seekers_allowance", _("Income-based Jobseeker's Allowance")),
26+
("employment_support", _("Income-related Employment and Support Allowance")),
27+
("universal_credit", _("Universal Credit")),
28+
("other-benefit", _("Any other benefits")),
29+
]
30+
benefits: list = field(default_factory=list)
31+
child_benefits: dict = field(default_factory=dict)
32+
33+
@property
34+
def passported_benefits(self):
35+
others = ["child_benefit", "other-benefit"]
36+
return [name for name, label in self.BENEFITS_CHOICES if name not in others]
37+
38+
@property
39+
def specific_benefits(self):
40+
return {
41+
"pension_credit": "pension_credit" in self.benefits,
42+
"job_seekers_allowance": "job_seekers_allowance" in self.benefits,
43+
"employment_support": "employment_support" in self.benefits,
44+
"universal_credit": "universal_credit" in self.benefits,
45+
"income_support": "income_support" in self.benefits,
46+
}
47+
48+
@property
49+
def is_passported(self) -> bool:
50+
return bool(set(self.benefits).intersection(self.passported_benefits))
51+
52+
53+
@dataclass
54+
class AdditionalBenefitData:
55+
benefits: list = field(default_factory=list)
56+
other_benefits: list = field(default_factory=list)
57+
total_other_benefit: dict = field(default_factory=dict)
58+
1759

1860
def get_benefits_choices():
1961
choices = BenefitsData.BENEFITS_CHOICES.copy()
@@ -81,6 +123,27 @@ def data(self):
81123
def should_show(cls) -> bool:
82124
return session.get("eligibility").on_benefits
83125

126+
def get_payload(self) -> dict:
127+
"""Returns the benefits payload for the user and the partner.
128+
If a field can not be found the default of MoneyField(0) will be used.
129+
"""
130+
payload = {
131+
"specific_benefits": {
132+
"pension_credit": "pension_credit" in self.get("benefits", []),
133+
"job_seekers_allowance": "job_seekers_allowance"
134+
in self.get("benefits", []),
135+
"employment_support": "employment_support" in self.get("benefits", []),
136+
"universal_credit": "universal_credit" in self.get("benefits", []),
137+
"income_support": "income_support" in self.get("benefits", []),
138+
},
139+
"on_passported_benefits": session.get(
140+
"eligibility"
141+
).has_passported_benefits,
142+
"child_benefits": self.get("child_benefits", {}),
143+
}
144+
145+
return payload
146+
84147

85148
class AdditionalBenefitsForm(BaseMeansTestForm):
86149
title = _("Your additional benefits")
@@ -164,3 +227,16 @@ def data(self):
164227
def should_show(cls) -> bool:
165228
data = session.get("eligibility").forms.get("benefits")
166229
return data and "other-benefit" in data["benefits"]
230+
231+
def get_payload(
232+
self,
233+
) -> dict:
234+
"""Returns the additional benefits payload for the user and the partner.
235+
If a field can not be found the default of MoneyField(0) will be used.
236+
"""
237+
payload = {
238+
"on_nass_benefits": False,
239+
"benefits": self.get("total_other_benefit"),
240+
}
241+
242+
return payload

app/means_test/forms/income.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,7 @@ def get_payload(
430430
self.data.get("maintenance_received", 0)
431431
),
432432
"pension": MoneyInterval(self.data.get("pension", 0)),
433-
"other_income": MoneyInterval(
434-
self.data.get("other_income", 0)
435-
), # TODO: Add income from rent here
433+
"other_income": MoneyInterval(self.data.get("other_income", 0)),
436434
"self_employed": self_employed,
437435
},
438436
"deductions": {

app/means_test/forms/property.py

+11
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,14 @@ def should_show(cls) -> bool:
238238
)
239239

240240
template = "means_test/property.html"
241+
242+
def get_payload(
243+
self,
244+
has_property: bool | None = False,
245+
) -> dict:
246+
"""Returns the property payload for the user and the partner.
247+
If a field can not be found the default of MoneyField(0) will be used.
248+
"""
249+
payload = PropertiesPayload(self)
250+
251+
return payload

app/means_test/views.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ class MeansTest(View):
1515
forms = {
1616
"about-you": AboutYouForm,
1717
"benefits": BenefitsForm,
18-
"property": MultiplePropertiesForm,
1918
"additional-benefits": AdditionalBenefitsForm,
19+
"property": MultiplePropertiesForm,
2020
"savings": SavingsForm,
2121
"income": IncomeForm,
2222
}

tests/unit_tests/means_test/data/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)