Sitzungen (3.3): aus Stunde erzeugen, löschen, Kalenderüberblick; Doppelstunden-Bugfix Serienerzeugung
Kapitel 3.3: neuer Button erzeugt eine Mitarbeitssitzung aus einer geplanten Stunde (Datum/Thema, dupl.-sicher über Lesson.LessonId), Sitzungen lassen sich jetzt mit Rückfrage bei vorhandenen Bewertungen löschen, und der Dashboard-Kalender zeigt Sitzungen als dritten Termintyp neben Stunden/ Klausuren. Das Bearbeiten von Sitzungen war bereits vorhanden (undokumentiert aus früherer Ad-hoc-Arbeit) und wird hier nur nachgezogen. Bugfix: "Serie erzeugen" legte für Doppelstunden zwei Lessons mit gleichem Datum an statt einer, da jede Stundenplan-Periode einzeln behandelt wurde. Folgeperioden werden jetzt der Lesson der ersten Periode zugerechnet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,7 +40,8 @@ public sealed class DashboardViewModelTests
|
||||
FakeReportGrades? reportGrades = null, FakeMemberships? memberships = null,
|
||||
FakeWorkTasks? tasks = null, FakeStudents? students = null, FakeDocumentation? documentation = null,
|
||||
DashboardSettingsService? dashboardSettings = null, FakeSchoolHolidays? schoolHolidays = null,
|
||||
FakeLessons? lessons = null, FakeSubstitutionEntries? substitutions = null)
|
||||
FakeLessons? lessons = null, FakeSubstitutionEntries? substitutions = null,
|
||||
FakeSessions? sessions = null)
|
||||
{
|
||||
lessons ??= new FakeLessons();
|
||||
lessons.Add(lesson);
|
||||
@@ -48,7 +49,7 @@ public sealed class DashboardViewModelTests
|
||||
new FakeGroups([group]), new FakeSubjects([]), lessons,
|
||||
exams ?? new FakeExams([]), results ?? new FakeResults(), grades ?? new FakeGrades(),
|
||||
reportGrades ?? new FakeReportGrades(), memberships ?? new FakeMemberships([]),
|
||||
tasks ?? new FakeWorkTasks(), new FakeSessions([]), new FakeEntries(),
|
||||
tasks ?? new FakeWorkTasks(), sessions ?? new FakeSessions([]), new FakeEntries(),
|
||||
students ?? new FakeStudents([]), documentation ?? new FakeDocumentation(),
|
||||
slots ?? new FakeTimetableSlots(), periodSchedule ?? NewPeriodSchedule(),
|
||||
new AttendanceBalanceService(), new SchoolYearService(), dashboardSettings ?? NewDashboardSettings(),
|
||||
@@ -223,6 +224,25 @@ public sealed class DashboardViewModelTests
|
||||
Assert.Contains(vm.SelectedDayEvents, e => e.Kind == CalendarEventKind.Exam && e.Title == "Test");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Kalender_ZeigtMitarbeitssitzungenAlsEigenenTermintyp()
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var group = new LearningGroup { Name = "9c" };
|
||||
var sessionDate = today.AddDays(3);
|
||||
var session = new ParticipationSession { GroupId = group.Id, Date = sessionDate, Comment = "Aufsatz" };
|
||||
var vm = BuildVm(group, new Lesson { GroupId = group.Id, Date = today },
|
||||
sessions: new FakeSessions([session]));
|
||||
|
||||
var day = vm.CalendarDays.Single(d => d.Date == sessionDate);
|
||||
Assert.True(day.HasSession);
|
||||
|
||||
vm.SelectCalendarDayCommand.Execute(day);
|
||||
|
||||
Assert.Contains(vm.SelectedDayEvents,
|
||||
e => e.Kind == CalendarEventKind.ParticipationSession && e.Subtitle == "Aufsatz");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DashboardKacheln_SichtbarkeitUndReihenfolgeWerdenGespeichert()
|
||||
{
|
||||
|
||||
@@ -85,7 +85,7 @@ public sealed class GenerateLessonSeriesDialogViewModelTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_Doppelstunde_ErzeugtZweiStundenAmSelbenTagMitUnterschiedlicherStundennummer()
|
||||
public void Save_Doppelstunde_ErzeugtNurEineStundeVerankertAnDerErstenPeriode()
|
||||
{
|
||||
var groupId = Guid.NewGuid();
|
||||
var unitId = Guid.NewGuid();
|
||||
@@ -98,9 +98,50 @@ public sealed class GenerateLessonSeriesDialogViewModelTests
|
||||
|
||||
vm.SaveCommand.Execute(null);
|
||||
|
||||
Assert.Equal(1, vm.Result!.Created);
|
||||
var created = lessons.GetByGroupAndRange(groupId, from, from).Select(l => l.LessonNumber).ToList();
|
||||
Assert.Equal([3], created);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_Dreifachstunde_ErzeugtNurEineStundeVerankertAnDerErstenPeriode()
|
||||
{
|
||||
var groupId = Guid.NewGuid();
|
||||
var unitId = Guid.NewGuid();
|
||||
var from = new DateOnly(2025, 9, 1);
|
||||
var slots = new FakeTimetableSlots();
|
||||
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 3 });
|
||||
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 4 });
|
||||
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 5 });
|
||||
var lessons = new FakeLessons();
|
||||
var vm = BuildVm(slots, lessons, new FakeSchoolHolidays(), unitId, groupId, from, from);
|
||||
|
||||
vm.SaveCommand.Execute(null);
|
||||
|
||||
Assert.Equal(1, vm.Result!.Created);
|
||||
var created = lessons.GetByGroupAndRange(groupId, from, from).Select(l => l.LessonNumber).ToList();
|
||||
Assert.Equal([3], created);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_ZweiGetrennteEinzelstundenAmSelbenTagBleibenGetrennt()
|
||||
{
|
||||
// Perioden 1 und 3 sind NICHT aufeinanderfolgend (Periode 2 fehlt) — keine Doppelstunde,
|
||||
// beide bekommen eine eigene Lesson.
|
||||
var groupId = Guid.NewGuid();
|
||||
var unitId = Guid.NewGuid();
|
||||
var from = new DateOnly(2025, 9, 1);
|
||||
var slots = new FakeTimetableSlots();
|
||||
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 1 });
|
||||
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 3 });
|
||||
var lessons = new FakeLessons();
|
||||
var vm = BuildVm(slots, lessons, new FakeSchoolHolidays(), unitId, groupId, from, from);
|
||||
|
||||
vm.SaveCommand.Execute(null);
|
||||
|
||||
Assert.Equal(2, vm.Result!.Created);
|
||||
var created = lessons.GetByGroupAndRange(groupId, from, from).Select(l => l.LessonNumber).OrderBy(n => n).ToList();
|
||||
Assert.Equal([3, 4], created);
|
||||
Assert.Equal([1, 3], created);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -22,7 +22,7 @@ public sealed class GroupDetailViewModelTests
|
||||
students, memberships, groups, new FakeCompetencyDomains()),
|
||||
new GradeOverviewTabViewModel(grades, exams, new FakeResults(), students, memberships, new GradingService()),
|
||||
new PlanningTabViewModel(new FakeUnits(), new FakeLessons(), groups, subjects,
|
||||
new FakeCompetencyDomains(), TestSupport.BuildAiSettingsService()),
|
||||
new FakeCompetencyDomains(), TestSupport.BuildAiSettingsService(), new FakeSessions([])),
|
||||
new CompetencyOverviewTabViewModel(new FakeUnits(), exams, new FakeResults(),
|
||||
new FakeCompetencyDomains(), students, new CompetencyAnalysisService()),
|
||||
new SeatingPlanTabViewModel(new FakeSeatingPlans(), students, memberships,
|
||||
|
||||
@@ -59,4 +59,49 @@ public sealed class ParticipationSessionEditingTests
|
||||
Assert.Equal("Nachbesprechung Elektrizität", sessions.GetById(session.Id)?.Comment);
|
||||
Assert.Contains("Nachbesprechung Elektrizität", vm.SelectedSessionDisplay);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoeschenBefehl_FragtBestaetigungAbUndEntferntSessionMitsamtBewertungen()
|
||||
{
|
||||
var group = new LearningGroup { Name = "8a", SchoolYear = "2026/27" };
|
||||
var session = new ParticipationSession { GroupId = group.Id, Date = new DateOnly(2026, 8, 19) };
|
||||
var sessions = new FakeSessions([session]);
|
||||
var entries = new FakeEntries();
|
||||
entries.Add(new ParticipationEntry { SessionId = session.Id, StudentId = Guid.NewGuid() });
|
||||
var vm = new ParticipationTabViewModel(
|
||||
sessions, entries, new FakeAspects(), new FakeStudents([]),
|
||||
new FakeMemberships([]), new FakeGroups([group]), new FakeCompetencyDomains());
|
||||
vm.Initialize(group.Id, group.SchoolYear);
|
||||
vm.SelectedSession = vm.Sessions.Single(s => s.Id == session.Id);
|
||||
|
||||
int? passedEntryCount = null;
|
||||
vm.OnConfirmDeleteSession = (_, count) =>
|
||||
{
|
||||
passedEntryCount = count;
|
||||
return Task.FromResult(true);
|
||||
};
|
||||
|
||||
await vm.DeleteSessionCommand.ExecuteAsync(null);
|
||||
|
||||
Assert.Equal(1, passedEntryCount);
|
||||
Assert.Null(sessions.GetById(session.Id));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoeschenBefehl_BrichtBeiAbgelehnterBestaetigungAb()
|
||||
{
|
||||
var group = new LearningGroup { Name = "8a", SchoolYear = "2026/27" };
|
||||
var session = new ParticipationSession { GroupId = group.Id, Date = new DateOnly(2026, 8, 19) };
|
||||
var sessions = new FakeSessions([session]);
|
||||
var vm = new ParticipationTabViewModel(
|
||||
sessions, new FakeEntries(), new FakeAspects(), new FakeStudents([]),
|
||||
new FakeMemberships([]), new FakeGroups([group]), new FakeCompetencyDomains());
|
||||
vm.Initialize(group.Id, group.SchoolYear);
|
||||
vm.SelectedSession = vm.Sessions.Single(s => s.Id == session.Id);
|
||||
vm.OnConfirmDeleteSession = (_, _) => Task.FromResult(false);
|
||||
|
||||
await vm.DeleteSessionCommand.ExecuteAsync(null);
|
||||
|
||||
Assert.NotNull(sessions.GetById(session.Id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class PlanningTabViewModelTests
|
||||
var lessons = new FakeLessons();
|
||||
|
||||
var vm = new PlanningTabViewModel(units, lessons, groups, subjects, competencyDomains,
|
||||
TestSupport.BuildAiSettingsService());
|
||||
TestSupport.BuildAiSettingsService(), new FakeSessions([]));
|
||||
vm.Initialize(groupId);
|
||||
|
||||
return (vm, units, lessons, groupId);
|
||||
@@ -227,4 +227,71 @@ public class PlanningTabViewModelTests
|
||||
|
||||
Assert.Equal(["L->AB01", "Plenum"], vm.KnownShorthands);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateParticipationSession_LegtSitzungMitDatumUndThemaDerStundeAn()
|
||||
{
|
||||
var groupId = Guid.NewGuid();
|
||||
var group = new LearningGroup { Id = groupId, Name = "Testgruppe" };
|
||||
var groups = new FakeGroups([group]);
|
||||
var units = new FakeUnits();
|
||||
var lessons = new FakeLessons();
|
||||
var sessions = new FakeSessions([]);
|
||||
var vm = new PlanningTabViewModel(units, lessons, groups, new FakeSubjects([]),
|
||||
new FakeCompetencyDomains(), TestSupport.BuildAiSettingsService(), sessions);
|
||||
vm.Initialize(groupId);
|
||||
|
||||
var unit = new Unit { GroupId = groupId, Title = "Optik" };
|
||||
units.Add(unit);
|
||||
var lesson = new Lesson
|
||||
{
|
||||
UnitId = unit.Id, GroupId = groupId, Date = new DateOnly(2025, 9, 1), Topic = "Brechung",
|
||||
};
|
||||
lessons.Add(lesson);
|
||||
vm.RefreshPlanning(unit.Id, lesson.Id);
|
||||
vm.SelectedLesson = vm.Lessons.Single(l => l.Id == lesson.Id);
|
||||
|
||||
string? notified = null;
|
||||
vm.OnNotify = m => notified = m;
|
||||
|
||||
vm.CreateParticipationSessionCommand.Execute(null);
|
||||
|
||||
var created = Assert.Single(sessions.GetByGroup(groupId));
|
||||
Assert.Equal(lesson.Id, created.LessonId);
|
||||
Assert.Equal(lesson.Date, created.Date);
|
||||
Assert.Equal("Brechung", created.Comment);
|
||||
Assert.Equal("Sitzung aus der Stunde erstellt.", notified);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateParticipationSession_ZweiterAufrufLegtKeineDoppelteSitzungAn()
|
||||
{
|
||||
var groupId = Guid.NewGuid();
|
||||
var group = new LearningGroup { Id = groupId, Name = "Testgruppe" };
|
||||
var groups = new FakeGroups([group]);
|
||||
var units = new FakeUnits();
|
||||
var lessons = new FakeLessons();
|
||||
var sessions = new FakeSessions([]);
|
||||
var vm = new PlanningTabViewModel(units, lessons, groups, new FakeSubjects([]),
|
||||
new FakeCompetencyDomains(), TestSupport.BuildAiSettingsService(), sessions);
|
||||
vm.Initialize(groupId);
|
||||
|
||||
var unit = new Unit { GroupId = groupId, Title = "Optik" };
|
||||
units.Add(unit);
|
||||
var lesson = new Lesson
|
||||
{
|
||||
UnitId = unit.Id, GroupId = groupId, Date = new DateOnly(2025, 9, 1), Topic = "Brechung",
|
||||
};
|
||||
lessons.Add(lesson);
|
||||
vm.RefreshPlanning(unit.Id, lesson.Id);
|
||||
vm.SelectedLesson = vm.Lessons.Single(l => l.Id == lesson.Id);
|
||||
|
||||
vm.CreateParticipationSessionCommand.Execute(null);
|
||||
string? notified = null;
|
||||
vm.OnNotify = m => notified = m;
|
||||
vm.CreateParticipationSessionCommand.Execute(null);
|
||||
|
||||
Assert.Single(sessions.GetByGroup(groupId));
|
||||
Assert.Equal("Für diese Stunde existiert bereits eine Sitzung.", notified);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user