diff --git a/env_secrets/local_chrigu.env b/env_secrets/local_chrigu.env index 431043ff..23475a25 100644 Binary files a/env_secrets/local_chrigu.env and b/env_secrets/local_chrigu.env differ diff --git a/server/vbv_lernwelt/assignment/export.py b/server/vbv_lernwelt/assignment/export.py index fe845274..39ff9247 100644 --- a/server/vbv_lernwelt/assignment/export.py +++ b/server/vbv_lernwelt/assignment/export.py @@ -76,12 +76,24 @@ def export_competence_certificates( }, label="assignment_export", ) + + # handle the case where there are no competence certificate elements for the course session + try: + cces = grouped_cce[course_session_title] + except KeyError: + cces = [] + + try: + acs = grouped_ac[course_session_title] + except KeyError: + acs = [] + _create_sheet( wb, course_session_title, cs_users, - grouped_cce[course_session_title], - grouped_ac[course_session_title], + cces, + acs, circle_ids, ) @@ -105,7 +117,7 @@ def _create_sheet( ): sheet = wb.create_sheet(title=sanitize_sheet_name(title)) - if len(users) == 0: + if len(users) == 0 or len(competence_certificate_element) == 0: return sheet # headers @@ -121,7 +133,7 @@ def _create_sheet( if circle_ids and circle.id not in circle_ids: continue - col_prefix = f'Circle "{circle.title}" {cse.learning_content.title} ' + col_prefix = f'Circle "{circle.title}" {cse.learning_content.title}' sheet.cell( row=1, diff --git a/server/vbv_lernwelt/assignment/tests/test_assignment_completions_export.py b/server/vbv_lernwelt/assignment/tests/test_assignment_completions_export.py index 10f6da0f..ee21e875 100644 --- a/server/vbv_lernwelt/assignment/tests/test_assignment_completions_export.py +++ b/server/vbv_lernwelt/assignment/tests/test_assignment_completions_export.py @@ -1,5 +1,8 @@ -from django.test import TestCase +import io +from openpyxl import load_workbook + +from vbv_lernwelt.assignment.export import export_competence_certificates from vbv_lernwelt.assignment.models import Assignment from vbv_lernwelt.assignment.services import update_assignment_completion from vbv_lernwelt.core.constants import TEST_STUDENT1_USER_ID, TEST_STUDENT2_USER_ID @@ -7,28 +10,32 @@ from vbv_lernwelt.core.create_default_users import create_default_users from vbv_lernwelt.core.models import User from vbv_lernwelt.course.creators.test_course import create_test_course from vbv_lernwelt.course.models import CourseSession +from vbv_lernwelt.course_session.models import ( + CourseSessionAssignment, + CourseSessionEdoniqTest, +) +from vbv_lernwelt.course_session.tests.test_attendance_export import ExportBaseTextCase -class AttendanceExportTestCase(TestCase): +class AssignmentCompletionExportTestCase(ExportBaseTextCase): def setUp(self): create_default_users() self.course = create_test_course(include_vv=False, with_sessions=True) self.course_session_be = CourseSession.objects.get(title="Test Bern 2022 a") self.course_session_zh = CourseSession.objects.get(title="Test Zürich 2022 a") - self.attendance_course_be = ( - self.course_session_be.coursesessionattendancecourse_set.first() - ) - some = ( + self.casework = ( self.course.coursepage.get_descendants() .exact_type(Assignment) .filter(assignment__assignment_type="CASEWORK") + .first() + .specific ) - self.assignment = ( + self.edoniq_test = ( self.course.coursepage.get_descendants() .exact_type(Assignment) - .filter(assignment__assignment_type="CASEWORK") + .filter(assignment__assignment_type="EDONIQ_TEST") .first() .specific ) @@ -44,13 +51,156 @@ class AttendanceExportTestCase(TestCase): test_student3 = User.objects.get(email="test-student3@example.com") + # Bern assignments update_assignment_completion( assignment_user=self.test_student1, - assignment=self.assignment, + assignment=self.casework, course_session=self.course_session_be, completion_data={}, evaluation_points=20, ) - def test_attendance_export_single_cs(self): - self.assertTrue(True) + update_assignment_completion( + assignment_user=self.test_student1, + assignment=self.edoniq_test, + course_session=self.course_session_be, + completion_data={}, + evaluation_points=14, + evaluation_passed=False, + ) + + update_assignment_completion( + assignment_user=self.test_student2, + assignment=self.edoniq_test, + course_session=self.course_session_be, + completion_data={}, + evaluation_points=24, + evaluation_passed=True, + ) + + self.expected_data_be = [ + self._make_header(), + [ + self.test_student1.first_name, + self.test_student1.last_name, + self.test_student1.email, + self.test_student1.additional_json_data["Lehrvertragsnummer"], + "Nicht bestanden", + 58, + "Bestanden", + 83, + ], + [ + self.test_student2.first_name, + self.test_student2.last_name, + self.test_student2.email, + self.test_student2.additional_json_data["Lehrvertragsnummer"], + "Bestanden", + 100, + "Keine Daten", + "Keine Daten", + ], + [ + test_student3.first_name, + test_student3.last_name, + test_student3.email, + None, + "Keine Daten", + "Keine Daten", + "Keine Daten", + "Keine Daten", + ], + ] + + def _generate_workbook(self, course_session_ids): + export_data = io.BytesIO( + export_competence_certificates(course_session_ids, save_as_file=False) + ) + return load_workbook(export_data) + + def _make_header( + self, + ): + casework_assignment = CourseSessionAssignment.objects.filter( + course_session__id=self.course_session_be.id, + learning_content__content_assignment__competence_certificate__isnull=False, + ).first() + + edoniq_assignment = CourseSessionEdoniqTest.objects.filter( + course_session__id=self.course_session_be.id, + learning_content__content_assignment__competence_certificate__isnull=False, + ).first() + + return [ + "Vorname", + "Nachname", + "Email", + "Lehrvertragsnummer", + f'Circle "{self.edoniq_test.get_attached_circle_title()}" {edoniq_assignment.learning_content.title} bestanden', + f'Circle "{self.edoniq_test.get_attached_circle_title()}" {edoniq_assignment.learning_content.title} Resultat %', + f'Circle "{self.casework.get_attached_circle_title()}" {casework_assignment.learning_content.title} bestanden', + f'Circle "{self.casework.get_attached_circle_title()}" {casework_assignment.learning_content.title} Resultat %', + ] + + def test_export_single_cs(self): + wb = self._generate_workbook([self.course_session_be.id]) + self.assertEqual(len(wb.sheetnames), 1) + self.assertEqual(wb.sheetnames[0], "Test Bern 2022 a") + + self._check_export(wb, self.expected_data_be, 4, 8) + + def test_export_only_kn_elements(self): + self.edoniq_test.competence_certificate = None + self.edoniq_test.save() + + expected_data = [] + for row in self.expected_data_be: + expected_data.append( + [cell for i, cell in enumerate(row) if (i != 4 and i != 5)] + ) + + wb = self._generate_workbook([self.course_session_be.id]) + self._check_export(wb, expected_data, 4, 6) + + def test_export_multiple_cs(self): + update_assignment_completion( + assignment_user=self.test_student2, + assignment=self.casework, + course_session=self.course_session_zh, + completion_data={}, + evaluation_points=18, + ) + + update_assignment_completion( + assignment_user=self.test_student2, + assignment=self.edoniq_test, + course_session=self.course_session_zh, + completion_data={}, + evaluation_points=22, + evaluation_passed=False, + ) + + expected_data = [ + [cell for i, cell in enumerate(self._make_header()) if (i != 4 and i != 5)], + [ + self.test_student2.first_name, + self.test_student2.last_name, + self.test_student2.email, + self.test_student2.additional_json_data["Lehrvertragsnummer"], + "Bestanden", + 75, + ], + ] + + wb = self._generate_workbook( + [self.course_session_be.id, self.course_session_zh.id] + ) + self.assertEqual(len(wb.sheetnames), 2) + self.assertEqual(wb.sheetnames[0], "Test Bern 2022 a") + self.assertEqual(wb.sheetnames[1], "Test Zürich 2022 a") + + self._check_export(wb, self.expected_data_be, 4, 5) + + wb.active = wb["Test Zürich 2022 a"] + + self._check_export(wb, expected_data, 2, 5) diff --git a/server/vbv_lernwelt/course/creators/test_course.py b/server/vbv_lernwelt/course/creators/test_course.py index 968be54e..7b6c9bd4 100644 --- a/server/vbv_lernwelt/course/creators/test_course.py +++ b/server/vbv_lernwelt/course/creators/test_course.py @@ -282,6 +282,13 @@ def create_test_course( ) csac.due_date.save() + _csa = CourseSessionAssignment.objects.create( + course_session=cs_zurich, + learning_content=LearningContentAssignment.objects.get( + slug=f"{course.slug}-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice" + ), + ) + region1 = CourseSessionGroup.objects.create( name="Region 1", course=course, diff --git a/server/vbv_lernwelt/course_session/tests/test_attendance_export.py b/server/vbv_lernwelt/course_session/tests/test_attendance_export.py index 49f1c085..40d82517 100644 --- a/server/vbv_lernwelt/course_session/tests/test_attendance_export.py +++ b/server/vbv_lernwelt/course_session/tests/test_attendance_export.py @@ -11,7 +11,16 @@ from vbv_lernwelt.course.models import CourseSession from vbv_lernwelt.course_session.services.export_attendance import export_attendance -class AttendanceExportTestCase(TestCase): +class ExportBaseTextCase(TestCase): + def _check_export(self, wb, expected_data, max_row, max_col): + for row in wb.active.iter_rows(max_col=max_col, max_row=max_row): + for cell in row: + self.assertEqual( + cell.value, expected_data[row[0].row - 1][row.index(cell)] + ) + + +class AttendanceExportTestCase(ExportBaseTextCase): def setUp(self): create_default_users() create_test_course(include_vv=False, with_sessions=True) @@ -76,29 +85,20 @@ class AttendanceExportTestCase(TestCase): return load_workbook(export_data) def _make_header(self, csac): - return ( - [ - "Vorname", - "Nachname", - "Email", - "Lehrvertragsnummer", - f"Anwesenheit {csac.get_circle().title} {csac.attendance_course_zh.due_date.start.strftime('%d.%m.%Y')}", - ], - ) - - def _check_attendance_export(self, wb, expected_data, max_row, max_col): - for row in wb.active.iter_rows(max_col=max_col, max_row=max_row): - for cell in row: - self.assertEqual( - cell.value, expected_data[row[0].row - 1][row.index(cell)] - ) + return [ + "Vorname", + "Nachname", + "Email", + "Lehrvertragsnummer", + f"Anwesenheit {csac.get_circle().title} {csac.attendance_course_zh.due_date.start.strftime('%d.%m.%Y')}", + ] def test_attendance_export_single_cs(self): wb = self._generate_workbook([self.course_session_be.id]) self.assertEqual(len(wb.sheetnames), 1) self.assertEqual(wb.sheetnames[0], "Test Bern 2022 a") - self._check_attendance_export(wb, self.expected_data_be, 4, 5) + self._check_export(wb, self.expected_data_be, 4, 5) def test_attendance_export_multiple_cs(self): self.attendance_course_zh.attendance_user_list = [ @@ -131,5 +131,7 @@ class AttendanceExportTestCase(TestCase): self.assertEqual(wb.sheetnames[0], "Test Bern 2022 a") self.assertEqual(wb.sheetnames[1], "Test Zürich 2022 a") + self._check_export(wb, self.expected_data_be, 4, 5) + wb.active = wb["Test Zürich 2022 a"] - self._check_attendance_export(wb, expected_data_zh, 2, 5) + self._check_export(wb, expected_data_zh, 2, 5)