Integrate qualification master data (QualifikationMasterTable) with functionary models, update schema and repository logic, refactor satzID references, and harmonize database migration (V010).
This commit is contained in:
+14
-8
@@ -19,9 +19,12 @@ import kotlin.uuid.Uuid
|
||||
*/
|
||||
class FunktionaerController(private val funktionaerRepository: FunktionaerRepository) {
|
||||
|
||||
/**
|
||||
* DTO für die API-Response eines Funktionärs.
|
||||
*/
|
||||
data class FunktionaerDto(
|
||||
val funktionaerId: String,
|
||||
val satzID: String,
|
||||
val satzId: String,
|
||||
val satzNummer: Int,
|
||||
val name: String? = null,
|
||||
val qualifikationen: List<String> = emptyList(),
|
||||
@@ -31,9 +34,12 @@ class FunktionaerController(private val funktionaerRepository: FunktionaerReposi
|
||||
val updatedAt: Instant
|
||||
)
|
||||
|
||||
/**
|
||||
* Request-Body zum Anlegen eines neuen Funktionärs.
|
||||
*/
|
||||
@Serializable
|
||||
data class FunktionaerCreateRequest(
|
||||
val satzID: String,
|
||||
val satzId: String,
|
||||
val satzNummer: Int,
|
||||
val name: String? = null,
|
||||
val qualifikationen: List<String> = emptyList(),
|
||||
@@ -82,12 +88,12 @@ class FunktionaerController(private val funktionaerRepository: FunktionaerReposi
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /funktionaer/satz/{satzID}/{satzNummer} — Sucht einen Funktionär nach Satz-ID und Nummer.
|
||||
* GET /funktionaer/satz/{satzId}/{satzNummer} — Sucht einen Funktionär nach Satz-ID und Nummer.
|
||||
*/
|
||||
get("/satz/{satzID}/{satzNummer}") {
|
||||
val satzID = call.parameters["satzID"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
get("/satz/{satzId}/{satzNummer}") {
|
||||
val satzId = call.parameters["satzId"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
val satzNummer = call.parameters["satzNummer"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
val funktionaer = funktionaerRepository.findBySatz(satzID, satzNummer)
|
||||
val funktionaer = funktionaerRepository.findBySatz(satzId, satzNummer)
|
||||
if (funktionaer != null) call.respond(funktionaer.toDto()) else call.respond(HttpStatusCode.NotFound)
|
||||
}
|
||||
|
||||
@@ -97,7 +103,7 @@ class FunktionaerController(private val funktionaerRepository: FunktionaerReposi
|
||||
post {
|
||||
val req = call.receive<FunktionaerCreateRequest>()
|
||||
val domFunktionaer = Funktionaer(
|
||||
satzId = req.satzID,
|
||||
satzId = req.satzId,
|
||||
satzNummer = req.satzNummer,
|
||||
name = req.name,
|
||||
qualifikationen = req.qualifikationen,
|
||||
@@ -141,7 +147,7 @@ class FunktionaerController(private val funktionaerRepository: FunktionaerReposi
|
||||
|
||||
private fun Funktionaer.toDto() = FunktionaerDto(
|
||||
funktionaerId = funktionaerId.toString(),
|
||||
satzID = satzId,
|
||||
satzId = satzId,
|
||||
satzNummer = satzNummer,
|
||||
name = name,
|
||||
qualifikationen = qualifikationen,
|
||||
|
||||
+3
-2
@@ -15,13 +15,14 @@ import kotlin.uuid.Uuid
|
||||
*
|
||||
* Repräsentiert eine Person mit einer definierten Rolle bei Turnieren (Richter, TBA,
|
||||
* Parcoursbauer etc.). Die Qualifikation wird gegen `RICHT01.DAT` oder `PARCO01.DAT`
|
||||
* aus dem ZNS geprüft.
|
||||
* aus dem ZNS geprüft und gegen die `QualifikationMasterTable` validiert.
|
||||
*
|
||||
* @property funktionaerId Eindeutige interne ID (UUID).
|
||||
* @property personId Optionale Verknüpfung zu einer Basis-Person (actor-context).
|
||||
* @property satzId Typ des Satzes (X = Richter, Y = Parcoursbauer). Aus ZNS (RICHT01.DAT / PARCO01.DAT).
|
||||
* @property satzNummer Satznummer (6-stellig). Aus ZNS (RICHT01.DAT / PARCO01.DAT).
|
||||
* @property name Vollständiger Name (Nachname, Vorname). Aus ZNS (RICHT01.DAT / PARCO01.DAT).
|
||||
* @property qualifikation Qualifikationen (getrennt durch `,`). Aus ZNS (RICHT01.DAT / PARCO01.DAT).
|
||||
* @property qualifikationen Liste der Qualifikations-Kürzel (z.B. "D", "S", "P1"). Wird in Join-Tabelle persistiert.
|
||||
* @property istAktiv Ob der Funktionär aktuell aktiv/einsatzbereit ist.
|
||||
* @property bemerkungen Interne Notizen.
|
||||
* @property datenQuelle Herkunft des Datensatzes (ZNS-Import oder manuell).
|
||||
|
||||
+15
-4
@@ -5,14 +5,23 @@ import at.mocode.core.domain.model.DatenQuelleE
|
||||
import at.mocode.core.utils.database.DatabaseFactory
|
||||
import at.mocode.masterdata.domain.model.Funktionaer
|
||||
import at.mocode.masterdata.domain.repository.FunktionaerRepository
|
||||
import at.mocode.masterdata.infrastructure.persistence.funktionaer.*
|
||||
import org.jetbrains.exposed.v1.core.*
|
||||
import org.jetbrains.exposed.v1.jdbc.*
|
||||
import org.jetbrains.exposed.v1.core.ResultRow
|
||||
import org.jetbrains.exposed.v1.core.and
|
||||
import org.jetbrains.exposed.v1.core.eq
|
||||
import org.jetbrains.exposed.v1.core.inList
|
||||
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.slf4j.LoggerFactory
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Exposed-basierte Implementierung des Funktionaer-Repositorys.
|
||||
*
|
||||
* Verwaltet die Persistenz von Funktionären und deren Qualifikationen.
|
||||
* Die Qualifikationen werden beim Speichern gegen die [QualifikationMasterTable]
|
||||
* aufgelöst, um Datenintegrität bezüglich offizieller ÖTO-Kürzel sicherzustellen.
|
||||
*/
|
||||
class FunktionaerExposedRepository : FunktionaerRepository {
|
||||
private val log = LoggerFactory.getLogger(FunktionaerExposedRepository::class.java)
|
||||
@@ -21,7 +30,7 @@ class FunktionaerExposedRepository : FunktionaerRepository {
|
||||
return Funktionaer(
|
||||
funktionaerId = row[FunktionaerTable.id],
|
||||
personId = row[FunktionaerTable.personId],
|
||||
satzId = row[FunktionaerTable.satzId] ?: "X",
|
||||
satzId = row[FunktionaerTable.satzId],
|
||||
satzNummer = row[FunktionaerTable.satzNummer] ?: 0,
|
||||
name = row[FunktionaerTable.name],
|
||||
qualifikationen = qualifikationen,
|
||||
@@ -99,6 +108,8 @@ class FunktionaerExposedRepository : FunktionaerRepository {
|
||||
}
|
||||
|
||||
// Qualifikationen synchronisieren (über Master-Daten Auflösung)
|
||||
// Wir löschen bestehende Zuordnungen und bauen sie basierend auf den Master-Daten neu auf.
|
||||
// Unbekannte Kürzel werden nicht persistiert, sondern geloggt.
|
||||
FunktionaerQualifikationTable.deleteWhere { funktionaerId eq funktionaer.funktionaerId }
|
||||
|
||||
val typ = if (funktionaer.istRichter()) "RICHTER" else "PARCOURSBAUER"
|
||||
|
||||
+17
-4
@@ -10,15 +10,21 @@ import kotlin.uuid.ExperimentalUuidApi
|
||||
|
||||
/**
|
||||
* Exposed-Tabellendefinition für die Funktionär-Entität.
|
||||
* Speichert Basisdaten und Kontaktinformationen.
|
||||
*/
|
||||
object FunktionaerTable : Table("funktionaer") {
|
||||
val id = uuid("funktionaer_id")
|
||||
val personId = uuid("person_id").nullable()
|
||||
|
||||
// === ZNS.zip RICHT01.DAT === ANFANG ===
|
||||
// === ZNS.zip RICHT01.DAT (Zentrales Nennungssystem) === ANFANG ===
|
||||
|
||||
/** Typ des Satzes: "X" = Richter, "Y" = Parcoursbauer */
|
||||
val satzId = varchar("satz_id", 1)
|
||||
|
||||
/** 6-stellige Satznummer (eindeutig pro Typ) */
|
||||
val satzNummer = integer("satz_nummer").nullable()
|
||||
|
||||
/** Vollständiger Name (Nachname, Vorname) */
|
||||
val name = varchar("name", 200).nullable()
|
||||
|
||||
// === ZNS.zip RICHT01.DAT === ENDE ===
|
||||
@@ -54,12 +60,19 @@ object FunktionaerTable : Table("funktionaer") {
|
||||
|
||||
/**
|
||||
* Exposed-Tabellendefinition für die Qualifikation-Master-Daten.
|
||||
* Enthält offizielle ÖTO/FEI Kürzel (z.B. "D", "S", "P1").
|
||||
*/
|
||||
object QualifikationMasterTable : Table("qualifikation_master") {
|
||||
val id = uuid("qualifikation_id")
|
||||
val code = varchar("code", 10) // z.B. "D", "S", "SPF", "P1"
|
||||
val bezeichnung = varchar("bezeichnung", 100) // z.B. "Dressur", "Springpferde"
|
||||
val typ = varchar("typ", 20) // "RICHTER" oder "PARCOURSBAUER"
|
||||
|
||||
/** Offizielles Kürzel (z.B. "SPF" für Springpferde) */
|
||||
val code = varchar("code", 10)
|
||||
|
||||
/** Fachlich ausgeschriebene Bezeichnung */
|
||||
val bezeichnung = varchar("bezeichnung", 100)
|
||||
|
||||
/** Bereich der Qualifikation: "RICHTER" oder "PARCOURSBAUER" */
|
||||
val typ = varchar("typ", 20)
|
||||
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
|
||||
|
||||
+12
-3
@@ -74,11 +74,20 @@ ALTER TABLE funktionaer ADD COLUMN IF NOT EXISTS plz VARCHAR(10);
|
||||
ALTER TABLE funktionaer ADD COLUMN IF NOT EXISTS ort VARCHAR(100);
|
||||
ALTER TABLE funktionaer ADD COLUMN IF NOT EXISTS bundesland VARCHAR(100);
|
||||
|
||||
-- 5. Qualifikations-Tabelle für Funktionäre
|
||||
-- 5. Qualifikations-Master-Tabelle und Join-Tabelle für Funktionäre
|
||||
CREATE TABLE IF NOT EXISTS qualifikation_master (
|
||||
qualifikation_id UUID NOT NULL,
|
||||
code VARCHAR(10) NOT NULL,
|
||||
bezeichnung VARCHAR(100) NOT NULL,
|
||||
typ VARCHAR(20) NOT NULL,
|
||||
PRIMARY KEY (qualifikation_id),
|
||||
CONSTRAINT idx_qualifikation_code_typ UNIQUE (code, typ)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS funktionaer_qualifikation (
|
||||
funktionaer_id UUID NOT NULL REFERENCES funktionaer(funktionaer_id),
|
||||
qualifikation VARCHAR(20) NOT NULL,
|
||||
PRIMARY KEY (funktionaer_id, qualifikation)
|
||||
qualifikation_id UUID NOT NULL REFERENCES qualifikation_master(qualifikation_id),
|
||||
PRIMARY KEY (funktionaer_id, qualifikation_id)
|
||||
);
|
||||
|
||||
-- Indizes (Exposed-Style)
|
||||
|
||||
Reference in New Issue
Block a user