feat(validation): integrate ÖTO/FEI rule validations and centralized validators

- Added `OetoValidators` with live-validation for OEPS numbers, FEI-IDs, license classes, and horse data to align with ÖTO/FEI 2026 standards.
- Expanded `ReiterProfilViewModel` and `PferdProfilViewModel` to include validation states (`ValidationResult`) for enhanced form feedback and dirty state tracking.
- Standardized mock data in `Stores.kt` and `NennungModels.kt` to comply with updated validation rules.
- Created `OetoValidatorsTest` to ensure validation logic accuracy (30 unit tests, all green).
- Updated `build.gradle.kts` to include `kotlin.test` dependency for JVM testing.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-03 09:04:08 +02:00
parent 2c8d16b27f
commit 14b458860c
9 changed files with 631 additions and 28 deletions
@@ -1,5 +1,7 @@
package at.mocode.frontend.features.pferde.presentation
import at.mocode.frontend.core.domain.validation.OetoValidators
import at.mocode.frontend.core.domain.validation.ValidationResult
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -16,9 +18,16 @@ data class PferdProfilState(
val geburtsjahr: String = "",
val farbe: String = "",
val rasse: String = "",
val validHints: List<String> = emptyList(),
// Validierungsergebnisse (Live-Feedback, ÖTO/FEI Regelwerk)
val oepsNummerValidation: ValidationResult = ValidationResult.Ok,
val feiIdValidation: ValidationResult = ValidationResult.Ok,
val dirty: Boolean = false,
)
) {
/** True wenn kein blockierender Fehler vorliegt (Speichern erlaubt). */
val isValid: Boolean
get() = listOf(oepsNummerValidation, feiIdValidation)
.none { it is ValidationResult.Error }
}
sealed interface PferdProfilIntent {
data class Load(val id: String) : PferdProfilIntent
@@ -90,7 +99,13 @@ class PferdProfilViewModel(
}
private inline fun edit(block: (PferdProfilState) -> PferdProfilState) {
reduce { block(it).copy(dirty = true) }
reduce { s ->
val updated = block(s).copy(dirty = true)
updated.copy(
oepsNummerValidation = OetoValidators.validateOepsNummer(updated.oepsNummer),
feiIdValidation = OetoValidators.validateFeiId(updated.feiId),
)
}
}
private inline fun reduce(block: (PferdProfilState) -> PferdProfilState) {