Skip to content
Snippets Groups Projects
Commit 6ec576a4 authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Merge branch '5-import-exams-announcement-from-calendar-via-mysql' into 'master'

Resolve "Import exams/announcement from calendar via MySQL"

Closes #5

See merge request !146
parents fd898f89 fd0d8b61
No related branches found
No related tags found
1 merge request!146Resolve "Import exams/announcement from calendar via MySQL"
Pipeline #72834 failed
Pipeline: AlekSIS

#72848

    ...@@ -14,6 +14,7 @@ Added ...@@ -14,6 +14,7 @@ Added
    * Support for configuring the Untis school ID * Support for configuring the Untis school ID
    * Add Ukrainian locale (contributed by Sergiy Gorichenko from Fre(i)e Software GmbH). * Add Ukrainian locale (contributed by Sergiy Gorichenko from Fre(i)e Software GmbH).
    * Import exams from Untis.
    Fixed Fixed
    ~~~~~ ~~~~~
    ......
    ...@@ -14,6 +14,7 @@ Features ...@@ -14,6 +14,7 @@ Features
    * Import breaks * Import breaks
    * Import classes * Import classes
    * Import events * Import events
    * Import exams
    * Import exported Untis database via MySQL import * Import exported Untis database via MySQL import
    * Import exported Untis XML files * Import exported Untis XML files
    * Import holidays * Import holidays
    ......
    ...@@ -74,3 +74,6 @@ chronos_models.Holiday.field( ...@@ -74,3 +74,6 @@ chronos_models.Holiday.field(
    chronos_models.ExtraLesson.field( chronos_models.ExtraLesson.field(
    import_ref_untis=IntegerField(verbose_name=_("UNTIS import reference"), null=True, blank=True) import_ref_untis=IntegerField(verbose_name=_("UNTIS import reference"), null=True, blank=True)
    ) )
    chronos_models.Exam.field(
    import_ref_untis=IntegerField(verbose_name=_("UNTIS import reference"), null=True, blank=True)
    )
    import logging
    from django.utils.translation import gettext as _
    from calendarweek import CalendarWeek
    from tqdm import tqdm
    from aleksis.apps.chronos import models as chronos_models
    from aleksis.apps.chronos.models import ExtraLesson, Lesson, ValidityRange
    from .... import models as mysql_models
    from ..util import (
    TQDM_DEFAULTS,
    connect_untis_fields,
    date_to_untis_date,
    get_first_period,
    get_last_period,
    move_weekday_to_range,
    run_default_filter,
    untis_date_to_date,
    untis_split_second,
    )
    logger = logging.getLogger(__name__)
    def import_exams(
    validity_range: ValidityRange,
    time_periods_ref,
    subjects_ref,
    teachers_ref,
    rooms_ref,
    ):
    ref = {}
    # Get absences
    exams = (
    run_default_filter(validity_range, mysql_models.Exam.objects, filter_term=False)
    .filter(
    date__lte=date_to_untis_date(validity_range.date_end),
    date__gte=date_to_untis_date(validity_range.date_start),
    )
    .order_by("exam_id")
    )
    existing_exams = []
    for exam in tqdm(exams, desc="Import exams", **TQDM_DEFAULTS):
    import_ref = exam.exam_id
    logger.info("Import exam {}".format(import_ref))
    # Build values
    title = exam.name
    comment = exam.text
    day = untis_date_to_date(exam.date)
    period_from = exam.lessonfrom
    period_to = exam.lessonto
    weekday = day.weekday()
    week = CalendarWeek.from_date(day)
    # Check min/max weekdays
    weekday = move_weekday_to_range(time_periods_ref, weekday)
    # Check min/max periods
    first_period = get_first_period(time_periods_ref, weekday)
    last_period = get_last_period(time_periods_ref, weekday)
    if period_from == 0:
    period_from = first_period
    if period_to == 0:
    period_to = last_period
    time_period_from = time_periods_ref[weekday][period_from]
    time_period_to = time_periods_ref[weekday][period_to]
    # Get groups, teachers and rooms
    raw_exams = connect_untis_fields(exam, "examelement", 10)
    first = True
    lesson = None
    subject = None
    exams = []
    for raw_exam in raw_exams:
    el = untis_split_second(raw_exam, remove_empty=False)
    if first:
    lesson_id = int(el[0])
    subject_id = int(el[1])
    lesson = Lesson.objects.get(validity=validity_range, lesson_id_untis=lesson_id)
    subject = subjects_ref[subject_id]
    first = False
    period = int(el[4])
    period = time_periods_ref[weekday][period]
    teacher_id = int(el[5])
    room_id = int(el[6])
    teacher = teachers_ref[teacher_id]
    room = rooms_ref[room_id]
    exams.append((period, teacher, room))
    if not lesson or not subject:
    logger.warning(f"Skip exam {import_ref} due to missing data.")
    continue
    new_exam, created = chronos_models.Exam.objects.update_or_create(
    import_ref_untis=import_ref,
    defaults={
    "date": day,
    "lesson": lesson,
    "period_from": time_period_from,
    "period_to": time_period_to,
    "title": title,
    "comment": comment,
    "school_term": validity_range.school_term,
    },
    )
    if created:
    logger.info(" New exam created")
    extra_lesson_pks = []
    for exam in exams:
    period, teacher, room = exam
    comment = new_exam.title or _("Exam")
    extra_lesson, __ = ExtraLesson.objects.get_or_create(
    exam=new_exam,
    period=period,
    defaults={
    "room": room,
    "week": week.week,
    "year": week.year,
    "comment": comment,
    "subject": subject,
    },
    )
    if (
    extra_lesson.room != room
    or extra_lesson.week != week.week
    or extra_lesson.year != week.year
    or extra_lesson.comment != comment
    or extra_lesson.subject != subject
    ):
    extra_lesson.room = room
    extra_lesson.week = week.week
    extra_lesson.year = week.year
    extra_lesson.comment = comment
    extra_lesson.subject = subject
    extra_lesson.save()
    extra_lesson.groups.set(lesson.groups.all())
    extra_lesson.teachers.set([teacher])
    extra_lesson_pks.append(extra_lesson.pk)
    # Delete no-longer necessary extra lessons
    ExtraLesson.objects.filter(exam=new_exam).exclude(pk__in=extra_lesson_pks).delete()
    existing_exams.append(import_ref)
    ref[import_ref] = new_exam
    # Delete all no longer existing exams
    for e in chronos_models.Exam.objects.within_dates(
    validity_range.date_start, validity_range.date_end
    ):
    if e.import_ref_untis and e.import_ref_untis not in existing_exams:
    logger.info("exam {} deleted".format(e.id))
    e.delete()
    ...@@ -21,6 +21,7 @@ from .importers.common_data import ( ...@@ -21,6 +21,7 @@ from .importers.common_data import (
    import_time_periods, import_time_periods,
    ) )
    from .importers.events import import_events from .importers.events import import_events
    from .importers.exams import import_exams
    from .importers.holidays import import_holidays from .importers.holidays import import_holidays
    from .importers.lessons import import_lessons from .importers.lessons import import_lessons
    from .importers.substitutions import import_substitutions from .importers.substitutions import import_substitutions
    ...@@ -93,3 +94,6 @@ def untis_import_mysql( ...@@ -93,3 +94,6 @@ def untis_import_mysql(
    # Events # Events
    import_events(validity_range, time_periods_ref, teachers_ref, classes_ref, rooms_ref) import_events(validity_range, time_periods_ref, teachers_ref, classes_ref, rooms_ref)
    # Exams
    import_exams(validity_range, time_periods_ref, subjects_ref, teachers_ref, rooms_ref)
    ...@@ -25,6 +25,7 @@ information from Untis can be imported into AlekSIS: ...@@ -25,6 +25,7 @@ information from Untis can be imported into AlekSIS:
    * Absences, absence reasons * Absences, absence reasons
    * Substitutions, extra lessons, cancellations * Substitutions, extra lessons, cancellations
    * Events * Events
    * Exams
    The Untis integration supports the versioning features of Untis. By default, The Untis integration supports the versioning features of Untis. By default,
    the most recent version of each object is imported. the most recent version of each object is imported.
    ...@@ -32,10 +33,10 @@ the most recent version of each object is imported. ...@@ -32,10 +33,10 @@ the most recent version of each object is imported.
    Currently, the following features are known not to be supported: Currently, the following features are known not to be supported:
    * Students, student groups, student choices * Students, student groups, student choices
    * Exams
    * Calendars
    * Prebookings * Prebookings
    * Statistical data * Statistical data
    * Special rooms (subject and group rooms) * Special rooms (subject and group rooms)
    AlekSIS does not support so-called "day texts" from Untis. These are incompatible with AlekSIS' announcement feature, which can be used as a replacement.
    .. _Untis MultiUser: https://www.untis.at/produkte/untis-das-grundpaket/multiuser .. _Untis MultiUser: https://www.untis.at/produkte/untis-das-grundpaket/multiuser
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment