feat(entries+time-scheduling): add support for automatic breaks and inspection type configurations
- **Domain Enhancements:** - Introduced `PausenKonfiguration` and `BesichtigungsBlock` entities to handle automatic breaks and inspection scheduling. - Added `BesichtigungsTypE` enum for inspection types (`ZU_FUSS`, `ZU_PFERD`). - Updated `Bewerb` and `Abteilung` models to include pause and inspection type fields. - **Service Updates:** - Enhanced `StartlistenService` to calculate start times, accounting for breaks and inspection buffers. - Extended `BewerbService` to support patchable time scheduling via new `updateZeitplan` API. - **Persistence Changes:** - Updated tables (`BewerbTable`, `AbteilungTable`) to persist break configurations and inspection types. - Implemented repository mappings to include these new fields. - **Testing:** - Introduced `BewerbeZeitplanIntegrationTest` to validate new scheduling behaviors, including automatic pauses and inspection handling. - **Documentation:** - Added rulebook and conceptual documents for inspection and scheduling logic in `docs/01_Architecture/`.
This commit is contained in:
+4
@@ -3,6 +3,7 @@
|
||||
package at.mocode.entries.domain.model
|
||||
|
||||
import at.mocode.core.domain.model.AbteilungsTeilungsTypE
|
||||
import at.mocode.core.domain.model.BesichtigungsTypE
|
||||
import at.mocode.core.domain.serialization.InstantSerializer
|
||||
import at.mocode.core.domain.serialization.UuidSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
@@ -55,6 +56,9 @@ data class Abteilung(
|
||||
// Zeitplanung
|
||||
var startzeit: String? = null,
|
||||
|
||||
/** Besichtigungstyp für diese Abteilung (optional, wenn abweichend von Standard). */
|
||||
var besichtigungsTyp: BesichtigungsTypE? = null,
|
||||
|
||||
// Verwaltung
|
||||
var bemerkungen: String? = null,
|
||||
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.entries.domain.model
|
||||
|
||||
import at.mocode.core.domain.model.BesichtigungsTypE
|
||||
import at.mocode.core.domain.serialization.UuidSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Repräsentiert einen Zeitblock für die Parcoursbesichtigung.
|
||||
* Kann mit mehreren Abteilungen oder Bewerben verknüpft sein.
|
||||
*/
|
||||
@Serializable
|
||||
data class BesichtigungsBlock(
|
||||
@Serializable(with = UuidSerializer::class)
|
||||
val besichtigungsBlockId: Uuid = Uuid.random(),
|
||||
|
||||
/** Typ der Besichtigung (zu Fuß / zu Pferd). */
|
||||
val typ: BesichtigungsTypE = BesichtigungsTypE.ZU_FUSS,
|
||||
|
||||
/** Geplante Dauer in Minuten. */
|
||||
val dauerMinuten: Int = 15,
|
||||
|
||||
/**
|
||||
* Liste der verknüpften Abteilungs-IDs.
|
||||
* Eine Besichtigung kann für mehrere Abteilungen gleichzeitig stattfinden.
|
||||
*/
|
||||
val abteilungIds: List<@Serializable(with = UuidSerializer::class) Uuid> = emptyList(),
|
||||
|
||||
/** Optionaler Puffer nach der Besichtigung bis zum ersten Start (Standard: 5 Min gemäß ÖTO). */
|
||||
val pufferMinuten: Int = 5
|
||||
)
|
||||
+19
@@ -97,6 +97,10 @@ data class Bewerb(
|
||||
var reitdauerMinuten: Int? = null,
|
||||
var umbauMinuten: Int? = null,
|
||||
var besichtigungMinuten: Int? = null,
|
||||
|
||||
/** Konfiguration für Pausen während der Prüfung. */
|
||||
var pausenKonfiguration: PausenKonfiguration? = null,
|
||||
|
||||
var stechenGeplant: Boolean = false,
|
||||
|
||||
// Finanzen
|
||||
@@ -297,3 +301,18 @@ data class Bewerb(
|
||||
*/
|
||||
fun withUpdatedTimestamp(): Bewerb = this.copy(updatedAt = Clock.System.now())
|
||||
}
|
||||
|
||||
/**
|
||||
* Konfiguration für automatische Pausen nach einer bestimmten Anzahl von Startern.
|
||||
*/
|
||||
@Serializable
|
||||
data class PausenKonfiguration(
|
||||
/** Pause alle X Starter (0 = keine automatischen Pausen). */
|
||||
val starterIntervall: Int = 0,
|
||||
|
||||
/** Dauer der Pause in Minuten. */
|
||||
val dauerMinuten: Int = 10,
|
||||
|
||||
/** Optionale Bezeichnung (z.B. "Platzpflege"). */
|
||||
val bezeichnung: String? = null
|
||||
)
|
||||
|
||||
+12
-4
@@ -98,16 +98,24 @@ class StartlistenService {
|
||||
// Besichtigung vor dem ersten Starter
|
||||
aktuelleZeitInMinuten += besichtigung
|
||||
|
||||
startliste.eintraege.forEach { eintrag ->
|
||||
// Puffer nach Besichtigung (ÖTO)
|
||||
if (besichtigung > 0) {
|
||||
aktuelleZeitInMinuten += 5
|
||||
}
|
||||
|
||||
startliste.eintraege.forEachIndexed { index, eintrag ->
|
||||
// Pause nach Intervall berücksichtigen
|
||||
val pausenKonf = bewerb.pausenKonfiguration
|
||||
if (pausenKonf != null && pausenKonf.starterIntervall > 0 && index > 0 && index % pausenKonf.starterIntervall == 0) {
|
||||
aktuelleZeitInMinuten += pausenKonf.dauerMinuten
|
||||
}
|
||||
|
||||
val stunden = aktuelleZeitInMinuten / 60
|
||||
val minuten = aktuelleZeitInMinuten % 60
|
||||
zeiten[eintrag.startnummer] = LocalTime(stunden % 24, minuten)
|
||||
|
||||
// Zeit für den nächsten Starter berechnen
|
||||
aktuelleZeitInMinuten += reitdauer
|
||||
|
||||
// TODO: Umbauzeiten nach bestimmten Intervallen (z.B. alle 10 Starter)
|
||||
// oder bei Abteilungswechsel berücksichtigen.
|
||||
}
|
||||
|
||||
return zeiten
|
||||
|
||||
Reference in New Issue
Block a user