diff --git a/FusionIIIT/applications/examination/urls.py b/FusionIIIT/applications/examination/urls.py index cf8a12637..0f1254858 100644 --- a/FusionIIIT/applications/examination/urls.py +++ b/FusionIIIT/applications/examination/urls.py @@ -30,7 +30,7 @@ path('download_excel/', DownloadExcelView.as_view(), name='download_excel'),#old #new - url(r'submitGrades/', views.submitGrades, name='submitGrades'),#new + url(r'submitGrades/', views.submitGrades.as_view(), name='submitGrades'),#new url(r'submitEntergrades/', views.submitEntergrades, name='submitEntergrades'),#new path('submitEntergradesStoring/', views.submitEntergradesStoring.as_view(),#new name='submitEntergradesStoring'), @@ -61,6 +61,9 @@ path('upload_grades_prof/',views.upload_grades_prof,name='upload_grades_prof'), path('validateDean/',views.validateDean,name='validateDean'), path('validateDeanSubmit/',views.validateDeanSubmit,name='validateDeanSubmit'), - + path('downloadGrades/',views.downloadGrades,name='downloadGrades'), + path('generate_pdf/',views.generate_pdf,name='generate_pdf'), + path('generate-result/',views.generate_result,name='generate_pdf'), +# path('get_courses/',views.get_courses,name='get_courses'), ] diff --git a/FusionIIIT/applications/examination/views.py b/FusionIIIT/applications/examination/views.py index b4d8cdb94..903e55eba 100644 --- a/FusionIIIT/applications/examination/views.py +++ b/FusionIIIT/applications/examination/views.py @@ -1,9 +1,14 @@ from notifications.signals import notify from django.views import View from django.views.generic import View +import traceback from django.http import HttpResponse import csv import json +from openpyxl import Workbook +from openpyxl.styles import Alignment, Font +from openpyxl.utils import get_column_letter +from io import BytesIO,StringIO from django.db.models import IntegerField from django.db.models.functions import Cast from django.db.models.query_utils import Q @@ -29,7 +34,7 @@ ) from applications.eis.models import faculty_about, emp_research_projects from applications.academic_information.models import Course -from applications.academic_procedures.models import course_registration, Register +from applications.academic_procedures.models import course_registration, Register,Semester from applications.programme_curriculum.filters import CourseFilter from notification.views import examination_notif from applications.department.models import SpecialRequest, Announcements @@ -56,10 +61,15 @@ from applications.online_cms.models import Student_grades from django.http import JsonResponse import csv -from applications.programme_curriculum.models import Course as Courses, CourseInstructor +from applications.programme_curriculum.models import Course as Courses, CourseInstructor,Discipline,Batch, CourseSlot from django.urls import reverse - - +from reportlab.pdfgen import canvas +from reportlab.lib.pagesizes import letter +from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle +from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer +from reportlab.lib import colors +from reportlab.lib.colors import HexColor +from reportlab.lib.units import inch @login_required(login_url="/accounts/login") def exam(request): """ @@ -505,29 +515,29 @@ def generate_transcript(request): # course_detail = Curriculum.objects.get( # course_id=course.course_id, batch=grade.batch) course_instance = Courses.objects.get(id=course.course_id_id) - check_authentication_object = authentication.objects.filter( - course_id=course_instance, course_year=grade.year) - all_authenticators_true = True - - if check_authentication_object: - # Iterate over each authentication object - for auth_obj in check_authentication_object: - # Check if all authenticators are true - if not (auth_obj.authenticator_1 and auth_obj.authenticator_2 and auth_obj.authenticator_3): - all_authenticators_true = False - break # No need to check further if any authenticator is False - else: + # check_authentication_object = authentication.objects.filter( + # course_id=course_instance, course_year=grade.year) + # all_authenticators_true = True + + # if check_authentication_object: + # # Iterate over each authentication object + # for auth_obj in check_authentication_object: + # # Check if all authenticators are true + # if not (auth_obj.authenticator_1 and auth_obj.authenticator_2 and auth_obj.authenticator_3): + # all_authenticators_true = False + # break # No need to check further if any authenticator is False + # else: # Create authentication object if it doesn't exist - authentication_object = authentication.objects.create( - course_id=course_instance, course_year=grade.year) + # authentication_object = authentication.objects.create( + # course_id=course_instance, course_year=grade.year) # Get all registrations for the course and year - registrations = authentication.objects.filter( - course_id=course_instance, course_year=grade.year) - all_authenticators_true = False + # registrations = authentication.objects.filter( + # course_id=course_instance, course_year=grade.year) + # all_authenticators_true = False course_grades[course_instance] = { 'grade': grade, - 'all_authenticators_true': all_authenticators_true + # 'all_authenticators_true': all_authenticators_true } # Store the grade except Student_grades.DoesNotExist: # Grade not available @@ -595,11 +605,11 @@ def updateGrades(request): id__in=unique_course_ids.values_list("course_id_int", flat=True) ) - unique_batch_ids = Student_grades.objects.values("batch").distinct() - + unique_year_ids = Student_grades.objects.values('year').distinct() + # print(unique_year_ids) context = { "courses_info": courses_info, - "unique_batch_ids": unique_batch_ids, + "unique_year_ids": unique_year_ids, } return render(request, "../templates/examination/submitGrade.html", context) @@ -607,10 +617,11 @@ def updateGrades(request): def updateEntergrades(request): course_id = request.GET.get("course") - semester_id = request.GET.get("semester") - batch = request.GET.get("batch") + + year = request.GET.get("year") + # print(course_id,semester_id ,year) course_present = Student_grades.objects.filter( - course_id=course_id, semester=semester_id, batch=batch + course_id=course_id, year=year ) if not course_present: @@ -669,29 +680,39 @@ def post(self, request): return render(request, '../templates/examination/grades_updated.html', {}) -@login_required(login_url="/accounts/login") -def submitGrades(request): - - unique_course_ids = course_registration.objects.values("course_id").distinct() - working_years = course_registration.objects.values("working_year").distinct() - - # Cast the course IDs to integers - unique_course_ids = unique_course_ids.annotate( - course_id_int=Cast("course_id", IntegerField()) - ) - - # Retrieve course names and course codes based on unique course IDs - - # print(unique_course_ids) - courses_info = Courses.objects.filter( - id__in=unique_course_ids.values_list("course_id_int", flat=True) - ) - - context = {"courses_info": courses_info, "working_years": working_years} - - # print(working_years) - - return render(request, "../templates/examination/gradeSubmission.html", context) +class submitGrades(APIView): + login_url = "/accounts/login" + + def get(self, request): + academic_year = request.GET.get('academic_year') + + if academic_year: + if academic_year is None or not academic_year.isdigit(): + return JsonResponse({}) + # Filter course registration based on the academic year and get unique course IDs + unique_course_ids = course_registration.objects.filter( + working_year=academic_year + ).values("course_id").distinct() + + # Cast the course IDs to integers + unique_course_ids = unique_course_ids.annotate( + course_id_int=Cast("course_id", IntegerField()) + ) + + # Retrieve course information based on the unique course IDs + courses_info = Courses.objects.filter( + id__in=unique_course_ids.values_list("course_id_int", flat=True) + ) + + # Return the course information as JSON response + return JsonResponse({"courses": list(courses_info.values())}) + + # If no academic year is provided, return the working years for the dropdown + working_years = course_registration.objects.values("working_year").distinct() + + context = {"working_years": working_years} + + return render(request, "../templates/examination/gradeSubmission.html", context) def submitEntergrades(request): @@ -884,19 +905,17 @@ def upload_grades(request): return JsonResponse( {"error": message, "redirect_url": redirect_url}, status=400 ) - - semester = students.first().semester_id_id - + try: # Parse the CSV file decoded_file = csv_file.read().decode("utf-8").splitlines() reader = csv.DictReader(decoded_file) - required_columns = ["roll_no", "name", "grade", "remarks"] + required_columns = ["roll_no", "grade", "remarks"] if not all(column in reader.fieldnames for column in required_columns): return JsonResponse( { - "error": "CSV file must contain the following columns: roll_no, name, grade, remarks." + "error": "CSV file must contain the following columns: roll_no, grade, remarks." }, status=400, ) @@ -907,7 +926,8 @@ def upload_grades(request): remarks = row["remarks"] batch_prefix = roll_no[:2] batch = int(f"20{batch_prefix}") - + semester=Student.objects.get(id_id=roll_no).curr_semester_no + Student_grades.objects.create( roll_no=roll_no, grade=grade, @@ -978,7 +998,7 @@ def submitGradesProf(request): # Retrieve course names and course codes based on unique course IDs - print(unique_course_ids) + # print(unique_course_ids) courses_info = Courses.objects.filter( id__in=unique_course_ids.values_list("course_id_int", flat=True) ) @@ -991,12 +1011,36 @@ def submitGradesProf(request): def download_template(request): - response = HttpResponse(content_type="text/csv") - response["Content-Disposition"] = f'attachment; filename="template.csv"' - writer = csv.writer(response) - writer.writerow(["roll_no", "name", "grade", "remarks"]) + course = request.GET.get('course') + year = request.GET.get('year') + + if not course or not year: + return JsonResponse({'error': 'Course and year are required'}, status=400) + + try: + + course_info = course_registration.objects.filter(course_id_id=course, working_year=year) + + + if not course_info.exists(): + return JsonResponse({'error': 'No registration data found for the provided course and year'}, status=404) + + + response = HttpResponse(content_type="text/csv") + response["Content-Disposition"] = f'attachment; filename="template.csv"' + writer = csv.writer(response) + + writer.writerow(["roll_no", "grade", "remarks"]) + + for entry in course_info: + student = entry.student_id + writer.writerow([student.id_id, "", ""]) + + return response + + except Exception as e: + return JsonResponse({'error': str(e)}, status=500) - return response @@ -1027,10 +1071,10 @@ def verifyGradesDean(request): def updateEntergradesDean(request): course_id = request.GET.get("course") - semester_id = request.GET.get("semester") + batch = request.GET.get("batch") course_present = Student_grades.objects.filter( - course_id=course_id, semester=semester_id, batch=batch + course_id=course_id, batch=batch ) if not course_present: @@ -1081,7 +1125,7 @@ def upload_grades_prof(request): return JsonResponse( {"error": message, "redirect_url": redirect_url}, status=400 ) - print(courses.first().reSubmit) + if courses and not courses.first().reSubmit: message = "THIS Course was Already Submitted" @@ -1090,18 +1134,18 @@ def upload_grades_prof(request): {"error": message, "redirect_url": redirect_url}, status=400 ) - semester = students.first().semester_id_id + try: # Parse the CSV file decoded_file = csv_file.read().decode("utf-8").splitlines() reader = csv.DictReader(decoded_file) - required_columns = ["roll_no", "name", "grade", "remarks"] + required_columns = ["roll_no", "grade", "remarks"] if not all(column in reader.fieldnames for column in required_columns): return JsonResponse( { - "error": "CSV file must contain the following columns: roll_no, name, grade, remarks." + "error": "CSV file must contain the following columns: roll_no, grade, remarks." }, status=400, ) @@ -1112,12 +1156,14 @@ def upload_grades_prof(request): remarks = row["remarks"] batch_prefix = roll_no[:2] batch = int(f"20{batch_prefix}") + semester=Student.objects.get(id_id=roll_no).curr_semester_no reSubmit=False Student_grades.objects.update_or_create( roll_no=roll_no, course_id_id=course_id, year=academic_year, semester=semester, + batch=batch, # Fields that will be updated if a match is found defaults={ 'grade': grade, @@ -1230,7 +1276,7 @@ def validateDeanSubmit(request): } return render(request, "../templates/examination/messageDean.html", context) - semester = students.first().semester_id_id + mismatch=[] for row in reader: roll_no = row["roll_no"] @@ -1238,6 +1284,7 @@ def validateDeanSubmit(request): remarks = row["remarks"] batch_prefix = roll_no[:2] batch = int(f"20{batch_prefix}") + semester=Student.objects.get(id_id=roll_no).curr_semester_no Student_grades.objects.filter( roll_no=roll_no, course_id_id=course_id, @@ -1278,3 +1325,361 @@ def validateDeanSubmit(request): "message": error_message, } return render(request, "../templates/examination/messageDean.html", context) + + +def downloadGrades(request): + academic_year = request.GET.get('academic_year') + + if academic_year: + if academic_year is None or not academic_year.isdigit(): + return JsonResponse({}) + # print(request.user,1) + unique_course_ids = ( + CourseInstructor.objects.filter(instructor_id_id=request.user.username) + .values("course_id_id") + .distinct() + ) + # unique_course_ids = course_registration.objects.values( + # 'course_id').distinct() + + # Cast the course IDs to integers + unique_course_ids = unique_course_ids.annotate( + course_id_int=Cast("course_id", IntegerField()) + ) + + # Retrieve course names and course codes based on unique course IDs + + # print(unique_course_ids) + courses_info = Student_grades.objects.filter( + year=academic_year, + course_id_id__in=unique_course_ids.values_list("course_id_int", flat=True) + ) + courses_details=Courses.objects.filter( + id__in=courses_info.values_list("course_id_id", flat=True) + ) + # print(courses_info.values(),'abcd') + return JsonResponse({"courses": list(courses_details.values())}) + + + working_years = course_registration.objects.values("working_year").distinct() + + context = {"working_years": working_years} + + return render(request, "../templates/examination/download_resultProf.html", context) + + +# def get_courses(request): +def generate_pdf(request): + course_id = request.POST.get('course_id') + academic_year = request.POST.get('academic_year') + course_info = get_object_or_404(Courses, id=course_id) + grades = Student_grades.objects.filter(course_id_id=course_id, year=academic_year).order_by("roll_no") + + # Calculate grade counts + all_grades = ["O", "A+", "A", "B+", "B", "C+", "C", "D+", "D", "F", "I", "S", "X"] + grade_counts = {grade: grades.filter(grade=grade).count() for grade in all_grades} + + response = HttpResponse(content_type="application/pdf") + response["Content-Disposition"] = f'attachment; filename="{course_info.code}_grades.pdf"' + + doc = SimpleDocTemplate(response, pagesize=letter) + elements = [] + styles = getSampleStyleSheet() + + # Custom Header Style + header_style = ParagraphStyle( + "HeaderStyle", + parent=styles["Heading1"], + fontName="Helvetica-Bold", + fontSize=16, + textColor=HexColor("#333333"), + spaceAfter=20, + alignment=1, # Center alignment + ) + subheader_style = ParagraphStyle( + "SubheaderStyle", + parent=styles["Normal"], + fontSize=12, + textColor=HexColor("#666666"), + spaceAfter=10, + ) + instructor = request.user.first_name + " " + request.user.last_name + + # Add Header + elements.append(Paragraph(f"Grade Sheet", header_style)) + field_label_style = ParagraphStyle( + "FieldLabelStyle", + parent=styles["Normal"], + fontSize=12, + textColor=colors.black, # Black text color for labels + spaceAfter=5, +) + field_value_style = ParagraphStyle( + "FieldValueStyle", + parent=styles["Normal"], + fontSize=12, + textColor=HexColor("#666666"), # Gray text color for values + spaceAfter=10, +) + +# Add fields with labels in black and values in gray + elements.append(Paragraph(f"Session: {academic_year}", field_label_style)) + elements.append(Paragraph(f"Semester: {grades.first().semester}", field_label_style)) + elements.append(Paragraph(f"Course Code: {course_info.code}", field_label_style)) + elements.append(Paragraph(f"Course Name: {course_info.name}", field_label_style)) + elements.append(Paragraph(f"Instructor: {instructor}", field_label_style)) + + # Table Data with Wider Column Widths + data = [["S.No.", "Roll Number", "Grade"]] + for i, grade in enumerate(grades, 1): + data.append([i, grade.roll_no, grade.grade]) + table = Table(data, colWidths=[80, 300, 100]) + + # Improved Table Style + table.setStyle( + TableStyle( + [ + ("BACKGROUND", (0, 0), (-1, 0), HexColor("#E0E0E0")), + ("TEXTCOLOR", (0, 0), (-1, 0), colors.black), + ("ALIGN", (0, 0), (-1, 0), "CENTER"), + ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"), + ("FONTSIZE", (0, 0), (-1, 0), 14), + ("BOTTOMPADDING", (0, 0), (-1, 0), 10), + ("BACKGROUND", (0, 1), (-1, -1), HexColor("#F9F9F9")), + ("ROWBACKGROUNDS", (0, 1), (-1, -1), [HexColor("#F9F9F9"), colors.white]), + ("TEXTCOLOR", (0, 1), (-1, -1), colors.black), + ("FONTNAME", (0, 1), (-1, -1), "Helvetica"), + ("FONTSIZE", (0, 1), (-1, -1), 12), + ("GRID", (0, 0), (-1, -1), 0.5, colors.grey), + ("ALIGN", (0, 0), (-1, -1), "CENTER"), + ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), + ] + ) + ) + elements.append(table) + elements.append(Spacer(1, 20)) + + # Add Grade Distribution with Row Splitting + elements.append(Paragraph(f"Grade Distribution:", header_style)) + + # First Grade Table + grade_data1 = [["O", "A+", "A", "B+", "B", "C+", "C", "D+"]] + grade_data1.append([grade_counts[grade] for grade in grade_data1[0]]) + grade_table1 = Table(grade_data1, colWidths=[60] * 8) + grade_table1.setStyle( + TableStyle( + [ + ("BACKGROUND", (0, 0), (-1, 0), HexColor("#E0E0E0")), + ("TEXTCOLOR", (0, 0), (-1, 0), colors.black), + ("ALIGN", (0, 0), (-1, -1), "CENTER"), + ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"), + ("FONTSIZE", (0, 0), (-1, 0), 12), + ("BOTTOMPADDING", (0, 0), (-1, 0), 8), + ("GRID", (0, 0), (-1, -1), 0.5, colors.grey), + ("BACKGROUND", (0, 1), (-1, -1), colors.white), + ("TEXTCOLOR", (0, 1), (-1, -1), colors.black), + ] + ) + ) + elements.append(grade_table1) + elements.append(Spacer(1, 10)) + + # Second Grade Table + grade_data2 = [["D", "F", "I", "S", "X"]] + grade_data2.append([grade_counts[grade] for grade in grade_data2[0]]) + grade_table2 = Table(grade_data2, colWidths=[60] * 5) + grade_table2.setStyle( + TableStyle( + [ + ("BACKGROUND", (0, 0), (-1, 0), HexColor("#E0E0E0")), + ("TEXTCOLOR", (0, 0), (-1, 0), colors.black), + ("ALIGN", (0, 0), (-1, -1), "CENTER"), + ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"), + ("FONTSIZE", (0, 0), (-1, 0), 12), + ("BOTTOMPADDING", (0, 0), (-1, 0), 8), + ("GRID", (0, 0), (-1, -1), 0.5, colors.grey), + ("BACKGROUND", (0, 1), (-1, -1), colors.white), + ("TEXTCOLOR", (0, 1), (-1, -1), colors.black), + ] + ) + ) + elements.append(grade_table2) + elements.append(Spacer(1, 20)) + + # Footer Signatures + def draw_signatures(canvas, doc): + canvas.saveState() + width, height = letter + canvas.drawString(inch, 0.75 * inch, "") + canvas.drawString(inch, 0.5 * inch, "Date") + canvas.drawString(width - 4 * inch, 0.75 * inch, "") + canvas.drawString(width - 4 * inch, 0.5 * inch, "Course Instructor's Signature") + canvas.restoreState() + + doc.build(elements, onLaterPages=draw_signatures, onFirstPage=draw_signatures) + return response + + + +def generate_result(request): + if request.method == 'POST': + try: + data = json.loads(request.body) + semester = data.get('semester') + branch = data.get('specialization') + batch = data.get('batch') + + branch_info = Discipline.objects.filter(acronym=branch).first() + if not branch_info: + return JsonResponse({'error': 'Branch not found'}, status=404) + + curriculum_id = Batch.objects.filter( + year=batch, discipline_id=branch_info.id + ).values_list('curriculum_id', flat=True).first() + if not curriculum_id: + return JsonResponse({'error': 'Curriculum not found'}, status=404) + + semester_info = Semester.objects.filter( + curriculum_id=curriculum_id, semester_no=semester + ).first() + if not semester_info: + return JsonResponse({'error': 'Semester not found'}, status=404) + + course_slots = CourseSlot.objects.filter(semester_id=semester_info) + course_ids = course_slots.values_list('courses', flat=True) + courses = Courses.objects.filter(id__in=course_ids) + courses_map={} + for course in courses: + courses_map[course.id]=(course.credit) + students = Student.objects.filter(batch=batch, specialization=branch).order_by('id') + print(students.first().id_id,"studejt id") + + wb = Workbook() + ws = wb.active + ws.title = "Student Grades" + + + # ws.merge_cells(start_row=1, start_column=1, end_row=4, end_column=1) + # ws.merge_cells(start_row=1, start_column=2, end_row=4, end_column=2) + ws["A1"] = "S. No" + ws["B1"] = "Roll No" + for cell in ("A1", "B1"): + ws[cell].alignment = Alignment(horizontal="center", vertical="center") + ws[cell].font = Font(bold=True) + + + ws.column_dimensions[get_column_letter(1)].width = 12 + ws.column_dimensions[get_column_letter(2)].width = 18 + col_idx = 3 + for course in courses: + + ws.merge_cells(start_row=1, start_column=col_idx, end_row=1, end_column=col_idx + 1) + ws.merge_cells(start_row=2, start_column=col_idx, end_row=2, end_column=col_idx + 1) + ws.merge_cells(start_row=3, start_column=col_idx, end_row=3, end_column=col_idx + 1) + + ws.cell(row=1, column=col_idx).value = course.code + ws.cell(row=1, column=col_idx).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=1, column=col_idx).font = Font(bold=True) + ws.cell(row=2, column=col_idx).value = course.name + ws.cell(row=2, column=col_idx).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=2, column=col_idx).font = Font(bold=True) + + ws.cell(row=3, column=col_idx).value=course.credit + ws.cell(row=3, column=col_idx).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=3, column=col_idx).font = Font(bold=True) + ws.cell(row=4, column=col_idx).value = "Grade" + ws.cell(row=4, column=col_idx + 1).value = "Remarks" + ws.cell(row=4, column=col_idx).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=4, column=col_idx+1).alignment = Alignment(horizontal="center", vertical="center") + ws.column_dimensions[get_column_letter(col_idx)].width = 25 + ws.column_dimensions[get_column_letter(col_idx+1)].width = 25 + col_idx += 2 + + # ws.merge_cells(start_row=1, start_column=col_idx, end_row=4, end_column=col_idx) # SPI + ws.cell(row=1, column=col_idx).value = "SPI" + ws.cell(row=1, column=col_idx).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=1, column=col_idx).font = Font(bold=True) + + # ws.merge_cells(start_row=1, start_column=col_idx + 1, end_row=4, end_column=col_idx + 1) # CPI + ws.cell(row=1, column=col_idx + 1).value = "CPI" + ws.cell(row=1, column=col_idx + 1).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=1, column=col_idx + 1).font = Font(bold=True) + + + row_idx = 5 + for idx, student in enumerate(students, start=1): + ws.cell(row=row_idx, column=1).value = idx + ws.cell(row=row_idx, column=2).value = student.id_id + + ws.cell(row=row_idx, column=1).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=row_idx, column=2).alignment = Alignment(horizontal="center", vertical="center") + student_grades = Student_grades.objects.filter( + roll_no=student.id_id, course_id_id__in=course_ids + ) + + grades_map = {} + for grade in student_grades: + grades_map[grade.course_id_id] = (grade.grade, grade.remarks,courses_map.get(grade.course_id_id) ) + + col_idx = 3 + gained_credit=0 + total_credit=0 + for course in courses: + grade, remark, credits = grades_map.get(course.id, ("N/A", "N/A",0)) + ws.cell(row=row_idx, column=col_idx).value = grade + ws.cell(row=row_idx, column=col_idx + 1).value = remark + ws.cell(row=row_idx, column=col_idx).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=row_idx, column=col_idx+1).alignment = Alignment(horizontal="center", vertical="center") + if grade=="O" or grade=="A+": + gained_credit+=1*credits + total_credit+=credits + elif grade=="A": + gained_credit+=0.9*credits + total_credit+=credits + elif grade=="B+": + gained_credit+=0.8*credits + total_credit+=credits + elif grade=="B": + gained_credit+=0.7*credits + total_credit+=credits + elif grade=="C+": + gained_credit+=0.6*credits + total_credit+=credits + elif grade=="C": + gained_credit+=0.5*credits + total_credit+=credits + elif grade=="D+": + gained_credit+=0.4*credits + total_credit+=credits + elif grade=="D": + gained_credit+=0.3*credits + total_credit+=credits + elif grade=="F": + gained_credit+=0.2*credits + total_credit+=credits + + + col_idx += 2 + if total_credit==0 : + ws.cell(row=row_idx, column=col_idx).value =0 + else: + ws.cell(row=row_idx, column=col_idx).value = 10*(gained_credit/total_credit) + ws.cell(row=row_idx, column=col_idx + 1).value = 0 + ws.cell(row=row_idx, column=col_idx).alignment = Alignment(horizontal="center", vertical="center") + ws.cell(row=row_idx, column=col_idx+1).alignment = Alignment(horizontal="center", vertical="center") + + row_idx += 1 + + response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + response['Content-Disposition'] = 'attachment; filename="student_grades.xlsx"' + wb.save(response) + return response + + except json.JSONDecodeError: + return JsonResponse({'error': 'Invalid JSON data'}, status=400) + except Exception as e: + traceback.print_exc() + return JsonResponse({'error': str(e)}, status=500) + + + return JsonResponse({'error': 'Invalid request method'}, status=405) \ No newline at end of file diff --git a/FusionIIIT/templates/examination/download_resultProf.html b/FusionIIIT/templates/examination/download_resultProf.html new file mode 100644 index 000000000..8c9cb2790 --- /dev/null +++ b/FusionIIIT/templates/examination/download_resultProf.html @@ -0,0 +1,139 @@ +{% extends 'examination/base.html' %} + +{% block sidetabmenu %} +
+{% endblock %} +{% block content %} +