Remove Dom prefix from domain models: delete DomVeranstaltung, rename models like DomNennung to Nennung, update references in repositories, services, and tests for consistency.

This commit is contained in:
2026-04-08 22:59:12 +02:00
parent 085656a85b
commit 2d42578378
13 changed files with 71 additions and 218 deletions
@@ -13,7 +13,7 @@ import kotlin.uuid.Uuid
/** /**
* Domain-Modell für eine Abteilung im registration-context. * Domain-Modell für eine Abteilung im registration-context.
* *
* Eine Abteilung ist die kleinste startbare Einheit innerhalb eines [DomBewerb]s. * Eine Abteilung ist die kleinste startbare Einheit innerhalb eines [Bewerb]s.
* Ein Bewerb kann in mehrere Abteilungen aufgeteilt sein (z.B. Abt. 1: ohne Lizenz, * Ein Bewerb kann in mehrere Abteilungen aufgeteilt sein (z.B. Abt. 1: ohne Lizenz,
* Abt. 2: mit Lizenz R1). Die Aufteilung erfolgt gemäß ÖTO § 39 und den * Abt. 2: mit Lizenz R1). Die Aufteilung erfolgt gemäß ÖTO § 39 und den
* spartenspezifischen Bestimmungen. * spartenspezifischen Bestimmungen.
@@ -32,7 +32,7 @@ import kotlin.uuid.Uuid
* @property updatedAt Letzter Änderungszeitpunkt. * @property updatedAt Letzter Änderungszeitpunkt.
*/ */
@Serializable @Serializable
data class DomAbteilung( data class Abteilung(
@Serializable(with = UuidSerializer::class) @Serializable(with = UuidSerializer::class)
val abteilungId: Uuid = Uuid.random(), val abteilungId: Uuid = Uuid.random(),
@@ -106,5 +106,5 @@ data class DomAbteilung(
/** /**
* Erstellt eine Kopie mit aktualisiertem Zeitstempel. * Erstellt eine Kopie mit aktualisiertem Zeitstempel.
*/ */
fun withUpdatedTimestamp(): DomAbteilung = this.copy(updatedAt = Clock.System.now()) fun withUpdatedTimestamp(): Abteilung = this.copy(updatedAt = Clock.System.now())
} }
@@ -13,7 +13,7 @@ import kotlin.uuid.Uuid
/** /**
* Domain-Modell für eine Startliste im registration-context. * Domain-Modell für eine Startliste im registration-context.
* *
* Eine Startliste gehört zu einer [DomAbteilung] und enthält die geordnete Liste * Eine Startliste gehört zu einer [Abteilung] und enthält die geordnete Liste
* der Starter (Nennungen) mit ihren Startnummern. Sie durchläuft einen definierten * der Starter (Nennungen) mit ihren Startnummern. Sie durchläuft einen definierten
* Workflow: NICHT_ERSTELLT → ENTWURF → VEROEFFENTLICHT → GESPERRT → ARCHIVIERT. * Workflow: NICHT_ERSTELLT → ENTWURF → VEROEFFENTLICHT → GESPERRT → ARCHIVIERT.
* *
@@ -128,7 +128,7 @@ data class DomStartliste(
/** /**
* Ein einzelner Eintrag in einer Startliste. * Ein einzelner Eintrag in einer Startliste.
* *
* Verbindet eine Startnummer mit einer Nennung ([DomNennung]). * Verbindet eine Startnummer mit einer Nennung ([Nennung]).
* *
* @property startnummer Die zugewiesene Startnummer (Kopfnummer gemäß Ubiquitous Language). * @property startnummer Die zugewiesene Startnummer (Kopfnummer gemäß Ubiquitous Language).
* @property nennungId Referenz auf die zugehörige Nennung (UUID). * @property nennungId Referenz auf die zugehörige Nennung (UUID).
@@ -40,7 +40,7 @@ import kotlin.uuid.Uuid
* @property updatedAt Timestamp when this entry was last updated. * @property updatedAt Timestamp when this entry was last updated.
*/ */
@Serializable @Serializable
data class DomNennung( data class Nennung(
@Serializable(with = UuidSerializer::class) @Serializable(with = UuidSerializer::class)
val nennungId: Uuid = Uuid.random(), val nennungId: Uuid = Uuid.random(),
@@ -95,5 +95,5 @@ data class DomNennung(
/** /**
* Creates a copy of this entry with an updated timestamp. * Creates a copy of this entry with an updated timestamp.
*/ */
fun withUpdatedTimestamp(): DomNennung = this.copy(updatedAt = Clock.System.now()) fun withUpdatedTimestamp(): Nennung = this.copy(updatedAt = Clock.System.now())
} }
@@ -40,7 +40,7 @@ import kotlin.uuid.Uuid
* @property createdAt Timestamp when this transfer was recorded. * @property createdAt Timestamp when this transfer was recorded.
*/ */
@Serializable @Serializable
data class DomNennungsTransfer( data class NennungsTransfer(
@Serializable(with = UuidSerializer::class) @Serializable(with = UuidSerializer::class)
val transferId: Uuid = Uuid.random(), val transferId: Uuid = Uuid.random(),
@@ -2,23 +2,23 @@
package at.mocode.entries.domain.repository package at.mocode.entries.domain.repository
import at.mocode.entries.domain.model.DomAbteilung import at.mocode.entries.domain.model.Abteilung
import at.mocode.entries.domain.model.DomBewerb import at.mocode.entries.domain.model.Bewerb
import kotlin.uuid.Uuid import kotlin.uuid.Uuid
/** /**
* Repository-Interface für DomBewerb und DomAbteilung Domain-Operationen. * Repository-Interface für Bewerb und Abteilung Domain-Operationen.
*/ */
interface CompetitionRepository { interface CompetitionRepository {
// Bewerbe // Bewerbe
suspend fun findBewerbById(id: Uuid): DomBewerb? suspend fun findBewerbById(id: Uuid): Bewerb?
suspend fun findBewerbeByTurnierId(turnierId: Uuid): List<DomBewerb> suspend fun findBewerbeByTurnierId(turnierId: Uuid): List<Bewerb>
suspend fun saveBewerb(bewerb: DomBewerb): DomBewerb suspend fun saveBewerb(bewerb: Bewerb): Bewerb
suspend fun deleteBewerb(id: Uuid): Boolean suspend fun deleteBewerb(id: Uuid): Boolean
// Abteilungen // Abteilungen
suspend fun findAbteilungById(id: Uuid): DomAbteilung? suspend fun findAbteilungById(id: Uuid): Abteilung?
suspend fun findAbteilungenByBewerbId(bewerbId: Uuid): List<DomAbteilung> suspend fun findAbteilungenByBewerbId(bewerbId: Uuid): List<Abteilung>
suspend fun saveAbteilung(abteilung: DomAbteilung): DomAbteilung suspend fun saveAbteilung(abteilung: Abteilung): Abteilung
suspend fun deleteAbteilung(id: Uuid): Boolean suspend fun deleteAbteilung(id: Uuid): Boolean
} }
@@ -3,11 +3,11 @@
package at.mocode.entries.domain.repository package at.mocode.entries.domain.repository
import at.mocode.core.domain.model.NennStatusE import at.mocode.core.domain.model.NennStatusE
import at.mocode.entries.domain.model.DomNennung import at.mocode.entries.domain.model.Nennung
import kotlin.uuid.Uuid import kotlin.uuid.Uuid
/** /**
* Repository-Interface für DomNennung (Nennung) Domain-Operationen. * Repository-Interface für Nennung (Nennung) Domain-Operationen.
* *
* Definiert den Vertrag für Datenzugriffs-Operationen ohne Abhängigkeit * Definiert den Vertrag für Datenzugriffs-Operationen ohne Abhängigkeit
* von konkreten Implementierungsdetails (Datenbank, etc.). * von konkreten Implementierungsdetails (Datenbank, etc.).
@@ -17,52 +17,52 @@ interface NennungRepository {
/** /**
* Sucht eine Nennung anhand ihrer eindeutigen ID. * Sucht eine Nennung anhand ihrer eindeutigen ID.
*/ */
suspend fun findById(id: Uuid): DomNennung? suspend fun findById(id: Uuid): Nennung?
/** /**
* Sucht alle Nennungen für einen bestimmten Bewerb. * Sucht alle Nennungen für einen bestimmten Bewerb.
*/ */
suspend fun findByBewerbId(bewerbId: Uuid): List<DomNennung> suspend fun findByBewerbId(bewerbId: Uuid): List<Nennung>
/** /**
* Sucht alle Nennungen für eine bestimmte Abteilung. * Sucht alle Nennungen für eine bestimmte Abteilung.
*/ */
suspend fun findByAbteilungId(abteilungId: Uuid): List<DomNennung> suspend fun findByAbteilungId(abteilungId: Uuid): List<Nennung>
/** /**
* Sucht alle Nennungen für ein bestimmtes Turnier. * Sucht alle Nennungen für ein bestimmtes Turnier.
*/ */
suspend fun findByTurnierId(turnierId: Uuid): List<DomNennung> suspend fun findByTurnierId(turnierId: Uuid): List<Nennung>
/** /**
* Sucht alle Nennungen eines bestimmten Reiters. * Sucht alle Nennungen eines bestimmten Reiters.
*/ */
suspend fun findByReiterId(reiterId: Uuid): List<DomNennung> suspend fun findByReiterId(reiterId: Uuid): List<Nennung>
/** /**
* Sucht alle Nennungen für ein bestimmtes Pferd. * Sucht alle Nennungen für ein bestimmtes Pferd.
*/ */
suspend fun findByPferdId(pferdId: Uuid): List<DomNennung> suspend fun findByPferdId(pferdId: Uuid): List<Nennung>
/** /**
* Sucht alle Nennungen eines Reiters für ein bestimmtes Turnier. * Sucht alle Nennungen eines Reiters für ein bestimmtes Turnier.
*/ */
suspend fun findByReiterIdAndTurnierId(reiterId: Uuid, turnierId: Uuid): List<DomNennung> suspend fun findByReiterIdAndTurnierId(reiterId: Uuid, turnierId: Uuid): List<Nennung>
/** /**
* Sucht alle Nennungen mit einem bestimmten Status. * Sucht alle Nennungen mit einem bestimmten Status.
*/ */
suspend fun findByStatus(status: NennStatusE): List<DomNennung> suspend fun findByStatus(status: NennStatusE): List<Nennung>
/** /**
* Sucht alle Nachnennungen für einen Bewerb. * Sucht alle Nachnennungen für einen Bewerb.
*/ */
suspend fun findNachnennungenByBewerbId(bewerbId: Uuid): List<DomNennung> suspend fun findNachnennungenByBewerbId(bewerbId: Uuid): List<Nennung>
/** /**
* Speichert eine Nennung (Insert oder Update). * Speichert eine Nennung (Insert oder Update).
*/ */
suspend fun save(nennung: DomNennung): DomNennung suspend fun save(nennung: Nennung): Nennung
/** /**
* Löscht eine Nennung anhand ihrer ID. * Löscht eine Nennung anhand ihrer ID.
@@ -2,14 +2,14 @@
package at.mocode.entries.domain.repository package at.mocode.entries.domain.repository
import at.mocode.entries.domain.model.DomNennungsTransfer import at.mocode.entries.domain.model.NennungsTransfer
import kotlin.uuid.Uuid import kotlin.uuid.Uuid
/** /**
* Repository-Interface für DomNennungsTransfer Domain-Operationen. * Repository-Interface für NennungsTransfer Domain-Operationen.
*/ */
interface NennungsTransferRepository { interface NennungsTransferRepository {
suspend fun findById(id: Uuid): DomNennungsTransfer? suspend fun findById(id: Uuid): NennungsTransfer?
suspend fun findByUrsprungsNennungId(nennungId: Uuid): List<DomNennungsTransfer> suspend fun findByUrsprungsNennungId(nennungId: Uuid): List<NennungsTransfer>
suspend fun save(transfer: DomNennungsTransfer): DomNennungsTransfer suspend fun save(transfer: NennungsTransfer): NennungsTransfer
} }
@@ -6,8 +6,8 @@ import at.mocode.core.domain.model.AbteilungsTeilungsTypE
import at.mocode.core.domain.model.ReiterLizenzKlasseE import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.domain.model.PruefungsTypE import at.mocode.core.domain.model.PruefungsTypE
import at.mocode.core.domain.model.SparteE import at.mocode.core.domain.model.SparteE
import at.mocode.entries.domain.model.DomAbteilung import at.mocode.entries.domain.model.Abteilung
import at.mocode.entries.domain.model.DomBewerb import at.mocode.entries.domain.model.Bewerb
import at.mocode.masterdata.domain.model.Reiter import at.mocode.masterdata.domain.model.Reiter
/** /**
@@ -32,13 +32,13 @@ class AbteilungsRegelService {
* @param bewerb Der betroffene Bewerb. * @param bewerb Der betroffene Bewerb.
* @param abteilungen Liste der verfügbaren Abteilungen des Bewerbs. * @param abteilungen Liste der verfügbaren Abteilungen des Bewerbs.
* @param reiter Der Reiter, der genannt werden soll. * @param reiter Der Reiter, der genannt werden soll.
* @return Die passende [DomAbteilung] oder null, wenn keine Zuordnung eindeutig möglich ist. * @return Die passende [Abteilung] oder null, wenn keine Zuordnung eindeutig möglich ist.
*/ */
fun bestimmeAbteilung( fun bestimmeAbteilung(
bewerb: DomBewerb, bewerb: Bewerb,
abteilungen: List<DomAbteilung>, abteilungen: List<Abteilung>,
reiter: Reiter reiter: Reiter
): DomAbteilung? { ): Abteilung? {
if (abteilungen.isEmpty()) return null if (abteilungen.isEmpty()) return null
if (abteilungen.size == 1) return abteilungen.first() if (abteilungen.size == 1) return abteilungen.first()
@@ -115,8 +115,8 @@ class AbteilungsRegelService {
* Beispiel CSN-C-NEU: Ein Bewerb muss zwingend eine Abteilung für lizenzfreie Reiter haben. * Beispiel CSN-C-NEU: Ein Bewerb muss zwingend eine Abteilung für lizenzfreie Reiter haben.
*/ */
fun validateStrukturelleVollstaendigkeit( fun validateStrukturelleVollstaendigkeit(
bewerb: DomBewerb, bewerb: Bewerb,
abteilungen: List<DomAbteilung> abteilungen: List<Abteilung>
): List<String> { ): List<String> {
val warnings = mutableListOf<String>() val warnings = mutableListOf<String>()
@@ -3,8 +3,8 @@
package at.mocode.entries.domain.service package at.mocode.entries.domain.service
import at.mocode.core.domain.model.* import at.mocode.core.domain.model.*
import at.mocode.entries.domain.model.DomAbteilung import at.mocode.entries.domain.model.Abteilung
import at.mocode.entries.domain.model.DomBewerb import at.mocode.entries.domain.model.Bewerb
import at.mocode.masterdata.domain.model.Reiter import at.mocode.masterdata.domain.model.Reiter
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -213,7 +213,7 @@ class AbteilungsRegelServiceTest {
pruefungsTyp: PruefungsTypE = PruefungsTypE.SPRINGEN_UEBRIG, pruefungsTyp: PruefungsTypE = PruefungsTypE.SPRINGEN_UEBRIG,
teilungsTyp: AbteilungsTeilungsTypE = AbteilungsTeilungsTypE.KEINE, teilungsTyp: AbteilungsTeilungsTypE = AbteilungsTeilungsTypE.KEINE,
hoeheCm: Int? = null hoeheCm: Int? = null
) = DomBewerb( ) = Bewerb(
turnierId = Uuid.random(), turnierId = Uuid.random(),
bewerbNummer = 1, bewerbNummer = 1,
bezeichnung = "Testbewerb", bezeichnung = "Testbewerb",
@@ -229,7 +229,7 @@ class AbteilungsRegelServiceTest {
nummer: Int, nummer: Int,
bezeichnung: String? = null, bezeichnung: String? = null,
starterAnzahl: Int = 0 starterAnzahl: Int = 0
) = DomAbteilung( ) = Abteilung(
bewerbId = bewerbId, bewerbId = bewerbId,
abteilungsNummer = nummer, abteilungsNummer = nummer,
bezeichnung = bezeichnung, bezeichnung = bezeichnung,
@@ -4,7 +4,7 @@ package at.mocode.entries.service.persistence
import at.mocode.core.domain.model.NennStatusE import at.mocode.core.domain.model.NennStatusE
import at.mocode.core.domain.model.StartwunschE import at.mocode.core.domain.model.StartwunschE
import at.mocode.entries.domain.model.DomNennung import at.mocode.entries.domain.model.Nennung
import at.mocode.entries.domain.repository.NennungRepository import at.mocode.entries.domain.repository.NennungRepository
import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.and import org.jetbrains.exposed.v1.core.and
@@ -24,7 +24,7 @@ import kotlin.uuid.toKotlinUuid
*/ */
class NennungRepositoryImpl : NennungRepository { class NennungRepositoryImpl : NennungRepository {
private fun rowToNennung(row: ResultRow): DomNennung = DomNennung( private fun rowToNennung(row: ResultRow): Nennung = Nennung(
nennungId = row[NennungTable.id].toKotlinUuid(), nennungId = row[NennungTable.id].toKotlinUuid(),
abteilungId = row[NennungTable.abteilungId].toKotlinUuid(), abteilungId = row[NennungTable.abteilungId].toKotlinUuid(),
bewerbId = row[NennungTable.bewerbId].toKotlinUuid(), bewerbId = row[NennungTable.bewerbId].toKotlinUuid(),
@@ -41,57 +41,57 @@ class NennungRepositoryImpl : NennungRepository {
updatedAt = row[NennungTable.updatedAt] updatedAt = row[NennungTable.updatedAt]
) )
override suspend fun findById(id: Uuid): DomNennung? = tenantTransaction { override suspend fun findById(id: Uuid): Nennung? = tenantTransaction {
NennungTable.selectAll().where { NennungTable.id eq id.toJavaUuid() } NennungTable.selectAll().where { NennungTable.id eq id.toJavaUuid() }
.map(::rowToNennung) .map(::rowToNennung)
.singleOrNull() .singleOrNull()
} }
override suspend fun findByBewerbId(bewerbId: Uuid): List<DomNennung> = tenantTransaction { override suspend fun findByBewerbId(bewerbId: Uuid): List<Nennung> = tenantTransaction {
NennungTable.selectAll().where { NennungTable.bewerbId eq bewerbId.toJavaUuid() } NennungTable.selectAll().where { NennungTable.bewerbId eq bewerbId.toJavaUuid() }
.map(::rowToNennung) .map(::rowToNennung)
} }
override suspend fun findByAbteilungId(abteilungId: Uuid): List<DomNennung> = tenantTransaction { override suspend fun findByAbteilungId(abteilungId: Uuid): List<Nennung> = tenantTransaction {
NennungTable.selectAll().where { NennungTable.abteilungId eq abteilungId.toJavaUuid() } NennungTable.selectAll().where { NennungTable.abteilungId eq abteilungId.toJavaUuid() }
.map(::rowToNennung) .map(::rowToNennung)
} }
override suspend fun findByTurnierId(turnierId: Uuid): List<DomNennung> = tenantTransaction { override suspend fun findByTurnierId(turnierId: Uuid): List<Nennung> = tenantTransaction {
NennungTable.selectAll().where { NennungTable.turnierId eq turnierId.toJavaUuid() } NennungTable.selectAll().where { NennungTable.turnierId eq turnierId.toJavaUuid() }
.map(::rowToNennung) .map(::rowToNennung)
} }
override suspend fun findByReiterId(reiterId: Uuid): List<DomNennung> = tenantTransaction { override suspend fun findByReiterId(reiterId: Uuid): List<Nennung> = tenantTransaction {
NennungTable.selectAll().where { NennungTable.reiterId eq reiterId.toJavaUuid() } NennungTable.selectAll().where { NennungTable.reiterId eq reiterId.toJavaUuid() }
.map(::rowToNennung) .map(::rowToNennung)
} }
override suspend fun findByPferdId(pferdId: Uuid): List<DomNennung> = tenantTransaction { override suspend fun findByPferdId(pferdId: Uuid): List<Nennung> = tenantTransaction {
NennungTable.selectAll().where { NennungTable.pferdId eq pferdId.toJavaUuid() } NennungTable.selectAll().where { NennungTable.pferdId eq pferdId.toJavaUuid() }
.map(::rowToNennung) .map(::rowToNennung)
} }
override suspend fun findByReiterIdAndTurnierId(reiterId: Uuid, turnierId: Uuid): List<DomNennung> = tenantTransaction { override suspend fun findByReiterIdAndTurnierId(reiterId: Uuid, turnierId: Uuid): List<Nennung> = tenantTransaction {
NennungTable.selectAll().where { NennungTable.selectAll().where {
(NennungTable.reiterId eq reiterId.toJavaUuid()) and (NennungTable.reiterId eq reiterId.toJavaUuid()) and
(NennungTable.turnierId eq turnierId.toJavaUuid()) (NennungTable.turnierId eq turnierId.toJavaUuid())
}.map(::rowToNennung) }.map(::rowToNennung)
} }
override suspend fun findByStatus(status: NennStatusE): List<DomNennung> = tenantTransaction { override suspend fun findByStatus(status: NennStatusE): List<Nennung> = tenantTransaction {
NennungTable.selectAll().where { NennungTable.status eq status.name } NennungTable.selectAll().where { NennungTable.status eq status.name }
.map(::rowToNennung) .map(::rowToNennung)
} }
override suspend fun findNachnennungenByBewerbId(bewerbId: Uuid): List<DomNennung> = tenantTransaction { override suspend fun findNachnennungenByBewerbId(bewerbId: Uuid): List<Nennung> = tenantTransaction {
NennungTable.selectAll().where { NennungTable.selectAll().where {
(NennungTable.bewerbId eq bewerbId.toJavaUuid()) and (NennungTable.bewerbId eq bewerbId.toJavaUuid()) and
(NennungTable.istNachnennung eq true) (NennungTable.istNachnennung eq true)
}.map(::rowToNennung) }.map(::rowToNennung)
} }
override suspend fun save(nennung: DomNennung): DomNennung = tenantTransaction { override suspend fun save(nennung: Nennung): Nennung = tenantTransaction {
val now = Clock.System.now() val now = Clock.System.now()
val existing = NennungTable.selectAll() val existing = NennungTable.selectAll()
.where { NennungTable.id eq nennung.nennungId.toJavaUuid() } .where { NennungTable.id eq nennung.nennungId.toJavaUuid() }
@@ -2,7 +2,7 @@
package at.mocode.entries.service.persistence package at.mocode.entries.service.persistence
import at.mocode.entries.domain.model.DomNennungsTransfer import at.mocode.entries.domain.model.NennungsTransfer
import at.mocode.entries.domain.repository.NennungsTransferRepository import at.mocode.entries.domain.repository.NennungsTransferRepository
import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.v1.core.eq
@@ -19,7 +19,7 @@ import kotlin.uuid.toKotlinUuid
*/ */
class NennungsTransferRepositoryImpl : NennungsTransferRepository { class NennungsTransferRepositoryImpl : NennungsTransferRepository {
private fun rowToTransfer(row: ResultRow): DomNennungsTransfer = DomNennungsTransfer( private fun rowToTransfer(row: ResultRow): NennungsTransfer = NennungsTransfer(
transferId = row[NennungsTransferTable.id].toKotlinUuid(), transferId = row[NennungsTransferTable.id].toKotlinUuid(),
ursprungsNennungId = row[NennungsTransferTable.ursprungsNennungId].toKotlinUuid(), ursprungsNennungId = row[NennungsTransferTable.ursprungsNennungId].toKotlinUuid(),
neueNennungId = row[NennungsTransferTable.neueNennungId].toKotlinUuid(), neueNennungId = row[NennungsTransferTable.neueNennungId].toKotlinUuid(),
@@ -34,19 +34,19 @@ class NennungsTransferRepositoryImpl : NennungsTransferRepository {
createdAt = row[NennungsTransferTable.createdAt] createdAt = row[NennungsTransferTable.createdAt]
) )
override suspend fun findById(id: Uuid): DomNennungsTransfer? = tenantTransaction { override suspend fun findById(id: Uuid): NennungsTransfer? = tenantTransaction {
NennungsTransferTable.selectAll().where { NennungsTransferTable.id eq id.toJavaUuid() } NennungsTransferTable.selectAll().where { NennungsTransferTable.id eq id.toJavaUuid() }
.map(::rowToTransfer) .map(::rowToTransfer)
.singleOrNull() .singleOrNull()
} }
override suspend fun findByUrsprungsNennungId(nennungId: Uuid): List<DomNennungsTransfer> = tenantTransaction { override suspend fun findByUrsprungsNennungId(nennungId: Uuid): List<NennungsTransfer> = tenantTransaction {
NennungsTransferTable.selectAll() NennungsTransferTable.selectAll()
.where { NennungsTransferTable.ursprungsNennungId eq nennungId.toJavaUuid() } .where { NennungsTransferTable.ursprungsNennungId eq nennungId.toJavaUuid() }
.map(::rowToTransfer) .map(::rowToTransfer)
} }
override suspend fun save(transfer: DomNennungsTransfer): DomNennungsTransfer = tenantTransaction { override suspend fun save(transfer: NennungsTransfer): NennungsTransfer = tenantTransaction {
val now = Clock.System.now() val now = Clock.System.now()
NennungsTransferTable.insert { stmt -> NennungsTransferTable.insert { stmt ->
stmt[id] = transfer.transferId.toJavaUuid() stmt[id] = transfer.transferId.toJavaUuid()
@@ -4,8 +4,8 @@ package at.mocode.entries.service.usecase
import at.mocode.core.domain.model.NennStatusE import at.mocode.core.domain.model.NennStatusE
import at.mocode.entries.api.* import at.mocode.entries.api.*
import at.mocode.entries.domain.model.DomNennung import at.mocode.entries.domain.model.Nennung
import at.mocode.entries.domain.model.DomNennungsTransfer import at.mocode.entries.domain.model.NennungsTransfer
import at.mocode.entries.domain.repository.NennungRepository import at.mocode.entries.domain.repository.NennungRepository
import at.mocode.entries.domain.repository.NennungsTransferRepository import at.mocode.entries.domain.repository.NennungsTransferRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -61,7 +61,7 @@ class NennungUseCases(
request.turnierId, request.bewerbId, request.reiterId request.turnierId, request.bewerbId, request.reiterId
) )
} }
val nennung = DomNennung( val nennung = Nennung(
abteilungId = request.abteilungId, abteilungId = request.abteilungId,
bewerbId = request.bewerbId, bewerbId = request.bewerbId,
turnierId = request.turnierId, turnierId = request.turnierId,
@@ -135,7 +135,7 @@ class NennungUseCases(
nennungRepository.save(geschlosseneNennung) nennungRepository.save(geschlosseneNennung)
// 2. Neue Nennung anlegen // 2. Neue Nennung anlegen
val neueNennung = DomNennung( val neueNennung = Nennung(
abteilungId = ursprung.abteilungId, abteilungId = ursprung.abteilungId,
bewerbId = ursprung.bewerbId, bewerbId = ursprung.bewerbId,
turnierId = ursprung.turnierId, turnierId = ursprung.turnierId,
@@ -150,7 +150,7 @@ class NennungUseCases(
val gespeicherteNeueNennung = nennungRepository.save(neueNennung) val gespeicherteNeueNennung = nennungRepository.save(neueNennung)
// 3. Transfer-Record speichern // 3. Transfer-Record speichern
val transfer = DomNennungsTransfer( val transfer = NennungsTransfer(
ursprungsNennungId = ursprung.nennungId, ursprungsNennungId = ursprung.nennungId,
neueNennungId = gespeicherteNeueNennung.nennungId, neueNennungId = gespeicherteNeueNennung.nennungId,
alterReiterId = if (request.neuerReiterId != null) ursprung.reiterId else null, alterReiterId = if (request.neuerReiterId != null) ursprung.reiterId else null,
@@ -175,7 +175,7 @@ class NennungUseCases(
// Mapping Helpers // Mapping Helpers
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
private fun DomNennung.toDetailDto() = NennungDetailDto( private fun Nennung.toDetailDto() = NennungDetailDto(
nennungId = nennungId, nennungId = nennungId,
abteilungId = abteilungId, abteilungId = abteilungId,
bewerbId = bewerbId, bewerbId = bewerbId,
@@ -193,7 +193,7 @@ class NennungUseCases(
updatedAt = updatedAt.toString() updatedAt = updatedAt.toString()
) )
private fun DomNennung.toSummaryDto() = NennungSummaryDto( private fun Nennung.toSummaryDto() = NennungSummaryDto(
nennungId = nennungId, nennungId = nennungId,
turnierId = turnierId, turnierId = turnierId,
bewerbId = bewerbId, bewerbId = bewerbId,
@@ -205,7 +205,7 @@ class NennungUseCases(
createdAt = createdAt.toString() createdAt = createdAt.toString()
) )
private fun DomNennungsTransfer.toDto() = NennungsTransferDto( private fun NennungsTransfer.toDto() = NennungsTransferDto(
transferId = transferId, transferId = transferId,
ursprungsNennungId = ursprungsNennungId, ursprungsNennungId = ursprungsNennungId,
neueNennungId = neueNennungId, neueNennungId = neueNennungId,
@@ -1,147 +0,0 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.events.domain.model
import at.mocode.core.domain.model.SparteE
import at.mocode.core.domain.model.VeranstaltungsStatusE
import at.mocode.core.domain.model.VeranstaltungsTypE
import at.mocode.core.domain.serialization.KotlinxInstantSerializer
import at.mocode.core.domain.serialization.UuidSerializer
import kotlinx.datetime.LocalDate
import kotlinx.serialization.Serializable
import kotlin.time.Clock
import kotlin.time.Instant
import kotlin.uuid.Uuid
/**
* Aggregate Root für eine pferdesportliche Veranstaltung gemäß ÖTO § 2 Abs. 1.
*
* Eine Veranstaltung ist der organisatorische Rahmen (z.B. "Frühjahrsturnier Wiener Neustadt").
* Sie kann ein oder mehrere Turniere enthalten. Die Unterscheidung Veranstaltung ≠ Turnier
* ist eine zentrale ADR-Entscheidung (ADR-0003).
*
* @property veranstaltungId Eindeutige interne ID (UUID).
* @property name Offizieller Name der Veranstaltung.
* @property veranstaltungsTyp Typ gemäß ÖTO (z.B. NATIONAL, INTERNATIONAL).
* @property sparten Liste der enthaltenen Sparten (Springen, Dressur, etc.).
* @property veranstalterVereinId ID des veranstaltenden Vereins (Referenz auf clubs-context).
* @property verantwortlicheFunktionaerId ID des verantwortlichen Funktionärs (Referenz auf officials-context).
* @property startDatum Erster Veranstaltungstag.
* @property endDatum Letzter Veranstaltungstag.
* @property ort Veranstaltungsort (Adresse / Reitanlage).
* @property nennschluss Nennschluss-Datum gemäß Ausschreibung.
* @property status Aktueller Status im Planungs-Workflow.
* @property ausschreibungsId Referenz auf die zugehörige Ausschreibung (optional bis Genehmigung).
* @property oepsGenehmigungsNummer Offizielle Genehmigungsnummer des Verbands (nach Genehmigung).
* @property bemerkungen Interne Bemerkungen.
* @property createdAt Erstellungszeitpunkt.
* @property updatedAt Letzter Änderungszeitpunkt.
*/
@Serializable
data class DomVeranstaltung(
@Serializable(with = UuidSerializer::class)
val veranstaltungId: Uuid = Uuid.random(),
// Basis-Informationen
var name: String,
var veranstaltungsTyp: VeranstaltungsTypE,
var sparten: List<SparteE> = emptyList(),
// Organisation
@Serializable(with = UuidSerializer::class)
var veranstalterVereinId: Uuid,
@Serializable(with = UuidSerializer::class)
var verantwortlicheFunktionaerId: Uuid? = null,
// Termine
var startDatum: LocalDate,
var endDatum: LocalDate,
var ort: String,
var nennschluss: LocalDate? = null,
// Workflow-Status
var status: VeranstaltungsStatusE = VeranstaltungsStatusE.IN_PLANUNG,
// Verknüpfungen
@Serializable(with = UuidSerializer::class)
var ausschreibungsId: Uuid? = null,
var oepsGenehmigungsNummer: String? = null,
// Administrativ
var bemerkungen: String? = null,
// Audit
@Serializable(with = KotlinxInstantSerializer::class)
val createdAt: Instant = Clock.System.now(),
@Serializable(with = KotlinxInstantSerializer::class)
var updatedAt: Instant = Clock.System.now()
) {
/**
* Gibt die Dauer der Veranstaltung in Tagen zurück.
*/
fun getDauerInTagen(): Int =
(endDatum.toEpochDays() - startDatum.toEpochDays()).toInt() + 1
/**
* Prüft ob die Veranstaltung mehrtägig ist.
*/
fun istMehrtaegig(): Boolean = startDatum != endDatum
/**
* Prüft ob Nennungen aktuell möglich sind (Status GENEHMIGT und Nennschluss nicht abgelaufen).
* Gibt Warnungen zurück keine harten Fehler (Warn-Logik statt Exception, ADR-0007).
*/
fun validateNennungsmoeglichkeit(): List<String> {
val warnings = mutableListOf<String>()
if (status != VeranstaltungsStatusE.GENEHMIGT) {
warnings.add(
"Veranstaltung ist nicht im Status GENEHMIGT (aktuell: $status). " +
"Nennungen sind erst nach Genehmigung möglich."
)
}
if (nennschluss == null) {
warnings.add("Kein Nennschluss definiert. Bitte Ausschreibung vervollständigen.")
}
if (veranstalterVereinId == null) {
warnings.add("Kein Veranstalter-Verein zugewiesen.")
}
return warnings
}
/**
* Validiert die Pflichtfelder für die Einreichung beim Verband.
* Gibt Warnungen zurück keine harten Fehler (Warn-Logik statt Exception, ADR-0007).
*/
fun validateFuerEinreichung(): List<String> {
val warnings = mutableListOf<String>()
if (name.isBlank()) {
warnings.add("Veranstaltungsname ist erforderlich.")
}
if (ort.isBlank()) {
warnings.add("Veranstaltungsort ist erforderlich.")
}
if (endDatum < startDatum) {
warnings.add("Enddatum darf nicht vor dem Startdatum liegen.")
}
if (sparten.isEmpty()) {
warnings.add("Mindestens eine Sparte muss angegeben werden.")
}
if (nennschluss == null) {
warnings.add("Nennschluss ist für die Einreichung erforderlich.")
}
nennschluss?.let { nl ->
if (nl >= startDatum) {
warnings.add("Nennschluss muss vor dem Veranstaltungsbeginn liegen (§ 2 ÖTO).")
}
}
if (ausschreibungsId == null) {
warnings.add("Keine Ausschreibung verknüpft. Einreichung ohne Ausschreibung nicht möglich.")
}
return warnings
}
/**
* Erstellt eine Kopie mit aktualisiertem Zeitstempel.
*/
fun withUpdatedTimestamp(): DomVeranstaltung = this.copy(updatedAt = Clock.System.now())
}