Skip to content

Commit

Permalink
IA-2456 quarterlyNov backend
Browse files Browse the repository at this point in the history
  • Loading branch information
mestachs committed Dec 20, 2024
1 parent 91c977e commit dcf36ad
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
2 changes: 1 addition & 1 deletion iaso/api/instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

class InstanceSerializer(serializers.ModelSerializer):
org_unit = serializers.PrimaryKeyRelatedField(queryset=OrgUnit.objects.all())
period = serializers.CharField(max_length=8, allow_blank=True)
period = serializers.CharField(max_length=9, allow_blank=True)

class Meta:
model = Instance
Expand Down
1 change: 1 addition & 0 deletions iaso/models/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class Form(SoftDeletableModel):
(periods.PERIOD_TYPE_DAY, _("Day")),
(periods.PERIOD_TYPE_MONTH, _("Month")),
(periods.PERIOD_TYPE_QUARTER, _("Quarter")),
(periods.PERIOD_TYPE_QUARTER_NOV, _("Quarter Nov")),
(periods.PERIOD_TYPE_SIX_MONTH, _("Six-month")),
(periods.PERIOD_TYPE_YEAR, _("Year")),
)
Expand Down
45 changes: 45 additions & 0 deletions iaso/periods.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
PERIOD_TYPE_DAY = "DAY"
PERIOD_TYPE_MONTH = "MONTH"
PERIOD_TYPE_QUARTER = "QUARTER"
PERIOD_TYPE_QUARTER_NOV = "QUARTER_NOV"
PERIOD_TYPE_SIX_MONTH = "SIX_MONTH"
PERIOD_TYPE_YEAR = "YEAR"

Expand All @@ -12,6 +13,9 @@ def detect(dhis2_period: str):
if len(dhis2_period) == 4:
return PERIOD_TYPE_YEAR

if "NovQ" in dhis2_period:
return PERIOD_TYPE_QUARTER_NOV

if "Q" in dhis2_period:
return PERIOD_TYPE_QUARTER

Expand All @@ -38,6 +42,8 @@ def from_string(period_string):
return MonthPeriod(period_string)
elif period_type == PERIOD_TYPE_QUARTER:
return QuarterPeriod(period_string)
elif period_type == PERIOD_TYPE_QUARTER_NOV:
return QuarterNovPeriod(period_string)
elif period_type == PERIOD_TYPE_SIX_MONTH:
return SemesterPeriod(period_string)
elif period_type == PERIOD_TYPE_DAY:
Expand Down Expand Up @@ -125,6 +131,8 @@ def range_period_to(self, other: "Period"):

QUARTER_TO_MONTHS = {1: [1, 2, 3], 2: [4, 5, 6], 3: [7, 8, 9], 4: [10, 11, 12]}

QUARTER_NOV_TO_MONTHS = {1: [11, 12, 1], 2: [2, 3, 4], 3: [5, 6, 7], 4: [8, 9, 10]}


class QuarterPeriod(Period):
LOWER_BOUND = "2000Q1"
Expand Down Expand Up @@ -161,6 +169,43 @@ def start_date(self):
return date(year=year, month=month, day=1)


class QuarterNovPeriod(Period):
LOWER_BOUND = "2000NovQ1"
HIGHER_BOUND = "2030NovQ4"

@staticmethod
def from_parts(year, quarter):
return QuarterNovPeriod(f"{year:04}NovQ{quarter}")

@property
def parts(self):
year, quarter = self.value.split("NovQ")
quarter = int(quarter)
year = int(year)
return year, quarter

def next_period(self):
year, quarter = self.parts
if quarter >= 4:
n_year = year + 1
n_quarter = 1
else:
n_quarter = quarter + 1
n_year = year
return QuarterNovPeriod.from_parts(n_year, n_quarter)

def gen_sub_periods(self):
year, quarter = self.parts
return [MonthPeriod.from_parts(year, month) for month in QUARTER_NOV_TO_MONTHS[quarter]]

def start_date(self):
year, quarter = self.parts
month = QUARTER_NOV_TO_MONTHS[quarter][0]
if quarter == 1:
year = year - 1
return date(year=year, month=month, day=1)


class YearPeriod(Period):
LOWER_BOUND = "2000"
HIGHER_BOUND = "2030"
Expand Down
37 changes: 36 additions & 1 deletion iaso/tests/test_periods.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime
from unittest import TestCase

from iaso.periods import QuarterPeriod, MonthPeriod, YearPeriod, SemesterPeriod, Period
from iaso.periods import QuarterPeriod, MonthPeriod, YearPeriod, SemesterPeriod, Period, QuarterNovPeriod


class PeriodTests(TestCase):
Expand Down Expand Up @@ -39,6 +39,7 @@ def test_semester(self):
)

def test_detection(self):
self.assertEqual(type(Period.from_string("2021NovQ2")), QuarterNovPeriod)
self.assertEqual(type(Period.from_string("2021Q2")), QuarterPeriod)
self.assertEqual(type(Period.from_string("2021")), YearPeriod)
self.assertEqual(type(Period.from_string("202102")), MonthPeriod)
Expand Down Expand Up @@ -136,6 +137,10 @@ def test_start_date(self):
["2024Q2", "2024-04-01"],
["2024Q3", "2024-07-01"],
["2024Q4", "2024-10-01"],
["2016NovQ1", "2015-11-01"],
["2016NovQ2", "2016-02-01"],
["2016NovQ3", "2016-05-01"],
["2016NovQ4", "2016-08-01"],
["2024S1", "2024-01-01"],
["2024S2", "2024-07-01"],
["202403", "2024-03-01"],
Expand All @@ -147,3 +152,33 @@ def test_start_date(self):
dhis2_period = Period.from_string(data[0])
start_date = dhis2_period.start_date().strftime("%Y-%m-%d")
self.assertEqual(start_date, data[1], data[0] + " to formatted start date " + start_date + " vs " + data[1])

def test_quarterly_nov_range_period_to(self):
calculated_periods = [
str(x) for x in QuarterNovPeriod("2018NovQ1").range_period_to(QuarterNovPeriod("2021NovQ1"))
]
expected_periods = [
"2018NovQ1",
"2018NovQ2",
"2018NovQ3",
"2018NovQ4",
"2019NovQ1",
"2019NovQ2",
"2019NovQ3",
"2019NovQ4",
"2020NovQ1",
"2020NovQ2",
"2020NovQ3",
"2020NovQ4",
"2021NovQ1",
]

self.assertEqual(calculated_periods, expected_periods)

def test_quarterly_nov_range_string_with_sub_periods(self):
from_period, to_period = Period.bound_range("2021NovQ1", "2021NovQ2")
calculated_periods = Period.range_string_with_sub_periods(from_period, to_period)

self.assertEqual(
calculated_periods, ["2021NovQ1", "2021NovQ2", "202111", "202112", "202101", "202102", "202103", "202104"]
)

0 comments on commit dcf36ad

Please sign in to comment.