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:
2026-04-11 12:21:37 +02:00
parent 97ed8ad20a
commit 0aa1a1b9b7
19 changed files with 423 additions and 20 deletions
@@ -0,0 +1,112 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.entries.service.bewerbe
import at.mocode.entries.service.persistence.*
import at.mocode.entries.service.tenant.Tenant
import at.mocode.entries.service.tenant.TenantContextHolder
import at.mocode.entries.service.tenant.tenantTransaction
import kotlin.time.Clock
import kotlinx.datetime.LocalTime
import org.jetbrains.exposed.v1.jdbc.SchemaUtils
import org.jetbrains.exposed.v1.jdbc.deleteAll
import org.jetbrains.exposed.v1.jdbc.insert
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
import kotlin.uuid.Uuid
import kotlin.uuid.toJavaUuid
@SpringBootTest
@ActiveProfiles("test")
class BewerbeZeitplanIntegrationTest {
@Autowired
private lateinit var bewerbService: BewerbService
private val turnierId = Uuid.random()
@BeforeEach
fun setup() {
TenantContextHolder.set(Tenant(turnierId.toString(), "PUBLIC", "jdbc:h2:mem:entries-test"))
kotlinx.coroutines.runBlocking {
tenantTransaction {
SchemaUtils.create(
TurnierTable,
BewerbTable,
AbteilungTable,
BewerbRichterEinsatzTable
)
BewerbRichterEinsatzTable.deleteAll()
BewerbTable.deleteAll()
AbteilungTable.deleteAll()
TurnierTable.deleteAll()
TurnierTable.insert {
it[id] = turnierId.toJavaUuid()
it[veranstaltungId] = Uuid.random().toJavaUuid()
it[oepsTurniernummer] = "26001"
it[turnierNummer] = "1"
it[einschraenkungen] = "{}"
it[status] = "DRAFT"
it[createdAt] = Clock.System.now()
it[updatedAt] = Clock.System.now()
}
}
}
}
@AfterEach
fun teardown() {
TenantContextHolder.clear()
}
@Test
fun `bewerb mit pausen erstellen und abrufen`() = kotlinx.coroutines.runBlocking {
// GIVEN
val request = CreateBewerbRequest(
klasse = "A",
bezeichnung = "Springpferdeprüfung",
pausenStarterIntervall = 20,
pausenDauerMinuten = 15,
pausenBezeichnung = "Platzpflege",
besichtigungMinuten = 20
)
// WHEN
val created = bewerbService.create(turnierId, request)
// THEN
val fetched = bewerbService.get(created.id)
assertEquals(20, fetched.pausenStarterIntervall)
assertEquals(15, fetched.pausenDauerMinuten)
assertEquals("Platzpflege", fetched.pausenBezeichnung)
assertEquals(20, fetched.besichtigungMinuten)
}
@Test
fun `zeitplan update via patch`() = kotlinx.coroutines.runBlocking {
// GIVEN
val bewerb = bewerbService.create(turnierId, CreateBewerbRequest(
klasse = "L",
bezeichnung = "Standardspringprüfung"
))
val patchRequest = UpdateZeitplanRequest(
geplantesDatum = null,
beginnZeit = LocalTime(14, 30),
austragungsplatzId = null
)
// WHEN
val updated = bewerbService.updateZeitplan(bewerb.id, patchRequest)
// THEN
assertEquals(LocalTime(14, 30), updated.beginnZeit)
val fetched = bewerbService.get(bewerb.id)
assertEquals(LocalTime(14, 30), fetched.beginnZeit)
}
}