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:
+6
-5
@@ -88,12 +88,13 @@ object NennungMockData {
|
||||
Pferd("1005", "Estrella", "Andalusier", "Schimmel", "Bauer Klaus", "Box 2"),
|
||||
)
|
||||
|
||||
// lizenzNr: OEPS-Mitgliedsnummer im Format OEPS-NNNNNNN oder plain 7-8 Ziffern (Validierungsregeln.md §1)
|
||||
val reiter = listOf(
|
||||
Reiter("2001", "Hans", "Müller", "RV Neumarkt", "AT-12345", true, 0.0),
|
||||
Reiter("2002", "Maria", "Huber", "RV Salzburg", "AT-23456", true, -45.0),
|
||||
Reiter("2003", "Josef", "Gruber", "RV Wien", "AT-34567", false, 0.0),
|
||||
Reiter("2004", "Anna", "Wagner", "RV Graz", "AT-45678", true, 120.0),
|
||||
Reiter("2005", "Klaus", "Bauer", "RV Linz", "AT-56789", true, 0.0),
|
||||
Reiter("2001", "Hans", "Müller", "RV Neumarkt", "OEPS-1234567", true, 0.0),
|
||||
Reiter("2002", "Maria", "Huber", "RV Salzburg", "OEPS-2345678", true, -45.0),
|
||||
Reiter("2003", "Josef", "Gruber", "RV Wien", "OEPS-3456789", false, 0.0),
|
||||
Reiter("2004", "Anna", "Wagner", "RV Graz", "OEPS-4567890", true, 120.0),
|
||||
Reiter("2005", "Klaus", "Bauer", "RV Linz", "OEPS-5678901", true, 0.0),
|
||||
)
|
||||
|
||||
val verkaufArtikel = listOf(
|
||||
|
||||
+18
-3
@@ -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) {
|
||||
|
||||
+20
-3
@@ -1,5 +1,7 @@
|
||||
package at.mocode.frontend.features.reiter.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,17 @@ data class ReiterProfilState(
|
||||
val feiId: String = "",
|
||||
val lizenzKlasse: String = "",
|
||||
val verein: String = "",
|
||||
val validHints: List<String> = emptyList(),
|
||||
// Validierungsergebnisse (Live-Feedback, ÖTO/FEI Regelwerk)
|
||||
val oepsNummerValidation: ValidationResult = ValidationResult.Ok,
|
||||
val feiIdValidation: ValidationResult = ValidationResult.Ok,
|
||||
val lizenzKlasseValidation: ValidationResult = ValidationResult.Ok,
|
||||
val dirty: Boolean = false,
|
||||
)
|
||||
) {
|
||||
/** True wenn kein blockierender Fehler vorliegt (Speichern erlaubt). */
|
||||
val isValid: Boolean
|
||||
get() = listOf(oepsNummerValidation, feiIdValidation, lizenzKlasseValidation)
|
||||
.none { it is ValidationResult.Error }
|
||||
}
|
||||
|
||||
sealed interface ReiterProfilIntent {
|
||||
data class Load(val id: String) : ReiterProfilIntent
|
||||
@@ -90,7 +100,14 @@ class ReiterProfilViewModel(
|
||||
}
|
||||
|
||||
private inline fun edit(block: (ReiterProfilState) -> ReiterProfilState) {
|
||||
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),
|
||||
lizenzKlasseValidation = OetoValidators.validateLizenzklasse(updated.lizenzKlasse),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun reduce(block: (ReiterProfilState) -> ReiterProfilState) {
|
||||
|
||||
Reference in New Issue
Block a user