11from collections import defaultdict
22
33from django .db .models import Count , Exists , OuterRef , Sum
4+ from django .db .models .functions import Coalesce
45
56from conferences .models .conference import Conference
67from countries import countries
@@ -26,10 +27,12 @@ def calculate(self, conference_id):
2627 """
2728 statuses = Grant .Status .choices
2829 conference = Conference .objects .get (id = conference_id )
29- filtered_grants = Grant .objects .for_conference (conference )
30+ filtered_grants = Grant .objects .for_conference (conference ).annotate (
31+ effective_status = Coalesce ("pending_status" , "status" )
32+ )
3033
3134 grants_by_country = filtered_grants .values (
32- "departure_country" , "pending_status "
35+ "departure_country" , "effective_status "
3336 ).annotate (total = Count ("id" ))
3437
3538 (
@@ -99,6 +102,7 @@ def _aggregate_data_by_country(self, grants_by_country, statuses):
99102 totals_per_continent = {}
100103
101104 for data in grants_by_country :
105+ effective_status : str = data ["effective_status" ]
102106 country = countries .get (code = data ["departure_country" ])
103107 continent = country .continent .name if country else "Unknown"
104108 country_name = f"{ country .name } { country .emoji } " if country else "Unknown"
@@ -108,13 +112,13 @@ def _aggregate_data_by_country(self, grants_by_country, statuses):
108112 if key not in summary :
109113 summary [key ] = {status [0 ]: 0 for status in statuses }
110114
111- summary [key ][data [ "pending_status" ] ] += data ["total" ]
112- status_totals [data [ "pending_status" ] ] += data ["total" ]
115+ summary [key ][effective_status ] += data ["total" ]
116+ status_totals [effective_status ] += data ["total" ]
113117
114118 # Update continent totals
115119 if continent not in totals_per_continent :
116120 totals_per_continent [continent ] = {status [0 ]: 0 for status in statuses }
117- totals_per_continent [continent ][data [ "pending_status" ] ] += data ["total" ]
121+ totals_per_continent [continent ][effective_status ] += data ["total" ]
118122
119123 return summary , status_totals , totals_per_continent
120124
@@ -123,34 +127,34 @@ def _aggregate_data_by_country_type(self, filtered_grants, statuses):
123127 Aggregates grant data by country type and status.
124128 """
125129 country_type_data = filtered_grants .values (
126- "country_type" , "pending_status "
130+ "country_type" , "effective_status "
127131 ).annotate (total = Count ("id" ))
128132 country_type_summary = defaultdict (
129133 lambda : {status [0 ]: 0 for status in statuses }
130134 )
131135
132136 for data in country_type_data :
133137 country_type = data ["country_type" ]
134- pending_status = data ["pending_status " ]
138+ effective_status : str = data ["effective_status " ]
135139 total = data ["total" ]
136- country_type_summary [country_type ][pending_status ] += total
140+ country_type_summary [country_type ][effective_status ] += total
137141
138142 return dict (country_type_summary )
139143
140144 def _aggregate_data_by_gender (self , filtered_grants , statuses ):
141145 """
142146 Aggregates grant data by gender and status.
143147 """
144- gender_data = filtered_grants .values ("gender" , "pending_status " ).annotate (
148+ gender_data = filtered_grants .values ("gender" , "effective_status " ).annotate (
145149 total = Count ("id" )
146150 )
147151 gender_summary = defaultdict (lambda : {status [0 ]: 0 for status in statuses })
148152
149153 for data in gender_data :
150154 gender = data ["gender" ] if data ["gender" ] else ""
151- pending_status = data ["pending_status " ]
155+ effective_status : str = data ["effective_status " ]
152156 total = data ["total" ]
153- gender_summary [gender ][pending_status ] += total
157+ gender_summary [gender ][effective_status ] += total
154158
155159 return dict (gender_summary )
156160
@@ -162,7 +166,7 @@ def _aggregate_financial_data_by_status(self, filtered_grants, statuses):
162166 overall_total = 0
163167
164168 for status in statuses :
165- grants_for_status = filtered_grants .filter (pending_status = status [0 ])
169+ grants_for_status = filtered_grants .filter (effective_status = status [0 ])
166170 reimbursements = GrantReimbursement .objects .filter (
167171 grant__in = grants_for_status
168172 )
@@ -178,28 +182,30 @@ def _aggregate_data_by_reimbursement_category(self, filtered_grants, statuses):
178182 Aggregates grant data by reimbursement category and status.
179183 """
180184 category_summary = defaultdict (lambda : {status [0 ]: 0 for status in statuses })
181- reimbursements = GrantReimbursement .objects .filter (grant__in = filtered_grants )
185+ reimbursements = GrantReimbursement .objects .filter (
186+ grant__in = filtered_grants
187+ ).select_related ("grant" , "category" )
182188 for r in reimbursements :
189+ effective_status : str = r .grant .current_or_pending_status
183190 category = r .category .category
184- status = r .grant .pending_status
185- category_summary [category ][status ] += 1
191+ category_summary [category ][effective_status ] += 1
186192 return dict (category_summary )
187193
188194 def _aggregate_data_by_grant_type (self , filtered_grants , statuses ):
189195 """
190196 Aggregates grant data by grant_type and status.
191197 """
192198 grant_type_data = filtered_grants .values (
193- "grant_type" , "pending_status "
199+ "grant_type" , "effective_status "
194200 ).annotate (total = Count ("id" ))
195201 grant_type_summary = defaultdict (lambda : {status [0 ]: 0 for status in statuses })
196202
197203 for data in grant_type_data :
198204 grant_types = data ["grant_type" ]
199- pending_status = data ["pending_status " ]
205+ effective_status : str = data ["effective_status " ]
200206 total = data ["total" ]
201207 for grant_type in grant_types :
202- grant_type_summary [grant_type ][pending_status ] += total
208+ grant_type_summary [grant_type ][effective_status ] += total
203209
204210 return dict (grant_type_summary )
205211
@@ -224,13 +230,13 @@ def _aggregate_data_by_speaker_status(self, filtered_grants, statuses):
224230
225231 proposed_speaker_data = (
226232 filtered_grants .filter (is_proposed_speaker = True )
227- .values ("pending_status " )
233+ .values ("effective_status " )
228234 .annotate (total = Count ("id" ))
229235 )
230236
231237 confirmed_speaker_data = (
232238 filtered_grants .filter (is_confirmed_speaker = True )
233- .values ("pending_status " )
239+ .values ("effective_status " )
234240 .annotate (total = Count ("id" ))
235241 )
236242
@@ -239,14 +245,16 @@ def _aggregate_data_by_speaker_status(self, filtered_grants, statuses):
239245 )
240246
241247 for data in proposed_speaker_data :
242- pending_status = data ["pending_status " ]
248+ effective_status : str = data ["effective_status " ]
243249 total = data ["total" ]
244- speaker_status_summary ["proposed_speaker" ][pending_status ] += total
250+ speaker_status_summary ["proposed_speaker" ][effective_status ] += total
245251
246252 for data in confirmed_speaker_data :
247- pending_status = data ["pending_status " ]
253+ effective_status_confirmed : str = data ["effective_status " ]
248254 total = data ["total" ]
249- speaker_status_summary ["confirmed_speaker" ][pending_status ] += total
255+ speaker_status_summary ["confirmed_speaker" ][effective_status_confirmed ] += (
256+ total
257+ )
250258
251259 return dict (speaker_status_summary )
252260
@@ -263,13 +271,13 @@ def _aggregate_data_by_requested_needs_summary(self, filtered_grants, statuses):
263271 for field in requested_needs_summary .keys ():
264272 field_data = (
265273 filtered_grants .filter (** {field : True })
266- .values ("pending_status " )
274+ .values ("effective_status " )
267275 .annotate (total = Count ("id" ))
268276 )
269277 for data in field_data :
270- pending_status = data ["pending_status " ]
278+ effective_status : str = data ["effective_status " ]
271279 total = data ["total" ]
272- requested_needs_summary [field ][pending_status ] += total
280+ requested_needs_summary [field ][effective_status ] += total
273281
274282 return requested_needs_summary
275283
@@ -278,14 +286,14 @@ def _aggregate_data_by_occupation(self, filtered_grants, statuses):
278286 Aggregates grant data by occupation and status.
279287 """
280288 occupation_data = filtered_grants .values (
281- "occupation" , "pending_status "
289+ "occupation" , "effective_status "
282290 ).annotate (total = Count ("id" ))
283291 occupation_summary = defaultdict (lambda : {status [0 ]: 0 for status in statuses })
284292
285293 for data in occupation_data :
286294 occupation = data ["occupation" ]
287- pending_status = data ["pending_status " ]
295+ effective_status : str = data ["effective_status " ]
288296 total = data ["total" ]
289- occupation_summary [occupation ][pending_status ] += total
297+ occupation_summary [occupation ][effective_status ] += total
290298
291299 return dict (occupation_summary )
0 commit comments