Document and implement CSN-C-NEU mandatory division rules: Add TURNIER_KLASSEN.md detailing forced divisions by license categories; establish uniform labels and keys (e.g., LZF_ONLY and R1_PLUS); draft optional youth division rules. Extend validation in Validierungsregeln.md. Implement FEI-ID resolver and mapping endpoint in Masterdata service.
This commit is contained in:
+29
@@ -0,0 +1,29 @@
|
||||
package at.mocode.masterdata.domain.service
|
||||
|
||||
/**
|
||||
* Auflösung von FEI-IDs: akzeptiert numerische IDs (Pass‑Through) und Legacy‑Referenzcodes
|
||||
* und liefert – wenn bekannt – die zugehörige numerische FEI‑ID zurück.
|
||||
*/
|
||||
interface FeiIdResolver {
|
||||
|
||||
/**
|
||||
* Löst eine eingegebene FEI‑Kennung auf.
|
||||
*
|
||||
* @param input Benutzer-/Importeingabe (numerisch 7–8 Stellen oder Legacy‑Code 3Z+2B+2Z)
|
||||
* @return [FeiIdResolution] mit normalisierter numerischer ID, oder null wenn unbekannt/ungültig
|
||||
*/
|
||||
fun resolve(input: String): FeiIdResolution?
|
||||
}
|
||||
|
||||
/**
|
||||
* Ergebnis der FEI‑ID Auflösung.
|
||||
*
|
||||
* @property normalizedNumericId Numerische FEI‑ID (7–8 Ziffern) als String
|
||||
* @property sourceFormat "NUMERIC" | "LEGACY_CODE"
|
||||
* @property wasMapped true, wenn aus Legacy nach numerisch gemappt wurde
|
||||
*/
|
||||
data class FeiIdResolution(
|
||||
val normalizedNumericId: String,
|
||||
val sourceFormat: String,
|
||||
val wasMapped: Boolean
|
||||
)
|
||||
@@ -31,6 +31,7 @@ dependencies {
|
||||
implementation(libs.spring.boot.starter.web)
|
||||
implementation(libs.spring.boot.starter.validation)
|
||||
implementation(libs.spring.boot.starter.actuator)
|
||||
implementation(libs.jackson.module.kotlin)
|
||||
//implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
||||
|
||||
// Ktor Server (für SCS: eigener kleiner HTTP-Server pro Kontext)
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package at.mocode.masterdata.service.fei
|
||||
|
||||
import at.mocode.masterdata.domain.service.FeiIdResolution
|
||||
import at.mocode.masterdata.domain.service.FeiIdResolver
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/fei")
|
||||
class FeiIdController(
|
||||
private val resolver: FeiIdResolver
|
||||
) {
|
||||
|
||||
data class ResolveResponse(
|
||||
val input: String,
|
||||
val normalizedNumericId: String?,
|
||||
val sourceFormat: String?,
|
||||
val wasMapped: Boolean,
|
||||
val found: Boolean
|
||||
)
|
||||
|
||||
@GetMapping("/resolve/{id}")
|
||||
fun resolve(@PathVariable("id") id: String): ResponseEntity<ResolveResponse> {
|
||||
val res: FeiIdResolution? = resolver.resolve(id)
|
||||
return if (res != null) {
|
||||
ResponseEntity.ok(
|
||||
ResolveResponse(
|
||||
input = id,
|
||||
normalizedNumericId = res.normalizedNumericId,
|
||||
sourceFormat = res.sourceFormat,
|
||||
wasMapped = res.wasMapped,
|
||||
found = true
|
||||
)
|
||||
)
|
||||
} else {
|
||||
ResponseEntity.status(404).body(
|
||||
ResolveResponse(
|
||||
input = id,
|
||||
normalizedNumericId = null,
|
||||
sourceFormat = null,
|
||||
wasMapped = false,
|
||||
found = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package at.mocode.masterdata.service.fei
|
||||
|
||||
import at.mocode.masterdata.domain.service.FeiIdResolution
|
||||
import at.mocode.masterdata.domain.service.FeiIdResolver
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import org.springframework.core.io.ClassPathResource
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/**
|
||||
* Einfache In‑Memory Implementierung des [FeiIdResolver],
|
||||
* lädt ein JSON‑Mapping aus Ressourcen: `data/fei-id-mapping.json`.
|
||||
*/
|
||||
@Component
|
||||
class FeiIdResolverImpl : FeiIdResolver {
|
||||
|
||||
private val legacyToNumeric: Map<String, String> by lazy {
|
||||
val res = ClassPathResource("data/fei-id-mapping.json")
|
||||
if (!res.exists()) return@lazy emptyMap<String, String>()
|
||||
val mapper = jacksonObjectMapper()
|
||||
res.inputStream.use { input ->
|
||||
mapper.readValue<Map<String, String>>(input)
|
||||
.mapKeys { it.key.trim().uppercase() }
|
||||
}
|
||||
}
|
||||
|
||||
private val numericRegex = Regex("^[0-9]{7,8}$")
|
||||
private val legacyRegex = Regex("^[0-9]{3}[A-Z]{2}[0-9]{2}$")
|
||||
|
||||
override fun resolve(input: String): FeiIdResolution? {
|
||||
val s = input.trim().uppercase()
|
||||
// Numerisch: Pass‑Through
|
||||
if (numericRegex.matches(s)) {
|
||||
return FeiIdResolution(normalizedNumericId = s, sourceFormat = "NUMERIC", wasMapped = false)
|
||||
}
|
||||
// Legacy: lookup
|
||||
if (legacyRegex.matches(s)) {
|
||||
val mapped = legacyToNumeric[s] ?: return null
|
||||
return FeiIdResolution(normalizedNumericId = mapped, sourceFormat = "LEGACY_CODE", wasMapped = true)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"104FE22": "10011469",
|
||||
"103RW04": "10019075",
|
||||
"102UB51": "10028445",
|
||||
"104UD89": "10011111"
|
||||
}
|
||||
Reference in New Issue
Block a user