def post(self, request, *args, **kwargs): profile = self.request.user.user_profile current_calendar = get_current_academic_calendar() if not current_calendar: raise Http404() study_class = get_object_or_404( StudyClass, id=self.kwargs['study_class_id'], academic_year=current_calendar.academic_year) subject = get_object_or_404( Subject.objects.distinct(), id=self.kwargs['subject_id'], teacher_class_through__study_class=study_class, teacher_class_through__teacher=profile, ) serializer = CsvUploadSerializer(data=request.data) serializer.is_valid(raise_exception=True) file = serializer.validated_data['file'] importer = CatalogsImporter(file=file, study_class=study_class, subject=subject, current_calendar=current_calendar) return Response(data=importer.import_catalogs_and_get_report())
def get_serializer_context(self): context = super().get_serializer_context() study_class = self.get_study_class() subject = self.get_subject() calendar = get_current_academic_calendar() is_technological_school = has_technological_category( study_class.school_unit) working_weeks_count_sem1 = get_working_weeks_count( calendar, 1, study_class, is_technological_school) working_weeks_count_sem2 = get_working_weeks_count( calendar, 2, study_class, is_technological_school) weekly_hours_count = get_weekly_hours_count(study_class, subject.id) third_of_hours_count_sem1 = (working_weeks_count_sem1 * weekly_hours_count) // 3 third_of_hours_count_sem2 = (working_weeks_count_sem2 * weekly_hours_count) // 3 context.update({ 'avg_limit': get_avg_limit_for_subject(study_class, subject.is_coordination, subject.id), 'third_of_hours_count_sem1': third_of_hours_count_sem1, 'third_of_hours_count_sem2': third_of_hours_count_sem2, 'third_of_hours_count_annual': third_of_hours_count_sem1 + third_of_hours_count_sem2, }) return context
def generate_next_year_academic_programs(): current_academic_year = get_current_academic_calendar().academic_year academic_programs = list( AcademicProgram.objects.filter( academic_year=current_academic_year - 1).prefetch_related('program_subjects_through')) academic_programs_to_clone = [] for academic_program in academic_programs: academic_programs_to_clone.append( clone_object_and_override_fields( academic_program, save=False, academic_year=current_academic_year, classes_count=0, students_at_risk_count=0, avg_sem1=None, avg_sem2=None, avg_annual=None, unfounded_abs_avg_sem1=None, unfounded_abs_avg_sem2=None, unfounded_abs_avg_annual=None)) cloned_programs = AcademicProgram.objects.bulk_create( academic_programs_to_clone, batch_size=100) program_subjects_through_to_clone = [] for index, academic_program in enumerate(academic_programs): for subject_through in academic_program.program_subjects_through.all(): program_subjects_through_to_clone.append( clone_object_and_override_fields( subject_through, save=False, academic_program=cloned_programs[index])) ProgramSubjectThrough.objects.bulk_create( program_subjects_through_to_clone, batch_size=100)
def has_assigned_study_classes(teacher): current_academic_calendar = get_current_academic_calendar() if current_academic_calendar is None: return False return teacher.teacher_class_through.filter( academic_year=current_academic_calendar.academic_year).exists()
def create_students_at_risk_counts_for_school_unit_task(school_unit_id): try: school_unit = RegisteredSchoolUnit.objects.get(id=school_unit_id) except ObjectDoesNotExist: return current_calendar = get_current_academic_calendar() if not current_calendar: return months_since_academic_year_start = get_months_since_academic_calendar_start( current_calendar) objects_to_create = [] for year, month in months_since_academic_year_start: days_in_month = monthrange(year, month)[1] if not StudentAtRiskCounts.objects.filter( month=month, year=year, school_unit=school_unit).exists(): objects_to_create.append( StudentAtRiskCounts(month=month, year=year, school_unit=school_unit, daily_counts=[{ 'count': 0, 'day': day, 'weekday': WEEKDAYS_MAP[datetime.datetime( year, month, day).weekday()] } for day in range(1, days_in_month + 1)])) StudentAtRiskCounts.objects.bulk_create(objects_to_create)
def send_alerts_for_school_situation(): today = timezone.now().date() two_weeks_ago = today - timezone.timedelta(days=14) one_week_ago = today - timezone.timedelta(days=8) time_period = get_time_period(two_weeks_ago, one_week_ago) current_calendar = get_current_academic_calendar() if not current_calendar: return second_semester_end_events = get_second_semester_end_events( current_calendar) for school_unit in RegisteredSchoolUnit.objects.all(): is_technological_school = has_technological_category(school_unit) for student in UserProfile.objects.filter( school_unit_id=school_unit.id, user_role=UserProfile.UserRoles.STUDENT, is_active=True).select_related('student_in_class'): try: current_semester = get_current_semester( today, current_calendar, second_semester_end_events, student.student_in_class.class_grade_arabic, is_technological_school) if current_semester is None: continue unfounded_absences_count = get_unfounded_absences_count_for_student( student.id, current_calendar.academic_year, current_semester) grades = get_grades_for_students(student.id, two_weeks_ago, one_week_ago) if unfounded_absences_count == 0 and grades.count() == 0: continue parents_with_emails, parents_with_phone_numbers = get_parents_contact( student) grouped_grades = group_grades_by_subject(grades) if parents_with_emails: formatted_grades_for_email = get_formatted_grades( grouped_grades) format_and_send_school_situation_email( student.full_name, time_period, formatted_grades_for_email, unfounded_absences_count, school_unit.name, parents_with_emails) if parents_with_phone_numbers: student_initials = get_student_initials(student.full_name) formatted_grades_for_sms = get_formatted_grades( grouped_grades, True) format_and_send_school_situation_sms( student_initials, time_period, formatted_grades_for_sms, unfounded_absences_count, parents_with_phone_numbers) except Exception: print("Couldn't send alert for student: {}".format( student.full_name)) print('Finished task send_alerts_for_school_situation')
def get_object(self): current_calendar = get_current_academic_calendar() if not current_calendar: raise Http404() return get_object_or_404(StudentCatalogPerYear, student__id=self.request.user.user_profile.id, academic_year=current_calendar.academic_year)
def get_queryset(self): current_calendar = get_current_academic_calendar() if not current_calendar: return AcademicProgram.objects.none() return AcademicProgram.objects.filter( school_unit_id=self.request.user.user_profile.school_unit_id, academic_year=current_calendar.academic_year, students_at_risk_count__gt=0).order_by('-students_at_risk_count', Lower('name'))
def create_stats_for_schools(apps, schema_editor): RegisteredSchoolUnit = apps.get_model('schools', 'RegisteredSchoolUnit') SchoolUnitStats = apps.get_model('statistics', 'SchoolUnitStats') calendar = get_current_academic_calendar() if calendar: for school in RegisteredSchoolUnit.objects.all(): SchoolUnitStats.objects.create( school_unit=school, school_unit_name=school.name, academic_year=calendar.academic_year)
def get_object(self): parent = self.request.user.user_profile current_calendar = get_current_academic_calendar() if not current_calendar: raise Http404() return get_object_or_404(StudentCatalogPerYear, student__id=self.kwargs['id'], student__parents__id=parent.id, student__school_unit_id=parent.school_unit_id, academic_year=current_calendar.academic_year)
def check_if_operation_allowed(self, operation_name, check_date_limit=True): current_calendar = get_current_academic_calendar() if not current_calendar: return _('No academic calendar defined.') study_class = self.get_object() if study_class.academic_year != current_calendar.academic_year: return _('Cannot {} a study class from a previous year.').format( operation_name)
def get_queryset(self): current_calendar = get_current_academic_calendar() if not current_calendar: return SchoolUnitStats.objects.none() order_by = 'unfounded_abs_avg_sem1' if timezone.now().date( ) < current_calendar.second_semester.ends_at else 'unfounded_abs_avg_annual' return SchoolUnitStats.objects.filter( academic_year=current_calendar.academic_year).order_by( F(order_by).desc(nulls_last=True), Lower('school_unit_name'))
def get_queryset(self): current_calendar = get_current_academic_calendar() if not current_calendar: return AcademicProgram.objects.none() order_by = 'unfounded_abs_avg_sem1' if timezone.now().date( ) < current_calendar.second_semester.ends_at else 'unfounded_abs_avg_annual' return AcademicProgram.objects.filter( school_unit_id=self.request.user.user_profile.school_unit_id, academic_year=current_calendar.academic_year).order_by( F(order_by).desc(nulls_last=True), Lower('name'))
def __init__(self, file, study_class, subject, current_calendar): self.report = {'errors': {}} self.file = file self.study_class = study_class self.subject = subject self.today = timezone.now().date() self.current_calendar = current_calendar or get_current_academic_calendar( ) self.reverse_field_mapping = { value: field for field, value in self.field_mapping.items() }
def get_queryset(self): current_calendar = get_current_academic_calendar() if not current_calendar: return StudyClass.objects.none() order_by = 'avg_sem1' if timezone.now().date( ) < current_calendar.second_semester.ends_at else 'avg_annual' return StudyClass.objects.filter( school_unit_id=self.request.user.user_profile.school_unit_id, academic_year=current_calendar.academic_year).order_by( F(order_by).desc(nulls_last=True), 'class_grade_arabic', 'class_letter')
def get_queryset(self): try: current_academic_year = get_current_academic_calendar().academic_year except AttributeError: return GenericAcademicProgram.objects.none() principal_school = self.request.user.user_profile.school_unit exclude_ids = AcademicProgram.objects.filter(academic_year=current_academic_year, school_unit=principal_school) \ .values_list('generic_academic_program_id', flat=True) return GenericAcademicProgram.objects.filter(academic_profile=principal_school.academic_profile, category_id__in=principal_school.categories.values_list('id', flat=True)) \ .exclude(id__in=exclude_ids)
def validate_and_get_semester(taken_at): today = timezone.now().date() current_calendar = get_current_academic_calendar() if taken_at > today: raise serializers.ValidationError( {'taken_at': _('The date cannot be in the future.')}) second_sem_start = current_calendar.second_semester.starts_at if taken_at < second_sem_start <= today: raise serializers.ValidationError( {'taken_at': _('The date cannot be in the first semester.')}) return 2 if today >= second_sem_start else 1
def create_students_at_risk_counts_task(): today = timezone.now().date() days_in_month = monthrange(today.year, today.month)[1] current_calendar = get_current_academic_calendar() if not current_calendar: return for school_unit in RegisteredSchoolUnit.objects.all(): StudentAtRiskCounts.objects.create( month=today.month, year=today.year, school_unit=school_unit, daily_counts=[{ 'day': day, 'weekday': WEEKDAYS_MAP[datetime.datetime(today.year, today.month, day).weekday()], 'count': 0 } for day in range(1, days_in_month + 1)]) for study_class in school_unit.study_classes.filter( academic_year=current_calendar.academic_year): StudentAtRiskCounts.objects.create( month=today.month, year=today.year, study_class=study_class, daily_counts=[{ 'day': day, 'weekday': WEEKDAYS_MAP[datetime.datetime(today.year, today.month, day).weekday()], 'count': 0 } for day in range(1, days_in_month + 1)]) StudentAtRiskCounts.objects.create( month=today.month, year=today.year, by_country=True, daily_counts=[{ 'day': day, 'weekday': WEEKDAYS_MAP[datetime.datetime(today.year, today.month, day).weekday()], 'count': 0 } for day in range(1, days_in_month + 1)])
def get(self, request, *args, **kwargs): today = timezone.now().date() month = self.request.GET.get('month') current_calendar = get_current_academic_calendar() if not current_calendar: raise Http404() if not month or not (month.isnumeric() and 1 <= int(month) <= 12): month = today.month filters = {} profile = self.request.user.user_profile if profile.user_role == UserProfile.UserRoles.ADMINISTRATOR: school_unit = self.request.GET.get('school_unit') filters.update({'school_unit_id': school_unit} if school_unit and school_unit.isnumeric() else {'by_country': True}) elif profile.user_role == UserProfile.UserRoles.PRINCIPAL: filters.update({'school_unit_id': profile.school_unit_id}) elif profile.user_role == UserProfile.UserRoles.TEACHER: current_calendar = get_current_academic_calendar() if current_calendar: filters.update({ 'study_class__class_master_id': profile.id, 'study_class__academic_year': current_calendar.academic_year }) stats = StudentAtRiskCounts.objects.filter( year=today.year if int(month) <= today.month else current_calendar.academic_year, month=month, **filters).first() return Response(stats.daily_counts if stats else [])
def get_queryset(self): teacher = self.request.user.user_profile current_calendar = get_current_academic_calendar() if not current_calendar: raise Http404() current_mastering_class = get_object_or_404( teacher.mastering_study_classes, academic_year=current_calendar.academic_year) return UserProfile.objects.filter( child__student_in_class=current_mastering_class, user_role=UserProfile.UserRoles.PARENT, school_unit_id=teacher.school_unit_id, last_online__lt=timezone.now() - timedelta(days=30)).order_by( '-last_online', Lower('full_name'))
def get_queryset(self): current_calendar = get_current_academic_calendar() if not current_calendar: raise Http404() mastering_study_class = get_object_or_404( self.request.user.user_profile.mastering_study_classes, academic_year=current_calendar.academic_year) order_by = self.get_order_by(current_calendar) return mastering_study_class.student_catalogs_per_year \ .select_related('student') \ .order_by( F(order_by).desc(nulls_last=True), Lower('student__full_name'))
def create(self, validated_data): instance = super().create(validated_data) instance.school_principal.school_unit = instance instance.school_principal.save() current_calendar = get_current_academic_calendar() if current_calendar: SchoolUnitStats.objects.create( school_unit=instance, school_unit_name=instance.name, academic_year=current_calendar.academic_year) update_school_unit_enrollment_stats_task.delay() create_students_at_risk_counts_for_school_unit_task.delay(instance.id) return instance
def get(self, request, *args, **kwargs): today = timezone.now().date() month = self.request.GET.get('month') current_calendar = get_current_academic_calendar() if not current_calendar: raise Http404() if not month or not (month.isnumeric() and 1 <= int(month) <= 12): month = today.month enrollment_stats = get_object_or_404( SchoolUnitEnrollmentStats, year=today.year if int(month) <= today.month else current_calendar.academic_year, month=month) return Response(enrollment_stats.daily_statistics)
def get_queryset(self): current_calendar = get_current_academic_calendar() if not current_calendar: return StudentCatalogPerYear.objects.none() order_by1 = '-unfounded_abs_count_sem1' if timezone.now().date( ) < current_calendar.second_semester.ends_at else '-unfounded_abs_count_annual' order_by2 = '-behavior_grade_sem1' if timezone.now().date( ) < current_calendar.second_semester.ends_at else '-behavior_grade_annual' profile = self.request.user.user_profile return StudentCatalogPerYear.objects.select_related('student', 'study_class') \ .filter(student__school_unit_id=profile.school_unit_id, academic_year=current_calendar.academic_year, student__is_at_risk=True) \ .distinct() \ .order_by(order_by1, order_by2, Lower('student__full_name'))
def get_queryset(self): current_calendar = get_current_academic_calendar() if not current_calendar: raise Http404() mastering_study_class = get_object_or_404( self.request.user.user_profile.mastering_study_classes, academic_year=current_calendar.academic_year) order_by1 = '-unfounded_abs_count_sem1' if timezone.now().date( ) < current_calendar.second_semester.ends_at else '-unfounded_abs_count_annual' order_by2 = '-behavior_grade_sem1' if timezone.now().date( ) < current_calendar.second_semester.ends_at else '-behavior_grade_annual' return mastering_study_class.student_catalogs_per_year.select_related('student') \ .filter(student__is_at_risk=True) \ .order_by(order_by1, order_by2, Lower('student__full_name'))
def get_current_school_cycle(study_class): calendar = get_current_academic_calendar() semester = 2 if calendar and timezone.now().date( ) >= calendar.second_semester.starts_at else 1 if semester == 1: current_cycle = [ grade for grade in get_school_cycle_for_class_grade( study_class.class_grade_arabic) if grade < study_class.class_grade_arabic ] else: current_cycle = [ grade for grade in get_school_cycle_for_class_grade( study_class.class_grade_arabic) if grade <= study_class.class_grade_arabic ] return current_cycle
def get_catalogs_per_subjects(self, obj): calendar = get_current_academic_calendar() study_class = self.context['study_class'] is_technological_school = has_technological_category(study_class.school_unit) self.context.update({ 'working_weeks_count_sem1': get_working_weeks_count(calendar, 1, study_class, is_technological_school), 'working_weeks_count_sem2': get_working_weeks_count(calendar, 2, study_class, is_technological_school) }) return StudentCatalogPerSubjectWithTeacherSerializer( instance=obj.student_catalogs_per_subject.filter(study_class=study_class, is_enrolled=True) .select_related('teacher', 'study_class__school_unit__academic_profile', 'study_class__academic_program') .prefetch_related('grades', 'absences', 'examination_grades') .order_by('-is_coordination_subject', Lower('subject_name')), many=True, context=self.context ).data
def get_absences_report_for_student(self, student): current_calendar = get_current_academic_calendar() if not current_calendar: return [] now = timezone.now() month = self.get_month_parameter() or now.month if month < current_calendar.first_semester.starts_at.month: year = now.year else: year = current_calendar.academic_year absences = student.absences.filter(taken_at__year=year, taken_at__month=month, created__lt=now - timezone.timedelta(hours=2)) month_range = calendar.monthrange(year, month) weekday = month_range[0] last_day_of_month = month_range[1] absences_map_by_month_days = self.map_absences_count_to_month_days( absences, last_day_of_month) filter_by_category = True if self.request.query_params.get( 'by_category') == 'true' else False results = [] for day in range(1, last_day_of_month + 1): result = { 'day': day, 'weekday': WEEKDAYS_MAP[weekday % 7], } if filter_by_category: result['founded_count'] = absences_map_by_month_days[day][ 'founded_count'] result['unfounded_count'] = absences_map_by_month_days[day][ 'unfounded_count'] else: result['total_count'] = absences_map_by_month_days[day]['founded_count'] + \ absences_map_by_month_days[day]['unfounded_count'] results.append(result) weekday += 1 return results
def to_representation(self, instance): study_class = self.context['study_class'] subject = self.context['subject'] calendar = get_current_academic_calendar() is_technological_school = has_technological_category( study_class.school_unit) working_weeks_count_sem1 = get_working_weeks_count( calendar, 1, study_class, is_technological_school) working_weeks_count_sem2 = get_working_weeks_count( calendar, 2, study_class, is_technological_school) weekly_hours_count = get_weekly_hours_count(study_class, subject.id) third_of_hours_count_sem1 = (working_weeks_count_sem1 * weekly_hours_count) // 3 third_of_hours_count_sem2 = (working_weeks_count_sem2 * weekly_hours_count) // 3 self.context.update({ 'avg_limit': get_avg_limit_for_subject(study_class, subject.is_coordination, subject.id), 'third_of_hours_count_sem1': third_of_hours_count_sem1, 'third_of_hours_count_sem2': third_of_hours_count_sem2, 'third_of_hours_count_annual': third_of_hours_count_sem1 + third_of_hours_count_sem2, }) catalogs = StudentCatalogPerSubjectSerializer( instance=StudentCatalogPerSubject.objects.filter( study_class_id=self.context['study_class'].id, subject_id=self.context['subject'].id, teacher_id=self.context['request'].user.user_profile.id, is_enrolled=True).prefetch_related( 'grades', 'absences', 'examination_grades').order_by( Lower('student__full_name')), many=True, context=self.context).data # Convert response data to dictionary return {"catalogs": catalogs}
def can_update_examination_grades(study_class, grade_type): current_calendar = get_current_academic_calendar() if current_calendar is None: return False if grade_type == ExaminationGrade.GradeTypes.SECOND_EXAMINATION and study_class.academic_year != current_calendar.academic_year: return False event_type = SchoolEvent.EventTypes.CORIGENTE if grade_type == ExaminationGrade.GradeTypes.SECOND_EXAMINATION \ else SchoolEvent.EventTypes.DIFERENTE event = current_calendar.school_events.filter( event_type=event_type).first() if event is None: return False if not event.starts_at <= timezone.now().date() <= event.ends_at: return False return True