Hide keyboard shortcuts

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 

6 

7from report.report_fields import LABELS 

8from report.models import ( 

9 Report, 

10 ProjectSOI, 

11 RegisterChildByAgeAndGender, 

12 PresenceAndParticipation, 

13 ChildFamilyParticipation, 

14 LanguagePeopleGroupDisability, 

15 SupportPariticipationDetail, 

16 

17 MostVulnerableChildrenIndicator, 

18 MostVulnerableChildrenVulnerabilityMarker, 

19) 

20from .models import SummaryGroup 

21 

22 

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): 

33 

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 

36 

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) 

60 

61 

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 ] 

75 

76 

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 } 

89 

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 ] 

101 

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 

110 

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} 

115 

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', 

125 

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'] 

135 

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'] 

145 

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 ) 

151 

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] 

157 

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 ) 

169 

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) 

178 

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 

190 

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 ) 

201 

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] 

216 

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 ) 

226 

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 ) 

234 

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 ) 

240 

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 ) 

254 

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 

259 

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 } 

275 

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 } 

291 

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 

301 

302 

303class SimpleSummaryGroupSerializer(serializers.ModelSerializer): 

304 class Meta: 

305 model = SummaryGroup 

306 fields = '__all__' 

307 

308 

309class SummaryGroupSerializer(SimpleSummaryGroupSerializer): 

310 summary = serializers.SerializerMethodField() 

311 

312 def get_summary(self, obj): 

313 return get_projects_summary(obj.projects.all()) 

314 

315 

316class SummaryGroupTrendSerializer(SummaryGroupSerializer): 

317 def get_summary(self, obj): 

318 return get_projects_summary(obj.projects.all(), group_by_date=True)