Skip to content

Commit cc53652

Browse files
committed
Change the extracting latest available year data logic
1 parent 3012ff9 commit cc53652

File tree

4 files changed

+540
-453
lines changed

4 files changed

+540
-453
lines changed

databank/admin.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,17 @@ class CountryOverviewAdmin(admin.ModelAdmin):
9999
{
100100
"fields": (
101101
"fdrs_income",
102+
"fdrs_income_data_year",
102103
"fdrs_expenditures",
104+
"fdrs_expenditures_data_year",
103105
"fdrs_volunteer_total",
106+
"fdrs_volunteer_data_year",
107+
"fdrs_staff_total",
108+
"fdrs_staff_data_year",
104109
"fdrs_trained_in_first_aid",
110+
"fdrs_trained_in_first_aid_data_year",
105111
"fdrs_branches",
112+
"fdrs_branches_data_year",
106113
),
107114
},
108115
),

databank/management/commands/ingest_databank.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,21 @@
99
from databank.models import CountryOverview
1010
from main.sentry import SentryMonitor
1111

12-
from .sources import FDRS
12+
from .sources import FDRS, FTS_HPC, INFORM, RELIEFWEB, START_NETWORK, WB
1313

1414
logger = logging.getLogger(__name__)
1515

16-
SOURCES = [(s, s.__name__.split(".")[-1]) for s in (FDRS,)]
16+
SOURCES = [
17+
(s, s.__name__.split(".")[-1])
18+
for s in (
19+
FDRS,
20+
FTS_HPC,
21+
INFORM,
22+
RELIEFWEB,
23+
START_NETWORK,
24+
WB,
25+
)
26+
]
1727

1828

1929
class Command(BaseCommand):

databank/management/commands/sources/FDRS.py

Lines changed: 102 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from typing import List, Optional, Tuple
23

34
import requests
45
from django.conf import settings
@@ -85,7 +86,7 @@
8586
("KPI_PStaff_Tot_age_18_29", CO.fdrs_staff_age_18_29),
8687
)
8788
FDRS_INDICATORS = (
88-
[indicator for indicator in FDRS_INDICATORS_FIELD_MAP.keys()]
89+
list(FDRS_INDICATORS_FIELD_MAP.keys())
8990
+ [indicator for indicator, _ in FDRS_VOLUNTEERS_DISAGGREGATION_INDICATORS_FIELD_MAP]
9091
+ [indicator for indicator, _ in FDRS_STAFF_DISAGGREGATION_INDICATORS_FIELD_MAP]
9192
)
@@ -100,63 +101,117 @@
100101
)
101102

102103

103-
@catch_error("Error occured while fetching from FDRS API.")
104+
@catch_error("Error occurred while fetching from FDRS API.")
104105
def prefetch():
105-
fdrs_entities = requests.get(FDRS_NS_API_ENDPOINT)
106-
if fdrs_entities.status_code != 200:
107-
return
108-
fdrs_entities.raise_for_status()
109-
fdrs_entities = fdrs_entities.json()
110-
111-
ns_iso_map = {
112-
# ISO3 are missing for some in FDRS & IFRC-GO only have ISO2 for countries
113-
ns["KPI_DON_code"]: ns["iso_2"]
114-
for ns in fdrs_entities
115-
}
116-
117-
return (
118-
{
119-
# KEY <ISO2>-<Indicator_ID>: {year: '', value: ''}
120-
# NOTE: We are fetching the latest data for each indicators
121-
f"{ns_iso_map[ns_data['id']].upper()}-{indicator_data['id']}": (
122-
max(ns_data["data"], key=lambda x: x["year"]) if (ns_data["data"] and len(ns_data["data"]) > 0) else None
123-
)
124-
for indicator_data in requests.get(FDRS_DATA_API_ENDPOINT).json()["data"]
125-
for ns_data in indicator_data["data"]
126-
},
127-
len(ns_iso_map),
128-
FDRS_DATA_API_ENDPOINT,
106+
response = requests.get(FDRS_NS_API_ENDPOINT)
107+
response.raise_for_status()
108+
fdrs_entities = response.json()
109+
110+
ns_iso_map = {ns["KPI_DON_code"]: ns["iso_2"] for ns in fdrs_entities}
111+
112+
fdrs_data_response = requests.get(FDRS_DATA_API_ENDPOINT)
113+
fdrs_data_response.raise_for_status()
114+
fdrs_data = fdrs_data_response.json()["data"]
115+
116+
# Getting the latest available data for the indicators
117+
processed_fdrs_data = {}
118+
119+
for indictor_data in fdrs_data:
120+
indicator_id = indictor_data["id"]
121+
122+
for ns_data in indictor_data["data"]:
123+
ns_id = ns_data["id"]
124+
iso_code = ns_iso_map.get(ns_id)
125+
126+
if not iso_code:
127+
continue
128+
129+
latest_data_with_value = None
130+
for data in ns_data["data"]:
131+
if data.get("value"):
132+
if latest_data_with_value is None or int(data["year"]) > int(latest_data_with_value["year"]):
133+
latest_data_with_value = data
134+
135+
if latest_data_with_value:
136+
processed_fdrs_data[f"{iso_code}-{indicator_id}"] = latest_data_with_value
137+
138+
return (processed_fdrs_data, len(ns_iso_map), FDRS_DATA_API_ENDPOINT)
139+
140+
141+
def set_latest_year_data(
142+
disaggregation_map: List[Tuple[str, CO]],
143+
data_year_field: CO,
144+
latest_year: int,
145+
fdrs_data: dict,
146+
country_iso: str,
147+
overview: CO,
148+
) -> None:
149+
"""
150+
Set only the latest year data for volunteers or staff for the provided year
151+
"""
152+
for indicator, field in disaggregation_map:
153+
data = fdrs_data.get(f"{country_iso}-{indicator}")
154+
if data and int(data.get("year")) == latest_year:
155+
setattr(overview, field.field.name, data.get("value"))
156+
157+
# Set the year field for the data
158+
setattr(overview, data_year_field.field.name, latest_year)
159+
160+
161+
def get_latest_year_from_indicators(disaggregation_map: List[Tuple[str, CO]], fdrs_data: dict, country_iso: str) -> Optional[int]:
162+
"""
163+
Get the latest year across all indicators where the value field exists
164+
"""
165+
return max(
166+
(
167+
int(data["year"])
168+
for indicator, _ in disaggregation_map
169+
if (data := fdrs_data.get(f"{country_iso}-{indicator}")) and data.get("value")
170+
),
171+
default=None,
129172
)
130173

131174

132-
@catch_error()
175+
@catch_error("Error occurred while loading FDRS data.")
133176
def load(country, overview, fdrs_data):
134-
if country.iso is None or fdrs_data is None:
177+
if not country.iso or not fdrs_data:
135178
return
136179

180+
country_iso = country.iso.upper()
181+
182+
# Country Key Indicators
137183
for indicator, (field, year_field) in FDRS_INDICATORS_FIELD_MAP.items():
138-
data = fdrs_data.get(f"{country.iso.upper()}-{indicator}")
184+
data = fdrs_data.get(f"{country_iso}-{indicator}")
139185
if data:
140186
setattr(overview, field.field.name, data.get("value"))
141187
setattr(overview, year_field.field.name, data.get("year"))
142188

143-
def set_disaggregation_data(disaggregation_map, data_year_field):
144-
"""
145-
Set disaggregation data for volunteers or staff for the latest year
146-
"""
147-
latest_year = None
148-
for indicator, field in disaggregation_map:
149-
data = fdrs_data.get(f"{country.iso.upper()}-{indicator}")
150-
if data:
151-
year = data.get("year")
152-
if latest_year is None or (year and int(year) > latest_year):
153-
latest_year = int(year)
154-
setattr(overview, field.field.name, data.get("value"))
155-
setattr(overview, data_year_field.field.name, latest_year)
156-
157-
# Volunteer disaggregation
158-
set_disaggregation_data(FDRS_VOLUNTEERS_DISAGGREGATION_INDICATORS_FIELD_MAP, CO.fdrs_volunteer_data_year)
159-
# Staff disaggregation
160-
set_disaggregation_data(FDRS_STAFF_DISAGGREGATION_INDICATORS_FIELD_MAP, CO.fdrs_staff_data_year)
189+
# Volunteer disaggregation data
190+
latest_year = get_latest_year_from_indicators(
191+
disaggregation_map=FDRS_VOLUNTEERS_DISAGGREGATION_INDICATORS_FIELD_MAP, fdrs_data=fdrs_data, country_iso=country_iso
192+
)
193+
if latest_year:
194+
set_latest_year_data(
195+
disaggregation_map=FDRS_VOLUNTEERS_DISAGGREGATION_INDICATORS_FIELD_MAP,
196+
data_year_field=CO.fdrs_volunteer_data_year,
197+
latest_year=latest_year,
198+
fdrs_data=fdrs_data,
199+
country_iso=country_iso,
200+
overview=overview,
201+
)
202+
203+
# Staff disaggregation data
204+
latest_year = get_latest_year_from_indicators(
205+
disaggregation_map=FDRS_STAFF_DISAGGREGATION_INDICATORS_FIELD_MAP, fdrs_data=fdrs_data, country_iso=country_iso
206+
)
207+
if latest_year:
208+
set_latest_year_data(
209+
disaggregation_map=FDRS_STAFF_DISAGGREGATION_INDICATORS_FIELD_MAP,
210+
data_year_field=CO.fdrs_staff_data_year,
211+
latest_year=latest_year,
212+
fdrs_data=fdrs_data,
213+
country_iso=country_iso,
214+
overview=overview,
215+
)
161216

162217
overview.save()

0 commit comments

Comments
 (0)