Skip to content

Commit 3620149

Browse files
authored
Merge pull request #137 from FEWS-NET/HEA-596/Relax-mandatory-field-requirements-for-some-LivelihoodActivity-subclasses
Hea 596/relax mandatory field requirements for some livelihood activity subclasses
2 parents ede1d27 + cc36228 commit 3620149

File tree

3 files changed

+435
-43
lines changed

3 files changed

+435
-43
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Generated by Django 5.1.1 on 2024-11-29 01:26
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("baseline", "0018_alter_livelihoodactivity_price_and_more"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="foodpurchase",
15+
name="times_per_year",
16+
field=models.PositiveSmallIntegerField(
17+
blank=True,
18+
help_text="Number of times in a year that the purchase is made",
19+
null=True,
20+
verbose_name="Times per year",
21+
),
22+
),
23+
migrations.AlterField(
24+
model_name="foodpurchase",
25+
name="unit_multiple",
26+
field=models.PositiveSmallIntegerField(
27+
blank=True,
28+
help_text="Multiple of the unit of measure in a single purchase",
29+
null=True,
30+
verbose_name="Unit Multiple",
31+
),
32+
),
33+
migrations.AlterField(
34+
model_name="othercashincome",
35+
name="times_per_year",
36+
field=models.PositiveSmallIntegerField(
37+
blank=True,
38+
help_text="Number of times in a year that the income is received",
39+
null=True,
40+
verbose_name="Times per year",
41+
),
42+
),
43+
migrations.AlterField(
44+
model_name="otherpurchase",
45+
name="times_per_year",
46+
field=models.PositiveSmallIntegerField(
47+
blank=True,
48+
help_text="Number of times in a year that the product is purchased",
49+
null=True,
50+
verbose_name="Times per year",
51+
),
52+
),
53+
migrations.AlterField(
54+
model_name="paymentinkind",
55+
name="months_per_year",
56+
field=models.PositiveSmallIntegerField(
57+
blank=True,
58+
help_text="Number of months in a year that the labor is performed",
59+
null=True,
60+
verbose_name="Months per year",
61+
),
62+
),
63+
migrations.AlterField(
64+
model_name="paymentinkind",
65+
name="people_per_household",
66+
field=models.PositiveSmallIntegerField(
67+
blank=True,
68+
help_text="Number of household members who perform the labor",
69+
null=True,
70+
verbose_name="People per household",
71+
),
72+
),
73+
migrations.AlterField(
74+
model_name="paymentinkind",
75+
name="times_per_year",
76+
field=models.PositiveSmallIntegerField(
77+
blank=True,
78+
help_text="Number of times in a year that the labor is performed",
79+
null=True,
80+
verbose_name="Times per year",
81+
),
82+
),
83+
migrations.AlterField(
84+
model_name="reliefgiftother",
85+
name="times_per_year",
86+
field=models.PositiveSmallIntegerField(
87+
blank=True,
88+
help_text="Number of times in a year that the item is received",
89+
null=True,
90+
verbose_name="Times per year",
91+
),
92+
),
93+
migrations.AlterField(
94+
model_name="reliefgiftother",
95+
name="unit_multiple",
96+
field=models.PositiveSmallIntegerField(
97+
blank=True,
98+
help_text="Multiple of the unit of measure received each time",
99+
null=True,
100+
verbose_name="Unit Multiple",
101+
),
102+
),
103+
]

apps/baseline/models.py

Lines changed: 100 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,7 +1553,10 @@ class FoodPurchase(LivelihoodActivity):
15531553

15541554
# unit_multiple has names like wt_of_measure in the BSS.
15551555
unit_multiple = models.PositiveSmallIntegerField(
1556-
verbose_name=_("Unit Multiple"), help_text=_("Multiple of the unit of measure in a single purchase")
1556+
blank=True,
1557+
null=True,
1558+
verbose_name=_("Unit Multiple"),
1559+
help_text=_("Multiple of the unit of measure in a single purchase"),
15571560
)
15581561
# This is a float field because data may be captured as "once per week",
15591562
# which equates to "52 per year", which is "4.33 per month".
@@ -1565,17 +1568,25 @@ class FoodPurchase(LivelihoodActivity):
15651568
help_text=_("Number of months in a year that the product is purchased"),
15661569
)
15671570
times_per_year = models.PositiveSmallIntegerField(
1571+
blank=True,
1572+
null=True,
15681573
verbose_name=_("Times per year"),
15691574
help_text=_("Number of times in a year that the purchase is made"),
15701575
)
15711576

15721577
def validate_quantity_produced(self):
1573-
if self.quantity_produced != self.unit_multiple * self.times_per_month * self.months_per_year:
1574-
raise ValidationError(
1575-
_(
1576-
"Quantity produced for a Food Purchase must be purchase amount * purchases per month * months per year" # NOQA: E501
1578+
if (
1579+
self.quantity_produced is not None
1580+
and self.unit_multiple is not None
1581+
and self.times_per_month is not None
1582+
and self.months_per_year is not None
1583+
):
1584+
if self.quantity_produced != self.unit_multiple * self.times_per_month * self.months_per_year:
1585+
raise ValidationError(
1586+
_(
1587+
"Quantity produced for a Food Purchase must be purchase amount * purchases per month * months per year" # NOQA: E501
1588+
)
15771589
)
1578-
)
15791590

15801591
class Meta:
15811592
verbose_name = LivelihoodStrategyType.FOOD_PURCHASE.label
@@ -1598,15 +1609,23 @@ class PaymentInKind(LivelihoodActivity):
15981609
help_text=_("Amount of item received each time the labor is performed"),
15991610
)
16001611
people_per_household = models.PositiveSmallIntegerField(
1601-
verbose_name=_("People per household"), help_text=_("Number of household members who perform the labor")
1612+
blank=True,
1613+
null=True,
1614+
verbose_name=_("People per household"),
1615+
help_text=_("Number of household members who perform the labor"),
16021616
)
16031617
# This is a float field because data may be captured as "once per week",
16041618
# which equates to "52 per year", which is "4.33 per month".
16051619
times_per_month = models.FloatField(blank=True, null=True, verbose_name=_("Labor per month"))
16061620
months_per_year = models.PositiveSmallIntegerField(
1607-
verbose_name=_("Months per year"), help_text=_("Number of months in a year that the labor is performed")
1621+
blank=True,
1622+
null=True,
1623+
verbose_name=_("Months per year"),
1624+
help_text=_("Number of months in a year that the labor is performed"),
16081625
)
16091626
times_per_year = models.PositiveSmallIntegerField(
1627+
blank=True,
1628+
null=True,
16101629
verbose_name=_("Times per year"),
16111630
help_text=_("Number of times in a year that the labor is performed"),
16121631
)
@@ -1621,15 +1640,21 @@ def clean(self):
16211640

16221641
def validate_quantity_produced(self):
16231642
if (
1624-
self.quantity_produced
1625-
and self.quantity_produced
1626-
!= self.payment_per_time * self.people_per_household * self.times_per_month * self.months_per_year
1643+
self.quantity_produced is not None
1644+
and self.payment_per_time is not None
1645+
and self.people_per_household is not None
1646+
and self.times_per_month is not None
1647+
and self.months_per_year is not None
16271648
):
1628-
raise ValidationError(
1629-
_(
1630-
"Quantity produced for Payment In Kind must be payment per time * number of people * labor per month * months per year" # NOQA: E501
1649+
if (
1650+
self.quantity_produced
1651+
!= self.payment_per_time * self.people_per_household * self.times_per_month * self.months_per_year
1652+
):
1653+
raise ValidationError(
1654+
_(
1655+
"Quantity produced for Payment In Kind must be payment per time * number of people * labor per month * months per year" # NOQA: E501
1656+
)
16311657
)
1632-
)
16331658

16341659
class Meta:
16351660
verbose_name = LivelihoodStrategyType.PAYMENT_IN_KIND.label
@@ -1647,7 +1672,10 @@ class ReliefGiftOther(LivelihoodActivity):
16471672
# Production calculation /validation is `unit_of_measure * unit_multiple * times_per_year`
16481673
# Also used for the number of children receiving school meals.
16491674
unit_multiple = models.PositiveSmallIntegerField(
1650-
verbose_name=_("Unit Multiple"), help_text=_("Multiple of the unit of measure received each time")
1675+
blank=True,
1676+
null=True,
1677+
verbose_name=_("Unit Multiple"),
1678+
help_text=_("Multiple of the unit of measure received each time"),
16511679
)
16521680
# This is a float field because data may be captured as "once per week",
16531681
# which equates to "52 per year", which is "4.33 per month".
@@ -1661,14 +1689,18 @@ class ReliefGiftOther(LivelihoodActivity):
16611689
help_text=_("Number of months in a year that the item is received"),
16621690
)
16631691
times_per_year = models.PositiveSmallIntegerField(
1664-
verbose_name=_("Times per year"), help_text=_("Number of times in a year that the item is received")
1692+
blank=True,
1693+
null=True,
1694+
verbose_name=_("Times per year"),
1695+
help_text=_("Number of times in a year that the item is received"),
16651696
)
16661697

16671698
def validate_quantity_produced(self):
1668-
if self.quantity_produced != self.unit_multiple * self.times_per_year:
1669-
raise ValidationError(
1670-
_("Quantity produced for Relief, Gifts, Other must be amount received * times per year")
1671-
)
1699+
if self.quantity_produced is not None and self.unit_multiple is not None and self.times_per_year is not None:
1700+
if self.quantity_produced != self.unit_multiple * self.times_per_year:
1701+
raise ValidationError(
1702+
_("Quantity produced for Relief, Gifts, Other must be amount received * times per year")
1703+
)
16721704

16731705
class Meta:
16741706
verbose_name = LivelihoodStrategyType.RELIEF_GIFT_OTHER.label
@@ -1752,6 +1784,8 @@ class OtherCashIncome(LivelihoodActivity):
17521784
help_text=_("Number of months in a year that the labor is performed"),
17531785
)
17541786
times_per_year = models.PositiveSmallIntegerField(
1787+
blank=True,
1788+
null=True,
17551789
verbose_name=_("Times per year"),
17561790
help_text=_("Number of times in a year that the income is received"),
17571791
)
@@ -1766,19 +1800,24 @@ def clean(self):
17661800

17671801
def validate_income(self):
17681802
if (
1769-
self.people_per_household
1770-
and self.income
1771-
!= self.payment_per_time * self.people_per_household * self.times_per_month * self.months_per_year
1803+
self.people_per_household is not None
1804+
and self.income is not None
1805+
and self.payment_per_time is not None
1806+
and self.times_per_month is not None
1807+
and self.months_per_year is not None
17721808
):
1773-
raise ValidationError(
1774-
_(
1775-
"Quantity produced for Other Cash Income must be payment per time * number of people * labor per month * months per year" # NOQA: E501
1809+
if (
1810+
self.income
1811+
!= self.payment_per_time * self.people_per_household * self.times_per_month * self.months_per_year
1812+
):
1813+
raise ValidationError(
1814+
_(
1815+
"Quantity produced for Other Cash Income must be payment per time * number of people * labor per month * months per year" # NOQA: E501
1816+
)
17761817
)
1777-
)
1778-
if self.income != self.payment_per_time * self.times_per_year:
1779-
raise ValidationError(
1780-
_("Quantity produced for Other Cash Income must be payment per time * times per year")
1781-
)
1818+
if self.income is not None and self.payment_per_time is not None and self.times_per_year is not None:
1819+
if self.income != self.payment_per_time * self.times_per_year:
1820+
raise ValidationError(_("Income for 'Other Cash Income' must be payment per time * times per year"))
17821821

17831822
def calculate_fields(self):
17841823
self.times_per_year = self.people_per_household * self.times_per_month * self.months_per_year
@@ -1817,21 +1856,40 @@ class OtherPurchase(LivelihoodActivity):
18171856
help_text=_("Number of months in a year that the product is purchased"),
18181857
)
18191858
times_per_year = models.PositiveSmallIntegerField(
1859+
blank=True,
1860+
null=True,
18201861
verbose_name=_("Times per year"),
18211862
help_text=_("Number of times in a year that the product is purchased"),
18221863
)
18231864

18241865
def validate_expenditure(self):
1825-
if (
1826-
self.times_per_month
1827-
and self.months_per_year
1828-
and self.times_per_month * self.months_per_year != self.times_per_year
1829-
):
1830-
raise ValidationError(_("Times per year must be times per month * months per year"))
1831-
if self.expenditure != self.price * self.unit_multiple * self.times_per_year:
1832-
raise ValidationError(
1833-
_("Expenditure for Other Purchases must be price * unit multiple * purchases per year")
1834-
)
1866+
errors = []
1867+
if self.times_per_month is not None and self.months_per_year is not None:
1868+
expected_times_per_year = self.times_per_month * self.months_per_year
1869+
if self.times_per_year is not None and self.times_per_year != expected_times_per_year:
1870+
errors.append(
1871+
_(
1872+
"Times per year must be times per month * months per year. Expected: %(expected)s, Found: %(found)s"
1873+
)
1874+
% {
1875+
"expected": expected_times_per_year,
1876+
"found": self.times_per_year,
1877+
}
1878+
)
1879+
if self.price is not None and self.unit_multiple is not None and self.times_per_year is not None:
1880+
expected_expenditure = self.price * self.unit_multiple * self.times_per_year
1881+
if self.expenditure is not None and self.expenditure != expected_expenditure:
1882+
errors.append(
1883+
_(
1884+
"Expenditure for Other Purchases must be price * unit multiple * purchases per year. Expected: %(expected)s, Found: %(found)s"
1885+
)
1886+
% {
1887+
"expected": expected_expenditure,
1888+
"found": self.expenditure,
1889+
}
1890+
)
1891+
if errors:
1892+
raise ValidationError(errors)
18351893

18361894
class Meta:
18371895
verbose_name = LivelihoodStrategyType.OTHER_PURCHASE.label

0 commit comments

Comments
 (0)