### feat: erweitere Stammdaten-Integration

- **Repositories:** Implementiere und integriere `KtorPferdRepository` und `KtorFunktionaerRepository`.
- **SQLite:** Erweitere Schema um `LocalPferd` und `LocalFunktionaer` mit passenden Queries.
- **ViewModels:** Passe `PferdeViewModel` und `FunktionaerViewModel` an, um Flows und Repository-Injektion zu nutzen.
- **DI-Module:** Aktualisiere `PferdeModule` und `FunktionaerModule` für Backend-Anbindung.
This commit is contained in:
2026-04-22 12:25:39 +02:00
parent d4cc0eb77d
commit 98c241fc64
12 changed files with 385 additions and 178 deletions
@@ -13,148 +13,185 @@ import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class DesktopMasterdataRepository(
private val db: AppDatabase
db: AppDatabase
) : MasterdataRepository {
private val queries = db.meldestelleDbQueries
private val queries = db.meldestelleDbQueries
override fun saveVereine(vereine: List<ZnsRemoteVerein>) {
println("[Repository] Speichere ${vereine.size} Vereine in SQLite")
val now = System.currentTimeMillis()
runBlocking {
queries.transaction {
vereine.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
queries.upsertVerein(
id = id,
oebs_nummer = remote.oepsNummer ?: "",
name = remote.name ?: "Unbekannt",
ort = remote.ort,
plz = null, // Falls vom Backend geliefert, hier mappen
bundesland = remote.bundesland,
is_active = 1,
last_updated = now
)
}
}
}
// Update Mock Store for backward compatibility during transition
override fun saveVereine(vereine: List<ZnsRemoteVerein>) {
println("[Repository] Speichere ${vereine.size} Vereine in SQLite")
val now = System.currentTimeMillis()
runBlocking {
queries.transaction {
vereine.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
val verein = Verein(
id = id,
name = remote.name ?: "Unbekannt",
oepsNummer = remote.oepsNummer ?: "",
ort = remote.ort,
bundesland = remote.bundesland,
istVeranstalter = true
)
val existingIdx = Store.vereine.indexOfFirst { it.id == id }
if (existingIdx >= 0) Store.vereine[existingIdx] = verein else Store.vereine.add(verein)
val id = remote.id.toLongOrNull() ?: return@forEach
queries.upsertVerein(
id = id,
oebs_nummer = remote.oepsNummer,
name = remote.name,
ort = remote.ort,
plz = null, // Falls vom Backend geliefert, hier mappen
bundesland = remote.bundesland,
is_active = 1,
last_updated = now
)
}
}
}
// Update Mock Store for backward compatibility during transition
vereine.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
val verein = Verein(
id = id,
name = remote.name,
oepsNummer = remote.oepsNummer,
ort = remote.ort,
bundesland = remote.bundesland,
istVeranstalter = true
)
val existingIdx = Store.vereine.indexOfFirst { it.id == id }
if (existingIdx >= 0) Store.vereine[existingIdx] = verein else Store.vereine.add(verein)
}
}
override fun saveReiter(reiter: List<ZnsRemoteReiter>) {
println("[Repository] Speichere ${reiter.size} Reiter in SQLite")
val now = System.currentTimeMillis()
runBlocking {
queries.transaction {
reiter.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
queries.upsertReiter(
id = id,
zns_nummer = remote.satznummer,
vorname = remote.vorname ?: "",
nachname = remote.nachname ?: "",
jahrgang = null, // Backend liefert aktuell kein Jahrgang direkt in ZnsRemoteReiter?
geschlecht = null,
nation = remote.nation ?: "AUT",
is_active = 1,
last_updated = now
)
}
}
}
// Sync to Store
override fun saveReiter(reiter: List<ZnsRemoteReiter>) {
println("[Repository] Speichere ${reiter.size} Reiter in SQLite")
val now = System.currentTimeMillis()
runBlocking {
queries.transaction {
reiter.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
val entry = Reiter(
id = id,
vorname = remote.vorname ?: "",
nachname = remote.nachname ?: "",
satznummer = remote.satznummer ?: "",
oepsNummer = remote.satznummer ?: "",
lizenzKlasse = remote.lizenzKlasse,
nation = remote.nation ?: "AUT",
bundesland = remote.bundesland
)
val existingIdx = Store.reiter.indexOfFirst { it.id == id }
if (existingIdx >= 0) Store.reiter[existingIdx] = entry else Store.reiter.add(entry)
val id = remote.id.toLongOrNull() ?: return@forEach
queries.upsertReiter(
id = id,
zns_nummer = remote.satznummer,
vorname = remote.vorname,
nachname = remote.nachname,
jahrgang = null, // Backend liefert aktuell kein Jahrgang direkt in ZnsRemoteReiter?
geschlecht = null,
nation = remote.nation ?: "AUT",
is_active = 1,
last_updated = now
)
}
}
}
// Sync to Store
reiter.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
val entry = Reiter(
id = id,
vorname = remote.vorname,
nachname = remote.nachname,
satznummer = remote.satznummer ?: "",
oepsNummer = remote.satznummer ?: "",
lizenzKlasse = remote.lizenzKlasse,
nation = remote.nation ?: "AUT",
bundesland = remote.bundesland
)
val existingIdx = Store.reiter.indexOfFirst { it.id == id }
if (existingIdx >= 0) Store.reiter[existingIdx] = entry else Store.reiter.add(entry)
}
}
override fun savePferde(pferde: List<ZnsRemotePferd>) {
println("[Repository] Speichere ${pferde.size} Pferde")
override fun savePferde(pferde: List<ZnsRemotePferd>) {
println("[Repository] Speichere ${pferde.size} Pferde in SQLite")
val now = System.currentTimeMillis()
runBlocking {
queries.transaction {
pferde.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
val existingIdx = Store.pferde.indexOfFirst { it.id == id }
val entry = Pferd(
id = id,
name = remote.name,
geschlecht = remote.geschlecht,
lebensnummer = remote.lebensnummer,
oepsNummer = remote.kopfnummer
)
if (existingIdx >= 0) {
Store.pferde[existingIdx] = entry
} else {
Store.pferde.add(entry)
}
val id = remote.id.toLongOrNull() ?: return@forEach
queries.upsertPferd(
id = id,
name = remote.name,
lebensnummer = remote.lebensnummer ?: "",
geschlecht = remote.geschlecht,
farbe = null,
geburtsjahr = null,
oebs_nummer = remote.kopfnummer,
is_active = 1,
last_updated = now
)
}
}
}
// Sync to Store
pferde.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
val entry = Pferd(
id = id,
name = remote.name,
geschlecht = remote.geschlecht,
lebensnummer = remote.lebensnummer ?: "",
oepsNummer = remote.kopfnummer
)
val existingIdx = Store.pferde.indexOfFirst { it.id == id }
if (existingIdx >= 0) Store.pferde[existingIdx] = entry else Store.pferde.add(entry)
}
}
override fun saveFunktionaere(funktionaere: List<ZnsRemoteFunktionaer>) {
println("[Repository] Speichere ${funktionaere.size} Funktionäre")
override fun saveFunktionaere(funktionaere: List<ZnsRemoteFunktionaer>) {
println("[Repository] Speichere ${funktionaere.size} Funktionäre in SQLite")
val now = System.currentTimeMillis()
runBlocking {
queries.transaction {
funktionaere.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
val existingIdx = Store.funktionaere.indexOfFirst { it.id == id }
val namen = remote.name?.split(" ") ?: listOf("Unbekannt")
val entry = Funktionaer(
id = id,
vorname = namen.firstOrNull() ?: "",
nachname = namen.drop(1).joinToString(" "),
rollen = remote.qualifikationen,
nation = remote.nation ?: "AUT",
bundesland = remote.bundesland
)
if (existingIdx >= 0) {
Store.funktionaere[existingIdx] = entry
} else {
Store.funktionaere.add(entry)
}
val id = remote.id.toLongOrNull() ?: return@forEach
val namen = remote.name?.split(" ") ?: listOf("Unbekannt")
queries.upsertFunktionaer(
id = id,
vorname = namen.firstOrNull() ?: "",
nachname = namen.drop(1).joinToString(" "),
richter_nummer = null,
disziplinen = remote.qualifikationen.joinToString(","),
qualifikation = null,
email = null,
is_active = 1,
last_updated = now
)
}
}
}
override fun getStats(): MasterdataStats {
val vereinCount = queries.selectAllVereine().executeAsList().size.toLong()
val reiterCount = queries.selectAllReiter().executeAsList().size.toLong()
val lastUpdate = listOf(
queries.selectAllVereine().executeAsList().maxOfOrNull { it.last_updated } ?: 0L,
queries.selectAllReiter().executeAsList().maxOfOrNull { it.last_updated } ?: 0L
).maxOrNull() ?: 0L
val lastImportStr = if (lastUpdate > 0) {
val dt = LocalDateTime.now() // Vereinfacht, idealerweise aus lastUpdate Zeitstempel
dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
} else "Nie"
return MasterdataStats(
lastImport = lastImportStr,
vereinCount = vereinCount.toInt(),
reiterCount = reiterCount.toInt(),
pferdCount = Store.pferde.size,
funktionaerCount = Store.funktionaere.size
)
// Sync to Store
funktionaere.forEach { remote ->
val id = remote.id.toLongOrNull() ?: return@forEach
val namen = remote.name?.split(" ") ?: listOf("Unbekannt")
val entry = Funktionaer(
id = id,
vorname = namen.firstOrNull() ?: "",
nachname = namen.drop(1).joinToString(" "),
rollen = remote.qualifikationen,
nation = remote.nation ?: "AUT",
bundesland = remote.bundesland
)
val existingIdx = Store.funktionaere.indexOfFirst { it.id == id }
if (existingIdx >= 0) Store.funktionaere[existingIdx] = entry else Store.funktionaere.add(entry)
}
}
override fun getStats(): MasterdataStats {
val vereinCount = queries.selectAllVereine().executeAsList().size.toLong()
val reiterCount = queries.selectAllReiter().executeAsList().size.toLong()
val pferdCount = queries.selectAllPferde().executeAsList().size.toLong()
val funktionaerCount = queries.selectAllFunktionaere().executeAsList().size.toLong()
val lastUpdate = listOf(
queries.selectAllVereine().executeAsList().maxOfOrNull { it.last_updated } ?: 0L,
queries.selectAllReiter().executeAsList().maxOfOrNull { it.last_updated } ?: 0L,
queries.selectAllPferde().executeAsList().maxOfOrNull { it.last_updated } ?: 0L,
queries.selectAllFunktionaere().executeAsList().maxOfOrNull { it.last_updated } ?: 0L
).maxOrNull() ?: 0L
val lastImportStr = if (lastUpdate > 0) {
val dt = LocalDateTime.now() // Vereinfacht, idealerweise aus lastUpdate-Zeitstempeln
dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
} else "Nie"
return MasterdataStats(
lastImport = lastImportStr,
vereinCount = vereinCount.toInt(),
reiterCount = reiterCount.toInt(),
pferdCount = pferdCount.toInt(),
funktionaerCount = funktionaerCount.toInt()
)
}
}