Files
LehrerApp/LehrerApp.Core/Models/Planning.cs
T
adminandClaude Sonnet 5 d6dee72acc Unterrichtsplanung: Serienerzeugung, Stundenraster, Aufsichten & Vertretung (Kapitel 4.2/4.3 Nachtrag)
Stunden serienweise aus dem Stundenplan erzeugen (4.2.5); Stundenraster
(Uhrzeiten je Stunde) in den Einstellungen mit Zeitbedarf-Rückmeldung im
Verlaufsplan-Editor; wiederkehrende Pausenaufsicht; neuer "Vertretung
eintragen"-Dialog für einmalige Vertretungsaufsicht, Vertretungsstunde,
Sondereinsätze (Ausflüge, Berufsmessen) und schlichten Stundenausfall.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 21:59:07 +02:00

223 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace LehrerApp.Core.Models;
public class Grade
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid StudentId { get; set; }
public Guid GroupId { get; set; }
public GradeCategory Category { get; set; }
public string Value { get; set; } = "";
public DateOnly Date { get; set; }
public double Weight { get; set; } = 1.0;
public string? Note { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
public enum GradeCategory { Oral, Homework, Participation, Project, Other }
/// <summary>
/// Prozentuale Gewichtung von Klausuren/Mitarbeit/sonstigen Leistungen für die Zeugnisnote.
/// Entweder gruppenspezifisch (<see cref="GroupId"/> gesetzt) oder als Voreinstellung je
/// Gruppentyp (<see cref="GroupType"/> gesetzt, <see cref="GroupId"/> null).
/// </summary>
public class GradingScheme
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid? GroupId { get; set; }
public GroupType? GroupType { get; set; }
public double ExamsPercent { get; set; }
public double ParticipationPercent { get; set; }
public double OtherPercent { get; set; }
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class Unit
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid GroupId { get; set; }
public string Title { get; set; } = "";
public DateOnly? StartDate { get; set; }
public DateOnly? EndDate { get; set; }
public List<string> Competencies { get; set; } = [];
public UnitStatus Status { get; set; } = UnitStatus.Planned;
public string? Notes { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
public class Lesson
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid UnitId { get; set; }
public Guid GroupId { get; set; }
public DateOnly Date { get; set; }
public int? LessonNumber { get; set; }
public string Topic { get; set; } = "";
/// Optionaler Stundenbeginn — solange kein Stundenplan (Kapitel 4.3) existiert, manuell
/// gepflegt. Dient nur der abgeleiteten Uhrzeit-Anzeige je Phase in <see cref="Phases"/>.
public TimeOnly? StartTime { get; set; }
public List<LessonPhaseStep> Phases { get; set; } = [];
public string? Homework { get; set; }
public string? Reflection { get; set; }
public LessonStatus Status { get; set; } = LessonStatus.Planned;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
/// <summary>
/// Eine Zeile im tabellarischen Stundenverlaufsplan (Phase/Dauer/Tätigkeit/Material/Kurzsymbol).
/// <see cref="DurationMinutes"/> ist die primäre Eingabe (man plant in Zeitblöcken); die Uhrzeit
/// je Phase wird im Editor daraus abgeleitet, wenn <see cref="Lesson.StartTime"/> gesetzt ist.
/// <see cref="Shorthand"/> ist bewusst ein einzelnes Freitextfeld statt einer erzwungenen
/// Von/Nach-Struktur: manchmal ist es ein Materialfluss-Pfeil ("AB001->S"), manchmal nur eine
/// Sozialform ohne Pfeil ("Plenum", "LDE"). Vorschläge kommen sowohl aus dem in den Einstellungen
/// gepflegten Kürzel-Katalog (<see cref="ShorthandCode"/>) als auch aus bereits in anderen Stunden
/// verwendeten Werten.
/// </summary>
public class LessonPhaseStep
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = "";
public int DurationMinutes { get; set; }
public string Activity { get; set; } = "";
public string Material { get; set; } = "";
public string Shorthand { get; set; } = "";
/// <summary>
/// null = Hauptweg. Sonst Verweis auf einen benannten <see cref="AlternativeLessonPath"/> aus
/// dem Katalog, über den Phasen alternativer Unterrichtsverläufe zusammengehören —
/// Verlaufsplan-Editor und -Ansicht gruppieren danach. Bewusst kein Fork-Punkt-Bezug zum
/// Hauptweg: eine Alternative beginnt in der Anzeige unabhängig ab dem Stundenbeginn, nicht ab
/// einer gemeinsamen Verzweigungsstelle — für den schnellen Überblick ausreichend, siehe TODO.md.
/// </summary>
public Guid? AlternativePathId { get; set; }
}
public enum UnitStatus { Planned, Active, Completed }
public enum LessonStatus { Planned, Conducted }
/// <summary>
/// Katalogeintrag für einen wiederverwendbaren "alternativen Ablauf" (z.B. "Kurzversion" bei
/// Zeitmangel), dem einzelne <see cref="LessonPhaseStep"/>-Zeilen über
/// <see cref="LessonPhaseStep.AlternativePathId"/> zugeordnet werden. Wird direkt beim Zuweisen im
/// Verlaufsplan-Editor angelegt (kein separates Verwaltungs-UI in den Einstellungen bisher).
/// </summary>
public class AlternativeLessonPath
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = "";
/// Freitext, wann/wofür dieser Ablauf gedacht ist, z.B. "Bei Zeitmangel, wenn Aufgabe 3 nicht
/// mehr passt." Absichtlich kein strukturiertes Bedingungsfeld (z.B. "wenn an Stelle X weniger
/// als Y Minuten übrig sind") — das setzt eine Live-Zeiterfassung während des Unterrichtens
/// voraus, die es noch nicht gibt (siehe Live-Unterrichtsmodus-Ideensammlung in TODO.md).
public string? Description { get; set; }
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
/// <summary>
/// Ein fester Termin im wöchentlichen Stundenplan (4.3): eine Lerngruppe trifft sich an einem
/// Wochentag zu einer bestimmten Stunde. Wiederkehrendes Muster, kein konkretes Datum — für
/// tatsächlich gehaltene Einzelstunden siehe <see cref="Lesson"/>. Pro Wochentag/Stunde ist
/// höchstens eine Gruppe eingetragen (ein Lehrer kann nicht gleichzeitig an zwei Orten sein).
/// </summary>
public class TimetableSlot
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid GroupId { get; set; }
public DayOfWeek Weekday { get; set; }
public int PeriodNumber { get; set; }
public string? Room { get; set; }
}
/// <summary>
/// Unterrichtsfreier Zeitraum (4.3.5): Schulferien werden manuell gepflegt (nicht algorithmisch
/// herleitbar, jährlich neu von den Bundesländern festgelegt). Gesetzliche Feiertage werden
/// dagegen berechnet (PublicHolidayService) und nicht in der Datenbank gespeichert.
/// </summary>
public class SchoolHoliday
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = "";
public DateOnly StartDate { get; set; }
public DateOnly EndDate { get; set; }
}
public enum GermanState
{
BW, BY, BE, BB, HB, HH, HE, MV, NI, NW, RP, SL, SN, ST, SH, TH
}
/// <summary>
/// Wiederkehrende Pausenaufsicht (kein Bezug zu einer Lerngruppe, anders als
/// <see cref="TimetableSlot"/>). <see cref="AfterPeriod"/> = 0 bedeutet "vor der 1. Stunde"
/// (Frühaufsicht), sonst "in der Pause nach dieser Stunde". Pro Wochentag/Pause höchstens eine
/// Aufsicht (ein Lehrer kann nicht an zwei Orten gleichzeitig Aufsicht führen).
/// </summary>
public class SupervisionDuty
{
public Guid Id { get; set; } = Guid.NewGuid();
public DayOfWeek Weekday { get; set; }
public int AfterPeriod { get; set; }
public string Location { get; set; } = "";
}
public enum SubstitutionKind { Supervision, Lesson, SpecialAssignment, Cancelled }
/// <summary>
/// Einmalige Ausnahme vom regulären Plan an einem konkreten Datum: eine Vertretungsaufsicht
/// (zusätzlich zur oder anstelle einer regulären <see cref="SupervisionDuty"/>), eine
/// Vertretungsstunde in einer eigenen oder fremden Lerngruppe, ein Sondereinsatz (Ausflug,
/// Berufsmesse, Exkursion, ...), der einen Teil des Tages oder den ganzen Tag blockiert, oder ein
/// schlichter Stundenausfall ohne Ersatz (z.B. weil die betroffene Gruppe selbst auf Klassenfahrt
/// ist). Bewusst getrennt von <see cref="Lesson"/>: die meisten dieser Einträge sind nicht Teil der
/// durchgeplanten Einheiten-Reihenfolge (siehe TODO.md, Nachtrag zu 4.3) — nur bei
/// <see cref="SubstitutionKind.Lesson"/> kann beim Anlegen ausdrücklich "als Stunde in der Einheit
/// übernehmen" gewählt werden, was zusätzlich eine echte <see cref="Lesson"/> erzeugt; dieser
/// Eintrag hier bleibt trotzdem bestehen, da er (unabhängig von der Einheiten-Fortschrittsanzeige)
/// das, was tatsächlich im Plan an diesem Tag stattfand, festhält.
/// </summary>
public class SubstitutionEntry
{
public Guid Id { get; set; } = Guid.NewGuid();
public DateOnly Date { get; set; }
public SubstitutionKind Kind { get; set; }
/// Bei <see cref="SubstitutionKind.Lesson"/> und <see cref="SubstitutionKind.Cancelled"/>
/// gesetzt — bei Cancelled wird Gruppe/Fach zur Anzeige aus dem an dieser Stelle regulär
/// eingetragenen <see cref="TimetableSlot"/> abgeleitet, nicht hier gespeichert.
public int? PeriodNumber { get; set; }
/// Nur bei <see cref="SubstitutionKind.Supervision"/> gesetzt — wie bei
/// <see cref="SupervisionDuty.AfterPeriod"/>, 0 = vor der 1. Stunde.
public int? AfterPeriod { get; set; }
/// Nur bei <see cref="SubstitutionKind.SpecialAssignment"/> und nicht <see cref="IsAllDay"/>:
/// der belegte Stundenbereich (inklusive).
public int? FromPeriod { get; set; }
public int? ToPeriod { get; set; }
/// Nur bei <see cref="SubstitutionKind.SpecialAssignment"/>: blockiert den ganzen Tag statt
/// nur <see cref="FromPeriod"/><see cref="ToPeriod"/>.
public bool IsAllDay { get; set; }
/// Gesetzt, wenn es sich um eine eigene Lerngruppe handelt — bei fremden/unbekannten Gruppen
/// oder Sondereinsätzen ohne Gruppenbezug (z.B. Berufsmesse) bleibt es null und nur
/// <see cref="GroupLabel"/> beschreibt ggf., um welche Gruppe es ging.
public Guid? GroupId { get; set; }
public string GroupLabel { get; set; } = "";
/// Thema (bei Lesson), Grund/Ort (bei Supervision, z.B. "Vertretung für Hr. Müller") bzw.
/// Bezeichnung (bei SpecialAssignment, z.B. "Ausflug ins Museum", "Berufsmesse").
public string Description { get; set; } = "";
public string? Notes { get; set; }
}
/// <summary>
/// Zeugnisnote eines Schülers in einer Lerngruppe für einen Zeitraum (Halbjahr/Gesamtjahr).
/// <see cref="CalculatedValue"/> ist das zuletzt berechnete Ergebnis; <see cref="OverrideValue"/>
/// überschreibt es bei pädagogischem Ermessen (erfordert <see cref="OverrideReason"/>).
/// Nach dem Festschreiben (<see cref="IsLocked"/>) wird der Datensatz nicht mehr neu berechnet.
/// </summary>
public class ReportGrade
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid StudentId { get; set; }
public Guid GroupId { get; set; }
public string Period { get; set; } = "";
public string CalculatedValue { get; set; } = "";
public string? OverrideValue { get; set; }
public string? OverrideReason { get; set; }
public bool IsLocked { get; set; }
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}