Add audit logging for Zeitplan updates, implement conflict validation for overlapping schedules and judge assignments, and enhance frontend with detailed warning visualizations in Zeitplan tab.
This commit is contained in:
+5
-1
@@ -44,7 +44,11 @@ enum class AbteilungsWarnungCodeE {
|
||||
/** Vorgeschriebene Abteilungs-Struktur nicht vorhanden */
|
||||
WARN_STRUKTURELLE_TEILUNG_FEHLT,
|
||||
/** Abteilungs-Struktur vorhanden, aber Teilnehmerkreis falsch/unvollständig */
|
||||
WARN_STRUKTURELLE_TEILUNG_UNVOLLSTAENDIG
|
||||
WARN_STRUKTURELLE_TEILUNG_UNVOLLSTAENDIG,
|
||||
/** Mehrere Bewerbe zur gleichen Zeit am gleichen Platz */
|
||||
WARN_ZEITPLAN_PLATZ_KONFLIKT,
|
||||
/** Richter hat zeitgleiche Einsätze in verschiedenen Bewerben */
|
||||
WARN_ZEITPLAN_RICHTER_KONFLIKT
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+75
@@ -3,7 +3,11 @@
|
||||
package at.mocode.entries.domain.service
|
||||
|
||||
import at.mocode.entries.domain.model.AbteilungsWarnung
|
||||
import at.mocode.entries.domain.model.AbteilungsWarnungCodeE
|
||||
import at.mocode.entries.domain.model.Bewerb
|
||||
import at.mocode.entries.domain.repository.CompetitionRepository
|
||||
import kotlinx.datetime.toJavaLocalTime
|
||||
import java.time.LocalTime
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
@@ -46,9 +50,80 @@ class CompetitionWarningService(
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Zeitplan-Konflikte (Turnier-weit)
|
||||
result.putAll(validateZeitplanKonflikte(bewerbe))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun validateZeitplanKonflikte(bewerbe: List<Bewerb>): Map<Uuid, List<AbteilungsWarnung>> {
|
||||
val conflicts = mutableMapOf<Uuid, List<AbteilungsWarnung>>()
|
||||
|
||||
// Nur Bewerbe mit Zeitangabe prüfen
|
||||
val zeitplanBewerbe = bewerbe.filter { it.geplantesDatum != null && it.beginnZeit != null }
|
||||
|
||||
for (b1 in zeitplanBewerbe) {
|
||||
val warnings = mutableListOf<AbteilungsWarnung>()
|
||||
val start1 = b1.beginnZeit!!
|
||||
val ende1 = berechneEnde(b1)
|
||||
|
||||
for (b2 in zeitplanBewerbe) {
|
||||
if (b1.bewerbId == b2.bewerbId) continue
|
||||
if (b1.geplantesDatum != b2.geplantesDatum) continue
|
||||
|
||||
val start2 = b2.beginnZeit!!
|
||||
val ende2 = berechneEnde(b2)
|
||||
|
||||
// Überlappungs-Check
|
||||
if (isOverlapping(start1, ende1, start2, ende2)) {
|
||||
// Platz-Konflikt
|
||||
if (b1.austragungsplatzId != null && b1.austragungsplatzId == b2.austragungsplatzId) {
|
||||
warnings.add(AbteilungsWarnung(
|
||||
code = AbteilungsWarnungCodeE.WARN_ZEITPLAN_PLATZ_KONFLIKT,
|
||||
bewerbId = b1.bewerbId,
|
||||
nachricht = "Zeitliche Überschneidung auf dem gleichen Platz mit Bewerb ${b2.bewerbNummer}",
|
||||
oetoParagraph = "Allgemeine Zeitplanung"
|
||||
))
|
||||
}
|
||||
|
||||
// Richter-Konflikt
|
||||
val gemeinsameRichter = b1.richterEinsaetze.map { it.funktionaerId }
|
||||
.intersect(b2.richterEinsaetze.map { it.funktionaerId }.toSet())
|
||||
|
||||
if (gemeinsameRichter.isNotEmpty()) {
|
||||
warnings.add(AbteilungsWarnung(
|
||||
code = AbteilungsWarnungCodeE.WARN_ZEITPLAN_RICHTER_KONFLIKT,
|
||||
bewerbId = b1.bewerbId,
|
||||
nachricht = "Richter-Doppelbelegung mit Bewerb ${b2.bewerbNummer}",
|
||||
oetoParagraph = "Richter-Einteilung"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (warnings.isNotEmpty()) {
|
||||
conflicts[b1.bewerbId] = (conflicts[b1.bewerbId] ?: emptyList()) + warnings
|
||||
}
|
||||
}
|
||||
return conflicts
|
||||
}
|
||||
|
||||
private fun berechneEnde(b: Bewerb): kotlinx.datetime.LocalTime {
|
||||
val start = b.beginnZeit!!
|
||||
val dauer = b.reitdauerMinuten ?: 0
|
||||
val umbau = b.umbauMinuten ?: 0
|
||||
val besichtigung = b.besichtigungMinuten ?: 0
|
||||
val gesamtMinuten = start.hour * 60 + start.minute + dauer + umbau + besichtigung
|
||||
|
||||
val endHour = (gesamtMinuten / 60) % 24
|
||||
val endMin = gesamtMinuten % 60
|
||||
return kotlinx.datetime.LocalTime(endHour, endMin)
|
||||
}
|
||||
|
||||
private fun isOverlapping(s1: kotlinx.datetime.LocalTime, e1: kotlinx.datetime.LocalTime,
|
||||
s2: kotlinx.datetime.LocalTime, e2: kotlinx.datetime.LocalTime): Boolean {
|
||||
return s1 < e2 && s2 < e1
|
||||
}
|
||||
|
||||
/**
|
||||
* Validiert einen einzelnen Bewerb und gibt Warnungen zurück.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user