Example #1
0
def student_family_grade_common(student):
    PASSING_GRADE = 3 # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it
    school_year = SchoolYear.objects.get(active_year=True)
    mps = MarkingPeriod.objects.filter(school_year=school_year, start_date__lte=datetime.date.today()).order_by('-start_date')
    calculation_rule = benchmark_find_calculation_rule(school_year)
    for mp in mps:
        mp.courses = Course.objects.filter(courseenrollment__user=student, graded=True, marking_period=mp).order_by('fullname')
        for course in mp.courses:
            course.categories = Category.objects.filter(item__course=course, item__mark__student=student).distinct()
            course.category_by_name = {}
            for category in course.categories:
                category.percentage = calculation_rule.per_course_category_set.get(
                    category=category, apply_to_departments=course.department).weight * 100
                category.percentage = category.percentage.quantize(Decimal('0'))
                category.average = gradebook_get_average(student, course, category, mp, None)
                items = Item.objects.filter(course=course, category=category, marking_period=mp, mark__student=student).annotate(best_mark=Max('mark__mark'))
                counts = {}
                counts['total'] = items.exclude(best_mark=None).distinct().count()
                counts['missing'] = items.filter(best_mark__lt=PASSING_GRADE).distinct().count()
                counts['passing'] = items.filter(best_mark__gte=PASSING_GRADE).distinct().count()
                if counts['total']:
                    counts['percentage'] = (Decimal(counts['passing']) / counts['total'] * 100).quantize(Decimal('0'))
                course.category_by_name[category.name] = counts
            course.average = gradebook_get_average(student, course, None, mp, None)
    return mps
Example #2
0
def student_family_grade_common(student):
    PASSING_GRADE = 3  # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it
    school_year = SchoolYear.objects.get(active_year=True)
    mps = MarkingPeriod.objects.filter(
        school_year=school_year,
        start_date__lte=datetime.date.today()).order_by('-start_date')
    calculation_rule = benchmark_find_calculation_rule(school_year)
    for mp in mps:
        mp.courses = Course.objects.filter(
            courseenrollment__user=student, graded=True,
            marking_period=mp).order_by('fullname')
        for course in mp.courses:
            course.categories = Category.objects.filter(
                item__course=course, item__mark__student=student).distinct()
            course.category_by_name = {}
            for category in course.categories:
                category.percentage = calculation_rule.per_course_category_set.get(
                    category=category,
                    apply_to_departments=course.department).weight * 100
                category.percentage = category.percentage.quantize(
                    Decimal('0'))
                category.average = gradebook_get_average(
                    student, course, category, mp, None)
                items = Item.objects.filter(course=course,
                                            category=category,
                                            marking_period=mp,
                                            mark__student=student).annotate(
                                                best_mark=Max('mark__mark'))
                counts = {}
                counts['total'] = items.exclude(
                    best_mark=None).distinct().count()
                counts['missing'] = items.filter(
                    best_mark__lt=PASSING_GRADE).distinct().count()
                counts['passing'] = items.filter(
                    best_mark__gte=PASSING_GRADE).distinct().count()
                if counts['total']:
                    counts['percentage'] = (Decimal(counts['passing']) /
                                            counts['total'] * 100).quantize(
                                                Decimal('0'))
                course.category_by_name[category.name] = counts
            course.average = gradebook_get_average(student, course, None, mp,
                                                   None)
    return mps
Example #3
0
    def get_student_transcript_data(self, student, omit_substitutions=False):
        # benchmark_grade transcripts aren't radically different,
        # but they have some additional data
        if "ecwsp.benchmark_grade" in settings.INSTALLED_APPS:
            from ecwsp.benchmark_grade.models import Aggregate
            from ecwsp.benchmark_grade.utility import gradebook_get_average, benchmark_find_calculation_rule, gradebook_get_category_average
        
        student.years = SchoolYear.objects.filter(
            markingperiod__show_reports=True,
            start_date__lt=self.for_date,
            markingperiod__course__courseenrollment__user=student,
            ).exclude(omityeargpa__student=student).distinct().order_by('start_date')
        for year in student.years:
            year.credits = 0
            year.possible_credits = 0
            year.mps = MarkingPeriod.objects.filter(course__courseenrollment__user=student, school_year=year, show_reports=True).distinct().order_by("start_date")
            i = 1
            for mp in year.mps:
                setattr(year, "mp" + str(i), mp.shortname)
                i += 1
            while i <= 6:
                setattr(year, "mp" + str(i), "")
                i += 1
            year.courses = Course.objects.filter(courseenrollment__user=student, graded=True, marking_period__school_year=year, marking_period__show_reports=True).distinct()
            year.courses = UserPreference.objects.get_or_create(user=self.user)[0].sort_courses(year.courses)
            year_grades = student.grade_set.filter(marking_period__show_reports=True, marking_period__end_date__lte=self.for_date)
            # course grades
            for course in year.courses:
                # Grades
                course_grades = year_grades.filter(course=course).distinct()
                course_aggregates = None
                if year.benchmark_grade:
                    course_aggregates = Aggregate.objects.filter(course=course, student=student)
                i = 1
                for mp in year.mps:
                    if mp not in course.marking_period.all():
                        # Obey the registrar! Don't include grades from marking periods when the course didn't meet.
                        setattr(course, "grade" + str(i), "")
                        i += 1
                        continue
                    if year.benchmark_grade:
                        setattr(course, "grade" + str(i), gradebook_get_average(student, course, None, mp, omit_substitutions = omit_substitutions))
                    else:
                        # We can't overwrite cells, so we have to get seperate variables for each mp grade.
                        try:
                            grade = course_grades.get(marking_period=mp).get_grade()
                            grade = "   " + str(grade) + "   "
                        except:
                            grade = ""
                        setattr(course, "grade" + str(i), grade)
                    i += 1
                while i <= 6:
                    setattr(course, "grade" + str(i), "")
                    i += 1
                course.final = course.get_final_grade(student, date_report=self.for_date)
                
                if (mp.end_date < self.for_date and
                    course.is_passing(
                        student,
                        cache_grade=course.final,
                        cache_passing=self.passing_grade,
                        cache_letter_passing=self.letter_passing_grade) and
                    course.credits):
                    year.credits += course.credits
                if course.credits:
                    year.possible_credits += course.credits

            year.categories_as_courses = []
            if year.benchmark_grade:
                calculation_rule = benchmark_find_calculation_rule(year)
                for category_as_course in calculation_rule.category_as_course_set.filter(include_departments=course.department):
                    i = 1
                    for mp in year.mps:
                        setattr(category_as_course.category, 'grade{}'.format(i), gradebook_get_category_average(student, category_as_course.category, mp))
                        i += 1
                    year.categories_as_courses.append(category_as_course.category)
            
            # Averages per marking period
            i = 1
            for mp in year.mps:
                if mp.end_date < self.for_date:
                    setattr(year, 'mp' + str(i) + 'ave', student.calculate_gpa_mp(mp))
                    i += 1
            while i <= 6:
                setattr(year, 'mp' + str(i) + 'ave', "")
                i += 1
            
            year.ave = student.calculate_gpa_year(year, self.for_date)
            
            
            # Attendance for year
            if not year.id in self.year_days:
                self.year_days[year.id] = year.get_number_days()
            year.total_days = self.year_days[year.id]
            year.nonmemb = student.student_attn.filter(status__code="nonmemb", date__range=(year.start_date, year.end_date)).count()
            year.absent = student.student_attn.filter(status__absent=True, date__range=(year.start_date, year.end_date)).count()
            year.tardy = student.student_attn.filter(status__tardy=True, date__range=(year.start_date, year.end_date)).count()
            year.dismissed = student.student_attn.filter(status__code="D", date__range=(year.start_date, year.end_date)).count()
            # credits per dept    
            student.departments = Department.objects.filter(course__courseenrollment__user=student).distinct()
            student.departments_text = ""
            for dept in student.departments:
                c = 0
                for course in student.course_set.filter(
                    department=dept,
                    marking_period__school_year__end_date__lt=self.for_date,
                    graded=True).distinct():
                    if course.credits and course.is_passing(
                        student,
                        cache_passing=self.passing_grade,
                        cache_letter_passing=self.letter_passing_grade):
                        c += course.credits
                dept.credits = c
                student.departments_text += "| %s: %s " % (dept, dept.credits)
            student.departments_text += "|"
            
            # Standardized tests
            if 'ecwsp.standard_test' in settings.INSTALLED_APPS:
                from ecwsp.standard_test.models import StandardTest
                student.tests = []
                student.highest_tests = []
                for test_result in student.standardtestresult_set.filter(
                    test__show_on_reports=True,
                    show_on_reports=True
                    ).order_by('test'):
                    test_result.categories = ""
                    for cat in test_result.standardcategorygrade_set.filter(category__is_total=False):
                        test_result.categories += '%s: %s  |  ' % (cat.category.name, strip_trailing_zeros(cat.grade))
                    test_result.categories = test_result.categories [:-3]
                    student.tests.append(test_result)
                    
                for test in StandardTest.objects.filter(standardtestresult__student=student, show_on_reports=True, standardtestresult__show_on_reports=True).distinct():
                    test.total = strip_trailing_zeros(test.get_cherry_pick_total(student))
                    student.highest_tests.append(test)
Example #4
0
def gradebook(request, course_id, for_export=False):
    course = get_object_or_404(Course, pk=course_id)
    # lots of stuff will fail unceremoniously if there are no MPs assigned
    if not course.marking_period.count():
        messages.add_message(request, messages.ERROR,
            'The gradebook cannot be opened because there are no marking periods assigned to the course ' +
            course.fullname + '.')
        return HttpResponseRedirect(reverse('admin:index'))

    school_year = course.marking_period.all()[0].school_year
    try:
        calculation_rule = benchmark_find_calculation_rule(school_year)
    except Exception as e:
        if "There is no suitable calculation rule for the school year" not in unicode(e):
            raise
        messages.add_message(request, messages.ERROR, e)
        return HttpResponseRedirect(reverse('admin:index'))
    teacher_courses = get_teacher_courses(request.user.username)
    extra_info = Configuration.get_or_default('Gradebook extra information').value.lower().strip()
    quantizer = Decimal(10) ** (-1 * calculation_rule.decimal_places)
    if not request.user.is_superuser and not request.user.groups.filter(name='registrar').count() and \
    (teacher_courses is None or course not in teacher_courses):
        messages.add_message(request, messages.ERROR,
            'You do not have access to the gradebook for ' + course.fullname + '.')
        return HttpResponseRedirect(reverse('admin:index'))

    students = Student.objects.filter(is_active=True,course=course)
    #students = Student.objects.filter(course=course)
    items = Item.objects.filter(course=course)
    filtered = False
    temporary_aggregate = False
    totals = {
        'filtered_average': Decimal(0),
        'filtered_average_count': Decimal(0),
        'course_average': Decimal(0),
        'course_average_count': Decimal(0),
        'filtered_standards_passing': 0,
        'filtered_standards_all': 0,
        'standards_passing': 0,
        'standards_all': 0
    }

    if request.GET:
        filter_form = GradebookFilterForm(request.GET)
        filter_form.update_querysets(course)
        if filter_form.is_valid():
            for filter_key, filter_value in filter_form.cleaned_data.iteritems():
                if filter_value is not None:
                    try:
                        if not len(filter_value):
                            continue
                    except TypeError:
                        # not everything has a len
                        pass
                    if filter_key == 'cohort': 
                        students = students.filter(cohorts=filter_value)
                        temporary_aggregate = True
                    if filter_key == 'marking_period':
                        items = items.filter(marking_period=filter_value)
                    if filter_key == 'benchmark':
                        items = items.filter(benchmark__in=filter_value)
                        temporary_aggregate = True
                    if filter_key == 'category':
                        items = items.filter(category=filter_value)
                    if filter_key == 'assignment_type':
                        items = items.filter(assignment_type=filter_value)
                        temporary_aggregate = True
                    if filter_key == 'name':
                        items = items.filter(name__icontains=filter_value)
                        temporary_aggregate = True
                    if filter_key == 'date_begin':
                        items = items.filter(date__gt=filter_value)
                        temporary_aggregate = True
                    if filter_key == 'date_end':
                        items = items.filter(date__lt=filter_value)
                        temporary_aggregate = True
                    filtered = True
    else:
        # show only the active marking period by default
        active_mps = course.marking_period.filter(active=True)
        if active_mps and not for_export: # no default filtering on export requests
            filter_form = GradebookFilterForm(initial={'marking_period': active_mps[0]})
            items = items.filter(marking_period=active_mps[0])
            filtered = True
        else:
            filter_form = GradebookFilterForm()
        filter_form.update_querysets(course)
        
    # make a note of any aggregates pending recalculation
    pending_aggregate_pks = Aggregate.objects.filter(course=course, aggregatetask__in=AggregateTask.objects.all()).values_list('pk', flat=True).distinct()
    
    # Freeze these now in case someone else gets in here!
    # TODO: something that actually works. all() does not evaluate a QuerySet.
    # https://docs.djangoproject.com/en/dev/ref/models/querysets/#when-querysets-are-evaluated
    items = items.order_by('id').all()
    # whoa, super roll of the dice. is Item.demonstration_set really guaranteed to be ordered by id?
    # precarious; sorting must match items (and demonstrations!) exactly
    marks = Mark.objects.filter(item__in=items).order_by('item__id', 'demonstration__id').all() 
    items_count = items.filter(demonstration=None).count() + Demonstration.objects.filter(item__in=items).count()
    for student in students:
        student_marks = marks.filter(student=student).select_related('item__category_id')
        student_marks_count = student_marks.count()
        if student_marks_count < items_count:
            # maybe student enrolled after assignments were created
            for item in items:
                if len(item.demonstration_set.all()):
                    # must create mark for each demonstration
                    for demonstration in item.demonstration_set.all():
                        mark, created = Mark.objects.get_or_create(item=item, demonstration=demonstration, student=student)
                else:
                    # a regular item without demonstrations; make only one mark
                    mark, created = Mark.objects.get_or_create(item=item, student=student)
        if student_marks_count > items_count:
            # Yikes, there are multiple marks per student per item. Stop loading the gradebook now.
            if 'dangerous' in request.GET:
                pass
            else:
                raise Exception('Multiple marks per student per item.')
        
        for mark in student_marks:
            mark.category_id = mark.item.category_id
        
        student.marks = student_marks
        student.average, student.average_pk = gradebook_get_average_and_pk(student, course, None, None, None)
        if student.average is not None:
            totals['course_average'] += Aggregate.objects.get(pk=student.average_pk).cached_value # can't use a substitution
            totals['course_average_count'] += 1
        if filtered:
            cleaned_or_initial = getattr(filter_form, 'cleaned_data', filter_form.initial)
            filter_category = cleaned_or_initial.get('category', None)
            filter_marking_period = cleaned_or_initial.get('marking_period', None)
            filter_items = items if temporary_aggregate else None
            student.filtered_average, student.filtered_average_pk = gradebook_get_average_and_pk(
                student, course, filter_category, filter_marking_period, filter_items)
            if student.filtered_average is not None:
                totals['filtered_average'] += Aggregate.objects.get(pk=student.filtered_average_pk).cached_value # can't use a substitution
                totals['filtered_average_count'] += 1
        if school_year.benchmark_grade and extra_info == 'demonstrations':
            # TC's column of counts
            # TODO: don't hardcode
            standards_category = Category.objects.get(name='Standards')
            PASSING_GRADE = 3
            standards_objects = Item.objects.filter(course=course, category=standards_category, mark__student=student).annotate(best_mark=Max('mark__mark')).exclude(best_mark=None)
            standards_count_passing = standards_objects.filter(best_mark__gte=PASSING_GRADE).count()
            standards_count_total = standards_objects.count()
            totals['standards_passing'] += standards_count_passing
            totals['standards_all'] += standards_count_total
            if standards_count_total:
                student.standards_counts = '{} / {} ({:.0f}%)'.format(standards_count_passing, standards_count_total, 100.0 * standards_count_passing / standards_count_total)
            else:
                student.standards_counts = None
            if filtered:
                standards_objects = items.filter(course=course, category=standards_category, mark__student=student).annotate(best_mark=Max('mark__mark')).exclude(best_mark=None)
                standards_count_passing = standards_objects.filter(best_mark__gte=PASSING_GRADE).count()
                standards_count_total = standards_objects.count()
                totals['filtered_standards_passing'] += standards_count_passing
                totals['filtered_standards_all'] += standards_count_total
                if standards_count_total:
                    student.filtered_standards_counts = '{} / {} ({:.0f}%)'.format(standards_count_passing, standards_count_total, 100.0 * standards_count_passing / standards_count_total)
                else:
                    student.filtered_standards_counts = None

            # TC's row of counts
            # TODO: don't hardcode
            for item in items:
                if item.category != standards_category:
                    item.marks_counts = 'N/A'
                    continue
                marks_count_passing = item.mark_set.filter(mark__gte=PASSING_GRADE).count()
                marks_count_total = item.mark_set.exclude(mark=None).count()
                if marks_count_total:
                    item.marks_counts = '{} / {} ({:.0f}%)'.format(marks_count_passing, marks_count_total, 100.0 * marks_count_passing / marks_count_total)
                else:
                    item.marks_counts = None

    if extra_info == 'averages':
        for item in items:
            # listify the QuerySet now so we can modify it and use it in the template
            # if the template just reads the DB and instantiates new objects, they will not have our class_average attribute
            item.demonstration_list = list(item.demonstration_set.all())
            for demonstration in item.demonstration_list:
                # TODO: make sure we only count enrolled students
                demonstration.class_average = demonstration.mark_set.aggregate(Avg('mark'))['mark__avg']
                try:
                    demonstration.class_average = Decimal(demonstration.class_average).quantize(quantizer)
                except TypeError: # e.g. Decimal(None)
                    pass
            item.class_average = item.mark_set.aggregate(Avg('mark'))['mark__avg']
            try:
                item.class_average = Decimal(item.class_average).quantize(quantizer)
            except TypeError: # e.g. Decimal(None)
                pass

    # Gather visual flagging criteria
    absolute_category_flag_criteria = {}
    normalized_category_flag_criteria = {}
    for category in Category.objects.filter(item__in=items).distinct():
        if category.fixed_points_possible:
            # assume the criterion is absolute if the category has fixed # of points possible
            use_dict = absolute_category_flag_criteria
        else:
            # assume we need to divide the mark by points possible before comparing to criterion
            use_dict = normalized_category_flag_criteria
        use_dict[category.pk] = []
        substitutions = calculation_rule.substitution_set.filter(apply_to_departments=course.department, apply_to_categories=category, flag_visually=True)
        for substitution in substitutions:
            use_dict[category.pk].append(substitution.operator + ' ' + str(substitution.match_value))

    # calculate course-wide averages and counts
    if totals['course_average_count']:
        totals['course_average'] = Decimal(totals['course_average'] / totals['course_average_count']).quantize(quantizer)
    else:
        totals['course_average'] = None
    if totals['filtered_average_count']:
        totals['filtered_average'] = Decimal(totals['filtered_average'] / totals['filtered_average_count']).quantize(quantizer)
    else:
        totals['filtered_average'] = None
    if totals['standards_all']:
        totals['standards_text'] = '{} / {} ({:.0f}%)'.format(totals['standards_passing'], totals['standards_all'],
            100.0 * totals['standards_passing'] / totals['standards_all'])
    else:
        totals['standards_text'] = None
    if totals['filtered_standards_all']:
        totals['filtered_standards_text'] = '{} / {} ({:.0f}%)'.format(totals['filtered_standards_passing'], totals['filtered_standards_all'],
            100.0 * totals['filtered_standards_passing'] / totals['filtered_standards_all'])
    else:
        totals['filtered_standards_text'] = None

    data_dictionary = {
        'items': items,
        'item_pks': ','.join(map(str,items.values_list('pk', flat=True))),
        'pending_aggregate_pks': json.dumps(map(str, pending_aggregate_pks)),
        'students': students,
        'course': course,
        'teacher_courses': teacher_courses,
        'filtered' : filtered,
        'filter_form': filter_form,
        'absolute_category_flag_criteria': absolute_category_flag_criteria,
        'normalized_category_flag_criteria': normalized_category_flag_criteria,
        'extra_info': extra_info,
        'totals': totals,
        'item_form_exclude': ItemForm().get_user_excludes(),
    }
    if for_export:
        return data_dictionary
    else:
        return render_to_response('benchmark_grade/gradebook.html', data_dictionary,
            RequestContext(request, {}),)
Example #5
0
def student_report(request, student_pk=None, course_pk=None, marking_period_pk=None):
    authorized = False
    family_available_students = None
    try:
        # is it a student?
        student = Student.objects.get(username=request.user.username)
        # ok! we'll ignore student_pk, and the student is authorized to see itself
        authorized = True
    except:
        student = None
    if not student:
        if request.user.is_staff:
            # hey, it's a staff member!
            student = get_object_or_404(Student, pk=student_pk)
            authorized = True
        else:
            # maybe it's a family member?
            family_available_students = Student.objects.filter(family_access_users=request.user)
            if student_pk:
                student = get_object_or_404(Student, pk=student_pk)
                if student in family_available_students:
                    authorized = True
            elif family_available_students.count():
                student = family_available_students[0]
                authorized = True
    
    # did all that make us comfortable with proceeding?
    if not authorized:
        error_message = 'Sorry, you are not authorized to see grades for this student. Please contact the school registrar.'
        return render_to_response('benchmark_grade/student_grade.html', {
            'error_message': error_message,
        }, RequestContext(request, {}),)

    # is this a summary or detail report?
    if not course_pk:
        # summary report for all courses
        PASSING_GRADE = 3 # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it
        school_year = SchoolYear.objects.get(active_year=True)
        all_mps = MarkingPeriod.objects.filter(school_year=school_year, start_date__lte=datetime.date.today()).order_by('-start_date')
        if marking_period_pk is None:
            if all_mps.count():
                mps = (all_mps[0],)
            else:
                mps = ()
        else:
            mps = all_mps.filter(pk=marking_period_pk)
        mp_pks = [x.pk for x in mps]
        other_mps = all_mps.exclude(pk__in=mp_pks)
        calculation_rule = benchmark_find_calculation_rule(school_year)
        for mp in mps:
            mp.courses = Course.objects.filter(courseenrollment__user=student, graded=True, marking_period=mp).order_by('fullname')
            for course in mp.courses:
                course.categories = Category.objects.filter(item__course=course, item__mark__student=student).distinct()
                course.category_by_name = {}
                for category in course.categories:
                    try:
                        category.percentage = calculation_rule.per_course_category_set.get(
                            category=category, apply_to_departments=course.department).weight * 100
                        category.percentage = category.percentage.quantize(Decimal('0'))
                    except CalculationRulePerCourseCategory.DoesNotExist:
                        # sometimes a course has items belonging to categories that don't count in the course average
                        # but we want to display them anyway
                        category.percentage = 0
                    category.average = gradebook_get_average(student, course, category, mp, None)
                    items = Item.objects.filter(course=course, category=category, marking_period=mp, mark__student=student).annotate(best_mark=Max('mark__mark'))
                    counts = {}
                    counts['total'] = items.exclude(best_mark=None).distinct().count()
                    counts['missing'] = items.filter(best_mark__lt=PASSING_GRADE).distinct().count()
                    counts['passing'] = items.filter(best_mark__gte=PASSING_GRADE).distinct().count()
                    if counts['total']:
                        counts['percentage'] = (Decimal(counts['passing']) / counts['total'] * 100).quantize(Decimal('0'))
                    course.category_by_name[category.name] = counts
                course.average = gradebook_get_average(student, course, None, mp, None)
                try:
                    course.legacy_grade = course.grade_set.get(student=student, marking_period=mp).get_grade()
                    if course.legacy_grade == '':
                        course.legacy_grade = None # be consistent
                except Grade.DoesNotExist:
                    course.legacy_grade = None

        return render_to_response('benchmark_grade/student_grade.html', {
            'student': student,
            'available_students': family_available_students,
            'mps': mps,
            'other_mps': other_mps
        }, RequestContext(request, {}),)

    else:
        # detail report for a single course
        course = get_object_or_404(Course, pk=course_pk)

        # TODO: move into CalculationRule?
        CATEGORY_NAME_TO_FLAG_CRITERIA = {
            'Standards': {'best_mark__lt': 3},
            'Engagement': {'best_mark__lt': 3},
            'Organization': {'best_mark__lt': 3},
            'Daily Practice': {'best_mark__lte': 0},
        }

        # be careful of empty string in POST, as int('') raises ValueError
        if 'item_pks' in request.POST and len(request.POST['item_pks']):
            item_pks = request.POST['item_pks'].split(',')
            items = Item.objects.filter(pk__in=item_pks)
            specific_items = True
        else:
            items = Item.objects
            specific_items = False
        # always filter in case a bad person passes us items from a different course
        items = items.filter(course=course, mark__student=student)

        all_mps = MarkingPeriod.objects.filter(item__in=items).distinct().order_by('-start_date')
        if specific_items:
            mps = all_mps
            other_mps = ()
        else:
            if marking_period_pk is None:
                if all_mps.count():
                    mps = (all_mps[0],)
                else:
                    mps = ()
            else:
                mps = all_mps.filter(pk=marking_period_pk)
            mp_pks = [x.pk for x in mps]
            other_mps = all_mps.exclude(pk__in=mp_pks)

        #if marking_period_pk:
        #    mp = get_object_or_404(MarkingPeriod, pk=marking_period_pk)
        #    mps = (mp,)
        #else:
        #    mps = MarkingPeriod.objects.filter(item__in=items).distinct().order_by('-start_date')

        for mp in mps:
            mp_items = items.filter(marking_period=mp)
            mp.categories = Category.objects.filter(item__in=mp_items).distinct()
            for category in mp.categories:
                category_items = mp_items.filter(category=category).annotate(best_mark=Max('mark__mark')).exclude(best_mark=None)
                item_names = category_items.values_list('name').distinct()
                category.item_groups = {}
                for item_name_tuple in item_names:
                    item_name = item_name_tuple[0]
                    category.item_groups[item_name] = category_items.filter(name=item_name).distinct() 
                if specific_items:
                    # get a disposable average for these specific items
                    category.average = gradebook_get_average(student, course, category, mp, category_items)
                else:
                    category.average = gradebook_get_average(student, course, category, mp, None)
                category.flagged_item_pks = []
                if category.name in CATEGORY_NAME_TO_FLAG_CRITERIA:
                    category.flagged_item_pks = category_items.filter(**CATEGORY_NAME_TO_FLAG_CRITERIA[category.name]).values_list('pk', flat=True)

        return render_to_response('benchmark_grade/student_grade_course_detail.html', {
            'student': student,
            'available_students': family_available_students,
            'course': course,
            'mps': mps,
            'other_mps': other_mps
        }, RequestContext(request, {}),)
Example #6
0
def get_benchmark_report_card_data(report_context, appy_context, students):
    PASSING_GRADE = 3 # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it
    data = appy_context
    for_date = report_context['date_end']
    try: omit_substitutions = report_context['omit_substitutions']
    except KeyError: omit_substitutions = False
    school_year = SchoolYear.objects.filter(start_date__lt=for_date).order_by('-start_date')[0]
    calculation_rule = benchmark_find_calculation_rule(school_year)
    attendance_marking_periods = MarkingPeriod.objects.filter(school_year=school_year,
                                                  start_date__lt=for_date,
                                                  show_reports=True)
    marking_period = attendance_marking_periods.order_by('-start_date')[0]
    for student in students:
        # Backwards compatibility for existing templates
        student.fname = student.first_name
        student.lname = student.last_name

        student.year_course_sections = CourseSection.objects.filter(
            courseenrollment__user=student,
            course__graded=True,
            marking_period__school_year=school_year,
        ).distinct().order_by('course__department')
        student.course_sections = []
        student.count_total_by_category_name = {}
        student.count_missing_by_category_name = {}
        student.count_passing_by_category_name = {}
        for course_section in student.year_course_sections:
            course_section.average = gradebook_get_average(student, course_section, None, marking_period, None, omit_substitutions = omit_substitutions)
            course_section.current_marking_periods = course_section.marking_period.filter(start_date__lt=for_date).order_by('start_date')
            course_section.categories = Category.objects.filter(item__course_section=course_section, item__mark__student=student).distinct()
            course_section.category_by_name = {}
            for category in course_section.categories:
                try:
                    category.weight_percentage = calculation_rule.per_course_category_set.get(category=category, apply_to_departments=course_section.department).weight * Decimal(100)
                except CalculationRulePerCourseCategory.DoesNotExist:
                    category.weight_percentage = Decimal(0)
                category.weight_percentage = category.weight_percentage.quantize(Decimal('0'), ROUND_HALF_UP)
                category.overall_count_total = 0
                category.overall_count_missing = 0
                category.overall_count_passing = 0
                for course_section_marking_period in course_section.current_marking_periods:
                    course_section_marking_period.category = category
                    course_section_marking_period.category.average = gradebook_get_average(student, course_section, category, course_section_marking_period, None, omit_substitutions = omit_substitutions)
                    items = Item.objects.filter(course_section=course_section, marking_period=course_section_marking_period, category=category, mark__student=student).annotate(best_mark=Max('mark__mark')).exclude(best_mark=None)
                    course_section_marking_period.category.count_total = items.exclude(best_mark=None).distinct().count()
                    course_section_marking_period.category.count_missing = items.filter(best_mark__lt=PASSING_GRADE).distinct().count()
                    course_section_marking_period.category.count_passing = items.filter(best_mark__gte=PASSING_GRADE).distinct().count()
                    if course_section_marking_period.category.count_total:
                        course_section_marking_period.category.count_percentage = (Decimal(course_section_marking_period.category.count_passing) / course_section_marking_period.category.count_total * 100).quantize(Decimal('0', ROUND_HALF_UP))

                    # TODO: We assume here that flagging something visually means it's "missing." This should be done in a better way that's not opaque to users.
                    if not calculation_rule.substitution_set.filter(apply_to_departments=course_section.department, flag_visually=True).exists():
                        course_section_marking_period.category.count_passing = course_section_marking_period.category.count_total
                        course_section_marking_period.category.count_missing = 0
                        course_section_marking_period.category.count_percentage = 100

                    category.overall_count_total += course_section_marking_period.category.count_total
                    category.overall_count_missing += course_section_marking_period.category.count_missing
                    category.overall_count_passing += course_section_marking_period.category.count_passing

                    item_names = items.values_list('name').distinct()
                    course_section_marking_period.category.item_groups = []
                    for item_name_tuple in item_names:
                        item_name = item_name_tuple[0]
                        item_group = struct()
                        item_group.name = item_name
                        item_group.items = items.filter(name=item_name).distinct()
                        course_section_marking_period.category.item_groups.append(item_group)

                    course_section_marking_period.category_by_name = getattr(course_section_marking_period, 'category_by_name', {})
                    # make a copy so we don't overwrite the last marking period's data
                    course_section_marking_period.category_by_name[category.name] = copy.copy(course_section_marking_period.category)
                    # the last time through the loop is the most current marking period,
                    # so give that to anyone who doesn't request an explicit marking period
                    #category = course_marking_period.category

                course_section.category_by_name[category.name] = category
                if category.overall_count_total:
                    category.overall_count_percentage = (Decimal(category.overall_count_passing) / category.overall_count_total * 100).quantize(Decimal('0', ROUND_HALF_UP))
                student.count_total_by_category_name[category.name] = student.count_total_by_category_name.get(category.name, 0) + category.overall_count_total
                student.count_missing_by_category_name[category.name] = student.count_missing_by_category_name.get(category.name, 0) + category.overall_count_missing
                student.count_passing_by_category_name[category.name] = student.count_passing_by_category_name.get(category.name, 0) + category.overall_count_passing

            # some components of report need access to course sections for entire year (student.year_course_sections)
            # but we must keep student.course_sections restricted to the current marking period for compatibility
            if marking_period in course_section.marking_period.all():
                student.course_sections.append(course_section)

        student.count_percentage_by_category_name = {}
        for category_name, value in student.count_total_by_category_name.items():
            if value:
                student.count_percentage_by_category_name[category_name] = (Decimal(student.count_passing_by_category_name[category_name]) / value * 100).quantize(Decimal('0', ROUND_HALF_UP))

        # make categories available 
        
        try:
            student.session_gpa = student.studentmarkingperiodgrade_set.get(
                marking_period=marking_period).grade
        except StudentMarkingPeriodGrade.DoesNotExist:
            student.session_gpa = None
        # Cannot just rely on student.gpa for the cumulative GPA; it does not reflect report's date
        student.current_report_cumulative_gpa = student.calculate_gpa(for_date)


        #Attendance for marking period
        i = 1
        student.absent_total = 0
        student.tardy_total = 0
        student.dismissed_total = 0
        student.attendance_marking_periods = []
        for mp in attendance_marking_periods.order_by('start_date'):
            absent = student.student_attn.filter(status__absent=True, date__range=(mp.start_date, mp.end_date)).count()
            tardy = student.student_attn.filter(status__tardy=True, date__range=(mp.start_date, mp.end_date)).count()
            dismissed = student.student_attn.filter(status__code="D", date__range=(mp.start_date, mp.end_date)).count()
            student.absent_total += absent
            student.tardy_total += tardy
            student.dismissed_total += dismissed
            amp = struct()
            amp.absent = absent
            amp.tardy = tardy
            amp.dismissed = dismissed
            amp.number = i
            student.attendance_marking_periods.append(amp)
            i += 1

    data['students'] = students
    data['school_year'] = school_year
    data['marking_period'] = marking_period.name # just passing object makes appy think it's undefined
    data['draw_gauge'] = draw_gauge
Example #7
0
def benchmark_report_card(grade_template_report, template, options, students, format="odt"):
    PASSING_GRADE = (
        3
    )  # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it
    data = grade_template_report.data
    for_date = grade_template_report.for_date
    try:
        omit_substitutions = options["omit_substitutions"]
    except KeyError:
        omit_substitutions = False
    school_year = SchoolYear.objects.filter(start_date__lt=for_date).order_by("-start_date")[0]
    calculation_rule = benchmark_find_calculation_rule(school_year)
    attendance_marking_periods = MarkingPeriod.objects.filter(
        school_year=school_year, start_date__lt=for_date, show_reports=True
    )
    marking_period = attendance_marking_periods.order_by("-start_date")[0]
    for student in students:
        student.year_courses = (
            Course.objects.filter(courseenrollment__user=student, graded=True, marking_period__school_year=school_year)
            .distinct()
            .order_by("department")
        )
        student.courses = []
        student.count_total_by_category_name = {}
        student.count_missing_by_category_name = {}
        student.count_passing_by_category_name = {}
        for course in student.year_courses:
            course.average = gradebook_get_average(
                student, course, None, marking_period, None, omit_substitutions=omit_substitutions
            )
            course.current_marking_periods = course.marking_period.filter(start_date__lt=for_date).order_by(
                "start_date"
            )
            course.categories = Category.objects.filter(item__course=course, item__mark__student=student).distinct()
            course.category_by_name = {}
            for category in course.categories:
                try:
                    category.weight_percentage = calculation_rule.per_course_category_set.get(
                        category=category, apply_to_departments=course.department
                    ).weight * Decimal(100)
                except CalculationRulePerCourseCategory.DoesNotExist:
                    category.weight_percentage = Decimal(0)
                category.weight_percentage = category.weight_percentage.quantize(Decimal("0"), ROUND_HALF_UP)
                category.overall_count_total = 0
                category.overall_count_missing = 0
                category.overall_count_passing = 0
                for course_marking_period in course.current_marking_periods:
                    course_marking_period.category = category
                    course_marking_period.category.average = gradebook_get_average(
                        student, course, category, course_marking_period, None, omit_substitutions=omit_substitutions
                    )
                    items = (
                        Item.objects.filter(
                            course=course,
                            marking_period=course_marking_period,
                            category=category,
                            mark__student=student,
                        )
                        .annotate(best_mark=Max("mark__mark"))
                        .exclude(best_mark=None)
                    )
                    course_marking_period.category.count_total = items.exclude(best_mark=None).distinct().count()
                    course_marking_period.category.count_missing = (
                        items.filter(best_mark__lt=PASSING_GRADE).distinct().count()
                    )
                    course_marking_period.category.count_passing = (
                        items.filter(best_mark__gte=PASSING_GRADE).distinct().count()
                    )
                    if course_marking_period.category.count_total:
                        course_marking_period.category.count_percentage = (
                            Decimal(course_marking_period.category.count_passing)
                            / course_marking_period.category.count_total
                            * 100
                        ).quantize(Decimal("0", ROUND_HALF_UP))

                    if (
                        course.department is not None and course.department.name == "Corporate Work Study"
                    ):  # TODO: Remove this terrible hack
                        course_marking_period.category.count_passing = course_marking_period.category.count_total
                        course_marking_period.category.count_missing = 0
                        course_marking_period.category.count_percentage = 100

                    category.overall_count_total += course_marking_period.category.count_total
                    category.overall_count_missing += course_marking_period.category.count_missing
                    category.overall_count_passing += course_marking_period.category.count_passing

                    item_names = items.values_list("name").distinct()
                    course_marking_period.category.item_groups = []
                    for item_name_tuple in item_names:
                        item_name = item_name_tuple[0]
                        item_group = struct()
                        item_group.name = item_name
                        item_group.items = items.filter(name=item_name).distinct()
                        course_marking_period.category.item_groups.append(item_group)

                    course_marking_period.category_by_name = getattr(course_marking_period, "category_by_name", {})
                    # make a copy so we don't overwrite the last marking period's data
                    course_marking_period.category_by_name[category.name] = copy.copy(course_marking_period.category)
                    # the last time through the loop is the most current marking period,
                    # so give that to anyone who doesn't request an explicit marking period
                    # category = course_marking_period.category

                course.category_by_name[category.name] = category
                if category.overall_count_total:
                    category.overall_count_percentage = (
                        Decimal(category.overall_count_passing) / category.overall_count_total * 100
                    ).quantize(Decimal("0", ROUND_HALF_UP))
                student.count_total_by_category_name[category.name] = (
                    student.count_total_by_category_name.get(category.name, 0) + category.overall_count_total
                )
                student.count_missing_by_category_name[category.name] = (
                    student.count_missing_by_category_name.get(category.name, 0) + category.overall_count_missing
                )
                student.count_passing_by_category_name[category.name] = (
                    student.count_passing_by_category_name.get(category.name, 0) + category.overall_count_passing
                )

            # some components of report need access to courses for entire year (student.year_courses)
            # but we must keep student.courses restricted to the current marking period for compatibility
            if marking_period in course.marking_period.all():
                student.courses.append(course)

        student.count_percentage_by_category_name = {}
        for category_name, value in student.count_total_by_category_name.items():
            if value:
                student.count_percentage_by_category_name[category_name] = (
                    Decimal(student.count_passing_by_category_name[category_name]) / value * 100
                ).quantize(Decimal("0", ROUND_HALF_UP))

        # make categories available

        student.session_gpa = student.calculate_gpa_mp(marking_period)
        # Cannot just rely on student.gpa for the cumulative GPA; it does not reflect report's date
        student.current_report_cumulative_gpa = student.calculate_gpa(for_date)

        # Attendance for marking period
        i = 1
        student.absent_total = 0
        student.tardy_total = 0
        student.dismissed_total = 0
        student.attendance_marking_periods = []
        for mp in attendance_marking_periods.order_by("start_date"):
            absent = student.student_attn.filter(status__absent=True, date__range=(mp.start_date, mp.end_date)).count()
            tardy = student.student_attn.filter(status__tardy=True, date__range=(mp.start_date, mp.end_date)).count()
            dismissed = student.student_attn.filter(status__code="D", date__range=(mp.start_date, mp.end_date)).count()
            student.absent_total += absent
            student.tardy_total += tardy
            student.dismissed_total += dismissed
            amp = struct()
            amp.absent = absent
            amp.tardy = tardy
            amp.dismissed = dismissed
            amp.number = i
            student.attendance_marking_periods.append(amp)
            i += 1

    data["students"] = students
    data["school_year"] = school_year
    data["marking_period"] = marking_period.name  # just passing object makes appy think it's undefined
    data["draw_gauge"] = draw_gauge
    return grade_template_report.pod_save(template)
Example #8
0
def pod_report_grade(request,
                     template,
                     options,
                     students,
                     format="odt",
                     transcript=True,
                     report_card=True,
                     benchmark_report_card=True):
    """ Generate report card and transcript grades via appy
    variables for apply:
    students                - contails all each student
    students.courses        - courses for the student (usually for report cards, one year)
    students.years          - years student is enrolled (and selected)
    students.years.courses  - courses for one year (usually for transcripts that span multiple years)
    year                    - Selected school year
    students.phone          - First phone number for student
    students.sat_highest    - Highest possible combination of SAT test scores. Looks for test named "SAT"
    students.years.ave      - Averaged grade for year
    students.years.total_days- School days this year
    students.years.absent   - Absents for year
    students.years.tardy    - Tardies for year
    students.years.dismissed - Dismissed for year
    studnets.years.credits  - Total credits for year
    """

    data = get_default_data()

    blank_grade = struct()
    blank_grade.comment = ""

    for_date = options[
        'date']  # In case we want a transcript from a future date
    data[
        'date_of_report'] = for_date  # In case we want to include a python date on our template, which is a bit gross
    try:
        omit_substitutions = options['omit_substitutions']
    except KeyError:
        omit_substitutions = False

    # if benchmark grading is installed and enabled for the selected template,
    # and this is a report card, bail out to another function
    if (benchmark_report_card
            and "ecwsp.benchmark_grade" in settings.INSTALLED_APPS):
        from ecwsp.benchmark_grade.report import benchmark_report_card
        return benchmark_report_card(template, options, students, format)

    # benchmark_grade transcripts aren't radically different,
    # but they have some additional data
    if (transcript and "ecwsp.benchmark_grade" in settings.INSTALLED_APPS):
        from ecwsp.benchmark_grade.models import Aggregate, Category
        from ecwsp.benchmark_grade.utility import gradebook_get_average, benchmark_find_calculation_rule, gradebook_get_category_average

    marking_periods = MarkingPeriod.objects.filter(
        school_year=SchoolYear.objects.filter(
            start_date__lt=for_date).order_by('-start_date')[0]).filter(
                show_reports=True)
    data['marking_periods'] = marking_periods.order_by('start_date')

    for student in students:
        # Cannot just rely on student.gpa for the cumulative GPA; it does not reflect report's date
        student.current_report_cumulative_gpa = student.calculate_gpa(for_date)

        # for report_card
        if report_card:
            courses = Course.objects.filter(
                courseenrollment__user=student,
                graded=True,
            )
            courses = courses.filter(marking_period__in=marking_periods
                                     ).distinct().order_by('department')
            for course in courses:
                grades = course.grade_set.filter(student=student).filter(
                    marking_period__isnull=False,
                    marking_period__show_reports=True)
                i = 1
                for grade in grades:
                    # course.grade1, course.grade2, etc
                    setattr(course, "grade" + str(i), grade)
                    i += 1
                while i <= 4:
                    setattr(course, "grade" + str(i), blank_grade)
                    i += 1
                course.final = course.get_final_grade(student)
            student.courses = courses

            #Attendance for marking period
            i = 1
            student.absent_total = 0
            student.absent_unexcused_total = 0
            student.tardy_total = 0
            student.tardy_unexcused_total = 0
            student.dismissed_total = 0
            for mp in marking_periods.order_by('start_date'):
                absent = student.student_attn.filter(
                    status__absent=True,
                    date__range=(mp.start_date, mp.end_date))
                tardy = student.student_attn.filter(status__tardy=True,
                                                    date__range=(mp.start_date,
                                                                 mp.end_date))
                dismissed = student.student_attn.filter(
                    status__code="D",
                    date__range=(mp.start_date, mp.end_date)).count()
                absent_unexcused = absent.exclude(status__excused=True).count()
                tardy_unexcused = tardy.exclude(status__excused=True).count()
                absent = absent.count()
                tardy = tardy.count()

                student.absent_total += absent
                student.tardy_total += tardy
                student.absent_unexcused_total += absent_unexcused
                student.tardy_unexcused_total += tardy_unexcused
                student.dismissed_total += dismissed
                setattr(student, "absent" + str(i), absent)
                setattr(student, "tardy" + str(i), tardy)
                setattr(student, "tardy_unexcused" + str(i), tardy_unexcused)
                setattr(student, "absent_unexcused" + str(i), absent_unexcused)
                setattr(student, "dismissed" + str(i), dismissed)
                i += 1
            while i <= 6:
                setattr(student, "absent" + str(i), "")
                setattr(student, "tardy" + str(i), "")
                setattr(student, "tardy_unexcused" + str(i), "")
                setattr(student, "absent_unexcused" + str(i), "")
                setattr(student, "dismissed" + str(i), "")
                i += 1

        ## for transcripts
        if transcript:
            student.years = SchoolYear.objects.filter(
                markingperiod__show_reports=True,
                start_date__lt=for_date,
                markingperiod__course__courseenrollment__user=student).exclude(
                    omityeargpa__student=student).distinct().order_by(
                        'start_date')
            for year in student.years:
                year.credits = 0
                year.possible_credits = 0
                year.mps = MarkingPeriod.objects.filter(
                    course__courseenrollment__user=student,
                    school_year=year,
                    show_reports=True).distinct().order_by("start_date")
                i = 1
                for mp in year.mps:
                    setattr(year, "mp" + str(i), mp.shortname)
                    i += 1
                while i <= 6:
                    setattr(year, "mp" + str(i), "")
                    i += 1
                year.courses = Course.objects.filter(
                    courseenrollment__user=student,
                    graded=True,
                    marking_period__school_year=year,
                    marking_period__show_reports=True).distinct()
                year.courses = UserPreference.objects.get_or_create(
                    user=request.user)[0].sort_courses(year.courses)
                year_grades = student.grade_set.filter(
                    marking_period__show_reports=True,
                    marking_period__end_date__lte=for_date)
                # course grades
                for course in year.courses:
                    # Grades
                    course_grades = year_grades.filter(
                        course=course).distinct()
                    course_aggregates = None
                    if year.benchmark_grade:
                        course_aggregates = Aggregate.objects.filter(
                            course=course, student=student)
                    i = 1
                    for mp in year.mps:
                        if mp not in course.marking_period.all():
                            # Obey the registrar! Don't include grades from marking periods when the course didn't meet.
                            setattr(course, "grade" + str(i), "")
                            i += 1
                            continue
                        if year.benchmark_grade:
                            setattr(
                                course, "grade" + str(i),
                                gradebook_get_average(
                                    student,
                                    course,
                                    None,
                                    mp,
                                    omit_substitutions=omit_substitutions))
                        else:
                            # We can't overwrite cells, so we have to get seperate variables for each mp grade.
                            try:
                                grade = course_grades.get(
                                    marking_period=mp).get_grade()
                                grade = "   " + str(grade) + "   "
                            except:
                                grade = ""
                            setattr(course, "grade" + str(i), grade)
                        i += 1
                    while i <= 6:
                        setattr(course, "grade" + str(i), "")
                        i += 1
                    course.final = course.get_final_grade(student,
                                                          date_report=for_date)

                    if mp.end_date < for_date and course.is_passing(
                            student) and course.credits:
                        year.credits += course.credits
                    if course.credits:
                        year.possible_credits += course.credits

                year.categories_as_courses = []
                if year.benchmark_grade:
                    calculation_rule = benchmark_find_calculation_rule(year)
                    for category_as_course in calculation_rule.category_as_course_set.filter(
                            include_departments=course.department):
                        i = 1
                        for mp in year.mps:
                            setattr(
                                category_as_course.category,
                                'grade{}'.format(i),
                                gradebook_get_category_average(
                                    student, category_as_course.category, mp))
                            i += 1
                        year.categories_as_courses.append(
                            category_as_course.category)

                # Averages per marking period
                i = 1
                for mp in year.mps:
                    if mp.end_date < for_date:
                        setattr(year, 'mp' + str(i) + 'ave',
                                student.calculate_gpa_mp(mp))
                        i += 1
                while i <= 6:
                    setattr(year, 'mp' + str(i) + 'ave', "")
                    i += 1

                year.ave = student.calculate_gpa_year(year, for_date)

                # Attendance for year
                year.total_days = year.get_number_days()
                year.nonmemb = student.student_attn.filter(
                    status__code="nonmemb",
                    date__range=(year.start_date, year.end_date)).count()
                year.absent = student.student_attn.filter(
                    status__absent=True,
                    date__range=(year.start_date, year.end_date)).count()
                year.tardy = student.student_attn.filter(
                    status__tardy=True,
                    date__range=(year.start_date, year.end_date)).count()
                year.dismissed = student.student_attn.filter(
                    status__code="D",
                    date__range=(year.start_date, year.end_date)).count()

            # credits per dept
            student.departments = Department.objects.filter(
                course__courseenrollment__user=student).distinct()
            student.departments_text = ""
            for dept in student.departments:
                c = 0
                for course in student.course_set.filter(
                        department=dept,
                        marking_period__school_year__end_date__lt=for_date,
                        graded=True).distinct():
                    if course.credits and course.is_passing(student):
                        c += course.credits
                dept.credits = c
                student.departments_text += "| %s: %s " % (dept, dept.credits)
            student.departments_text += "|"

            # Standardized tests
            if 'ecwsp.standard_test' in settings.INSTALLED_APPS:
                from ecwsp.standard_test.models import StandardTest
                student.tests = []
                student.highest_tests = []
                for test_result in student.standardtestresult_set.filter(
                        test__show_on_reports=True,
                        show_on_reports=True).order_by('test'):
                    test_result.categories = ""
                    for cat in test_result.standardcategorygrade_set.filter(
                            category__is_total=False):
                        test_result.categories += '%s: %s  |  ' % (
                            cat.category.name, strip_trailing_zeros(cat.grade))
                    test_result.categories = test_result.categories[:-3]
                    student.tests.append(test_result)

                for test in StandardTest.objects.filter(
                        standardtestresult__student=student,
                        show_on_reports=True,
                        standardtestresult__show_on_reports=True).distinct():
                    test.total = strip_trailing_zeros(
                        test.get_cherry_pick_total(student))
                    student.highest_tests.append(test)

    try:
        if options['student'].count == 1:
            data['student'] = options['student'][0]
    except:
        pass

    data['students'] = students
    data['strip_trailing_zeros'] = strip_trailing_zeros
    filename = 'output'
    return pod_save(filename, "." + str(format), data, template)
Example #9
0
def pod_report_grade(request, template, options, students, format="odt", transcript=True, report_card=True):
    """ Generate report card and transcript grades via appy
    variables for apply:
    students                - contails all each student
    students.courses        - courses for the student (usually for report cards, one year)
    students.years          - years student is enrolled (and selected)
    students.years.courses  - courses for one year (usually for transcripts that span multiple years)
    year                    - Selected school year
    students.phone          - First phone number for student
    students.sat_highest    - Highest possible combination of SAT test scores. Looks for test named "SAT"
    students.years.ave      - Averaged grade for year
    students.years.total_days- School days this year
    students.years.absent   - Absents for year
    students.years.tardy    - Tardies for year
    students.years.dismissed - Dismissed for year
    studnets.years.credits  - Total credits for year
    """

    data = get_default_data()

    blank_grade = struct()
    blank_grade.comment = ""

    for_date = options["date"]  # In case we want a transcript from a future date
    data["date_of_report"] = for_date  # In case we want to include a python date on our template, which is a bit gross

    # if benchmark grading is installed and enabled for the current school year,
    # and this is a report card, bail out to another function
    if (
        report_card
        and "ecwsp.benchmark_grade" in settings.INSTALLED_APPS
        and SchoolYear.objects.filter(start_date__lt=for_date).order_by("-start_date")[0].benchmark_grade
    ):
        from ecwsp.benchmark_grade.report import benchmark_report_card

        return benchmark_report_card(template, options, students, format)

    # benchmark_grade transcripts aren't radically different,
    # but they have some additional data
    if transcript and "ecwsp.benchmark_grade" in settings.INSTALLED_APPS:
        from ecwsp.benchmark_grade.models import Aggregate, Category
        from ecwsp.benchmark_grade.utility import (
            gradebook_get_average,
            benchmark_find_calculation_rule,
            gradebook_get_category_average,
        )

    marking_periods = MarkingPeriod.objects.filter(
        school_year=SchoolYear.objects.filter(start_date__lt=for_date).order_by("-start_date")[0]
    ).filter(show_reports=True)
    data["marking_periods"] = marking_periods.order_by("start_date")

    for student in students:
        # Cannot just rely on student.gpa for the cumulative GPA; it does not reflect report's date
        student.current_report_cumulative_gpa = student.calculate_gpa(for_date)

        # for report_card
        if report_card:
            courses = Course.objects.filter(courseenrollment__user=student, graded=True)
            courses = courses.filter(marking_period__in=marking_periods).distinct().order_by("department")
            for course in courses:
                grades = course.grade_set.filter(student=student).filter(
                    marking_period__isnull=False, marking_period__show_reports=True
                )
                i = 1
                for grade in grades:
                    # course.grade1, course.grade2, etc
                    setattr(course, "grade" + str(i), grade)
                    i += 1
                while i <= 4:
                    setattr(course, "grade" + str(i), blank_grade)
                    i += 1
                course.final = course.get_final_grade(student)
            student.courses = courses

            # Attendance for marking period
            i = 1
            student.absent_total = 0
            student.absent_unexcused_total = 0
            student.tardy_total = 0
            student.tardy_unexcused_total = 0
            student.dismissed_total = 0
            for mp in marking_periods.order_by("start_date"):
                absent = student.student_attn.filter(status__absent=True, date__range=(mp.start_date, mp.end_date))
                tardy = student.student_attn.filter(status__tardy=True, date__range=(mp.start_date, mp.end_date))
                dismissed = student.student_attn.filter(
                    status__code="D", date__range=(mp.start_date, mp.end_date)
                ).count()
                absent_unexcused = absent.exclude(status__excused=True)
                tardy_unexcused = tardy.exclude(status__excused=True)

                student.absent_total += absent.count()
                student.tardy_total += tardy.count()
                student.absent_unexcused_total += absent_unexcused.count()
                student.tardy_unexcused_total += tardy_unexcused.count()
                student.dismissed_total += dismissed
                setattr(student, "absent" + str(i), absent.count())
                setattr(student, "tardy" + str(i), tardy.count())
                setattr(student, "tardy_unexcused" + str(i), tardy_unexcused.count())
                setattr(student, "absent_unexcused" + str(i), absent_unexcused.count())
                setattr(student, "dismissed" + str(i), dismissed)
                i += 1
            while i <= 6:
                setattr(student, "absent" + str(i), "")
                setattr(student, "tardy" + str(i), "")
                setattr(student, "tardy_unexcused" + str(i), "")
                setattr(student, "absent_unexcused" + str(i), "")
                setattr(student, "dismissed" + str(i), "")
                i += 1

        ## for transcripts
        if transcript:
            student.years = (
                SchoolYear.objects.filter(
                    markingperiod__show_reports=True,
                    start_date__lt=for_date,
                    markingperiod__course__courseenrollment__user=student,
                )
                .exclude(omityeargpa__student=student)
                .distinct()
                .order_by("start_date")
            )
            for year in student.years:
                year.credits = 0
                year.possible_credits = 0
                year.mps = (
                    MarkingPeriod.objects.filter(
                        course__courseenrollment__user=student, school_year=year, show_reports=True
                    )
                    .distinct()
                    .order_by("start_date")
                )
                i = 1
                for mp in year.mps:
                    setattr(year, "mp" + str(i), mp.shortname)
                    i += 1
                while i <= 6:
                    setattr(year, "mp" + str(i), "")
                    i += 1
                year.courses = Course.objects.filter(
                    courseenrollment__user=student,
                    graded=True,
                    marking_period__school_year=year,
                    marking_period__show_reports=True,
                ).distinct()
                year.courses = UserPreference.objects.get_or_create(user=request.user)[0].sort_courses(year.courses)
                year_grades = student.grade_set.filter(
                    marking_period__show_reports=True, marking_period__end_date__lte=for_date
                )
                # course grades
                for course in year.courses:
                    # Grades
                    course_grades = year_grades.filter(course=course).distinct()
                    course_aggregates = None
                    if year.benchmark_grade:
                        course_aggregates = Aggregate.objects.filter(course=course, student=student)
                    i = 1
                    for mp in year.mps:
                        if mp not in course.marking_period.all():
                            # Obey the registrar! Don't include grades from marking periods when the course didn't meet.
                            setattr(course, "grade" + str(i), "")
                            i += 1
                            continue
                        if year.benchmark_grade:
                            setattr(course, "grade" + str(i), gradebook_get_average(student, course, None, mp))
                        else:
                            # We can't overwrite cells, so we have to get seperate variables for each mp grade.
                            try:
                                grade = course_grades.get(marking_period=mp).get_grade()
                                grade = "   " + str(grade) + "   "
                            except:
                                grade = ""
                            setattr(course, "grade" + str(i), grade)
                        i += 1
                    while i <= 6:
                        setattr(course, "grade" + str(i), "")
                        i += 1
                    course.final = course.get_final_grade(student, date_report=for_date)

                    if mp.end_date < for_date and course.is_passing(student) and course.credits:
                        year.credits += course.credits
                    if course.credits:
                        year.possible_credits += course.credits

                year.categories_as_courses = []
                if year.benchmark_grade:
                    calculation_rule = benchmark_find_calculation_rule(year)
                    for category_as_course in calculation_rule.category_as_course_set.filter(
                        include_departments=course.department
                    ):
                        i = 1
                        for mp in year.mps:
                            setattr(
                                category_as_course.category,
                                "grade{}".format(i),
                                gradebook_get_category_average(student, category_as_course.category, mp),
                            )
                            i += 1
                        year.categories_as_courses.append(category_as_course.category)

                # Averages per marking period
                i = 1
                for mp in year.mps:
                    if mp.end_date < for_date:
                        setattr(year, "mp" + str(i) + "ave", student.calculate_gpa_mp(mp))
                        i += 1
                while i <= 6:
                    setattr(year, "mp" + str(i) + "ave", "")
                    i += 1

                year.ave = student.calculate_gpa_year(year, for_date)

                # Attendance for year
                year.total_days = year.get_number_days()
                year.nonmemb = student.student_attn.filter(
                    status__code="nonmemb", date__range=(year.start_date, year.end_date)
                ).count()
                year.absent = student.student_attn.filter(
                    status__absent=True, date__range=(year.start_date, year.end_date)
                ).count()
                year.tardy = student.student_attn.filter(
                    status__tardy=True, date__range=(year.start_date, year.end_date)
                ).count()
                year.dismissed = student.student_attn.filter(
                    status__code="D", date__range=(year.start_date, year.end_date)
                ).count()

            # credits per dept
            student.departments = Department.objects.filter(course__courseenrollment__user=student).distinct()
            student.departments_text = ""
            for dept in student.departments:
                c = 0
                for course in student.course_set.filter(
                    department=dept, marking_period__school_year__end_date__lt=for_date, graded=True
                ).distinct():
                    if course.credits and course.is_passing(student):
                        c += course.credits
                dept.credits = c
                student.departments_text += "| %s: %s " % (dept, dept.credits)
            student.departments_text += "|"

            # Standardized tests
            if "ecwsp.standard_test" in settings.INSTALLED_APPS:
                from ecwsp.standard_test.models import StandardTest

                student.tests = []
                student.highest_tests = []
                for test_result in student.standardtestresult_set.filter(
                    test__show_on_reports=True, show_on_reports=True
                ).order_by("test"):
                    test_result.categories = ""
                    for cat in test_result.standardcategorygrade_set.filter(category__is_total=False):
                        test_result.categories += "%s: %s  |  " % (cat.category.name, strip_trailing_zeros(cat.grade))
                    test_result.categories = test_result.categories[:-3]
                    student.tests.append(test_result)

                for test in StandardTest.objects.filter(
                    standardtestresult__student=student, show_on_reports=True, standardtestresult__show_on_reports=True
                ).distinct():
                    test.total = strip_trailing_zeros(test.get_cherry_pick_total(student))
                    student.highest_tests.append(test)

    try:
        if options["student"].count == 1:
            data["student"] = options["student"][0]
    except:
        pass

    data["students"] = students
    data["strip_trailing_zeros"] = strip_trailing_zeros
    filename = "output"
    return pod_save(filename, "." + str(format), data, template)
Example #10
0
def student_report(request,
                   student_pk=None,
                   course_pk=None,
                   marking_period_pk=None):
    authorized = False
    family_available_students = None
    try:
        # is it a student?
        student = Student.objects.get(username=request.user.username)
        # ok! we'll ignore student_pk, and the student is authorized to see itself
        authorized = True
    except:
        student = None
    if not student:
        if request.user.is_staff:
            # hey, it's a staff member!
            student = get_object_or_404(Student, pk=student_pk)
            authorized = True
        else:
            # maybe it's a family member?
            family_available_students = Student.objects.filter(
                family_access_users=request.user)
            if student_pk:
                student = get_object_or_404(Student, pk=student_pk)
                if student in family_available_students:
                    authorized = True
            elif family_available_students.count():
                student = family_available_students[0]
                authorized = True

    # did all that make us comfortable with proceeding?
    if not authorized:
        error_message = 'Sorry, you are not authorized to see grades for this student. Please contact the school registrar.'
        return render_to_response(
            'benchmark_grade/student_grade.html',
            {
                'error_message': error_message,
            },
            RequestContext(request, {}),
        )

    # is this a summary or detail report?
    if not course_pk:
        # summary report for all courses
        PASSING_GRADE = 3  # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it
        school_year = SchoolYear.objects.get(active_year=True)
        mps = MarkingPeriod.objects.filter(
            school_year=school_year,
            start_date__lte=datetime.date.today()).order_by('-start_date')
        calculation_rule = benchmark_find_calculation_rule(school_year)
        for mp in mps:
            mp.courses = Course.objects.filter(
                courseenrollment__user=student, graded=True,
                marking_period=mp).order_by('fullname')
            for course in mp.courses:
                course.categories = Category.objects.filter(
                    item__course=course,
                    item__mark__student=student).distinct()
                course.category_by_name = {}
                for category in course.categories:
                    category.percentage = calculation_rule.per_course_category_set.get(
                        category=category,
                        apply_to_departments=course.department).weight * 100
                    category.percentage = category.percentage.quantize(
                        Decimal('0'))
                    category.average = gradebook_get_average(
                        student, course, category, mp, None)
                    items = Item.objects.filter(
                        course=course,
                        category=category,
                        marking_period=mp,
                        mark__student=student).annotate(
                            best_mark=Max('mark__mark'))
                    counts = {}
                    counts['total'] = items.exclude(
                        best_mark=None).distinct().count()
                    counts['missing'] = items.filter(
                        best_mark__lt=PASSING_GRADE).distinct().count()
                    counts['passing'] = items.filter(
                        best_mark__gte=PASSING_GRADE).distinct().count()
                    if counts['total']:
                        counts['percentage'] = (Decimal(counts['passing']) /
                                                counts['total'] *
                                                100).quantize(Decimal('0'))
                    course.category_by_name[category.name] = counts
                course.average = gradebook_get_average(student, course, None,
                                                       mp, None)

        return render_to_response(
            'benchmark_grade/student_grade.html',
            {
                'student': student,
                'available_students': family_available_students,
                'mps': mps
            },
            RequestContext(request, {}),
        )

    else:
        # detail report for a single course
        course = get_object_or_404(Course, pk=course_pk)

        # TODO: move into CalculationRule?
        CATEGORY_NAME_TO_FLAG_CRITERIA = {
            'Standards': {
                'best_mark__lt': 3
            },
            'Engagement': {
                'best_mark__lt': 3
            },
            'Organization': {
                'best_mark__lt': 3
            },
            'Daily Practice': {
                'best_mark__lte': 0
            },
        }

        if 'item_pks' in request.POST:
            item_pks = request.POST['item_pks'].split(',')
            items = Item.objects.filter(pk__in=item_pks)
            specific_items = True
        else:
            items = Item.objects
            specific_items = False
        # always filter in case a bad person passes us items from a different course
        items = items.filter(course=course, mark__student=student)

        if marking_period_pk:
            mp = get_object_or_404(MarkingPeriod, pk=marking_period_pk)
            mps = (mp, )
        else:
            mps = MarkingPeriod.objects.filter(
                item__in=items).distinct().order_by('-start_date')

        for mp in mps:
            mp_items = items.filter(marking_period=mp)
            mp.categories = Category.objects.filter(
                item__in=mp_items).distinct()
            for category in mp.categories:
                category_items = mp_items.filter(category=category).annotate(
                    best_mark=Max('mark__mark')).exclude(best_mark=None)
                item_names = category_items.values_list('name').distinct()
                category.item_groups = {}
                for item_name_tuple in item_names:
                    item_name = item_name_tuple[0]
                    category.item_groups[item_name] = category_items.filter(
                        name=item_name).distinct()
                if specific_items:
                    # get a disposable average for these specific items
                    category.average = gradebook_get_average(
                        student, course, category, mp, category_items)
                else:
                    category.average = gradebook_get_average(
                        student, course, category, mp, None)
                category.flagged_item_pks = []
                if category.name in CATEGORY_NAME_TO_FLAG_CRITERIA:
                    category.flagged_item_pks = category_items.filter(
                        **CATEGORY_NAME_TO_FLAG_CRITERIA[
                            category.name]).values_list('pk', flat=True)

        return render_to_response(
            'benchmark_grade/student_grade_course_detail.html',
            {
                'student': student,
                'course': course,
                'mps': mps
            },
            RequestContext(request, {}),
        )
Example #11
0
def gradebook(request, course_id):
    course = get_object_or_404(Course, pk=course_id)
    school_year = course.marking_period.all()[0].school_year
    teacher_courses = get_teacher_courses(request.user.username)
    if not request.user.is_superuser and not request.user.groups.filter(name='registrar').count() and \
    (teacher_courses is None or course not in teacher_courses):
        messages.add_message(
            request, messages.ERROR,
            'You do not have access to the gradebook for ' + course.fullname +
            '.')
        return HttpResponseRedirect(reverse('admin:index'))

    # lots of stuff will fail unceremoniously if there are no MPs assigned
    if not course.marking_period.count():
        messages.add_message(
            request, messages.ERROR,
            'The gradebook cannot be opened because there are no marking periods assigned to the course '
            + course.fullname + '.')
        return HttpResponseRedirect(reverse('admin:index'))

    students = Student.objects.filter(inactive=False, course=course)
    #students = Student.objects.filter(course=course)
    items = Item.objects.filter(course=course)
    filtered = False

    if request.GET:
        filter_form = GradebookFilterForm(request.GET)
        filter_form.update_querysets(course)
        if filter_form.is_valid():
            for filter_key, filter_value in filter_form.cleaned_data.iteritems(
            ):
                if filter_value is not None:
                    try:
                        if not len(filter_value):
                            continue
                    except TypeError:
                        # not everything has a len
                        pass
                    if filter_key == 'cohort':
                        students = students.filter(cohorts=filter_value)
                    if filter_key == 'marking_period':
                        items = items.filter(marking_period=filter_value)
                    if filter_key == 'benchmark':
                        items = items.filter(benchmark__in=filter_value)
                    if filter_key == 'category':
                        items = items.filter(category=filter_value)
                    if filter_key == 'assignment_type':
                        items = items.filter(assignment_type=filter_value)
                    if filter_key == 'name':
                        items = items.filter(name__icontains=filter_value)
                    if filter_key == 'date_begin':
                        items = items.filter(date__gt=filter_value)
                    if filter_key == 'date_end':
                        items = items.filter(date__lt=filter_value)
                    filtered = True
    else:
        # show only the active marking period by default
        active_mps = course.marking_period.filter(active=True)
        if active_mps:
            filter_form = GradebookFilterForm(
                initial={'marking_period': active_mps[0]})
            items = items.filter(marking_period=active_mps[0])
        else:
            filter_form = GradebookFilterForm()
        filter_form.update_querysets(course)

    # make a note of any aggregates pending recalculation
    pending_aggregate_pks = Aggregate.objects.filter(course=course).annotate(
        Count('aggregatetask')).filter(aggregatetask__count__gt=0).values_list(
            'pk', flat=True)

    # Freeze these now in case someone else gets in here!
    # TODO: something that actually works. all() does not evaluate a QuerySet.
    # https://docs.djangoproject.com/en/dev/ref/models/querysets/#when-querysets-are-evaluated
    items = items.order_by('id').all()
    # whoa, super roll of the dice. is Item.demonstration_set really guaranteed to be ordered by id?
    # precarious; sorting must match items (and demonstrations!) exactly
    marks = Mark.objects.filter(item__in=items).order_by(
        'item__id', 'demonstration__id').all()
    items_count = items.filter(
        demonstration=None).count() + Demonstration.objects.filter(
            item__in=items).count()
    for student in students:
        student_marks = marks.filter(
            student=student).select_related('item__category_id')
        student_marks_count = student_marks.count()
        if student_marks_count < items_count:
            # maybe student enrolled after assignments were created
            for item in items:
                if len(item.demonstration_set.all()):
                    # must create mark for each demonstration
                    for demonstration in item.demonstration_set.all():
                        mark, created = Mark.objects.get_or_create(
                            item=item,
                            demonstration=demonstration,
                            student=student)
                else:
                    # a regular item without demonstrations; make only one mark
                    mark, created = Mark.objects.get_or_create(item=item,
                                                               student=student)
        if student_marks_count > items_count:
            # Yikes, there are multiple marks per student per item. Stop loading the gradebook now.
            if 'dangerous' in request.GET:
                pass
            else:
                raise Exception('Multiple marks per student per item.')

        for mark in student_marks:
            mark.category_id = mark.item.category_id

        student.marks = student_marks
        student.average, student.average_pk = gradebook_get_average_and_pk(
            student, course, None, None, None)
        if filtered:
            student.filtered_average = gradebook_get_average(
                student, course, filter_form.cleaned_data['category'],
                filter_form.cleaned_data['marking_period'], items)
        if school_year.benchmark_grade:
            # TC's column of counts
            # TODO: don't hardcode
            standards_category = Category.objects.get(name='Standards')
            PASSING_GRADE = 3
            standards_objects = Item.objects.filter(
                course=course,
                category=standards_category,
                mark__student=student).annotate(
                    best_mark=Max('mark__mark')).exclude(best_mark=None)
            standards_count_passing = standards_objects.filter(
                best_mark__gte=PASSING_GRADE).count()
            standards_count_total = standards_objects.count()
            if standards_count_total:
                student.standards_counts = '{} / {} ({:.0f}%)'.format(
                    standards_count_passing, standards_count_total,
                    100.0 * standards_count_passing / standards_count_total)
            else:
                student.standards_counts_ = None
            if filtered:
                standards_objects = items.filter(
                    course=course,
                    category=standards_category,
                    mark__student=student).annotate(
                        best_mark=Max('mark__mark')).exclude(best_mark=None)
                standards_count_passing = standards_objects.filter(
                    best_mark__gte=PASSING_GRADE).count()
                standards_count_total = standards_objects.count()
                if standards_count_total:
                    student.filtered_standards_counts = '{} / {} ({:.0f}%)'.format(
                        standards_count_passing, standards_count_total, 100.0 *
                        standards_count_passing / standards_count_total)
                else:
                    student.filtered_standards_counts = None

            # TC's row of counts
            # TODO: don't hardcode
            for item in items:
                if item.category != standards_category:
                    item.marks_counts = 'N/A'
                    continue
                marks_count_passing = item.mark_set.filter(
                    mark__gte=PASSING_GRADE).count()
                marks_count_total = item.mark_set.exclude(mark=None).count()
                if marks_count_total:
                    item.marks_counts = '{} / {} ({:.0f}%)'.format(
                        marks_count_passing, marks_count_total,
                        100.0 * marks_count_passing / marks_count_total)
                else:
                    item.marks_counts = None

    # Gather visual flagging criteria
    calculation_rule = benchmark_find_calculation_rule(school_year)
    category_flag_criteria = {}
    for category in Category.objects.filter(item__in=items).distinct():
        category_flag_criteria[category.pk] = []
        substitutions = calculation_rule.substitution_set.filter(
            apply_to_departments=course.department,
            apply_to_categories=category,
            flag_visually=True)
        for substitution in substitutions:
            category_flag_criteria[category.pk].append(
                substitution.operator + ' ' + str(substitution.match_value))

    return render_to_response(
        'benchmark_grade/gradebook.html',
        {
            'items': items,
            'item_pks': ','.join(map(str, items.values_list('pk', flat=True))),
            'pending_aggregate_pks': json.dumps(map(str,
                                                    pending_aggregate_pks)),
            'students': students,
            'course': course,
            'teacher_courses': teacher_courses,
            'filtered': filtered,
            'filter_form': filter_form,
            'category_flag_criteria': category_flag_criteria,
        },
        RequestContext(request, {}),
    )
Example #12
0
def get_benchmark_report_card_data(report_context, appy_context, students):
    PASSING_GRADE = 3  # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it
    data = appy_context
    for_date = report_context['date_end']
    try:
        omit_substitutions = report_context['omit_substitutions']
    except KeyError:
        omit_substitutions = False
    school_year = SchoolYear.objects.filter(
        start_date__lt=for_date).order_by('-start_date')[0]
    calculation_rule = benchmark_find_calculation_rule(school_year)
    attendance_marking_periods = MarkingPeriod.objects.filter(
        school_year=school_year, start_date__lt=for_date, show_reports=True)
    marking_period = attendance_marking_periods.order_by('-start_date')[0]
    for student in students:
        # Backwards compatibility for existing templates
        student.fname = student.first_name
        student.lname = student.last_name

        student.year_course_sections = CourseSection.objects.filter(
            courseenrollment__user=student,
            course__graded=True,
            marking_period__school_year=school_year,
        ).distinct().order_by('course__department')
        student.course_sections = []
        student.count_total_by_category_name = {}
        student.count_missing_by_category_name = {}
        student.count_passing_by_category_name = {}
        for course_section in student.year_course_sections:
            course_section.average = gradebook_get_average(
                student,
                course_section,
                None,
                marking_period,
                None,
                omit_substitutions=omit_substitutions)
            course_section.current_marking_periods = course_section.marking_period.filter(
                start_date__lt=for_date).order_by('start_date')
            course_section.categories = Category.objects.filter(
                item__course_section=course_section,
                item__mark__student=student).distinct()
            course_section.category_by_name = {}
            for category in course_section.categories:
                try:
                    category.weight_percentage = calculation_rule.per_course_category_set.get(
                        category=category,
                        apply_to_departments=course_section.department
                    ).weight * Decimal(100)
                except CalculationRulePerCourseCategory.DoesNotExist:
                    category.weight_percentage = Decimal(0)
                category.weight_percentage = category.weight_percentage.quantize(
                    Decimal('0'), ROUND_HALF_UP)
                category.overall_count_total = 0
                category.overall_count_missing = 0
                category.overall_count_passing = 0
                for course_section_marking_period in course_section.current_marking_periods:
                    course_section_marking_period.category = category
                    course_section_marking_period.category.average = gradebook_get_average(
                        student,
                        course_section,
                        category,
                        course_section_marking_period,
                        None,
                        omit_substitutions=omit_substitutions)
                    items = Item.objects.filter(
                        course_section=course_section,
                        marking_period=course_section_marking_period,
                        category=category,
                        mark__student=student).annotate(
                            best_mark=Max('mark__mark')).exclude(
                                best_mark=None)
                    course_section_marking_period.category.count_total = items.exclude(
                        best_mark=None).distinct().count()
                    course_section_marking_period.category.count_missing = items.filter(
                        best_mark__lt=PASSING_GRADE).distinct().count()
                    course_section_marking_period.category.count_passing = items.filter(
                        best_mark__gte=PASSING_GRADE).distinct().count()
                    if course_section_marking_period.category.count_total:
                        course_section_marking_period.category.count_percentage = (
                            Decimal(course_section_marking_period.category.
                                    count_passing) /
                            course_section_marking_period.category.count_total
                            * 100).quantize(Decimal('0', ROUND_HALF_UP))

                    # TODO: We assume here that flagging something visually means it's "missing." This should be done in a better way that's not opaque to users.
                    if not calculation_rule.substitution_set.filter(
                            apply_to_departments=course_section.department,
                            flag_visually=True).exists():
                        course_section_marking_period.category.count_passing = course_section_marking_period.category.count_total
                        course_section_marking_period.category.count_missing = 0
                        course_section_marking_period.category.count_percentage = 100

                    category.overall_count_total += course_section_marking_period.category.count_total
                    category.overall_count_missing += course_section_marking_period.category.count_missing
                    category.overall_count_passing += course_section_marking_period.category.count_passing

                    item_names = items.values_list('name').distinct()
                    course_section_marking_period.category.item_groups = []
                    for item_name_tuple in item_names:
                        item_name = item_name_tuple[0]
                        item_group = struct()
                        item_group.name = item_name
                        item_group.items = items.filter(
                            name=item_name).distinct()
                        course_section_marking_period.category.item_groups.append(
                            item_group)

                    course_section_marking_period.category_by_name = getattr(
                        course_section_marking_period, 'category_by_name', {})
                    # make a copy so we don't overwrite the last marking period's data
                    course_section_marking_period.category_by_name[
                        category.name] = copy.copy(
                            course_section_marking_period.category)
                    # the last time through the loop is the most current marking period,
                    # so give that to anyone who doesn't request an explicit marking period
                    #category = course_marking_period.category

                course_section.category_by_name[category.name] = category
                if category.overall_count_total:
                    category.overall_count_percentage = (
                        Decimal(category.overall_count_passing) /
                        category.overall_count_total * 100).quantize(
                            Decimal('0', ROUND_HALF_UP))
                student.count_total_by_category_name[
                    category.name] = student.count_total_by_category_name.get(
                        category.name, 0) + category.overall_count_total
                student.count_missing_by_category_name[
                    category.
                    name] = student.count_missing_by_category_name.get(
                        category.name, 0) + category.overall_count_missing
                student.count_passing_by_category_name[
                    category.
                    name] = student.count_passing_by_category_name.get(
                        category.name, 0) + category.overall_count_passing

            # some components of report need access to course sections for entire year (student.year_course_sections)
            # but we must keep student.course_sections restricted to the current marking period for compatibility
            if marking_period in course_section.marking_period.all():
                student.course_sections.append(course_section)

        student.count_percentage_by_category_name = {}
        for category_name, value in student.count_total_by_category_name.items(
        ):
            if value:
                student.count_percentage_by_category_name[category_name] = (
                    Decimal(
                        student.count_passing_by_category_name[category_name])
                    / value * 100).quantize(Decimal('0', ROUND_HALF_UP))

        # make categories available

        try:
            student.session_gpa = student.studentmarkingperiodgrade_set.get(
                marking_period=marking_period).grade
        except StudentMarkingPeriodGrade.DoesNotExist:
            student.session_gpa = None
        # Cannot just rely on student.gpa for the cumulative GPA; it does not reflect report's date
        student.current_report_cumulative_gpa = student.calculate_gpa(for_date)

        #Attendance for marking period
        i = 1
        student.absent_total = 0
        student.tardy_total = 0
        student.dismissed_total = 0
        student.attendance_marking_periods = []
        for mp in attendance_marking_periods.order_by('start_date'):
            absent = student.student_attn.filter(
                status__absent=True,
                date__range=(mp.start_date, mp.end_date)).count()
            tardy = student.student_attn.filter(
                status__tardy=True,
                date__range=(mp.start_date, mp.end_date)).count()
            dismissed = student.student_attn.filter(
                status__code="D",
                date__range=(mp.start_date, mp.end_date)).count()
            student.absent_total += absent
            student.tardy_total += tardy
            student.dismissed_total += dismissed
            amp = struct()
            amp.absent = absent
            amp.tardy = tardy
            amp.dismissed = dismissed
            amp.number = i
            student.attendance_marking_periods.append(amp)
            i += 1

    data['students'] = students
    data['school_year'] = school_year
    data[
        'marking_period'] = marking_period.name  # just passing object makes appy think it's undefined
    data['draw_gauge'] = draw_gauge
Example #13
0
def gradebook(request, course_id):
    course = get_object_or_404(Course, pk=course_id)
    teacher_courses = get_teacher_courses(request.user.username)
    if not request.user.is_superuser and not request.user.groups.filter(name='registrar').count() and \
    (teacher_courses is None or course not in teacher_courses):
        messages.add_message(request, messages.ERROR,
            'You do not have access to the gradebook for ' + course.fullname + '.')
        return HttpResponseRedirect(reverse('admin:index'))

    # lots of stuff will fail unceremoniously if there are no MPs assigned
    if not course.marking_period.count():
        messages.add_message(request, messages.ERROR,
            'The gradebook cannot be opened because there are no marking periods assigned to the course ' +
            course.fullname + '.')
        return HttpResponseRedirect(reverse('admin:index'))

    students = Student.objects.filter(inactive=False,course=course)
    #students = Student.objects.filter(course=course)
    items = Item.objects.filter(course=course)
    filtered = False

    if request.GET:
        filter_form = GradebookFilterForm(request.GET)
        filter_form.update_querysets(course)
        if filter_form.is_valid():
            for filter_key, filter_value in filter_form.cleaned_data.iteritems():
                if filter_value is not None:
                    try:
                        if not len(filter_value):
                            continue
                    except TypeError:
                        # not everything has a len
                        pass
                    if filter_key == 'cohort': 
                        students = students.filter(cohorts=filter_value)
                    if filter_key == 'marking_period':
                        items = items.filter(marking_period=filter_value)
                    if filter_key == 'benchmark':
                        items = items.filter(benchmark__in=filter_value)
                    if filter_key == 'category':
                        items = items.filter(category=filter_value)
                    if filter_key == 'assignment_type':
                        items = items.filter(assignment_type=filter_value)
                    if filter_key == 'name':
                        items = items.filter(name__icontains=filter_value)
                    if filter_key == 'date_begin':
                        items = items.filter(date__gt=filter_value)
                    if filter_key == 'date_end':
                        items = items.filter(date__lt=filter_value)
                    filtered = True
    else:
        # show only the active marking period by default
        active_mps = course.marking_period.filter(active=True)
        if active_mps:
            filter_form = GradebookFilterForm(initial={'marking_period': active_mps[0]})
            items = items.filter(marking_period=active_mps[0])
        else:
            filter_form = GradebookFilterForm()
        filter_form.update_querysets(course)
    
    # Freeze these now in case someone else gets in here!
    items = items.order_by('id').all()
    # whoa, super roll of the dice. is Item.demonstration_set really guaranteed to be ordered by id?
    # precarious; sorting must match items (and demonstrations!) exactly
    marks = Mark.objects.filter(item__in=items).order_by('item__id', 'demonstration__id').all() 
    items_count = items.filter(demonstration=None).count() + Demonstration.objects.filter(item__in=items).count()
    for student in students:
        student_marks = marks.filter(student=student)
        if student_marks.count() < items_count:
            # maybe student enrolled after assignments were created
            for item in items:
                if len(item.demonstration_set.all()):
                    # must create mark for each demonstration
                    for demonstration in item.demonstration_set.all():
                        mark, created = Mark.objects.get_or_create(item=item, demonstration=demonstration, student=student)
                        if created:
                            mark.save()
                else:
                    # a regular item without demonstrations; make only one mark
                    mark, created = Mark.objects.get_or_create(item=item, student=student)
                    if created:
                        mark.save()
        if student_marks.count() > items_count:
            # Yikes, there are multiple marks per student per item. Stop loading the gradebook now.
            if 'dangerous' in request.GET:
                pass
            else:
                raise Exception('Multiple marks per student per item.')
        student.marks = student_marks
        student.average = gradebook_get_average(student, course, None, None, None)
        if filtered:
            student.filtered_average = gradebook_get_average(student, course, filter_form.cleaned_data['category'],
                                                             filter_form.cleaned_data['marking_period'], items)
        # TC's column of counts
        # TODO: don't hardcode
        standards_category = Category.objects.get(name='Standards')
        PASSING_GRADE = 3
        standards_objects = Item.objects.filter(course=course, category=standards_category, mark__student=student).annotate(best_mark=Max('mark__mark')).exclude(best_mark=None)
        standards_count_passing = standards_objects.filter(best_mark__gte=PASSING_GRADE).count()
        standards_count_total = standards_objects.count()
        if standards_count_total:
            student.standards_counts = '{} / {} ({:.0f}%)'.format(standards_count_passing, standards_count_total, 100.0 * standards_count_passing / standards_count_total)
        else:
            student.standards_counts_ = None
        if filtered:
            standards_objects = items.filter(course=course, category=standards_category, mark__student=student).annotate(best_mark=Max('mark__mark')).exclude(best_mark=None)
            standards_count_passing = standards_objects.filter(best_mark__gte=PASSING_GRADE).count()
            standards_count_total = standards_objects.count()
            if standards_count_total:
                student.filtered_standards_counts = '{} / {} ({:.0f}%)'.format(standards_count_passing, standards_count_total, 100.0 * standards_count_passing / standards_count_total)
            else:
                student.filtered_standards_counts = None

        # TC's row of counts
        # TODO: don't hardcode
        for item in items:
            if item.category != standards_category:
                item.marks_counts = 'N/A'
                continue
            marks_count_passing = item.mark_set.filter(mark__gte=PASSING_GRADE).count()
            marks_count_total = item.mark_set.exclude(mark=None).count()
            if marks_count_total:
                item.marks_counts = '{} / {} ({:.0f}%)'.format(marks_count_passing, marks_count_total, 100.0 * marks_count_passing / marks_count_total)
            else:
                item.marks_counts = None

    # Gather visual flagging criteria
    calculation_rule = benchmark_find_calculation_rule(course.marking_period.all()[0].school_year)
    category_flag_criteria = {}
    for category in Category.objects.filter(item__in=items).distinct():
        category_flag_criteria[category.pk] = []
        substitutions = calculation_rule.substitution_set.filter(apply_to_departments=course.department, apply_to_categories=category, flag_visually=True)
        for substitution in substitutions:
            category_flag_criteria[category.pk].append(substitution.operator + ' ' + str(substitution.match_value))

    return render_to_response('benchmark_grade/gradebook.html', {
        'items': items,
        'item_pks': ','.join(map(str,items.values_list('pk', flat=True))),
        'students': students,
        'course': course,
        'teacher_courses': teacher_courses,
        'filtered' : filtered,
        'filter_form': filter_form,
        'category_flag_criteria': category_flag_criteria,
    }, RequestContext(request, {}),)
Example #14
0
def benchmark_report_card(template, options, students, format="odt"):
    PASSING_GRADE = 3 # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it

    data = get_default_data()
    for_date = options['date']
    school_year = SchoolYear.objects.filter(start_date__lt=for_date).order_by('-start_date')[0]
    calculation_rule = benchmark_find_calculation_rule(school_year)
    attendance_marking_periods = MarkingPeriod.objects.filter(school_year=school_year,
                                                  start_date__lt=for_date,
                                                  show_reports=True)
    marking_period = attendance_marking_periods.order_by('-start_date')[0]
    for student in students:
        student.courses = Course.objects.filter(
            courseenrollment__user=student,
            graded=True,
            marking_period=marking_period,
        ).distinct().order_by('department')
        student.count_total_by_category_name = {}
        student.count_missing_by_category_name = {}
        student.count_passing_by_category_name = {}
        for course in student.courses:
            course.average = gradebook_get_average(student, course, None, marking_period, None)
            course.current_marking_periods = course.marking_period.filter(start_date__lt=for_date).order_by('start_date')
            course.categories = Category.objects.filter(item__course=course, item__mark__student=student).distinct()
            course.category_by_name = {}
            for category in course.categories:
                try:
                    category.weight_percentage = calculation_rule.per_course_category_set.get(category=category, apply_to_departments=course.department).weight * Decimal(100)
                except CalculationRulePerCourseCategory.DoesNotExist:
                    category.weight_percentage = Decimal(0)
                category.weight_percentage = category.weight_percentage.quantize(Decimal('0'), ROUND_HALF_UP)
                category.overall_count_total = 0
                category.overall_count_missing = 0
                category.overall_count_passing = 0
                for course_marking_period in course.current_marking_periods:
                    course_marking_period.category = category
                    course_marking_period.category.average = gradebook_get_average(student, course, category, course_marking_period, None)
                    items = Item.objects.filter(course=course, marking_period=course_marking_period, category=category, mark__student=student).annotate(best_mark=Max('mark__mark')).exclude(best_mark=None)
                    course_marking_period.category.count_total = items.exclude(best_mark=None).distinct().count()
                    course_marking_period.category.count_missing = items.filter(best_mark__lt=PASSING_GRADE).distinct().count()
                    course_marking_period.category.count_passing = items.filter(best_mark__gte=PASSING_GRADE).distinct().count()
                    if course_marking_period.category.count_total:
                        course_marking_period.category.count_percentage = (Decimal(course_marking_period.category.count_passing) / course_marking_period.category.count_total * 100).quantize(Decimal('0', ROUND_HALF_UP))

                    if course.department is not None and course.department.name == 'Corporate Work Study': # TODO: Remove this terrible hack
                        course_marking_period.category.count_passing = course_marking_period.category.count_total
                        course_marking_period.category.count_missing = 0
                        course_marking_period.category.count_percentage = 100

                    category.overall_count_total += course_marking_period.category.count_total
                    category.overall_count_missing += course_marking_period.category.count_missing
                    category.overall_count_passing += course_marking_period.category.count_passing

                    item_names = items.values_list('name').distinct()
                    course_marking_period.category.item_groups = []
                    for item_name_tuple in item_names:
                        item_name = item_name_tuple[0]
                        item_group = struct()
                        item_group.name = item_name
                        item_group.items = items.filter(name=item_name).distinct()
                        course_marking_period.category.item_groups.append(item_group)

                    course_marking_period.category_by_name = getattr(course_marking_period, 'category_by_name', {})
                    # make a copy so we don't overwrite the last marking period's data
                    course_marking_period.category_by_name[category.name] = copy.copy(course_marking_period.category)
                    # the last time through the loop is the most current marking period,
                    # so give that to anyone who doesn't request an explicit marking period
                    #category = course_marking_period.category

                course.category_by_name[category.name] = category
                if category.overall_count_total:
                    category.overall_count_percentage = (Decimal(category.overall_count_passing) / category.overall_count_total * 100).quantize(Decimal('0', ROUND_HALF_UP))
                student.count_total_by_category_name[category.name] = student.count_total_by_category_name.get(category.name, 0) + category.overall_count_total
                student.count_missing_by_category_name[category.name] = student.count_missing_by_category_name.get(category.name, 0) + category.overall_count_missing
                student.count_passing_by_category_name[category.name] = student.count_passing_by_category_name.get(category.name, 0) + category.overall_count_passing

        student.count_percentage_by_category_name = {}
        for category_name, value in student.count_total_by_category_name.items():
            if value:
                student.count_percentage_by_category_name[category_name] = (Decimal(student.count_passing_by_category_name[category_name]) / value * 100).quantize(Decimal('0', ROUND_HALF_UP))

        # make categories available 
            
        student.session_gpa = student.calculate_gpa_mp(marking_period)
        # Cannot just rely on student.gpa for the cumulative GPA; it does not reflect report's date
        student.current_report_cumulative_gpa = student.calculate_gpa(for_date)


        #Attendance for marking period
        i = 1
        student.absent_total = 0
        student.tardy_total = 0
        student.dismissed_total = 0
        student.attendance_marking_periods = []
        for mp in attendance_marking_periods.order_by('start_date'):
            absent = student.student_attn.filter(status__absent=True, date__range=(mp.start_date, mp.end_date)).count()
            tardy = student.student_attn.filter(status__tardy=True, date__range=(mp.start_date, mp.end_date)).count()
            dismissed = student.student_attn.filter(status__code="D", date__range=(mp.start_date, mp.end_date)).count()
            student.absent_total += absent
            student.tardy_total += tardy
            student.dismissed_total += dismissed
            amp = struct()
            amp.absent = absent
            amp.tardy = tardy
            amp.dismissed = dismissed
            amp.number = i
            student.attendance_marking_periods.append(amp)
            i += 1

    data['students'] = students
    data['school_year'] = school_year
    data['marking_period'] = marking_period.name # just passing object makes appy think it's undefined
    filename = 'output'
    #return pod_save(filename, ".pdf", data, template)
    return pod_save(filename, "." + str(format), data, template)
Example #15
0
def benchmark_report_card(template, options, students, format="odt"):
    PASSING_GRADE = 3  # TODO: pull config value. Roche has it set to something crazy now and I don't want to deal with it

    data = get_default_data()
    for_date = options['date']
    try:
        omit_substitutions = options['omit_substitutions']
    except KeyError:
        omit_substitutions = False
    school_year = SchoolYear.objects.filter(
        start_date__lt=for_date).order_by('-start_date')[0]
    calculation_rule = benchmark_find_calculation_rule(school_year)
    attendance_marking_periods = MarkingPeriod.objects.filter(
        school_year=school_year, start_date__lt=for_date, show_reports=True)
    marking_period = attendance_marking_periods.order_by('-start_date')[0]
    for student in students:
        student.year_courses = Course.objects.filter(
            courseenrollment__user=student,
            graded=True,
            marking_period__school_year=school_year,
        ).distinct().order_by('department')
        student.courses = []
        student.count_total_by_category_name = {}
        student.count_missing_by_category_name = {}
        student.count_passing_by_category_name = {}
        for course in student.year_courses:
            course.average = gradebook_get_average(
                student,
                course,
                None,
                marking_period,
                None,
                omit_substitutions=omit_substitutions)
            course.current_marking_periods = course.marking_period.filter(
                start_date__lt=for_date).order_by('start_date')
            course.categories = Category.objects.filter(
                item__course=course, item__mark__student=student).distinct()
            course.category_by_name = {}
            for category in course.categories:
                try:
                    category.weight_percentage = calculation_rule.per_course_category_set.get(
                        category=category,
                        apply_to_departments=course.department
                    ).weight * Decimal(100)
                except CalculationRulePerCourseCategory.DoesNotExist:
                    category.weight_percentage = Decimal(0)
                category.weight_percentage = category.weight_percentage.quantize(
                    Decimal('0'), ROUND_HALF_UP)
                category.overall_count_total = 0
                category.overall_count_missing = 0
                category.overall_count_passing = 0
                for course_marking_period in course.current_marking_periods:
                    course_marking_period.category = category
                    course_marking_period.category.average = gradebook_get_average(
                        student,
                        course,
                        category,
                        course_marking_period,
                        None,
                        omit_substitutions=omit_substitutions)
                    items = Item.objects.filter(
                        course=course,
                        marking_period=course_marking_period,
                        category=category,
                        mark__student=student).annotate(
                            best_mark=Max('mark__mark')).exclude(
                                best_mark=None)
                    course_marking_period.category.count_total = items.exclude(
                        best_mark=None).distinct().count()
                    course_marking_period.category.count_missing = items.filter(
                        best_mark__lt=PASSING_GRADE).distinct().count()
                    course_marking_period.category.count_passing = items.filter(
                        best_mark__gte=PASSING_GRADE).distinct().count()
                    if course_marking_period.category.count_total:
                        course_marking_period.category.count_percentage = (
                            Decimal(
                                course_marking_period.category.count_passing) /
                            course_marking_period.category.count_total *
                            100).quantize(Decimal('0', ROUND_HALF_UP))

                    if course.department is not None and course.department.name == 'Corporate Work Study':  # TODO: Remove this terrible hack
                        course_marking_period.category.count_passing = course_marking_period.category.count_total
                        course_marking_period.category.count_missing = 0
                        course_marking_period.category.count_percentage = 100

                    category.overall_count_total += course_marking_period.category.count_total
                    category.overall_count_missing += course_marking_period.category.count_missing
                    category.overall_count_passing += course_marking_period.category.count_passing

                    item_names = items.values_list('name').distinct()
                    course_marking_period.category.item_groups = []
                    for item_name_tuple in item_names:
                        item_name = item_name_tuple[0]
                        item_group = struct()
                        item_group.name = item_name
                        item_group.items = items.filter(
                            name=item_name).distinct()
                        course_marking_period.category.item_groups.append(
                            item_group)

                    course_marking_period.category_by_name = getattr(
                        course_marking_period, 'category_by_name', {})
                    # make a copy so we don't overwrite the last marking period's data
                    course_marking_period.category_by_name[
                        category.name] = copy.copy(
                            course_marking_period.category)
                    # the last time through the loop is the most current marking period,
                    # so give that to anyone who doesn't request an explicit marking period
                    #category = course_marking_period.category

                course.category_by_name[category.name] = category
                if category.overall_count_total:
                    category.overall_count_percentage = (
                        Decimal(category.overall_count_passing) /
                        category.overall_count_total * 100).quantize(
                            Decimal('0', ROUND_HALF_UP))
                student.count_total_by_category_name[
                    category.name] = student.count_total_by_category_name.get(
                        category.name, 0) + category.overall_count_total
                student.count_missing_by_category_name[
                    category.
                    name] = student.count_missing_by_category_name.get(
                        category.name, 0) + category.overall_count_missing
                student.count_passing_by_category_name[
                    category.
                    name] = student.count_passing_by_category_name.get(
                        category.name, 0) + category.overall_count_passing

            # some components of report need access to courses for entire year (student.year_courses)
            # but we must keep student.courses restricted to the current marking period for compatibility
            if marking_period in course.marking_period.all():
                student.courses.append(course)

        student.count_percentage_by_category_name = {}
        for category_name, value in student.count_total_by_category_name.items(
        ):
            if value:
                student.count_percentage_by_category_name[category_name] = (
                    Decimal(
                        student.count_passing_by_category_name[category_name])
                    / value * 100).quantize(Decimal('0', ROUND_HALF_UP))

        # make categories available

        student.session_gpa = student.calculate_gpa_mp(marking_period)
        # Cannot just rely on student.gpa for the cumulative GPA; it does not reflect report's date
        student.current_report_cumulative_gpa = student.calculate_gpa(for_date)

        #Attendance for marking period
        i = 1
        student.absent_total = 0
        student.tardy_total = 0
        student.dismissed_total = 0
        student.attendance_marking_periods = []
        for mp in attendance_marking_periods.order_by('start_date'):
            absent = student.student_attn.filter(
                status__absent=True,
                date__range=(mp.start_date, mp.end_date)).count()
            tardy = student.student_attn.filter(
                status__tardy=True,
                date__range=(mp.start_date, mp.end_date)).count()
            dismissed = student.student_attn.filter(
                status__code="D",
                date__range=(mp.start_date, mp.end_date)).count()
            student.absent_total += absent
            student.tardy_total += tardy
            student.dismissed_total += dismissed
            amp = struct()
            amp.absent = absent
            amp.tardy = tardy
            amp.dismissed = dismissed
            amp.number = i
            student.attendance_marking_periods.append(amp)
            i += 1

    data['students'] = students
    data['school_year'] = school_year
    data[
        'marking_period'] = marking_period.name  # just passing object makes appy think it's undefined
    data['draw_gauge'] = draw_gauge
    filename = 'output'
    #return pod_save(filename, ".pdf", data, template)
    return pod_save(filename, "." + str(format), data, template)
Example #16
0
    def get_student_transcript_data(self, student, omit_substitutions=False):
        # benchmark_grade transcripts aren't radically different,
        # but they have some additional data
        if "ecwsp.benchmark_grade" in settings.INSTALLED_APPS:
            from ecwsp.benchmark_grade.models import Aggregate
            from ecwsp.benchmark_grade.utility import gradebook_get_average, benchmark_find_calculation_rule, gradebook_get_category_average

        student.years = SchoolYear.objects.filter(
            markingperiod__show_reports=True,
            start_date__lt=self.for_date,
            markingperiod__course__courseenrollment__user=student,
        ).exclude(
            omityeargpa__student=student).distinct().order_by('start_date')
        for year in student.years:
            year.credits = 0
            year.possible_credits = 0
            year.mps = MarkingPeriod.objects.filter(
                course__courseenrollment__user=student,
                school_year=year,
                show_reports=True).distinct().order_by("start_date")
            i = 1
            for mp in year.mps:
                setattr(year, "mp" + str(i), mp.shortname)
                i += 1
            while i <= 6:
                setattr(year, "mp" + str(i), "")
                i += 1
            year.courses = Course.objects.filter(
                courseenrollment__user=student,
                graded=True,
                marking_period__school_year=year,
                marking_period__show_reports=True).distinct()
            year.courses = UserPreference.objects.get_or_create(
                user=self.user)[0].sort_courses(year.courses)
            year_grades = student.grade_set.filter(
                marking_period__show_reports=True,
                marking_period__end_date__lte=self.for_date)
            # course grades
            for course in year.courses:
                # Grades
                course_grades = year_grades.filter(course=course).distinct()
                course_aggregates = None
                if year.benchmark_grade:
                    course_aggregates = Aggregate.objects.filter(
                        course=course, student=student)
                i = 1
                for mp in year.mps:
                    if mp not in course.marking_period.all():
                        # Obey the registrar! Don't include grades from marking periods when the course didn't meet.
                        setattr(course, "grade" + str(i), "")
                        i += 1
                        continue
                    if year.benchmark_grade:
                        setattr(
                            course, "grade" + str(i),
                            gradebook_get_average(
                                student,
                                course,
                                None,
                                mp,
                                omit_substitutions=omit_substitutions))
                    else:
                        # We can't overwrite cells, so we have to get seperate variables for each mp grade.
                        try:
                            grade = course_grades.get(
                                marking_period=mp).get_grade()
                            grade = "   " + str(grade) + "   "
                        except:
                            grade = ""
                        setattr(course, "grade" + str(i), grade)
                    i += 1
                while i <= 6:
                    setattr(course, "grade" + str(i), "")
                    i += 1
                course.final = course.get_final_grade(
                    student, date_report=self.for_date)

                if (mp.end_date < self.for_date and course.is_passing(
                        student,
                        cache_grade=course.final,
                        cache_passing=self.passing_grade,
                        cache_letter_passing=self.letter_passing_grade)
                        and course.credits):
                    year.credits += course.credits
                if course.credits:
                    year.possible_credits += course.credits

            year.categories_as_courses = []
            if year.benchmark_grade:
                calculation_rule = benchmark_find_calculation_rule(year)
                for category_as_course in calculation_rule.category_as_course_set.filter(
                        include_departments=course.department):
                    i = 1
                    for mp in year.mps:
                        setattr(
                            category_as_course.category, 'grade{}'.format(i),
                            gradebook_get_category_average(
                                student, category_as_course.category, mp))
                        i += 1
                    year.categories_as_courses.append(
                        category_as_course.category)

            # Averages per marking period
            i = 1
            for mp in year.mps:
                if mp.end_date < self.for_date:
                    setattr(year, 'mp' + str(i) + 'ave',
                            student.calculate_gpa_mp(mp))
                    i += 1
            while i <= 6:
                setattr(year, 'mp' + str(i) + 'ave', "")
                i += 1

            year.ave = student.calculate_gpa_year(year, self.for_date)

            # Attendance for year
            if not year.id in self.year_days:
                self.year_days[year.id] = year.get_number_days()
            year.total_days = self.year_days[year.id]
            year.nonmemb = student.student_attn.filter(
                status__code="nonmemb",
                date__range=(year.start_date, year.end_date)).count()
            year.absent = student.student_attn.filter(
                status__absent=True,
                date__range=(year.start_date, year.end_date)).count()
            year.tardy = student.student_attn.filter(
                status__tardy=True,
                date__range=(year.start_date, year.end_date)).count()
            year.dismissed = student.student_attn.filter(
                status__code="D",
                date__range=(year.start_date, year.end_date)).count()
            # credits per dept
            student.departments = Department.objects.filter(
                course__courseenrollment__user=student).distinct()
            student.departments_text = ""
            for dept in student.departments:
                c = 0
                for course in student.course_set.filter(
                        department=dept,
                        marking_period__school_year__end_date__lt=self.
                        for_date,
                        graded=True).distinct():
                    if course.credits and course.is_passing(
                            student,
                            cache_passing=self.passing_grade,
                            cache_letter_passing=self.letter_passing_grade):
                        c += course.credits
                dept.credits = c
                student.departments_text += "| %s: %s " % (dept, dept.credits)
            student.departments_text += "|"

            # Standardized tests
            if 'ecwsp.standard_test' in settings.INSTALLED_APPS:
                from ecwsp.standard_test.models import StandardTest
                student.tests = []
                student.highest_tests = []
                for test_result in student.standardtestresult_set.filter(
                        test__show_on_reports=True,
                        show_on_reports=True).order_by('test'):
                    test_result.categories = ""
                    for cat in test_result.standardcategorygrade_set.filter(
                            category__is_total=False):
                        test_result.categories += '%s: %s  |  ' % (
                            cat.category.name, strip_trailing_zeros(cat.grade))
                    test_result.categories = test_result.categories[:-3]
                    student.tests.append(test_result)

                for test in StandardTest.objects.filter(
                        standardtestresult__student=student,
                        show_on_reports=True,
                        standardtestresult__show_on_reports=True).distinct():
                    test.total = strip_trailing_zeros(
                        test.get_cherry_pick_total(student))
                    student.highest_tests.append(test)