diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8b55fc8dd21619cd55817143df53fd08627e9fe0..f6162fac619ddd09347f009f2a777cad9807fc32 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,7 @@ Added * Add fuzzy matching mode for searching course groups: If no 100 % match is found, the importer will search a match by a subset of parent groups. +* Register data match failures as data check problems. Changed ~~~~~~~ diff --git a/aleksis/apps/untis/data_checks.py b/aleksis/apps/untis/data_checks.py new file mode 100644 index 0000000000000000000000000000000000000000..fc7b47512c6302e1e17e3dbfbd2a597a8712d446 --- /dev/null +++ b/aleksis/apps/untis/data_checks.py @@ -0,0 +1,36 @@ +from django.utils.translation import gettext_lazy as _ + +from aleksis.core.data_checks import DataCheck, IgnoreSolveOption + + +class CourseGroupNotFoundAndCreated(DataCheck): + name = "untis_mysql_course_group_not_found_and_created" + verbose_name = _( + "Course groups created by the Untis import because no matching group has been found." + ) + problem_name = _( + "The Untis import created a new course group because no matching group has been found." + ) + + solve_options = {IgnoreSolveOption.name: IgnoreSolveOption} + + @classmethod + def run_check_data(cls): + pass + + +class CourseGroupNotFoundAndNotCreated(DataCheck): + name = "untis_not_created_not_primary_source" + verbose_name = _( + "Course group not set by the Untis import because no matching group has been found." + ) + problem_name = _( + "The Untis import didn't set a course group " + "for a lesson because no matching group has been found." + ) + + solve_options = {IgnoreSolveOption.name: IgnoreSolveOption} + + @classmethod + def run_check_data(cls): + pass diff --git a/aleksis/apps/untis/models.py b/aleksis/apps/untis/models.py index c616ba84b71f5812668681ff4477a7b523719770..d29083f3edc034940ed444961821666e92adaaee 100644 --- a/aleksis/apps/untis/models.py +++ b/aleksis/apps/untis/models.py @@ -8,6 +8,8 @@ from django.utils.translation import gettext as _ from aleksis.core.mixins import PureDjangoModel +from .data_checks import CourseGroupNotFoundAndCreated, CourseGroupNotFoundAndNotCreated + class Absence(models.Model, PureDjangoModel): school_id = models.IntegerField( @@ -4244,6 +4246,8 @@ class Views(models.Model, PureDjangoModel): class GlobalPermissions(models.Model, PureDjangoModel): + data_checks = [CourseGroupNotFoundAndCreated, CourseGroupNotFoundAndNotCreated] + class Meta: managed = False permissions = (("assign_subjects_to_groups", _("Can assign subjects to groups")),) diff --git a/aleksis/apps/untis/preferences.py b/aleksis/apps/untis/preferences.py index 36e54d9790f8c272e986d43528a833a1bcd98f16..d95f5bc30cb306d3bca40c0db60f682a26a86143 100644 --- a/aleksis/apps/untis/preferences.py +++ b/aleksis/apps/untis/preferences.py @@ -86,9 +86,24 @@ class UseCourseGroups(BooleanPreference): name = "use_course_groups" default = True verbose_name = _("Use course groups") - help_text = _( - "Build or search course groups for every course" " instead of setting classes as groups." - ) + help_text = _("Search course groups for every course instead of setting classes as groups.") + + +@site_preferences_registry.register +class CreateCourseGroups(BooleanPreference): + section = untis_mysql + name = "create_course_groups" + default = True + verbose_name = _("Create non-existing course groups") + help_text = _("Only used if 'Use course groups' is enabled.") + + +@site_preferences_registry.register +class DataCheckNotFoundCourseGroups(BooleanPreference): + section = untis_mysql + name = "data_check_for_not_found_course_groups" + default = True + verbose_name = _("Register a data problem if a course group has been not found.") @site_preferences_registry.register diff --git a/aleksis/apps/untis/util/mysql/importers/lessons.py b/aleksis/apps/untis/util/mysql/importers/lessons.py index dc7aa154c85b4ca21c05030c53e7a49f9d25a81b..006fc497f3b57920e12237da04196912b2cc2abb 100644 --- a/aleksis/apps/untis/util/mysql/importers/lessons.py +++ b/aleksis/apps/untis/util/mysql/importers/lessons.py @@ -13,6 +13,7 @@ from aleksis.core import models as core_models from aleksis.core.util.core_helpers import get_site_preferences from .... import models as mysql_models +from ....data_checks import CourseGroupNotFoundAndCreated, CourseGroupNotFoundAndNotCreated from ..util import ( TQDM_DEFAULTS, compare_m2m, @@ -120,6 +121,7 @@ def import_lessons( c = classes_ref[class_id] course_classes.append(c) + course_group_not_found_and_not_created = False if get_site_preferences()["untis_mysql__use_course_groups"]: # Negative import_ref denotes a course group group_import_ref = -int("{}{}".format(lesson_id, i)) @@ -132,7 +134,7 @@ def import_lessons( ).filter(Q(school_term__isnull=True) | Q(school_term=validity_range.school_term)) # Check if found groups match - match = False + course_group = None for found_group in qs: if compare_m2m(course_classes, found_group.parent_groups.all()) and compare_m2m( teachers, found_group.owners.all() @@ -173,7 +175,11 @@ def import_lessons( ) changed = False - if not match: + register_data_check = get_site_preferences()[ + "untis_mysql__data_check_for_not_found_course_groups" + ] + if not course_group and get_site_preferences()["untis_mysql__create_course_groups"]: + # No matching group found # Build names and refs for course groups @@ -206,29 +212,40 @@ def import_lessons( changed = True - # Update owners - course_group.owners.set(teachers) + if created and register_data_check: + # No match, new course group created, so create a data problem if activated + CourseGroupNotFoundAndCreated.register_result(course_group) + elif register_data_check: + # No match, create deactivated, so create a data problem later if activated + course_group_not_found_and_not_created = True + + if course_group: + # Update owners + course_group.owners.set(teachers) + + # Update import ref + if course_group.import_ref_untis != group_import_ref: + course_group.import_ref_untis = group_import_ref + logger.info(" Import reference of course group updated") + changed = True - # Update import ref - if course_group.import_ref_untis != group_import_ref: - course_group.import_ref_untis = group_import_ref - logger.info(" Import reference of course group updated") - changed = True + if course_group.subject != subject: + course_group.subject = subject + logger.info(" Subject reference of course group updated") + changed = True - if course_group.subject != subject: - course_group.subject = subject - logger.info(" Subject reference of course group updated") - changed = True + if course_group.school_term != validity_range.school_term: + course_group.school_term = validity_range.school_term + logger.info(" School term reference of course group updated") + changed = True - if course_group.school_term != validity_range.school_term: - course_group.school_term = validity_range.school_term - logger.info(" School term reference of course group updated") - changed = True + if changed: + course_group.save() - if changed: - course_group.save() + groups = [course_group] - groups = [course_group] + else: + groups = [] else: groups = course_classes @@ -259,8 +276,13 @@ def import_lessons( ) logger.info(" New lesson created") + if course_group_not_found_and_not_created: + # Register data problem here because before the lesson object is unknown + CourseGroupNotFoundAndNotCreated.register_result(lesson) + # Sync groups - lesson.groups.set(groups) + if groups: + lesson.groups.set(groups) # Sync teachers lesson.teachers.set(teachers) diff --git a/docs/admin/20_configuration.rst b/docs/admin/20_configuration.rst index 9984da36cbdd7c181b4263f00c51f8d1da779a39..065dbf319fad22935f44ce1218d645ae9e2d7496 100644 --- a/docs/admin/20_configuration.rst +++ b/docs/admin/20_configuration.rst @@ -67,8 +67,15 @@ The way data are imported can be configured from the menu under existing rooms if Untis has different data. * **Update existing supervision areas:** This will update the values of already existing supervision areas if Untis has different data. -* **Use course groups:** This will build or search course groups (groups +* **Use course groups:** This will search course groups (groups for each subject in a class) instead of setting the classes as groups. +* **Create non-existing course groups**: In combination with _Use course groups_ being enabled, + this will create new course groups if no matching group was found. +* **Register a data problem if a course group has been not found:** When this is activated, + the import will register a data problem if no matching course group was found, + independent of whether a new course group was created or not. +* **Ignore incomplete substitutions**: If this is activated, Untis won't import any substitutions + which are not cancelled or without a new room, new teacher or new subject . Scheduling import tasks -----------------------