feat(core+frontend+domain): add ZNS Bewerb parser and integrate start list feature
- **Parser Implementation:** - Introduced `ZnsBewerbParser` to parse n2-XXXXX.dat files and map B-Satz lines to the `ZnsBewerb` domain model. - Added test coverage for parsing B-Satz lines and edge cases in `ZnsParserTest`. - **Frontend Integration:** - Integrated ZNS import functionality into the `BewerbeTabContent` for uploading and previewing Bewerb data before import. - Enhanced `BewerbViewModel` with state and intents for managing ZNS import, preview dialogs, and import confirmation. - Supported start list generation and added modal for previewing generated start lists. - **Domain Services:** - Implemented `StartlistenService` to generate and calculate start times for start lists with respect to participant preferences. - Added extensive test coverage in `StartlistenServiceTest` to validate sorting, preferences, and time calculations. - **UI Enhancements:** - Updated `Bewerbe` tab layout with search, filtering, and action buttons for ZNS import and start list generation. - Introduced dialogs for ZNS import previews and start list previews.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package at.mocode.zns.parser
|
||||
|
||||
import at.mocode.core.utils.parser.FixedWidthLineReader
|
||||
import kotlinx.datetime.LocalDate
|
||||
|
||||
/**
|
||||
* Domänen-Modell für einen ZNS-Bewerb (B-Satz).
|
||||
*/
|
||||
data class ZnsBewerb(
|
||||
val bewerbNummer: Int,
|
||||
val abteilung: Int,
|
||||
val name: String,
|
||||
val klasse: String,
|
||||
val kategorie: String,
|
||||
val datum: LocalDate?
|
||||
)
|
||||
|
||||
/**
|
||||
* Spezialisierter Parser für B-Sätze aus der n2-XXXXX.dat Datei.
|
||||
*/
|
||||
object ZnsBewerbParser {
|
||||
|
||||
/**
|
||||
* Parst eine Zeile aus der n2-XXXXX.dat Datei, sofern es sich um einen B-Satz handelt.
|
||||
* Ein B-Satz beginnt an Stelle 1 mit einem Blank, gefolgt von der Bewerbnummer.
|
||||
* ACHTUNG: Die Kopfzeile 'BBEWERBE' muss vorher ausgefiltert werden.
|
||||
*/
|
||||
fun parse(line: String): ZnsBewerb? {
|
||||
// Ein valider B-Satz hat mindestens 52 Zeichen (bis zum Datum)
|
||||
if (line.length < 52) return null
|
||||
|
||||
// Kopfzeilen oder andere Sätze ignorieren
|
||||
if (line.startsWith("BBEWERBE") || line.startsWith("A") || line.startsWith("RREITERLISTE")) {
|
||||
return null
|
||||
}
|
||||
|
||||
val reader = FixedWidthLineReader(line)
|
||||
|
||||
// Stelle 1: ID (Blank)
|
||||
val id = reader.getString(1, 1)
|
||||
if (id.isNotBlank()) return null
|
||||
|
||||
// Stelle 2-3: Bewerbnummer (2-stellig)
|
||||
// Stelle 61-63: Bewerbnummer (3-stellig) - bevorzugt verwenden, falls vorhanden
|
||||
val bewerbNummer3 = reader.getIntOrNull(61, 3)
|
||||
val bewerbNummer2 = reader.getIntOrNull(2, 2)
|
||||
val finalBewerbNummer = bewerbNummer3 ?: bewerbNummer2 ?: return null
|
||||
|
||||
// Stelle 4: Abteilung
|
||||
val abteilung = reader.getIntOrNull(4, 1) ?: 0
|
||||
|
||||
// Stelle 5-39: Bewerbname
|
||||
val name = reader.getString(5, 35)
|
||||
|
||||
// Stelle 40-43: Klasse
|
||||
val klasse = reader.getString(40, 4)
|
||||
|
||||
// Stelle 44-51: Kategorie
|
||||
val kategorie = reader.getString(44, 8)
|
||||
|
||||
// Stelle 52-59: Datum (JJJJMMTT)
|
||||
val datum = reader.getLocalDateOrNull(53, 8)
|
||||
|
||||
return ZnsBewerb(
|
||||
bewerbNummer = finalBewerbNummer,
|
||||
abteilung = abteilung,
|
||||
name = name,
|
||||
klasse = klasse,
|
||||
kategorie = kategorie,
|
||||
datum = datum
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -91,4 +91,21 @@ class ZnsParserTest {
|
||||
assertEquals("Stöglehner Otto", funktionaer.name)
|
||||
assertEquals(listOf("DPF", "DSGP", "SS*"), funktionaer.qualifikationen)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parseBewerb should extract B-Satz correctly`() {
|
||||
// ID(1) + BEWNR(2) + ABT(1) + NAME(35) + KLASSE(4) + KAT(8) + DATUM(8) + BEWNR3(3)
|
||||
// 1 2 3 4 5 6
|
||||
// 12345678901234567890123456789012345678901234567890123456789012
|
||||
val line = " 010Standardspringprüfung L CSN-C 20260410001"
|
||||
val bewerb = ZnsBewerbParser.parse(line)
|
||||
|
||||
assertNotNull(bewerb)
|
||||
assertEquals(1, bewerb.bewerbNummer)
|
||||
assertEquals(0, bewerb.abteilung)
|
||||
assertEquals("Standardspringprüfung", bewerb.name)
|
||||
assertEquals("L", bewerb.klasse)
|
||||
assertEquals("CSN-C", bewerb.kategorie)
|
||||
assertEquals("2026-04-10", bewerb.datum.toString())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user