Coverage for apps/summary_group/serializers.py : 88%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from django.db.models import Prefetch, Sum, Q
2from rest_framework import serializers
3from django.contrib.postgres.fields.jsonb import KeyTextTransform
4from django.db.models.functions import Cast
5from django.db import models
7from report.report_fields import LABELS
8from report.models import (
9 Report,
10 ProjectSOI,
11 RegisterChildByAgeAndGender,
12 PresenceAndParticipation,
13 ChildFamilyParticipation,
14 LanguagePeopleGroupDisability,
15 SupportPariticipationDetail,
17 MostVulnerableChildrenIndicator,
18 MostVulnerableChildrenVulnerabilityMarker,
19)
20from .models import SummaryGroup
23def _get_report_data(
24 increment_obj_field,
25 report,
26 child_monitoring,
27 health_nutrition,
28 correspondences,
29 education,
30 education_fields,
31 rc,
32):
34 if not report.data: 34 ↛ 35line 34 didn't jump to line 35, because the condition on line 34 was never true
35 return
37 data = report.data
38 date = report.date
39 for datum in data['childMonitoring']:
40 key = datum['key']
41 if key in child_monitoring:
42 increment_obj_field(child_monitoring, key, datum['value'], date)
43 for datum in data['healthNutrition']:
44 key = datum['key']
45 if key in health_nutrition:
46 increment_obj_field(health_nutrition, key, datum['value'], date)
47 for datum in data['correspondences']:
48 for key in correspondences.keys():
49 increment_obj_field(correspondences, key, datum[key], date)
50 for datum in data['education']['children']:
51 for key in education_fields[:2]:
52 if key == datum.get('key'):
53 increment_obj_field(education, key, datum.get('size'), date)
54 for c_datum in datum['children']:
55 for key in education_fields[2:]:
56 if key == c_datum.get('key'):
57 increment_obj_field(education, key, c_datum.get('size'), date)
58 for key in rc.keys():
59 increment_obj_field(rc, key, data['rcData'].get(key) or 0, date)
62def _add_date_to_query(data, fields, year_key='date__year', month_key='date__month'):
63 return [
64 {
65 **{
66 field: datum[field]
67 for field in fields
68 },
69 'date': '{:04d}-{:02d}'.format(
70 datum[year_key],
71 datum[month_key],
72 )
73 } for datum in data
74 ]
77def get_projects_summary(qs, group_by_date=False):
78 def map_normalize(fields, data):
79 if group_by_date:
80 return {
81 key: {'value': data[key][date], 'label': LABELS[key], 'date': date}
82 for key in fields
83 for date in data[key]
84 }
85 return {
86 key: {'value': data[key], 'label': LABELS[key]}
87 for key in fields
88 }
90 def normalize(fields, data):
91 if group_by_date:
92 return [
93 {'key': key, 'value': data[key][date], 'label': LABELS[key], 'date': date}
94 for key in fields
95 for date in data[key]
96 ]
97 return [
98 {'key': key, 'value': data[key], 'label': LABELS[key]}
99 for key in fields
100 ]
102 def increment_obj_field(obj, key, increment, date):
103 year_month = date and date.strftime('%Y-%m')
104 if group_by_date:
105 if obj[key].get(year_month) is None:
106 obj[key][year_month] = 0
107 obj[key][year_month] += increment
108 else:
109 obj[key] += increment
111 def initial_dict(fields):
112 if group_by_date:
113 return {field: {} for field in fields}
114 return {field: 0 for field in fields}
116 child_monitoring_fields = [
117 '@NotSighted30Days', '@NotSighted60Days', '@NotSighted90Days',
118 '@VisitCompleted'
119 ]
120 health_nutrition_fields = ['@HealthSatisfactory', '@HealthNotSatisfactory']
121 correspondences_fields = ['pendingCurrent', 'pendingOverDue']
122 education_fields = [
123 '@PrimarySchoolAge', '@SecondarySchoolAge',
124 '@PrimarySchoolAgeFormal', '@PrimarySchoolAgeNonFormal', '@PrimarySchoolAgeNoEducation',
126 '@SecondarySchoolAgeFormal', '@SecondarySchoolAgeNonFormal', '@SecondarySchoolAgeVocational',
127 '@SecondarySchoolAgeNoEducation',
128 ]
129 rc_fields = [
130 'planned', 'totalRc', 'sponsored', 'available', 'hold',
131 'death', 'totalMale', 'totalFemale', 'totalLeft',
132 ]
133 soi_fields = ['total_closed', 'closed_on']
134 presenceandparticipation_fields = ['total_rc_temporarily_away', 'total_no_of_rc_records_dropped_during_the_month']
136 child_monitoring = initial_dict(child_monitoring_fields)
137 health_nutrition = initial_dict(health_nutrition_fields)
138 correspondences = initial_dict(correspondences_fields)
139 education = initial_dict(education_fields)
140 rc = initial_dict(rc_fields)
141 soi = initial_dict(soi_fields)
142 presenceandparticipation = initial_dict(presenceandparticipation_fields)
143 total_child_marriage_count = qs.aggregate(
144 total_child_marriage_count=Sum('child_marriage_count'))['total_child_marriage_count']
146 projects = qs.prefetch_related(
147 Prefetch('reports', queryset=Report.objects.order_by('-date')),
148 Prefetch('projectsoi_set', queryset=ProjectSOI.objects.order_by('-date')),
149 Prefetch('presenceandparticipation_set', queryset=PresenceAndParticipation.objects.order_by('-date')),
150 )
152 for project in projects:
153 index = None if group_by_date else 1
154 reports = project.reports.all()[:index]
155 psois = project.projectsoi_set.all()[:index]
156 ppresenceandparticipations = project.presenceandparticipation_set.all()[:index]
158 for report in reports:
159 _get_report_data(
160 increment_obj_field,
161 report,
162 child_monitoring,
163 health_nutrition,
164 correspondences,
165 education,
166 education_fields,
167 rc,
168 )
170 for instances, data in (
171 (psois, soi),
172 (ppresenceandparticipations, presenceandparticipation)
173 ):
174 for instance in instances: 174 ↛ 175line 174 didn't jump to line 175, because the loop on line 174 never started
175 date = instance.date
176 for key in data:
177 increment_obj_field(data, key, getattr(instance, key), date)
179 registerchildbyageandgender_annotate = {
180 '<=6': Sum('count', filter=Q(age__lte=6)),
181 '7-12': Sum('count', filter=Q(age__gt=6, age__lte=12)),
182 '13-18': Sum('count', filter=Q(age__gt=12, age__lte=18)),
183 '18+': Sum('count', filter=Q(age__gt=18)),
184 }
185 registerchildbyageandgender = []
186 childfamilyparticipation = []
187 support_pariticipation_detail = []
188 most_vulnerable_children_indicator = None
189 most_vulnerable_children_vulnerability_marker = None
191 if group_by_date:
192 fields = ('date__year', 'date__month', 'gender')
193 query = RegisterChildByAgeAndGender.objects.filter(
194 project__in=projects,
195 ).order_by(*fields).values(*fields).annotate(
196 **registerchildbyageandgender_annotate,
197 ).values(*fields, *registerchildbyageandgender_annotate.keys())
198 registerchildbyageandgender = _add_date_to_query(
199 query, ['gender', *registerchildbyageandgender_annotate.keys()]
200 )
202 fields = ('type', 'participation', 'gender', 'date__year', 'date__month',)
203 query = ChildFamilyParticipation.objects.filter(
204 project__in=projects,
205 ).order_by(*fields).values(*fields).annotate(
206 count_sum=Sum('count')
207 ).values(*fields, 'count_sum')
208 childfamilyparticipation = _add_date_to_query(query, fields[:3])
209 else:
210 registerchildbyageandgenderdates = RegisterChildByAgeAndGender.objects.filter(
211 project__in=projects,
212 ).order_by('-date').values_list('date', flat=True)[:1]
213 childfamilyparticipationdates = ChildFamilyParticipation.objects.filter(
214 project__in=projects,
215 ).order_by('-date').values_list('date', flat=True)[:1]
217 if registerchildbyageandgenderdates: 217 ↛ 218line 217 didn't jump to line 218, because the condition on line 217 was never true
218 date = registerchildbyageandgenderdates[0]
219 fields = ('gender',)
220 registerchildbyageandgender = list(
221 RegisterChildByAgeAndGender.objects.filter(project__in=projects, date=date)
222 .order_by(*fields).values(*fields).annotate(
223 **registerchildbyageandgender_annotate,
224 ).values(*fields, *registerchildbyageandgender_annotate.keys())
225 )
227 if childfamilyparticipationdates: 227 ↛ 228line 227 didn't jump to line 228, because the condition on line 227 was never true
228 childfamilyparticipation_date = childfamilyparticipationdates[0]
229 fields = ('type', 'participation', 'gender')
230 childfamilyparticipation = list(
231 ChildFamilyParticipation.objects.filter(project__in=projects, date=childfamilyparticipation_date)
232 .order_by(*fields).values(*fields).annotate(count_sum=Sum('count')).values(*fields, 'count_sum')
233 )
235 fields = ('type', 'comment',)
236 support_pariticipation_detail = list(
237 SupportPariticipationDetail.objects.filter(project__in=projects)
238 .order_by(*fields).values(*fields).annotate(count_sum=Sum('count')).values(*fields, 'count_sum')
239 )
241 most_vulnerable_children_indicator = MostVulnerableChildrenIndicator.objects.filter(project__in=projects).aggregate(
242 total_mvc_count=Sum('mvc_count'),
243 total_rc_not_vc_count=Sum('rc_not_vc_count'),
244 total_rc_count=Sum('rc_count'),
245 )
246 most_vulnerable_children_vulnerability_marker = MostVulnerableChildrenVulnerabilityMarker.objects.filter(
247 project__in=projects,
248 ).aggregate(
249 **{
250 field_label: Sum(Cast(KeyTextTransform(field, 'data'), models.IntegerField()))
251 for field, field_label in MostVulnerableChildrenVulnerabilityMarker.get_data_fields()
252 },
253 )
255 reportDates = projects.filter(
256 reports__date__isnull=False,
257 ).order_by('reports__date').values_list('reports__date', flat=True)[:1]
258 reportDate = reportDates[0] if reportDates else None
260 disability_qs = LanguagePeopleGroupDisability.objects.filter(project__in=projects)
261 language_people_group_disability = {
262 'language': disability_qs.values('date', 'language').annotate(
263 count=Sum('count', distinct=True),
264 ).order_by('date', '-count', 'language').values('date', 'language', 'count'),
265 # NOTE: Using list for djangorestframework-camel-case
266 'people_group': list(
267 disability_qs.values('date', 'people_group').annotate(
268 count=Sum('count', distinct=True),
269 ).order_by('date', '-count', 'people_group').values('date', 'people_group', 'count')
270 ),
271 'disability': disability_qs.values('date', 'disability').annotate(
272 count=Sum('count', distinct=True),
273 ).order_by('date', '-count', 'disability').values('date', 'disability', 'count'),
274 }
276 common_stats = {
277 'report_date': reportDate,
278 'total_child_marriage_count': total_child_marriage_count,
279 'child_monitoring': normalize(child_monitoring_fields, child_monitoring),
280 'health_nutrition': normalize(health_nutrition_fields, health_nutrition),
281 'correspondences': normalize(correspondences_fields, correspondences),
282 'education': normalize(education_fields, education),
283 'rc': normalize(rc_fields, rc),
284 'soi': normalize(soi_fields, soi),
285 'presence_and_participation': normalize(presenceandparticipation_fields, presenceandparticipation),
286 'register_child_by_age_and_gender': registerchildbyageandgender,
287 'child_family_participation_date': locals().get('childfamilyparticipation_date'),
288 'child_family_participation': childfamilyparticipation,
289 'language_people_group_disability': language_people_group_disability,
290 }
292 if not group_by_date:
293 # Not required for trend data
294 return {
295 **common_stats,
296 'support_pariticipation_detail': support_pariticipation_detail,
297 'most_vulnerable_children_indicator': most_vulnerable_children_indicator,
298 'most_vulnerable_children_vulnerability_marker': most_vulnerable_children_vulnerability_marker,
299 }
300 return common_stats
303class SimpleSummaryGroupSerializer(serializers.ModelSerializer):
304 class Meta:
305 model = SummaryGroup
306 fields = '__all__'
309class SummaryGroupSerializer(SimpleSummaryGroupSerializer):
310 summary = serializers.SerializerMethodField()
312 def get_summary(self, obj):
313 return get_projects_summary(obj.projects.all())
316class SummaryGroupTrendSerializer(SummaryGroupSerializer):
317 def get_summary(self, obj):
318 return get_projects_summary(obj.projects.all(), group_by_date=True)