diff --git a/server/vbv_lernwelt/assignment/tests/test_assignment_api.py b/server/vbv_lernwelt/assignment/tests/test_assignment_api.py index 704705b6..86fe4edf 100644 --- a/server/vbv_lernwelt/assignment/tests/test_assignment_api.py +++ b/server/vbv_lernwelt/assignment/tests/test_assignment_api.py @@ -28,7 +28,6 @@ class AssignmentApiTestCase(APITestCase): self.cs = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Test Lehrgang Session", - import_id="Test Lehrgang Session", ) self.student = User.objects.get(username="student") self.student_csu = CourseSessionUser.objects.create( diff --git a/server/vbv_lernwelt/assignment/tests/test_services.py b/server/vbv_lernwelt/assignment/tests/test_services.py index 56bf9558..64e24d77 100644 --- a/server/vbv_lernwelt/assignment/tests/test_services.py +++ b/server/vbv_lernwelt/assignment/tests/test_services.py @@ -33,7 +33,6 @@ class UpdateAssignmentCompletionTestCase(TestCase): self.course_session = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Bern 2022 a", - import_id="Bern 2022 a", ) self.user = User.objects.get(username="student") self.trainer = User.objects.get(username="admin") diff --git a/server/vbv_lernwelt/course/creators/test_course.py b/server/vbv_lernwelt/course/creators/test_course.py index 66b46e69..e6681709 100644 --- a/server/vbv_lernwelt/course/creators/test_course.py +++ b/server/vbv_lernwelt/course/creators/test_course.py @@ -83,13 +83,11 @@ def create_test_course(include_uk=True, include_vv=True, with_sessions=False): cs_bern = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Test Bern 2022 a", - import_id="Test Bern 2022 a", id=TEST_COURSE_SESSION_BERN_ID, ) cs_zurich = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Test Zürich 2022 a", - import_id="Test Zürich 2022 a", id=TEST_COURSE_SESSION_ZURICH_ID, ) diff --git a/server/vbv_lernwelt/course/management/commands/create_default_courses.py b/server/vbv_lernwelt/course/management/commands/create_default_courses.py index 6eba6df4..12363a7e 100644 --- a/server/vbv_lernwelt/course/management/commands/create_default_courses.py +++ b/server/vbv_lernwelt/course/management/commands/create_default_courses.py @@ -1,3 +1,4 @@ +import os import random import djclick as click @@ -43,9 +44,15 @@ from vbv_lernwelt.course.creators.uk_training_course import ( from vbv_lernwelt.course.creators.versicherungsvermittlerin import ( create_versicherungsvermittlerin_with_categories, ) -from vbv_lernwelt.course.models import CoursePage, CourseSession, CourseSessionUser +from vbv_lernwelt.course.models import ( + CoursePage, + CourseSession, + CourseSessionUser, + Course, +) from vbv_lernwelt.course.services import mark_course_completion from vbv_lernwelt.feedback.creators.create_demo_feedback import create_feedback +from vbv_lernwelt.importer.services import import_course_sessions_from_excel from vbv_lernwelt.learnpath.create_vv_new_learning_path import ( create_vv_new_learning_path, ) @@ -117,7 +124,6 @@ def create_versicherungsvermittlerin_course(): cs = CourseSession.objects.create( course_id=COURSE_VERSICHERUNGSVERMITTLERIN_ID, title="Versicherungsvermittler/-in", - import_id="Versicherungsvermittler/-in", ) for user_data in default_users: CourseSessionUser.objects.create( @@ -186,7 +192,6 @@ def create_course_uk_de(): cs = CourseSession.objects.create( course_id=COURSE_UK, title="Bern 2023 a", - import_id="Bern 2023 a", attendance_courses=[ { "learningContentId": LearningContentAttendanceCourse.objects.get( @@ -282,7 +287,6 @@ def create_course_uk_de(): cs = CourseSession.objects.create( course_id=COURSE_UK, title="Zürich 2023 a", - import_id="Zürich 2023 a", ) # for user_data in default_users: # CourseSessionUser.objects.create( @@ -325,7 +329,6 @@ def create_course_uk_fr(): cs = CourseSession.objects.create( course_id=COURSE_UK_FR, title="Cours hors établissement année 1 - Région Fribourg", - import_id="Cours hors établissement année 1 - Région Fribourg", ) csu = CourseSessionUser.objects.create( @@ -443,22 +446,16 @@ def create_course_training_de(): create_uk_training_competence_profile(course_id=COURSE_UK_TRAINING) create_default_media_library(course_id=COURSE_UK_TRAINING) - cs = CourseSession.objects.create( - course_id=COURSE_UK_TRAINING, - title="myVBV Training", - import_id="myVBV Training", - attendance_courses=[ - { - "learningContentId": LearningContentAttendanceCourse.objects.get( - slug=f"{course.slug}-lp-circle-fahrzeug-lc-präsenzkurs-fahrzeug" - ).id, - "start": "2023-05-23T08:30:00+0200", - "end": "2023-05-23T17:00:00+0200", - "location": "Handelsschule KV Bern, Zimmer 123, Eigerstrasse 16, 3012 Bern", - "trainer": "Roland Grossenbacher, roland.grossenbacher@helvetia.ch", - } - ], - assignment_details_list=[ + current_dir = os.path.dirname(os.path.realpath(__file__)) + print(current_dir) + course = Course.objects.get(id=COURSE_UK_TRAINING) + import_course_sessions_from_excel( + course, + f"{current_dir}/../../../importer/tests/Schulungen_Durchfuehrung_Trainer.xlsx", + ) + + for cs in CourseSession.objects.filter(course_id=COURSE_UK_TRAINING): + cs.assignment_details_list = [ { "learningContentId": LearningContentAssignment.objects.get( slug=f"{course.slug}-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice" @@ -473,5 +470,5 @@ def create_course_training_de(): "submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z", "evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z", }, - ], - ) + ] + cs.save() diff --git a/server/vbv_lernwelt/course/migrations/0004_import_fields.py b/server/vbv_lernwelt/course/migrations/0004_import_fields.py index a9d05b81..15296edb 100644 --- a/server/vbv_lernwelt/course/migrations/0004_import_fields.py +++ b/server/vbv_lernwelt/course/migrations/0004_import_fields.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.13 on 2023-05-31 14:56 +# Generated by Django 3.2.13 on 2023-05-31 15:59 from django.db import migrations, models @@ -23,8 +23,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='coursesession', name='import_id', - field=models.TextField(default='', unique=True), - preserve_default=False, + field=models.TextField(blank=True, default=''), ), migrations.AddField( model_name='coursesession', diff --git a/server/vbv_lernwelt/course/models.py b/server/vbv_lernwelt/course/models.py index 4942e936..2a49e8d9 100644 --- a/server/vbv_lernwelt/course/models.py +++ b/server/vbv_lernwelt/course/models.py @@ -216,7 +216,8 @@ class CourseSession(models.Model): course = models.ForeignKey("course.Course", on_delete=models.CASCADE) title = models.TextField(unique=True) - import_id = models.TextField(unique=True) + + import_id = models.TextField(blank=True, default="") generation = models.TextField(blank=True, default="") region = models.TextField(blank=True, default="") diff --git a/server/vbv_lernwelt/course/tests/test_completion_api.py b/server/vbv_lernwelt/course/tests/test_completion_api.py index 1860e29a..4c5db0af 100644 --- a/server/vbv_lernwelt/course/tests/test_completion_api.py +++ b/server/vbv_lernwelt/course/tests/test_completion_api.py @@ -22,7 +22,6 @@ class CourseCompletionApiTestCase(APITestCase): self.cs = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Test Lehrgang Session", - import_id="Test Lehrgang Session", ) csu = CourseSessionUser.objects.create( course_session=self.cs, diff --git a/server/vbv_lernwelt/course/tests/test_course_session_api.py b/server/vbv_lernwelt/course/tests/test_course_session_api.py index 423b8493..17d3616c 100644 --- a/server/vbv_lernwelt/course/tests/test_course_session_api.py +++ b/server/vbv_lernwelt/course/tests/test_course_session_api.py @@ -19,7 +19,6 @@ class CourseCompletionApiTestCase(APITestCase): self.course_session = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Test Lehrgang Session", - import_id="Test Lehrgang Session", ) self.client.login(username="student", password="test") diff --git a/server/vbv_lernwelt/course/tests/test_document_uploads.py b/server/vbv_lernwelt/course/tests/test_document_uploads.py index 2d69adb3..4d08b6cf 100644 --- a/server/vbv_lernwelt/course/tests/test_document_uploads.py +++ b/server/vbv_lernwelt/course/tests/test_document_uploads.py @@ -23,7 +23,6 @@ class DocumentUploadApiTestCase(APITestCase): self.course_session = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Test Lehrgang Session", - import_id="Test Lehrgang Session", ) csu = CourseSessionUser.objects.create( diff --git a/server/vbv_lernwelt/feedback/tests/test_feedback_api.py b/server/vbv_lernwelt/feedback/tests/test_feedback_api.py index 22efad7a..6ad2136c 100644 --- a/server/vbv_lernwelt/feedback/tests/test_feedback_api.py +++ b/server/vbv_lernwelt/feedback/tests/test_feedback_api.py @@ -23,7 +23,6 @@ class FeedbackApiBaseTestCase(APITestCase): self.course_session = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Test Lehrgang Session", - import_id="Test Lehrgang Session", ) csu = CourseSessionUser.objects.create( diff --git a/server/vbv_lernwelt/importer/services.py b/server/vbv_lernwelt/importer/services.py index d1fa0bab..a7ac207f 100644 --- a/server/vbv_lernwelt/importer/services.py +++ b/server/vbv_lernwelt/importer/services.py @@ -1,5 +1,7 @@ from typing import Dict, Any +from openpyxl.reader.excel import load_workbook + from vbv_lernwelt.core.models import User from vbv_lernwelt.course.models import Course, CourseSession from vbv_lernwelt.importer.utils import try_parse_datetime @@ -35,6 +37,19 @@ def create_or_update_user( return user +def import_course_sessions_from_excel(course: Course, filename: str): + workbook = load_workbook(filename=filename) + sheet = workbook["Schulungen Durchführung"] + + header = [cell.value for cell in sheet[1]] + + for row in sheet.iter_rows(min_row=2, values_only=True): + row_with_header = list(zip(header, row)) + cs = create_or_update_course_session( + course, dict(row_with_header), circles=["Fahrzeug"] + ) + + def create_or_update_course_session(course: Course, data: Dict[str, Any], circles=None): """ :param data: the following keys are required to process the data: Generation, Region, Klasse @@ -45,15 +60,16 @@ def create_or_update_course_session(course: Course, data: Dict[str, Any], circle circles = [] # TODO: validation - generation = str(data["Generation"]).strip() - region = data["Region"].strip() group = data["Klasse"].strip() import_id = data["ID"].strip() + generation = str(data["Generation"]).strip() + region = data["Region"].strip() + title = f"{region} {generation} {group}" cs, _created = CourseSession.objects.get_or_create( - import_id=import_id, course=course + import_id=import_id, group=group, course=course ) cs.additional_json_data["import_data"] = data @@ -67,16 +83,6 @@ def create_or_update_course_session(course: Course, data: Dict[str, Any], circle cs.save() - """ - ("Fahrzeug Start", "06.06.2023, 13:30"), - ("Fahrzeug Ende", "06.06.2023, 15:00"), - ( - "Fahrzeug Raum", - "https://teams.microsoft.com/l/meetup-join/19%3ameeting_N2I5YzViZTQtYTM2Ny00OTYwLTgzNzAtYWI4OTQzODcxNTlj%40thread.v2/0?context=%7b%22Tid%22%3a%22fedd03c8-a756-4803-8f27-0db8f7c488f2%22%2c%22Oid%22%3a%22f92e6382-3884-4e71-a2fd-b305a75d9812%22%7d", - ), - ("Fahrzeug Standort", None), - ("Fahrzeug Adresse", None), - """ for circle in circles: attendance_course_lp_qs = LearningContentAttendanceCourse.objects.filter( slug=f"{course.slug}-lp-circle-{circle.lower()}-lc-präsenzkurs-{circle.lower()}" diff --git a/server/vbv_lernwelt/importer/tests/test_import_course_sessions.py b/server/vbv_lernwelt/importer/tests/test_import_course_sessions.py index 68a5223b..fb9c6dc2 100644 --- a/server/vbv_lernwelt/importer/tests/test_import_course_sessions.py +++ b/server/vbv_lernwelt/importer/tests/test_import_course_sessions.py @@ -4,43 +4,32 @@ from django.test import TestCase from openpyxl.reader.excel import load_workbook from vbv_lernwelt.course.creators.test_course import create_test_course +from vbv_lernwelt.course.models import CourseSession from vbv_lernwelt.importer.services import create_or_update_course_session test_dir = os.path.dirname(os.path.abspath(__file__)) class ImportCourseSessionTestCase(TestCase): - def test_open_excel_file(self): + def setUp(self): + self.course = create_test_course(include_vv=False) + + def test_import_excel_file(self): workbook = load_workbook( filename=f"{test_dir}/Schulungen_Durchfuehrung_Trainer.xlsx" ) sheet = workbook["Schulungen Durchführung"] - # Read the header row separately header = [cell.value for cell in sheet[1]] - # Loop through the remaining rows in the sheet for row in sheet.iter_rows(min_row=2, values_only=True): row_with_header = list(zip(header, row)) - print(row_with_header) + cs = create_or_update_course_session( + self.course, dict(row_with_header), circles=["Fahrzeug"] + ) + print(cs.title) - def test_create_or_update_course_session(self): - row = [ - ("ID", "DE 2023 A"), - ("Generation", 2023), - ("Region", "Deutschschweiz"), - ("Klasse", "A"), - ("Fahrzeug Start", "06.06.2023, 13:30"), - ("Fahrzeug Ende", "06.06.2023, 15:00"), - ( - "Fahrzeug Raum", - "https://teams.microsoft.com/l/meetup-join/19%3ameeting_N2I5YzViZTQtYTM2Ny00OTYwLTgzNzAtYWI4OTQzODcxNTlj%40thread.v2/0?context=%7b%22Tid%22%3a%22fedd03c8-a756-4803-8f27-0db8f7c488f2%22%2c%22Oid%22%3a%22f92e6382-3884-4e71-a2fd-b305a75d9812%22%7d", - ), - ("Fahrzeug Standort", None), - ("Fahrzeug Adresse", None), - ] - - print(dict(row)) + self.assertEqual(CourseSession.objects.count(), 6) class CreateOrUpdateCourseSessionTestCase(TestCase): @@ -88,3 +77,54 @@ class CreateOrUpdateCourseSessionTestCase(TestCase): "trainer": "", }, ) + + def test_update_course_session(self): + cs = CourseSession.objects.create( + course_id=self.course.id, + title="Deutschschweiz 2023 A", + import_id="DE 2023", + group="A", + ) + + row = [ + ("ID", "DE 2023"), + ("Generation", 2023), + ("Region", "Deutschschweiz"), + ("Klasse", "A"), + ("Fahrzeug Start", "06.06.2023, 13:30"), + ("Fahrzeug Ende", "06.06.2023, 15:00"), + ( + "Fahrzeug Raum", + "https://teams.microsoft.com/l/meetup-join/19%3ameeting_N2I5YzViZTQtYTM2Ny00OTYwLTgzNzAtYWI4OTQzODcxNTlj%40thread.v2/0?context=%7b%22Tid%22%3a%22fedd03c8-a756-4803-8f27-0db8f7c488f2%22%2c%22Oid%22%3a%22f92e6382-3884-4e71-a2fd-b305a75d9812%22%7d", + ), + ("Fahrzeug Standort", None), + ("Fahrzeug Adresse", None), + ] + + data = dict(row) + + cs = create_or_update_course_session(self.course, data, circles=["Fahrzeug"]) + + self.assertEqual(1, CourseSession.objects.count()) + + self.assertEqual(cs.import_id, "DE 2023") + self.assertEqual(cs.title, "Deutschschweiz 2023 A") + self.assertEqual(cs.generation, "2023") + self.assertEqual(cs.region, "Deutschschweiz") + self.assertEqual(cs.group, "A") + + attendance_course = cs.attendance_courses[0] + attendance_course = { + k: v + for k, v in attendance_course.items() + if k not in ["learningContentId", "location"] + } + + self.assertDictEqual( + attendance_course, + { + "start": "2023-06-06T13:30:00", + "end": "2023-06-06T15:00:00", + "trainer": "", + }, + ) diff --git a/server/vbv_lernwelt/learnpath/tests/test_api.py b/server/vbv_lernwelt/learnpath/tests/test_api.py index 46c45490..da6c8cc3 100644 --- a/server/vbv_lernwelt/learnpath/tests/test_api.py +++ b/server/vbv_lernwelt/learnpath/tests/test_api.py @@ -45,7 +45,6 @@ class TestRetrieveLearingPathContents(APITestCase): course_session = CourseSession.objects.create( course_id=COURSE_TEST_ID, title="Test Lehrgang Session", - import_id="Test Lehrgang Session", ) CourseSessionUser.objects.create( course_session=course_session,