diff --git a/client/src/locales/de/translation.json b/client/src/locales/de/translation.json index 55a8ebec..dd5b1340 100644 --- a/client/src/locales/de/translation.json +++ b/client/src/locales/de/translation.json @@ -269,7 +269,7 @@ "selfEvaluationNo": "@:selfEvaluation: Muss ich nochmals anschauen.", "selfEvaluationYes": "@:selfEvaluation: Ich kann das.", "steps": "Schritt {{current}} von {{max}}", - "title": "@:selfEvaluation.selfEvaluation {{title}}", + "title": "Selbsteinschätzung {{title}}", "yes": "Ja, ich kann das" }, "settings": { diff --git a/client/src/pages/DashboardPage.vue b/client/src/pages/DashboardPage.vue index f7ca56d5..bd246037 100644 --- a/client/src/pages/DashboardPage.vue +++ b/client/src/pages/DashboardPage.vue @@ -91,7 +91,9 @@ const getNextStepLink = (courseSession: CourseSession) => {
{{ $t("uk.contact.address") }}
- uk.contact.email + + uek-support@vbv-afa.ch +

diff --git a/server/config/urls.py b/server/config/urls.py index 4268109e..0c60936a 100644 --- a/server/config/urls.py +++ b/server/config/urls.py @@ -37,7 +37,11 @@ from vbv_lernwelt.course.views import ( request_course_completion, request_course_completion_for_user, ) -from vbv_lernwelt.edoniq_test.views import export_students, export_trainers +from vbv_lernwelt.edoniq_test.views import ( + export_students, + export_students_and_trainers, + export_trainers, +) from vbv_lernwelt.feedback.views import ( get_expert_feedbacks_for_course, get_feedback_for_circle, @@ -148,6 +152,8 @@ urlpatterns = [ # edoniq test path(r'api/core/edoniq-test/export-users/', export_students, name='edoniq_export_students'), path(r'api/core/edoniq-test/export-trainers/', export_trainers, name='edoniq_export_trainers'), + path(r'api/core/edoniq-test/export-users-trainers/', export_students_and_trainers, + name='edoniq_export_students_and_trainers'), # importer path( diff --git a/server/vbv_lernwelt/edoniq_test/tests/test_edoniq_export.py b/server/vbv_lernwelt/edoniq_test/tests/test_edoniq_export.py index fae09e0e..893ca698 100644 --- a/server/vbv_lernwelt/edoniq_test/tests/test_edoniq_export.py +++ b/server/vbv_lernwelt/edoniq_test/tests/test_edoniq_export.py @@ -6,7 +6,9 @@ from vbv_lernwelt.core.admin import User from vbv_lernwelt.core.create_default_users import create_default_users from vbv_lernwelt.course.consts import COURSE_TEST_ID from vbv_lernwelt.course.creators.test_course import create_test_course +from vbv_lernwelt.course.models import CourseSession, CourseSessionUser from vbv_lernwelt.edoniq_test.views import ( + fetch_course_session_all_users, fetch_course_session_users, generate_export_response, ) @@ -36,6 +38,37 @@ class EdoniqUserExportTestCase(TestCase): users = fetch_course_session_users([COURSE_TEST_ID]) self.assertEqual(len(users), 2) + def test_fetch_course_session_trainers(self): + users = fetch_course_session_users( + [COURSE_TEST_ID], role=CourseSessionUser.Role.EXPERT + ) + self.assertEqual(len(users), 1) + + def test_remove_eiger_versicherungen(self): + user1 = User.objects.get(email="test-student1@example.com") + user1.email = "some@eiger-versicherungen.ch" + user1.save() + users = fetch_course_session_users([COURSE_TEST_ID]) + self.assertEqual(len(users), 1) + + def test_export_students_and_trainers(self): + users = fetch_course_session_all_users([COURSE_TEST_ID]) + self.assertEqual(len(users), 3) + + def test_deduplicates_users(self): + trainer1 = User.objects.get(email="test-trainer1@example.com") + cs_zrh = CourseSession.objects.get( + title="Test Zürich 2022 a", + ) + _csu = CourseSessionUser.objects.create( + course_session=cs_zrh, + user=trainer1, + ) + users = fetch_course_session_all_users([COURSE_TEST_ID]) + for u in users: + print(u.edoniq_role, u.email) + self.assertEqual(len(users), 3) + def test_response_csv(self): users = fetch_course_session_users([COURSE_TEST_ID]) response = generate_export_response(users) diff --git a/server/vbv_lernwelt/edoniq_test/views.py b/server/vbv_lernwelt/edoniq_test/views.py index 1fe5cf44..30f65398 100644 --- a/server/vbv_lernwelt/edoniq_test/views.py +++ b/server/vbv_lernwelt/edoniq_test/views.py @@ -1,8 +1,10 @@ import csv from datetime import date +from itertools import chain from typing import List from django.contrib.admin.views.decorators import staff_member_required +from django.db.models import CharField, Value from django.http import HttpResponse from vbv_lernwelt.core.models import User @@ -18,26 +20,53 @@ def export_students(request): return generate_export_response(course_session_users) +@staff_member_required def export_trainers(request): course_session_users = fetch_course_session_users( UK_COURSE_IDS, role=CourseSessionUser.Role.EXPERT ) - return generate_export_response(course_session_users, role="Trainer") + return generate_export_response(course_session_users) + + +@staff_member_required +def export_students_and_trainers(request): + course_session_users = fetch_course_session_all_users(UK_COURSE_IDS) + return generate_export_response(course_session_users) def fetch_course_session_users(courses: List[int], role=CourseSessionUser.Role.MEMBER): + if role == CourseSessionUser.Role.EXPERT: + edoniq_role = "Trainer" + else: + edoniq_role = "Lernende" + # if users should be exported per course session, remove the distinct() call return ( User.objects.filter( coursesessionuser__course_session__course__id__in=courses, coursesessionuser__role=role, ) + .exclude(email__contains="eiger-versicherungen.ch") # exclude test users + .exclude(email__contains="assurance.ch") .order_by("email") + .annotate(edoniq_role=Value(edoniq_role, output_field=CharField())) .distinct() ) -def generate_export_response(cs_users: List[User], role="Lernende") -> HttpResponse: +def fetch_course_session_all_users(courses: List[int]): + course_session_users = fetch_course_session_users(courses) + course_session_trainers = fetch_course_session_users( + courses, role=CourseSessionUser.Role.EXPERT + ) + combined_queryset = chain(course_session_users, course_session_trainers) + + # use email as key to remove duplicates. Maybe we can use the sso id in the future, but it is not set for all users + unique_dict = {obj.email: obj for obj in combined_queryset} + return list(unique_dict.values()) + + +def generate_export_response(cs_users: List[User]) -> HttpResponse: response = HttpResponse(content_type="text/csv") response[ "Content-Disposition" @@ -71,7 +100,7 @@ def generate_export_response(cs_users: List[User], role="Lernende") -> HttpRespo cs_user.language, cs_user.email, cs_user.additional_json_data.get("Geburtsdatum", ""), - role, + cs_user.edoniq_role, cs_user.additional_json_data.get("Firmenname", ""), cs_user.additional_json_data.get("Lehrvertragsnummer", ""), cs_user.coursesessionuser_set.first().course_session.import_id, diff --git a/server/vbv_lernwelt/importer/services.py b/server/vbv_lernwelt/importer/services.py index 30b35e9a..2cd64419 100644 --- a/server/vbv_lernwelt/importer/services.py +++ b/server/vbv_lernwelt/importer/services.py @@ -185,6 +185,7 @@ def create_or_update_user( last_name: str = "", sso_id: str = None, contract_number: str = "", + date_of_birth: str = "", ): logger.debug( "create_or_update_user", @@ -200,9 +201,13 @@ def create_or_update_user( if user_qs.exists(): user = user_qs.first() + # use the ID from DBPLAP2 (Lehrvertragsnummer, firstname, lastname, date of birth) if not user and contract_number: user_qs = User.objects.filter( - additional_json_data__Lehrvertragsnummer=contract_number + first_name=first_name, + last_name=last_name, + additional_json_data__Lehrvertragsnummer=contract_number, + additional_json_data__Geburtsdatum=date_of_birth, ) if user_qs.exists(): user = user_qs.first() @@ -502,6 +507,8 @@ def import_students_from_excel(filename: str): "Name", "Sprache", "Durchführungen", + "Lehrvertragsnummer", + "Geburtsdatum", ], ) create_or_update_student(data) @@ -514,11 +521,14 @@ def create_or_update_student(data: Dict[str, Any]): label="import", ) + date_of_birth = _get_date_of_birth(data) + user = create_or_update_user( email=data["Email"].lower(), first_name=data["Vorname"], last_name=data["Name"], contract_number=data.get("Lehrvertragsnummer", ""), + date_of_birth=date_of_birth, ) user.language = data["Sprache"] @@ -535,6 +545,16 @@ def create_or_update_student(data: Dict[str, Any]): csu.save() +def _get_date_of_birth(data: Dict[str, Any]) -> str: + date_of_birth = data.get("Geburtsdatum", None) + if date_of_birth is None: + return "" + elif date_of_birth is date or date_of_birth is datetime: + return date_of_birth.strftime("%d.%m.%Y") + elif type(date_of_birth) is str: + return date_of_birth + + def sync_students_from_t2l_excel(filename: str): workbook = load_workbook(filename=filename) sheet = workbook.active @@ -546,10 +566,13 @@ def sync_students_from_t2l_excel(filename: str): def sync_students_from_t2l(data): - # ignore errors + date_of_birth = _get_date_of_birth(data) try: user = User.objects.get( - additional_json_data__Lehrvertragsnummer=data["Lehrvertragsnummer"] + first_name=data["Vorname"], + last_name=data["Name"], + additional_json_data__Lehrvertragsnummer=data["Lehrvertragsnummer"], + additional_json_data__Geburtsdatum=date_of_birth, ) except User.DoesNotExist: return diff --git a/server/vbv_lernwelt/importer/tests/Schulungen_Teilnehmende.xlsx b/server/vbv_lernwelt/importer/tests/Schulungen_Teilnehmende.xlsx index 743518fa..b79f00e0 100644 Binary files a/server/vbv_lernwelt/importer/tests/Schulungen_Teilnehmende.xlsx and b/server/vbv_lernwelt/importer/tests/Schulungen_Teilnehmende.xlsx differ diff --git a/server/vbv_lernwelt/importer/tests/__init__.py b/server/vbv_lernwelt/importer/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/vbv_lernwelt/importer/tests/test_import_students.py b/server/vbv_lernwelt/importer/tests/test_import_students.py index e9597c25..d771d89d 100644 --- a/server/vbv_lernwelt/importer/tests/test_import_students.py +++ b/server/vbv_lernwelt/importer/tests/test_import_students.py @@ -51,6 +51,7 @@ class CreateOrUpdateStudentTestCase(TestCase): "Durchführungen": "DE 2023 A", "Lehrvertragsnummer": "1234", "Tel. Privat": "079 593 83 43", + "Geburtsdatum": "01.01.2000", } def test_create_student(self): diff --git a/server/vbv_lernwelt/importer/tests/test_t2l_sync.py b/server/vbv_lernwelt/importer/tests/test_t2l_sync.py index cc889a80..c800a52e 100644 --- a/server/vbv_lernwelt/importer/tests/test_t2l_sync.py +++ b/server/vbv_lernwelt/importer/tests/test_t2l_sync.py @@ -32,6 +32,7 @@ class SyncT2lTestCase(TestCase): "Durchführungen": "DE 2023 A", "Lehrvertragsnummer": "1234", "Tel. Privat": "079 593 83 43", + "Geburtsdatum": "01.01.2000", } create_or_update_student(self.user_dict) @@ -44,6 +45,7 @@ class SyncT2lTestCase(TestCase): "Durchführungen": "DE 2023 A", "Lehrvertragsnummer": "1234", "Tel. Privat": "079 593 83 65", + "Geburtsdatum": "01.01.2000", } sync_students_from_t2l(user_dict) @@ -65,6 +67,7 @@ class SyncT2lTestCase(TestCase): "Lehrvertragsnummer": "1234", "Tel. Privat": "079 593 83 43", "Firma": "VBV", + "Geburtsdatum": "01.01.2000", } sync_students_from_t2l(user_dict) @@ -84,6 +87,7 @@ class SyncT2lTestCase(TestCase): "Durchführungen": "DE 2023 B", "Lehrvertragsnummer": "1234", "Tel. Privat": "079 593 83 43", + "Geburtsdatum": "01.01.2000", } sync_students_from_t2l(user_dict) diff --git a/server/vbv_lernwelt/templates/admin/index.html b/server/vbv_lernwelt/templates/admin/index.html index ffdf0dc3..564c0c92 100644 --- a/server/vbv_lernwelt/templates/admin/index.html +++ b/server/vbv_lernwelt/templates/admin/index.html @@ -31,9 +31,13 @@

Export Edoniq Teilnehmer

Teilnehmer exportieren -

Export Edoniq Trainer

+

Export Edoniq Trainer

Trainer exportieren +

Export Edoniq Teilnehmer und Trainer

+ Teilnehmer und Trainer exportieren + +

Reset

{% csrf_token %}