Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 87 additions & 74 deletions FusionIIIT/applications/examination/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1373,6 +1373,14 @@ class GenerateResultAPI(APIView):
"""
permission_classes = [IsAuthenticated]

@staticmethod
def _ordinal_suffix(n):
n = int(n)
if 11 <= (n % 100) <= 13:
return f"{n}th"
suffix = {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th")
return f"{n}{suffix}"

def post(self, request):
try:
role = request.data.get("Role")
Expand Down Expand Up @@ -1413,7 +1421,8 @@ def post(self, request):
).exclude(grade__isnull=True).exclude(grade="").values_list('course_id_id', flat=True).distinct()

courses = Courses.objects.filter(id__in=course_ids).order_by('code')
courses_map = {course.id: course.credit for course in courses}
courses_list = list(courses) # evaluate once; order is now stable
courses_map = {course.id: course.credit for course in courses_list}

disc_name = batch_obj.discipline.name
spec_match = re.search(r'\(([^)]+)\)', disc_name)
Expand All @@ -1431,6 +1440,25 @@ def post(self, request):
sem_label = f"Sem{semester}"
download_filename = f"{programme_str}_{disc_str}_{batch_year}_{sem_label}_{acad_year_str}.xlsx"

if batch_obj.curriculum_id:
category = batch_obj.curriculum.programme.category
elif batch_obj.name.startswith('PhD'):
category = 'PHD'
elif batch_obj.name.startswith('M.Tech') or batch_obj.name == 'M.Des':
category = 'PG'
else:
category = 'UG'
batch_label = f"{category}{batch_year}"
branch_label = branch if branch else batch_obj.discipline.acronym
if semester_type == "Summer Semester":
sem_clause = f"SUMMER-{semester // 2}"
else:
sem_clause = f"SEM-{self._ordinal_suffix(semester)}"
heading = (
f"Approval sheet for {semester_type} AY{acad_year_str} "
f"({batch_label} Batch ({branch_label})) - {sem_clause}"
)

wb = Workbook()
ws = wb.active
ws.title = "Student Grades"
Expand All @@ -1443,119 +1471,105 @@ def post(self, request):
left=Side(style="thin"), right=Side(style="thin"),
top=Side(style="thin"), bottom=Side(style="thin")
)
center_align = Alignment(horizontal="center", vertical="center", wrap_text=True)

total_cols = 3 + 2 * len(courses_list) + 7
last_col_letter = get_column_letter(max(total_cols, 1))

ws.merge_cells(f"A1:{last_col_letter}1")
heading_cell = ws["A1"]
heading_cell.value = heading
heading_cell.font = Font(bold=True, size=12)
heading_cell.alignment = center_align
ws.row_dimensions[1].height = 24

NUM_ROW = 2
HDR_START = 3
HDR_END = 6
DATA_START = HDR_END + 1

# Setup header rows: S. No, Roll No and Name in columns A, B and C.
ws["A1"] = "S. No"
ws["B1"] = "Roll No"
ws["C1"] = "Name"
for col in ("A", "B"):
cell = ws[col + "1"]
cell.alignment = Alignment(horizontal="center", vertical="center")
col_idx = 4
for subject_no, course in enumerate(courses_list, start=1):
ws.merge_cells(start_row=NUM_ROW, start_column=col_idx, end_row=NUM_ROW, end_column=col_idx + 1)
cell = ws.cell(row=NUM_ROW, column=col_idx)
cell.value = subject_no
cell.alignment = center_align
cell.font = Font(bold=True)
cell.fill = header_fill
col_idx += 2

for col_num, label in enumerate(["S. No", "Roll No", "Name"], start=1):
ws.merge_cells(start_row=NUM_ROW, start_column=col_num, end_row=HDR_END, end_column=col_num)
cell = ws.cell(row=NUM_ROW, column=col_num)
cell.value = label
cell.alignment = center_align
cell.font = Font(bold=True)
cell.fill = header_fill
cell = ws["C1"]
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.fill = header_fill
ws.column_dimensions[get_column_letter(1)].width = 12
ws.column_dimensions[get_column_letter(2)].width = 18
ws.column_dimensions[get_column_letter(3)].width = 30

# Starting from column 4, add headers for each course (each course uses 2 columns for Grade and Remarks).
col_idx = 4
for course in courses:
for course in courses_list:
# Merge cells for the course code header.
ws.merge_cells(start_row=1, start_column=col_idx, end_row=1, end_column=col_idx+1)
cell = ws.cell(row=1, column=col_idx)
ws.merge_cells(start_row=HDR_START, start_column=col_idx, end_row=HDR_START, end_column=col_idx+1)
cell = ws.cell(row=HDR_START, column=col_idx)
cell.value = course.code
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.alignment = center_align
cell.font = Font(bold=True)
cell.fill = header_fill

ws.merge_cells(start_row=2, start_column=col_idx, end_row=2, end_column=col_idx+1)
cell = ws.cell(row=2, column=col_idx)
ws.merge_cells(start_row=HDR_START+1, start_column=col_idx, end_row=HDR_START+1, end_column=col_idx+1)
cell = ws.cell(row=HDR_START+1, column=col_idx)
cell.value = course.name
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.alignment = center_align
cell.font = Font(bold=True)
cell.fill = header_fill

ws.merge_cells(start_row=3, start_column=col_idx, end_row=3, end_column=col_idx+1)
cell = ws.cell(row=3, column=col_idx)
ws.merge_cells(start_row=HDR_START+2, start_column=col_idx, end_row=HDR_START+2, end_column=col_idx+1)
cell = ws.cell(row=HDR_START+2, column=col_idx)
cell.value = course.credit
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.alignment = center_align
cell.font = Font(bold=True)
cell.fill = header_fill

cell = ws.cell(row=4, column=col_idx)
cell = ws.cell(row=HDR_END, column=col_idx)
cell.value = "Grade"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.alignment = center_align
cell.font = Font(bold=True)
cell.fill = header_fill

cell = ws.cell(row=4, column=col_idx+1)
cell = ws.cell(row=HDR_END, column=col_idx+1)
cell.value = "Remarks"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.alignment = center_align
cell.font = Font(bold=True)
cell.fill = header_fill

ws.column_dimensions[get_column_letter(col_idx)].width = 25
ws.column_dimensions[get_column_letter(col_idx+1)].width = 25
col_idx += 2

# Append headers for SPI and CPI.
cell = ws.cell(row=1, column=col_idx)
cell.value = "SPI"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.fill = header_fill

cell = ws.cell(row=1, column=col_idx+1)
cell.value = "CPI"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.fill = header_fill

cell = ws.cell(row=1, column=col_idx+2)
cell.value = "SU"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.fill = header_fill

cell = ws.cell(row=1, column=col_idx+3)
cell.value = "TU"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.fill = header_fill

cell = ws.cell(row=1, column=col_idx+4)
cell.value = "SP"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.fill = header_fill

cell = ws.cell(row=1, column=col_idx+5)
cell.value = "TP"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.fill = header_fill

cell = ws.cell(row=1, column=col_idx+6)
cell.value = "WARNING"
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.fill = header_fill
for label in ("SPI", "CPI", "SU", "TU", "SP", "TP", "WARNING"):
ws.merge_cells(start_row=NUM_ROW, start_column=col_idx, end_row=HDR_END, end_column=col_idx)
cell = ws.cell(row=NUM_ROW, column=col_idx)
cell.value = label
cell.alignment = center_align
cell.font = Font(bold=True)
cell.fill = header_fill
ws.column_dimensions[get_column_letter(col_idx)].width = 10
col_idx += 1

max_col = ws.max_column
for row in range(1, 5):
for row in range(NUM_ROW, HDR_END + 1):
for col in range(1, max_col + 1):
cell = ws.cell(row=row, column=col)
cell.fill = header_fill
cell.border = thin_border
cell.alignment = center_align
total_columns = ws.max_column

# Fill in student rows, starting from row 5.
row_idx = 5
row_idx = DATA_START

# --- Bulk prefetch to avoid N+1 for 300+ students ---
User = get_user_model()
Expand Down Expand Up @@ -1594,7 +1608,7 @@ def post(self, request):

grades_map = grades_by_student.get(student.id_id, {})
col_ptr = 4
for course in courses:
for course in courses_list:
grade_entry = grades_map.get(course.id)
grade_val = grade_entry.grade if grade_entry else '-'

Expand Down Expand Up @@ -1664,9 +1678,8 @@ def post(self, request):

row_idx += 1

# Apply borders on all populated cells (headers + student rows).
last_data_row = row_idx - 1
for row in range(1, last_data_row + 1):
for row in range(NUM_ROW, last_data_row + 1):
for col in range(1, total_columns + 1):
ws.cell(row=row, column=col).border = thin_border

Expand Down
Loading