feat(masterdata): add controllers, services, and repositories for Reiter, Horse, and Verein domains
- Introduced entities `ReiterController`, `HorseController`, and `VereinController`, with associated REST routes. - Implemented upsert functionality for `Reiter`, `Horse`, and `Verein` repositories. - Added services for `Altersklasse` calculations and integrated them into the domain layer. - Updated database schema to include `ReiterTable`, `HorseTable`, `VereinTable`, and `FunktionaerTable`. - Refactored `masterdataApiModule` to register new domain controllers. - Adjusted Ktor server and Spring configurations to support new domains. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
+11
-8
@@ -1,24 +1,24 @@
|
|||||||
package at.mocode.masterdata.api
|
package at.mocode.masterdata.api
|
||||||
|
|
||||||
import at.mocode.masterdata.api.plugins.IdempotencyPlugin
|
import at.mocode.masterdata.api.plugins.IdempotencyPlugin
|
||||||
import at.mocode.masterdata.api.rest.AltersklasseController
|
import at.mocode.masterdata.api.rest.*
|
||||||
import at.mocode.masterdata.api.rest.BundeslandController
|
import io.ktor.server.application.*
|
||||||
import at.mocode.masterdata.api.rest.CountryController
|
import io.ktor.server.routing.*
|
||||||
import at.mocode.masterdata.api.rest.PlatzController
|
|
||||||
import io.ktor.server.application.Application
|
|
||||||
import io.ktor.server.routing.routing
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ktor-Modul für den Masterdata-Bounded-Context.
|
* Ktor-Modul für den Masterdata-Bounded-Context.
|
||||||
*
|
*
|
||||||
* - Installiert das IdempotencyPlugin (Header „Idempotency-Key“) global.
|
* - Installiert das IdempotencyPlugin (Header „Idempotency-Key“) global.
|
||||||
* - Registriert alle Masterdata-Routen (Country, Bundesland, Altersklasse, Platz).
|
* - Registriert alle Masterdata-Routen (Country, Bundesland, Altersklasse, Platz, Reiter, Horse, Verein).
|
||||||
*/
|
*/
|
||||||
fun Application.masterdataApiModule(
|
fun Application.masterdataApiModule(
|
||||||
countryController: CountryController,
|
countryController: CountryController,
|
||||||
bundeslandController: BundeslandController,
|
bundeslandController: BundeslandController,
|
||||||
altersklasseController: AltersklasseController,
|
altersklasseController: AltersklasseController,
|
||||||
platzController: PlatzController
|
platzController: PlatzController,
|
||||||
|
reiterController: ReiterController,
|
||||||
|
horseController: HorseController,
|
||||||
|
vereinController: VereinController
|
||||||
) {
|
) {
|
||||||
// Installiere das Idempotency-Plugin global für alle Routen
|
// Installiere das Idempotency-Plugin global für alle Routen
|
||||||
IdempotencyPlugin.install(this)
|
IdempotencyPlugin.install(this)
|
||||||
@@ -29,5 +29,8 @@ fun Application.masterdataApiModule(
|
|||||||
with(bundeslandController) { registerRoutes() }
|
with(bundeslandController) { registerRoutes() }
|
||||||
with(altersklasseController) { registerRoutes() }
|
with(altersklasseController) { registerRoutes() }
|
||||||
with(platzController) { registerRoutes() }
|
with(platzController) { registerRoutes() }
|
||||||
|
with(reiterController) { registerRoutes() }
|
||||||
|
with(horseController) { registerRoutes() }
|
||||||
|
with(vereinController) { registerRoutes() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||||
|
|
||||||
|
package at.mocode.masterdata.api.rest
|
||||||
|
|
||||||
|
import at.mocode.core.domain.serialization.InstantSerializer
|
||||||
|
import at.mocode.core.domain.serialization.LocalDateSerializer
|
||||||
|
import at.mocode.masterdata.domain.model.DomPferd
|
||||||
|
import at.mocode.masterdata.domain.repository.HorseRepository
|
||||||
|
import io.ktor.http.*
|
||||||
|
import io.ktor.server.response.*
|
||||||
|
import io.ktor.server.routing.*
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlin.time.Instant
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller für Pferde-bezogene REST-Endpunkte.
|
||||||
|
*/
|
||||||
|
class HorseController(private val horseRepository: HorseRepository) {
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HorseDto(
|
||||||
|
val pferdId: String,
|
||||||
|
val pferdeName: String,
|
||||||
|
val geschlecht: String,
|
||||||
|
@Serializable(with = LocalDateSerializer::class)
|
||||||
|
val geburtsdatum: LocalDate? = null,
|
||||||
|
val rasse: String? = null,
|
||||||
|
val lebensnummer: String? = null,
|
||||||
|
val oepsNummer: String? = null,
|
||||||
|
val feiNummer: String? = null,
|
||||||
|
val istAktiv: Boolean,
|
||||||
|
@Serializable(with = InstantSerializer::class)
|
||||||
|
val updatedAt: Instant
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Route.registerRoutes() {
|
||||||
|
route("/horse") {
|
||||||
|
/**
|
||||||
|
* Sucht Pferde nach Name.
|
||||||
|
*/
|
||||||
|
get("/search") {
|
||||||
|
val query = call.request.queryParameters["q"] ?: ""
|
||||||
|
val results = horseRepository.findByName(query)
|
||||||
|
call.respond(results.map { it.toDto() })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruft ein spezifisches Pferd ab.
|
||||||
|
*/
|
||||||
|
get("/{id}") {
|
||||||
|
val idStr = call.parameters["id"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
val id = try {
|
||||||
|
Uuid.parse(idStr)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val pferd = horseRepository.findById(id)
|
||||||
|
if (pferd != null) {
|
||||||
|
call.respond(pferd.toDto())
|
||||||
|
} else {
|
||||||
|
call.respond(HttpStatusCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sucht ein Pferd nach seiner Lebensnummer.
|
||||||
|
*/
|
||||||
|
get("/lebensnummer/{nr}") {
|
||||||
|
val nr = call.parameters["nr"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
val pferd = horseRepository.findByLebensnummer(nr)
|
||||||
|
if (pferd != null) {
|
||||||
|
call.respond(pferd.toDto())
|
||||||
|
} else {
|
||||||
|
call.respond(HttpStatusCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DomPferd.toDto() = HorseDto(
|
||||||
|
pferdId = pferdId.toString(),
|
||||||
|
pferdeName = pferdeName,
|
||||||
|
geschlecht = geschlecht.name,
|
||||||
|
geburtsdatum = geburtsdatum,
|
||||||
|
rasse = rasse,
|
||||||
|
lebensnummer = lebensnummer,
|
||||||
|
oepsNummer = oepsNummer,
|
||||||
|
feiNummer = feiNummer,
|
||||||
|
istAktiv = istAktiv,
|
||||||
|
updatedAt = updatedAt
|
||||||
|
)
|
||||||
|
}
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||||
|
|
||||||
|
package at.mocode.masterdata.api.rest
|
||||||
|
|
||||||
|
import at.mocode.core.domain.serialization.InstantSerializer
|
||||||
|
import at.mocode.core.domain.serialization.LocalDateSerializer
|
||||||
|
import at.mocode.masterdata.domain.model.DomReiter
|
||||||
|
import at.mocode.masterdata.domain.repository.ReiterRepository
|
||||||
|
import io.ktor.http.*
|
||||||
|
import io.ktor.server.response.*
|
||||||
|
import io.ktor.server.routing.*
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlin.time.Instant
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller für Reiter-bezogene REST-Endpunkte.
|
||||||
|
*/
|
||||||
|
class ReiterController(private val reiterRepository: ReiterRepository) {
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ReiterDto(
|
||||||
|
val reiterId: String,
|
||||||
|
val satznummer: String,
|
||||||
|
val nachname: String,
|
||||||
|
val vorname: String,
|
||||||
|
@Serializable(with = LocalDateSerializer::class)
|
||||||
|
val geburtsdatum: LocalDate? = null,
|
||||||
|
val lizenzNummer: String? = null,
|
||||||
|
val lizenzKlasse: String,
|
||||||
|
val startkartAktiv: Boolean,
|
||||||
|
val nation: String? = null,
|
||||||
|
val vereinsName: String? = null,
|
||||||
|
@Serializable(with = InstantSerializer::class)
|
||||||
|
val updatedAt: Instant
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Route.registerRoutes() {
|
||||||
|
route("/reiter") {
|
||||||
|
/**
|
||||||
|
* Sucht Reiter nach Name oder Satznummer.
|
||||||
|
*/
|
||||||
|
get("/search") {
|
||||||
|
val query = call.request.queryParameters["q"] ?: ""
|
||||||
|
val results = reiterRepository.findByName(query)
|
||||||
|
call.respond(results.map { it.toDto() })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruft einen spezifischen Reiter ab.
|
||||||
|
*/
|
||||||
|
get("/{id}") {
|
||||||
|
val idStr = call.parameters["id"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
val id = try {
|
||||||
|
Uuid.parse(idStr)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val reiter = reiterRepository.findById(id)
|
||||||
|
if (reiter != null) {
|
||||||
|
call.respond(reiter.toDto())
|
||||||
|
} else {
|
||||||
|
call.respond(HttpStatusCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sucht einen Reiter nach seiner Satznummer.
|
||||||
|
*/
|
||||||
|
get("/satznummer/{nr}") {
|
||||||
|
val nr = call.parameters["nr"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
val reiter = reiterRepository.findBySatznummer(nr)
|
||||||
|
if (reiter != null) {
|
||||||
|
call.respond(reiter.toDto())
|
||||||
|
} else {
|
||||||
|
call.respond(HttpStatusCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DomReiter.toDto() = ReiterDto(
|
||||||
|
reiterId = reiterId.toString(),
|
||||||
|
satznummer = satznummer,
|
||||||
|
nachname = nachname,
|
||||||
|
vorname = vorname,
|
||||||
|
geburtsdatum = geburtsdatum,
|
||||||
|
lizenzNummer = lizenzNummer,
|
||||||
|
lizenzKlasse = lizenzKlasse.name,
|
||||||
|
startkartAktiv = startkartAktiv,
|
||||||
|
nation = nation,
|
||||||
|
vereinsName = vereinsName,
|
||||||
|
updatedAt = updatedAt
|
||||||
|
)
|
||||||
|
}
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||||
|
|
||||||
|
package at.mocode.masterdata.api.rest
|
||||||
|
|
||||||
|
import at.mocode.core.domain.serialization.InstantSerializer
|
||||||
|
import at.mocode.masterdata.domain.model.DomVerein
|
||||||
|
import at.mocode.masterdata.domain.repository.VereinRepository
|
||||||
|
import io.ktor.http.*
|
||||||
|
import io.ktor.server.response.*
|
||||||
|
import io.ktor.server.routing.*
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller für Vereins-bezogene REST-Endpunkte.
|
||||||
|
*/
|
||||||
|
class VereinController(private val vereinRepository: VereinRepository) {
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class VereinDto(
|
||||||
|
val vereinId: String,
|
||||||
|
val vereinsNummer: String,
|
||||||
|
val name: String,
|
||||||
|
val kurzname: String? = null,
|
||||||
|
val bundesland: String,
|
||||||
|
val ort: String? = null,
|
||||||
|
val istVeranstalter: Boolean,
|
||||||
|
val istAktiv: Boolean,
|
||||||
|
@Serializable(with = InstantSerializer::class)
|
||||||
|
val updatedAt: kotlin.time.Instant
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Route.registerRoutes() {
|
||||||
|
route("/verein") {
|
||||||
|
/**
|
||||||
|
* Sucht Vereine nach Name oder Kurzname.
|
||||||
|
*/
|
||||||
|
get("/search") {
|
||||||
|
val query = call.request.queryParameters["q"] ?: ""
|
||||||
|
val results = vereinRepository.findByName(query)
|
||||||
|
call.respond(results.map { it.toDto() })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruft einen spezifischen Verein ab.
|
||||||
|
*/
|
||||||
|
get("/{id}") {
|
||||||
|
val idStr = call.parameters["id"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
val id = try {
|
||||||
|
Uuid.parse(idStr)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val verein = vereinRepository.findById(id)
|
||||||
|
if (verein != null) {
|
||||||
|
call.respond(verein.toDto())
|
||||||
|
} else {
|
||||||
|
call.respond(HttpStatusCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sucht einen Verein nach seiner Vereinsnummer.
|
||||||
|
*/
|
||||||
|
get("/nummer/{nr}") {
|
||||||
|
val nr = call.parameters["nr"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||||
|
val verein = vereinRepository.findByVereinsNummer(nr)
|
||||||
|
if (verein != null) {
|
||||||
|
call.respond(verein.toDto())
|
||||||
|
} else {
|
||||||
|
call.respond(HttpStatusCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DomVerein.toDto() = VereinDto(
|
||||||
|
vereinId = vereinId.toString(),
|
||||||
|
vereinsNummer = vereinsNummer,
|
||||||
|
name = name,
|
||||||
|
kurzname = kurzname,
|
||||||
|
bundesland = bundesland ?: "",
|
||||||
|
ort = ort,
|
||||||
|
istVeranstalter = istVeranstalter,
|
||||||
|
istAktiv = istAktiv,
|
||||||
|
updatedAt = updatedAt
|
||||||
|
)
|
||||||
|
}
|
||||||
+7
-1
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
package at.mocode.masterdata.domain.repository
|
package at.mocode.masterdata.domain.repository
|
||||||
|
|
||||||
import at.mocode.masterdata.domain.model.DomPferd
|
|
||||||
import at.mocode.core.domain.model.PferdeGeschlechtE
|
import at.mocode.core.domain.model.PferdeGeschlechtE
|
||||||
|
import at.mocode.masterdata.domain.model.DomPferd
|
||||||
import kotlin.uuid.Uuid
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -245,4 +245,10 @@ interface HorseRepository {
|
|||||||
* @return The count of FEI registered horses
|
* @return The count of FEI registered horses
|
||||||
*/
|
*/
|
||||||
suspend fun countFeiRegistered(activeOnly: Boolean = true): Long
|
suspend fun countFeiRegistered(activeOnly: Boolean = true): Long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speichert ein Pferd basierend auf der Lebensnummer (Upsert).
|
||||||
|
* Wenn ein Pferd mit der Lebensnummer existiert, wird es aktualisiert, ansonsten neu angelegt.
|
||||||
|
*/
|
||||||
|
suspend fun upsertByLebensnummer(horse: DomPferd): DomPferd
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -86,4 +86,10 @@ interface ReiterRepository {
|
|||||||
* Prüft ob ein Reiter mit der gegebenen Satznummer bereits existiert.
|
* Prüft ob ein Reiter mit der gegebenen Satznummer bereits existiert.
|
||||||
*/
|
*/
|
||||||
suspend fun existsBySatznummer(satznummer: String): Boolean
|
suspend fun existsBySatznummer(satznummer: String): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speichert einen Reiter basierend auf der Satznummer (Upsert).
|
||||||
|
* Wenn ein Reiter mit der Satznummer existiert, wird er aktualisiert, ansonsten neu angelegt.
|
||||||
|
*/
|
||||||
|
suspend fun upsertBySatznummer(reiter: DomReiter): DomReiter
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -69,4 +69,10 @@ interface VereinRepository {
|
|||||||
* Prüft ob ein Verein mit der gegebenen Vereinsnummer bereits existiert.
|
* Prüft ob ein Verein mit der gegebenen Vereinsnummer bereits existiert.
|
||||||
*/
|
*/
|
||||||
suspend fun existsByVereinsNummer(vereinsNummer: String): Boolean
|
suspend fun existsByVereinsNummer(vereinsNummer: String): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speichert einen Verein basierend auf der Vereinsnummer (Upsert).
|
||||||
|
* Wenn ein Verein mit der Nummer existiert, wird er aktualisiert, ansonsten neu angelegt.
|
||||||
|
*/
|
||||||
|
suspend fun upsertByVereinsNummer(verein: DomVerein): DomVerein
|
||||||
}
|
}
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package at.mocode.masterdata.domain.service
|
||||||
|
|
||||||
|
import at.mocode.core.domain.model.SparteE
|
||||||
|
import at.mocode.masterdata.domain.model.AltersklasseDefinition
|
||||||
|
import at.mocode.masterdata.domain.model.DomReiter
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service zur Berechnung und Ermittlung von Altersklassen gemäß ÖTO.
|
||||||
|
*/
|
||||||
|
interface AltersklasseRechner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ermittelt das Alter einer Person für ein bestimmtes Jahr gemäß der ÖTO-Stichtagsregel
|
||||||
|
* (Alter am 31.12. des laufenden Kalenderjahres).
|
||||||
|
*
|
||||||
|
* @param geburtsdatum Das Geburtsdatum der Person.
|
||||||
|
* @param referenzJahr Das Kalenderjahr, für das das Alter berechnet werden soll.
|
||||||
|
* @return Das Alter in Jahren.
|
||||||
|
*/
|
||||||
|
fun berechneOetoAlter(geburtsdatum: LocalDate, referenzJahr: Int): Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ermittelt alle zutreffenden Altersklassen für einen Reiter in einem bestimmten Jahr und einer Sparte.
|
||||||
|
*
|
||||||
|
* @param reiter Der Reiter, für den die Altersklasse ermittelt werden soll.
|
||||||
|
* @param referenzJahr Das Kalenderjahr des Turniers.
|
||||||
|
* @param sparte Die Sparte des Bewerbs (optional).
|
||||||
|
* @param verfügbareDefinitionen Die Liste der im System definierten Altersklassen.
|
||||||
|
* @return Eine Liste der zutreffenden Altersklassen-Definitionen.
|
||||||
|
*/
|
||||||
|
fun ermittleAltersklassen(
|
||||||
|
reiter: DomReiter,
|
||||||
|
referenzJahr: Int,
|
||||||
|
sparte: SparteE? = null,
|
||||||
|
verfügbareDefinitionen: List<AltersklasseDefinition>
|
||||||
|
): List<AltersklasseDefinition>
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package at.mocode.masterdata.domain.service
|
||||||
|
|
||||||
|
import at.mocode.core.domain.model.SparteE
|
||||||
|
import at.mocode.masterdata.domain.model.AltersklasseDefinition
|
||||||
|
import at.mocode.masterdata.domain.model.DomReiter
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard-Implementierung des [AltersklasseRechner] gemäß ÖTO.
|
||||||
|
*/
|
||||||
|
class AltersklasseRechnerImpl : AltersklasseRechner {
|
||||||
|
|
||||||
|
override fun berechneOetoAlter(geburtsdatum: LocalDate, referenzJahr: Int): Int {
|
||||||
|
// Gemäß ÖTO: Stichtag für alle Altersklassen ist der 31. Dezember des laufenden Kalenderjahres.
|
||||||
|
// Das bedeutet einfach: ReferenzJahr - GeburtsJahr.
|
||||||
|
return referenzJahr - geburtsdatum.year
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ermittleAltersklassen(
|
||||||
|
reiter: DomReiter,
|
||||||
|
referenzJahr: Int,
|
||||||
|
sparte: SparteE?,
|
||||||
|
verfügbareDefinitionen: List<AltersklasseDefinition>
|
||||||
|
): List<AltersklasseDefinition> {
|
||||||
|
val geburtsdatum = reiter.geburtsdatum ?: return emptyList()
|
||||||
|
val alter = berechneOetoAlter(geburtsdatum, referenzJahr)
|
||||||
|
|
||||||
|
return verfügbareDefinitionen.filter { def ->
|
||||||
|
if (!def.istAktiv) return@filter false
|
||||||
|
|
||||||
|
// Sparte prüfen (falls in der Definition eine Sparte vorgegeben ist)
|
||||||
|
if (def.sparteFilter != null && sparte != null && def.sparteFilter != sparte) {
|
||||||
|
return@filter false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alter prüfen
|
||||||
|
val minMatch = def.minAlter == null || alter >= def.minAlter!!
|
||||||
|
val maxMatch = def.maxAlter == null || alter <= def.maxAlter!!
|
||||||
|
|
||||||
|
minMatch && maxMatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -174,4 +174,35 @@ class ExposedReiterRepository : ReiterRepository {
|
|||||||
override suspend fun existsBySatznummer(satznummer: String): Boolean = DatabaseFactory.dbQuery {
|
override suspend fun existsBySatznummer(satznummer: String): Boolean = DatabaseFactory.dbQuery {
|
||||||
ReiterTable.selectAll().where { ReiterTable.satznummer eq satznummer }.any()
|
ReiterTable.selectAll().where { ReiterTable.satznummer eq satznummer }.any()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun upsertBySatznummer(reiter: DomReiter): DomReiter = DatabaseFactory.dbQuery {
|
||||||
|
val existing = ReiterTable.selectAll().where { ReiterTable.satznummer eq reiter.satznummer }
|
||||||
|
.map(::rowToDomReiter)
|
||||||
|
.singleOrNull()
|
||||||
|
|
||||||
|
if (existing != null) {
|
||||||
|
val toUpdate = reiter.copy(reiterId = existing.reiterId)
|
||||||
|
ReiterTable.update({ ReiterTable.id eq existing.reiterId }) {
|
||||||
|
it[personId] = toUpdate.personId
|
||||||
|
it[nachname] = toUpdate.nachname
|
||||||
|
it[vorname] = toUpdate.vorname
|
||||||
|
it[geburtsdatum] = toUpdate.geburtsdatum
|
||||||
|
it[lizenzNummer] = toUpdate.lizenzNummer
|
||||||
|
it[lizenzKlasse] = toUpdate.lizenzKlasse.name
|
||||||
|
it[startkartAktiv] = toUpdate.startkartAktiv
|
||||||
|
it[startkartSaison] = toUpdate.startkartSaison
|
||||||
|
it[feiId] = toUpdate.feiId
|
||||||
|
it[nation] = toUpdate.nation
|
||||||
|
it[vereinsNummer] = toUpdate.vereinsNummer
|
||||||
|
it[vereinsName] = toUpdate.vereinsName
|
||||||
|
it[istGastreiter] = toUpdate.istGastreiter
|
||||||
|
it[istAktiv] = toUpdate.istAktiv
|
||||||
|
it[datenQuelle] = toUpdate.datenQuelle.name
|
||||||
|
it[updatedAt] = toUpdate.updatedAt
|
||||||
|
}
|
||||||
|
toUpdate
|
||||||
|
} else {
|
||||||
|
save(reiter)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-6
@@ -7,14 +7,10 @@ import at.mocode.core.utils.database.DatabaseFactory
|
|||||||
import at.mocode.masterdata.domain.model.DomVerein
|
import at.mocode.masterdata.domain.model.DomVerein
|
||||||
import at.mocode.masterdata.domain.repository.VereinRepository
|
import at.mocode.masterdata.domain.repository.VereinRepository
|
||||||
import org.jetbrains.exposed.v1.core.ResultRow
|
import org.jetbrains.exposed.v1.core.ResultRow
|
||||||
import org.jetbrains.exposed.v1.core.or
|
|
||||||
import org.jetbrains.exposed.v1.jdbc.deleteWhere
|
|
||||||
import org.jetbrains.exposed.v1.jdbc.insert
|
|
||||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
|
||||||
import org.jetbrains.exposed.v1.jdbc.update
|
|
||||||
import org.jetbrains.exposed.v1.core.eq
|
import org.jetbrains.exposed.v1.core.eq
|
||||||
import org.jetbrains.exposed.v1.core.like
|
import org.jetbrains.exposed.v1.core.like
|
||||||
import org.jetbrains.exposed.v1.jdbc.andWhere
|
import org.jetbrains.exposed.v1.core.or
|
||||||
|
import org.jetbrains.exposed.v1.jdbc.*
|
||||||
import kotlin.uuid.Uuid
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,4 +147,35 @@ class ExposedVereinRepository : VereinRepository {
|
|||||||
override suspend fun existsByVereinsNummer(vereinsNummer: String): Boolean = DatabaseFactory.dbQuery {
|
override suspend fun existsByVereinsNummer(vereinsNummer: String): Boolean = DatabaseFactory.dbQuery {
|
||||||
VereinTable.selectAll().where { VereinTable.vereinsNummer eq vereinsNummer }.any()
|
VereinTable.selectAll().where { VereinTable.vereinsNummer eq vereinsNummer }.any()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun upsertByVereinsNummer(verein: DomVerein): DomVerein = DatabaseFactory.dbQuery {
|
||||||
|
val existing = VereinTable.selectAll().where { VereinTable.vereinsNummer eq verein.vereinsNummer }
|
||||||
|
.map(::rowToDomVerein)
|
||||||
|
.singleOrNull()
|
||||||
|
|
||||||
|
if (existing != null) {
|
||||||
|
val toUpdate = verein.copy(vereinId = existing.vereinId)
|
||||||
|
VereinTable.update({ VereinTable.id eq existing.vereinId }) {
|
||||||
|
it[vereinsNummer] = toUpdate.vereinsNummer
|
||||||
|
it[name] = toUpdate.name
|
||||||
|
it[kurzname] = toUpdate.kurzname
|
||||||
|
it[bundesland] = toUpdate.bundesland
|
||||||
|
it[ort] = toUpdate.ort
|
||||||
|
it[plz] = toUpdate.plz
|
||||||
|
it[strasse] = toUpdate.strasse
|
||||||
|
it[email] = toUpdate.email
|
||||||
|
it[telefon] = toUpdate.telefon
|
||||||
|
it[website] = toUpdate.website
|
||||||
|
it[oepsRegionNummer] = toUpdate.oepsRegionNummer
|
||||||
|
it[istVeranstalter] = toUpdate.istVeranstalter
|
||||||
|
it[istAktiv] = toUpdate.istAktiv
|
||||||
|
it[bemerkungen] = toUpdate.bemerkungen
|
||||||
|
it[datenQuelle] = toUpdate.datenQuelle.name
|
||||||
|
it[updatedAt] = toUpdate.updatedAt
|
||||||
|
}
|
||||||
|
toUpdate
|
||||||
|
} else {
|
||||||
|
save(verein)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+39
@@ -283,4 +283,43 @@ class HorseRepositoryImpl : HorseRepository {
|
|||||||
}
|
}
|
||||||
query.count()
|
query.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun upsertByLebensnummer(horse: DomPferd): DomPferd = DatabaseFactory.dbQuery {
|
||||||
|
val lebensnummer = horse.lebensnummer ?: return@dbQuery save(horse)
|
||||||
|
|
||||||
|
val existing = HorseTable.selectAll().where { HorseTable.lebensnummer eq lebensnummer }
|
||||||
|
.map(::rowToDomPferd)
|
||||||
|
.singleOrNull()
|
||||||
|
|
||||||
|
if (existing != null) {
|
||||||
|
val toUpdate = horse.copy(pferdId = existing.pferdId)
|
||||||
|
HorseTable.update({ HorseTable.id eq existing.pferdId }) {
|
||||||
|
it[pferdeName] = toUpdate.pferdeName
|
||||||
|
it[geschlecht] = toUpdate.geschlecht.name
|
||||||
|
it[geburtsdatum] = toUpdate.geburtsdatum
|
||||||
|
it[rasse] = toUpdate.rasse
|
||||||
|
it[farbe] = toUpdate.farbe
|
||||||
|
it[besitzerId] = toUpdate.besitzerId
|
||||||
|
it[verantwortlichePersonId] = toUpdate.verantwortlichePersonId
|
||||||
|
it[zuechterName] = toUpdate.zuechterName
|
||||||
|
it[zuchtbuchNummer] = toUpdate.zuchtbuchNummer
|
||||||
|
it[lebensnummer] = toUpdate.lebensnummer
|
||||||
|
it[chipNummer] = toUpdate.chipNummer
|
||||||
|
it[passNummer] = toUpdate.passNummer
|
||||||
|
it[oepsNummer] = toUpdate.oepsNummer
|
||||||
|
it[feiNummer] = toUpdate.feiNummer
|
||||||
|
it[vaterName] = toUpdate.vaterName
|
||||||
|
it[mutterName] = toUpdate.mutterName
|
||||||
|
it[mutterVaterName] = toUpdate.mutterVaterName
|
||||||
|
it[stockmass] = toUpdate.stockmass
|
||||||
|
it[istAktiv] = toUpdate.istAktiv
|
||||||
|
it[bemerkungen] = toUpdate.bemerkungen
|
||||||
|
it[datenQuelle] = toUpdate.datenQuelle.name
|
||||||
|
it[updatedAt] = toUpdate.updatedAt
|
||||||
|
}
|
||||||
|
toUpdate
|
||||||
|
} else {
|
||||||
|
save(horse)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -1,16 +1,10 @@
|
|||||||
package at.mocode.masterdata.service.config
|
package at.mocode.masterdata.service.config
|
||||||
|
|
||||||
import at.mocode.masterdata.api.masterdataApiModule
|
import at.mocode.masterdata.api.masterdataApiModule
|
||||||
import at.mocode.masterdata.api.rest.AltersklasseController
|
import at.mocode.masterdata.api.rest.*
|
||||||
import at.mocode.masterdata.api.rest.BundeslandController
|
import io.ktor.server.engine.*
|
||||||
import at.mocode.masterdata.api.rest.CountryController
|
import io.ktor.server.netty.*
|
||||||
import at.mocode.masterdata.api.rest.PlatzController
|
|
||||||
import io.ktor.server.engine.embeddedServer
|
|
||||||
import io.ktor.server.engine.EmbeddedServer
|
|
||||||
import io.ktor.server.netty.Netty
|
|
||||||
import io.ktor.server.netty.NettyApplicationEngine
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.DisposableBean
|
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
@@ -33,7 +27,10 @@ class KtorServerConfiguration {
|
|||||||
countryController: CountryController,
|
countryController: CountryController,
|
||||||
bundeslandController: BundeslandController,
|
bundeslandController: BundeslandController,
|
||||||
altersklasseController: AltersklasseController,
|
altersklasseController: AltersklasseController,
|
||||||
platzController: PlatzController
|
platzController: PlatzController,
|
||||||
|
reiterController: ReiterController,
|
||||||
|
horseController: HorseController,
|
||||||
|
vereinController: VereinController
|
||||||
): EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration> {
|
): EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration> {
|
||||||
log.info("Starting Masterdata Ktor server on port {}", port)
|
log.info("Starting Masterdata Ktor server on port {}", port)
|
||||||
val engine = embeddedServer(Netty, port = port) {
|
val engine = embeddedServer(Netty, port = port) {
|
||||||
@@ -41,7 +38,10 @@ class KtorServerConfiguration {
|
|||||||
countryController = countryController,
|
countryController = countryController,
|
||||||
bundeslandController = bundeslandController,
|
bundeslandController = bundeslandController,
|
||||||
altersklasseController = altersklasseController,
|
altersklasseController = altersklasseController,
|
||||||
platzController = platzController
|
platzController = platzController,
|
||||||
|
reiterController = reiterController,
|
||||||
|
horseController = horseController,
|
||||||
|
vereinController = vereinController
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
engine.start(wait = false)
|
engine.start(wait = false)
|
||||||
|
|||||||
+16
-1
@@ -1,9 +1,9 @@
|
|||||||
package at.mocode.masterdata.service.config
|
package at.mocode.masterdata.service.config
|
||||||
|
|
||||||
|
import at.mocode.masterdata.api.rest.*
|
||||||
import at.mocode.masterdata.application.usecase.*
|
import at.mocode.masterdata.application.usecase.*
|
||||||
import at.mocode.masterdata.domain.repository.*
|
import at.mocode.masterdata.domain.repository.*
|
||||||
import at.mocode.masterdata.infrastructure.persistence.*
|
import at.mocode.masterdata.infrastructure.persistence.*
|
||||||
import at.mocode.masterdata.api.rest.*
|
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.context.annotation.Profile
|
import org.springframework.context.annotation.Profile
|
||||||
@@ -134,6 +134,21 @@ class MasterdataConfiguration {
|
|||||||
): PlatzController {
|
): PlatzController {
|
||||||
return PlatzController(getPlatzUseCase, createPlatzUseCase)
|
return PlatzController(getPlatzUseCase, createPlatzUseCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun reiterController(reiterRepository: ReiterRepository): ReiterController {
|
||||||
|
return ReiterController(reiterRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun horseController(horseRepository: HorseRepository): HorseController {
|
||||||
|
return HorseController(horseRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun vereinController(vereinRepository: VereinRepository): VereinController {
|
||||||
|
return VereinController(vereinRepository)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+11
-6
@@ -1,10 +1,7 @@
|
|||||||
package at.mocode.masterdata.service.config
|
package at.mocode.masterdata.service.config
|
||||||
|
|
||||||
|
|
||||||
import at.mocode.masterdata.infrastructure.persistence.AltersklasseTable
|
import at.mocode.masterdata.infrastructure.persistence.*
|
||||||
import at.mocode.masterdata.infrastructure.persistence.BundeslandTable
|
|
||||||
import at.mocode.masterdata.infrastructure.persistence.LandTable
|
|
||||||
import at.mocode.masterdata.infrastructure.persistence.PlatzTable
|
|
||||||
import jakarta.annotation.PostConstruct
|
import jakarta.annotation.PostConstruct
|
||||||
import jakarta.annotation.PreDestroy
|
import jakarta.annotation.PreDestroy
|
||||||
import org.jetbrains.exposed.v1.jdbc.SchemaUtils
|
import org.jetbrains.exposed.v1.jdbc.SchemaUtils
|
||||||
@@ -36,7 +33,11 @@ class MasterdataDatabaseConfiguration {
|
|||||||
LandTable,
|
LandTable,
|
||||||
BundeslandTable,
|
BundeslandTable,
|
||||||
AltersklasseTable,
|
AltersklasseTable,
|
||||||
PlatzTable
|
PlatzTable,
|
||||||
|
ReiterTable,
|
||||||
|
HorseTable,
|
||||||
|
VereinTable,
|
||||||
|
FunktionaerTable
|
||||||
)
|
)
|
||||||
log.info("Masterdata database schema initialized successfully")
|
log.info("Masterdata database schema initialized successfully")
|
||||||
}
|
}
|
||||||
@@ -72,7 +73,11 @@ class MasterdataTestDatabaseConfiguration {
|
|||||||
LandTable,
|
LandTable,
|
||||||
BundeslandTable,
|
BundeslandTable,
|
||||||
AltersklasseTable,
|
AltersklasseTable,
|
||||||
PlatzTable
|
PlatzTable,
|
||||||
|
ReiterTable,
|
||||||
|
HorseTable,
|
||||||
|
VereinTable,
|
||||||
|
FunktionaerTable
|
||||||
)
|
)
|
||||||
log.info("Test masterdata database schema initialized successfully")
|
log.info("Test masterdata database schema initialized successfully")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user