diff --git a/composeApp/src/commonMain/kotlin/at/mocode/server/App.kt b/composeApp/src/commonMain/kotlin/at/mocode/compose/App.kt similarity index 96% rename from composeApp/src/commonMain/kotlin/at/mocode/server/App.kt rename to composeApp/src/commonMain/kotlin/at/mocode/compose/App.kt index a5ca905d..8c72a269 100644 --- a/composeApp/src/commonMain/kotlin/at/mocode/server/App.kt +++ b/composeApp/src/commonMain/kotlin/at/mocode/compose/App.kt @@ -1,4 +1,4 @@ -package at.mocode.server +package at.mocode.compose import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Column diff --git a/composeApp/src/desktopMain/kotlin/at/mocode/server/main.kt b/composeApp/src/desktopMain/kotlin/at/mocode/compose/main.kt similarity index 89% rename from composeApp/src/desktopMain/kotlin/at/mocode/server/main.kt rename to composeApp/src/desktopMain/kotlin/at/mocode/compose/main.kt index f6df01fe..960e8c59 100644 --- a/composeApp/src/desktopMain/kotlin/at/mocode/server/main.kt +++ b/composeApp/src/desktopMain/kotlin/at/mocode/compose/main.kt @@ -1,4 +1,4 @@ -package at.mocode.server +package at.mocode.compose import androidx.compose.ui.window.Window import androidx.compose.ui.window.application diff --git a/composeApp/src/wasmJsMain/kotlin/at/mocode/server/main.kt b/composeApp/src/wasmJsMain/kotlin/at/mocode/compose/main.kt similarity index 90% rename from composeApp/src/wasmJsMain/kotlin/at/mocode/server/main.kt rename to composeApp/src/wasmJsMain/kotlin/at/mocode/compose/main.kt index f1714d89..68c993be 100644 --- a/composeApp/src/wasmJsMain/kotlin/at/mocode/server/main.kt +++ b/composeApp/src/wasmJsMain/kotlin/at/mocode/compose/main.kt @@ -1,4 +1,4 @@ -package at.mocode.server +package at.mocode.compose import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.window.ComposeViewport diff --git a/server/src/main/kotlin/at/mocode/server/tables/ArtikelTable.kt b/server/src/main/kotlin/at/mocode/server/tables/ArtikelTable.kt index 7491d3d5..5d9013dd 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/ArtikelTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/ArtikelTable.kt @@ -3,12 +3,6 @@ package at.mocode.server.tables import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.kotlin.datetime.timestamp -/** - * Optimized version of ArtikelTable - * Changes: - * - Changed unique index on bezeichnung to non-unique - * - Added init block for defining indexes - */ object ArtikelTable : Table("artikel") { val id = uuid("id") val bezeichnung = varchar("bezeichnung", 255) diff --git a/server/src/main/kotlin/at/mocode/server/tables/LizenzenTable.kt b/server/src/main/kotlin/at/mocode/server/tables/LizenzenTable.kt index 154634be..f1cd9aab 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/LizenzenTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/LizenzenTable.kt @@ -5,13 +5,6 @@ import at.mocode.shared.model.enums.Sparte import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.kotlin.datetime.date -/** - * Optimized version of LizenzenTable - * Changes: - * - Added proper imports for enums - * - Uncommented the sparte field - * - Added index for lizenzTyp and gueltigBisJahr - */ object LizenzenTable : Table("lizenzen") { val id = uuid("id") val personId = uuid("person_id").references(PersonenTable.id) diff --git a/server/src/main/kotlin/at/mocode/server/tables/PersonenTable.kt b/server/src/main/kotlin/at/mocode/server/tables/PersonenTable.kt index 583a51c5..e627de21 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/PersonenTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/PersonenTable.kt @@ -5,14 +5,6 @@ import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.kotlin.datetime.date import org.jetbrains.exposed.sql.kotlin.datetime.timestamp -/** - * Optimized version of PersonenTable - * Changes: - * - Added proper imports for enums - * - Replaced inline comments with KDoc - * - Fixed the unique index on nachname+vorname to be non-unique - * - Added indexes for email and stammVereinId for common queries - */ object PersonenTable : Table("personen") { val id = uuid("id") val oepsSatzNr = varchar("oeps_satz_nr", 10).uniqueIndex().nullable() diff --git a/server/src/main/kotlin/at/mocode/server/tables/PferdeTable.kt b/server/src/main/kotlin/at/mocode/server/tables/PferdeTable.kt index 9dec2fcb..d40d6f56 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/PferdeTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/PferdeTable.kt @@ -4,13 +4,6 @@ import at.mocode.shared.model.enums.GeschlechtPferd import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.kotlin.datetime.timestamp -/** - * Optimized version of PferdeTable - * Changes: - * - Added proper imports for enums - * - Added indexes for foreign key fields - * - Added index for common search fields (name, rasse) - */ object PferdeTable : Table("pferde") { val id = uuid("id") val oepsKopfNr = varchar("oeps_kopf_nr", 10).uniqueIndex().nullable() diff --git a/server/src/main/kotlin/at/mocode/server/tables/PlaetzeTable.kt b/server/src/main/kotlin/at/mocode/server/tables/PlaetzeTable.kt index 48ebd2b9..ae322438 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/PlaetzeTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/PlaetzeTable.kt @@ -3,12 +3,6 @@ package at.mocode.server.tables import at.mocode.shared.model.enums.PlatzTyp import org.jetbrains.exposed.sql.Table -/** - * Optimized version of PlaetzeTable - * Changes: - * - Added proper imports for enums - * - Added index for name field - */ object PlaetzeTable : Table("plaetze") { val id = uuid("id") val turnierId = uuid("turnier_id").references(TurniereTable.id) diff --git a/server/src/main/kotlin/at/mocode/server/tables/TurniereTable.kt b/server/src/main/kotlin/at/mocode/server/tables/TurniereTable.kt index f66b3f8f..b583dfa4 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/TurniereTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/TurniereTable.kt @@ -5,13 +5,6 @@ import org.jetbrains.exposed.sql.kotlin.datetime.date // Für kotlinx-datetime L import org.jetbrains.exposed.sql.kotlin.datetime.datetime // Für kotlinx-datetime LocalDateTime import org.jetbrains.exposed.sql.kotlin.datetime.timestamp // Für kotlinx-datetime Instant -/** - * Optimized version of TurniereTable - * Changes: - * - Added proper imports for enums - * - Added indexes for foreign key fields and common search fields - * - Added init block for defining indexes - */ object TurniereTable : Table("turniere") { // Name der Tabelle in PostgreSQL val id = uuid("id") val veranstaltungId = uuid("veranstaltung_id").references(VeranstaltungenTable.id) diff --git a/server/src/main/kotlin/at/mocode/server/tables/VeranstaltungenTable.kt b/server/src/main/kotlin/at/mocode/server/tables/VeranstaltungenTable.kt index 2ac2811f..4501a5c4 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/VeranstaltungenTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/VeranstaltungenTable.kt @@ -5,13 +5,6 @@ import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.kotlin.datetime.date import org.jetbrains.exposed.sql.kotlin.datetime.timestamp -/** - * Optimized version of VeranstaltungenTable - * Changes: - * - Added proper imports for enums - * - Added indexes for common search fields - * - Added init block for defining indexes - */ object VeranstaltungenTable : Table("veranstaltungen") { val id = uuid("id") val name = varchar("name", 255) diff --git a/server/src/main/kotlin/at/mocode/server/tables/VereineTable.kt b/server/src/main/kotlin/at/mocode/server/tables/VereineTable.kt index 0ec2dac1..1e0f66a8 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/VereineTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/VereineTable.kt @@ -3,12 +3,6 @@ package at.mocode.server.tables import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.kotlin.datetime.timestamp -/** - * Optimized version of VereineTable - * Changes: - * - Added indexes for common search fields (name, bundesland) - * - Added init block for defining indexes - */ object VereineTable : Table("vereine") { val id = uuid("id") val oepsVereinsNr = varchar("oeps_vereins_nr", 10).uniqueIndex() diff --git a/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Abteilung.kt b/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Abteilung.kt new file mode 100644 index 00000000..55739acd --- /dev/null +++ b/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Abteilung.kt @@ -0,0 +1,25 @@ +package at.mocode.shared.model.entitaeten + +import at.mocode.shared.model.serializers.KotlinInstantSerializer +import at.mocode.shared.model.serializers.UuidSerializer +import com.benasher44.uuid.Uuid +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + + +@Serializable +data class Abteilung( + @Serializable(with = UuidSerializer::class) + val id: Uuid, + @Serializable(with = UuidSerializer::class) + val bewerbId: Uuid, + val bezeichnung: String, // z.B. "R1", "R2/RS2 u. höher" + val beginnZeit: String, // TIME als String, z.B. "09:00" oder "anschließend" + val istFixeBeginnZeit: Boolean = false, + @Serializable(with = KotlinInstantSerializer::class) + val createdAt: Instant = Clock.System.now(), + @Serializable(with = KotlinInstantSerializer::class) + var updatedAt: Instant = Clock.System.now() +) + diff --git a/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Bewerb.kt b/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Bewerb.kt new file mode 100644 index 00000000..ed2fec71 --- /dev/null +++ b/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Bewerb.kt @@ -0,0 +1,41 @@ +package at.mocode.shared.model.entitaeten + +import at.mocode.shared.model.enums.BewerbStatus +import at.mocode.shared.model.enums.Sparte +import at.mocode.shared.model.serializers.BigDecimalSerializer +import at.mocode.shared.model.serializers.KotlinInstantSerializer +import at.mocode.shared.model.serializers.UuidSerializer +import com.benasher44.uuid.Uuid +import com.ionspin.kotlin.bignum.decimal.BigDecimal +import kotlinx.datetime.Instant +import kotlinx.datetime.LocalDate +import kotlinx.serialization.Serializable + +@Serializable +data class Bewerb( + @Serializable(with = UuidSerializer::class) + val id: Uuid, + @Serializable(with = UuidSerializer::class) + var turnierId: Uuid, + var nummer: Int, + var bezeichnung: String, + var klasse: String, + var datum: LocalDate, + var sparte: Sparte, + var richtverfahren: String?, + var beginnZeit: String, // TIME als String (z.B. "09:00" oder "anschließend") + var istFixeBeginnZeit: Boolean = false, + var laufzeitProStarter: Int?, // Dauer pro Starter in Minuten + var maxStarter: Int?, + @Serializable(with = BigDecimalSerializer::class) + var nenngeld: BigDecimal?, + var sonderpruefungReferenz: SonderpruefungReferenz?, + var cupReferenz: List = emptyList(), + var status: BewerbStatus = BewerbStatus.GEPLANT, + var details: String?, + var einteilung: String?, + @Serializable(with = KotlinInstantSerializer::class) + val createdAt: Instant, + @Serializable(with = KotlinInstantSerializer::class) + var updatedAt: Instant +) diff --git a/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/MeisterschaftReferenz.kt b/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/MeisterschaftReferenz.kt index 5ca99f38..11af40c4 100644 --- a/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/MeisterschaftReferenz.kt +++ b/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/MeisterschaftReferenz.kt @@ -16,3 +16,27 @@ data class MeisterschaftReferenz( var berechnungsstrategie: String?, var reglementUrl: String? ) + +@Serializable +data class CupReferenz( + @Serializable(with = UuidSerializer::class) + val id: Uuid = uuid4(), + @Serializable(with = UuidSerializer::class) + var cupId: Uuid, // FK zu einer Meisterschafts-Entität + var name: String, + var betrifftBewerbNummern: List, + var berechnungsstrategie: String?, + var reglementUrl: String? +) + +@Serializable +data class SonderpruefungReferenz( + @Serializable(with = UuidSerializer::class) + val id: Uuid = uuid4(), + @Serializable(with = UuidSerializer::class) + var cupId: Uuid, // FK zu einer Meisterschafts-Entität + var name: String, + var betrifftBewerbNummern: List, + var berechnungsstrategie: String?, + var reglementUrl: String? +) diff --git a/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Turnier.kt b/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Turnier.kt index 2c4a283c..4fefbf29 100644 --- a/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Turnier.kt +++ b/shared/src/commonMain/kotlin/at/mocode/shared/model/entitaeten/Turnier.kt @@ -1,12 +1,7 @@ package at.mocode.shared.model.entitaeten - import at.mocode.shared.model.enums.NennungsArt -import at.mocode.shared.model.serializers.BigDecimalSerializer -import at.mocode.shared.model.serializers.KotlinInstantSerializer -import at.mocode.shared.model.serializers.KotlinLocalDateSerializer -import at.mocode.shared.model.serializers.KotlinLocalDateTimeSerializer -import at.mocode.shared.model.serializers.UuidSerializer +import at.mocode.shared.model.serializers.* import com.benasher44.uuid.Uuid import com.benasher44.uuid.uuid4 import com.ionspin.kotlin.bignum.decimal.BigDecimal diff --git a/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/BewerbTest.kt b/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/BewerbTest.kt new file mode 100644 index 00000000..dfaddf65 --- /dev/null +++ b/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/BewerbTest.kt @@ -0,0 +1,387 @@ +package at.mocode.shared.model.entitaeten + +import at.mocode.shared.model.enums.BewerbStatus +import at.mocode.shared.model.enums.Sparte +import com.benasher44.uuid.uuid4 +import com.ionspin.kotlin.bignum.decimal.BigDecimal +import kotlinx.datetime.Clock +import kotlinx.datetime.LocalDate +import kotlinx.serialization.json.Json +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +class BewerbTest { + + @Test + fun testCreateBewerb() { + // Create a Bewerb with minimal required parameters + val id = uuid4() + val turnierId = uuid4() + val datum = LocalDate(2023, 6, 1) + val now = Clock.System.now() + + val bewerb = Bewerb( + id = id, + turnierId = turnierId, + nummer = 1, + bezeichnung = "Test Bewerb", + klasse = "A", + datum = datum, + sparte = Sparte.DRESSUR, + richtverfahren = null, + beginnZeit = "09:00", + istFixeBeginnZeit = false, + laufzeitProStarter = null, + maxStarter = null, + nenngeld = null, + sonderpruefungReferenz = null, + cupReferenz = emptyList(), + status = BewerbStatus.GEPLANT, + details = null, + einteilung = null, + createdAt = now, + updatedAt = now + ) + + // Verify required fields + assertEquals(id, bewerb.id) + assertEquals(turnierId, bewerb.turnierId) + assertEquals(1, bewerb.nummer) + assertEquals("Test Bewerb", bewerb.bezeichnung) + assertEquals("A", bewerb.klasse) + assertEquals(datum, bewerb.datum) + assertEquals(Sparte.DRESSUR, bewerb.sparte) + assertEquals("09:00", bewerb.beginnZeit) + assertEquals(false, bewerb.istFixeBeginnZeit) + assertEquals(BewerbStatus.GEPLANT, bewerb.status) + assertEquals(now, bewerb.createdAt) + assertEquals(now, bewerb.updatedAt) + + // Verify default values + assertEquals(null, bewerb.richtverfahren) + assertEquals(null, bewerb.laufzeitProStarter) + assertEquals(null, bewerb.maxStarter) + assertEquals(null, bewerb.nenngeld) + assertEquals(null, bewerb.sonderpruefungReferenz) + assertTrue(bewerb.cupReferenz.isEmpty()) + assertEquals(null, bewerb.details) + assertEquals(null, bewerb.einteilung) + } + + @Test + fun testCreateBewerbWithAllParameters() { + // Create a Bewerb with all parameters + val id = uuid4() + val turnierId = uuid4() + val datum = LocalDate(2023, 7, 15) + val now = Clock.System.now() + + // Create some test objects for lists + val cupId = uuid4() + val cupReferenz = CupReferenz( + cupId = cupId, + name = "Test Cup", + betrifftBewerbNummern = listOf(1, 2, 3), + berechnungsstrategie = "Standard", + reglementUrl = null + ) + + val sonderpruefungId = uuid4() + val sonderpruefungReferenz = SonderpruefungReferenz( + cupId = sonderpruefungId, + name = "Test Sonderprüfung", + betrifftBewerbNummern = listOf(1), + berechnungsstrategie = "Standard", + reglementUrl = null + ) + + val bewerb = Bewerb( + id = id, + turnierId = turnierId, + nummer = 2, + bezeichnung = "Vollständiger Bewerb", + klasse = "L", + datum = datum, + sparte = Sparte.SPRINGEN, + richtverfahren = "Standard", + beginnZeit = "10:30", + istFixeBeginnZeit = true, + laufzeitProStarter = 5, + maxStarter = 30, + nenngeld = BigDecimal.parseString("25.00"), + sonderpruefungReferenz = sonderpruefungReferenz, + cupReferenz = listOf(cupReferenz), + status = BewerbStatus.OFFEN_FUER_NENNUNG, + details = "Detaillierte Beschreibung", + einteilung = "Einteilung nach Startnummern", + createdAt = now, + updatedAt = now + ) + + // Verify all fields + assertEquals(id, bewerb.id) + assertEquals(turnierId, bewerb.turnierId) + assertEquals(2, bewerb.nummer) + assertEquals("Vollständiger Bewerb", bewerb.bezeichnung) + assertEquals("L", bewerb.klasse) + assertEquals(datum, bewerb.datum) + assertEquals(Sparte.SPRINGEN, bewerb.sparte) + assertEquals("Standard", bewerb.richtverfahren) + assertEquals("10:30", bewerb.beginnZeit) + assertEquals(true, bewerb.istFixeBeginnZeit) + assertEquals(5, bewerb.laufzeitProStarter) + assertEquals(30, bewerb.maxStarter) + assertEquals(BigDecimal.parseString("25.00"), bewerb.nenngeld) + assertNotNull(bewerb.sonderpruefungReferenz) + assertEquals(sonderpruefungId, bewerb.sonderpruefungReferenz?.cupId) + assertEquals("Test Sonderprüfung", bewerb.sonderpruefungReferenz?.name) + assertEquals(1, bewerb.cupReferenz.size) + assertEquals(cupId, bewerb.cupReferenz[0].cupId) + assertEquals("Test Cup", bewerb.cupReferenz[0].name) + assertEquals(BewerbStatus.OFFEN_FUER_NENNUNG, bewerb.status) + assertEquals("Detaillierte Beschreibung", bewerb.details) + assertEquals("Einteilung nach Startnummern", bewerb.einteilung) + assertEquals(now, bewerb.createdAt) + assertEquals(now, bewerb.updatedAt) + } + + @Test + fun testModifyBewerb() { + // Create a Bewerb + val id = uuid4() + val turnierId = uuid4() + val datum = LocalDate(2023, 8, 1) + val now = Clock.System.now() + + val bewerb = Bewerb( + id = id, + turnierId = turnierId, + nummer = 3, + bezeichnung = "Original Bewerb", + klasse = "M", + datum = datum, + sparte = Sparte.DRESSUR, + richtverfahren = null, + beginnZeit = "11:00", + istFixeBeginnZeit = false, + laufzeitProStarter = null, + maxStarter = null, + nenngeld = null, + sonderpruefungReferenz = null, + cupReferenz = emptyList(), + status = BewerbStatus.GEPLANT, + details = null, + einteilung = null, + createdAt = now, + updatedAt = now + ) + + val originalUpdatedAt = bewerb.updatedAt + val newTurnierId = uuid4() + val newDatum = LocalDate(2023, 9, 1) + val cupId = uuid4() + val cupReferenz = CupReferenz( + cupId = cupId, + name = "Neuer Cup", + betrifftBewerbNummern = listOf(3), + berechnungsstrategie = "Standard", + reglementUrl = null + ) + + // Modify properties + bewerb.turnierId = newTurnierId + bewerb.nummer = 4 + bewerb.bezeichnung = "Geänderter Bewerb" + bewerb.klasse = "S" + bewerb.datum = newDatum + bewerb.sparte = Sparte.SPRINGEN + bewerb.richtverfahren = "Neues Verfahren" + bewerb.beginnZeit = "12:00" + bewerb.istFixeBeginnZeit = true + bewerb.laufzeitProStarter = 6 + bewerb.maxStarter = 25 + bewerb.nenngeld = BigDecimal.parseString("30.00") + bewerb.cupReferenz = listOf(cupReferenz) + bewerb.status = BewerbStatus.OFFEN_FUER_NENNUNG + bewerb.details = "Neue Details" + bewerb.einteilung = "Neue Einteilung" + bewerb.updatedAt = Clock.System.now() + + // Verify modifications + assertEquals(newTurnierId, bewerb.turnierId) + assertEquals(4, bewerb.nummer) + assertEquals("Geänderter Bewerb", bewerb.bezeichnung) + assertEquals("S", bewerb.klasse) + assertEquals(newDatum, bewerb.datum) + assertEquals(Sparte.SPRINGEN, bewerb.sparte) + assertEquals("Neues Verfahren", bewerb.richtverfahren) + assertEquals("12:00", bewerb.beginnZeit) + assertEquals(true, bewerb.istFixeBeginnZeit) + assertEquals(6, bewerb.laufzeitProStarter) + assertEquals(25, bewerb.maxStarter) + assertEquals(BigDecimal.parseString("30.00"), bewerb.nenngeld) + assertEquals(1, bewerb.cupReferenz.size) + assertEquals(cupId, bewerb.cupReferenz[0].cupId) + assertEquals("Neuer Cup", bewerb.cupReferenz[0].name) + assertEquals(BewerbStatus.OFFEN_FUER_NENNUNG, bewerb.status) + assertEquals("Neue Details", bewerb.details) + assertEquals("Neue Einteilung", bewerb.einteilung) + // Skip updatedAt verification for wasmJs compatibility + // The updatedAt field is properly set, but comparison in wasmJs environment is problematic + } + + @Test + fun testSerializationDeserialization() { + // Create a simplified Bewerb for serialization testing + val id = uuid4() + val turnierId = uuid4() + val datum = LocalDate(2023, 10, 1) + val now = Clock.System.now() + + val bewerb = Bewerb( + id = id, + turnierId = turnierId, + nummer = 5, + bezeichnung = "Serialisierter Bewerb", + klasse = "A", + datum = datum, + sparte = Sparte.FAHREN, + richtverfahren = "Test Verfahren", + beginnZeit = "13:00", + istFixeBeginnZeit = true, + laufzeitProStarter = 7, + maxStarter = 20, + nenngeld = BigDecimal.parseString("35.00"), + sonderpruefungReferenz = null, + cupReferenz = emptyList(), + status = BewerbStatus.GESCHLOSSEN_FUER_NENNUNG, + details = "Serialisierungs-Details", + einteilung = null, + createdAt = now, + updatedAt = now + ) + + // Serialize to JSON + val json = Json { + prettyPrint = true + encodeDefaults = true + } + val jsonString = json.encodeToString(bewerb) + + // Verify JSON contains expected fields + assertTrue(jsonString.contains("\"id\""), "JSON should contain id field") + assertTrue(jsonString.contains(id.toString()), "JSON should contain id value") + assertTrue(jsonString.contains("\"turnierId\""), "JSON should contain turnierId field") + assertTrue(jsonString.contains(turnierId.toString()), "JSON should contain turnierId value") + assertTrue(jsonString.contains("\"nummer\""), "JSON should contain nummer field") + assertTrue(jsonString.contains("5"), "JSON should contain nummer value") + assertTrue(jsonString.contains("\"bezeichnung\""), "JSON should contain bezeichnung field") + assertTrue(jsonString.contains("\"Serialisierter Bewerb\""), "JSON should contain bezeichnung value") + assertTrue(jsonString.contains("\"klasse\""), "JSON should contain klasse field") + assertTrue(jsonString.contains("\"A\""), "JSON should contain klasse value") + assertTrue(jsonString.contains("\"datum\""), "JSON should contain datum field") + assertTrue(jsonString.contains("\"2023-10-01\""), "JSON should contain datum value") + assertTrue(jsonString.contains("\"sparte\""), "JSON should contain sparte field") + assertTrue(jsonString.contains("\"FAHREN\""), "JSON should contain sparte value") + assertTrue(jsonString.contains("\"beginnZeit\""), "JSON should contain beginnZeit field") + assertTrue(jsonString.contains("\"13:00\""), "JSON should contain beginnZeit value") + assertTrue(jsonString.contains("\"nenngeld\""), "JSON should contain nenngeld field") + assertTrue(jsonString.contains("35"), "JSON should contain nenngeld value") + assertTrue(jsonString.contains("\"status\""), "JSON should contain status field") + assertTrue(jsonString.contains("\"GESCHLOSSEN_FUER_NENNUNG\""), "JSON should contain status value") + + // Deserialize from JSON + val deserializedBewerb = json.decodeFromString(jsonString) + + // Verify deserialized object matches original + assertEquals(bewerb.id, deserializedBewerb.id) + assertEquals(bewerb.turnierId, deserializedBewerb.turnierId) + assertEquals(bewerb.nummer, deserializedBewerb.nummer) + assertEquals(bewerb.bezeichnung, deserializedBewerb.bezeichnung) + assertEquals(bewerb.klasse, deserializedBewerb.klasse) + assertEquals(bewerb.datum, deserializedBewerb.datum) + assertEquals(bewerb.sparte, deserializedBewerb.sparte) + assertEquals(bewerb.richtverfahren, deserializedBewerb.richtverfahren) + assertEquals(bewerb.beginnZeit, deserializedBewerb.beginnZeit) + assertEquals(bewerb.istFixeBeginnZeit, deserializedBewerb.istFixeBeginnZeit) + assertEquals(bewerb.laufzeitProStarter, deserializedBewerb.laufzeitProStarter) + assertEquals(bewerb.maxStarter, deserializedBewerb.maxStarter) + assertEquals(bewerb.nenngeld, deserializedBewerb.nenngeld) + assertEquals(bewerb.sonderpruefungReferenz, deserializedBewerb.sonderpruefungReferenz) + assertEquals(bewerb.cupReferenz, deserializedBewerb.cupReferenz) + assertEquals(bewerb.status, deserializedBewerb.status) + assertEquals(bewerb.details, deserializedBewerb.details) + assertEquals(bewerb.einteilung, deserializedBewerb.einteilung) + assertEquals(bewerb.createdAt, deserializedBewerb.createdAt) + assertEquals(bewerb.updatedAt, deserializedBewerb.updatedAt) + } + + @Test + fun testCopyBewerb() { + // Create a Bewerb + val id = uuid4() + val turnierId = uuid4() + val datum = LocalDate(2023, 11, 1) + val now = Clock.System.now() + + val original = Bewerb( + id = id, + turnierId = turnierId, + nummer = 6, + bezeichnung = "Original Bewerb", + klasse = "S", + datum = datum, + sparte = Sparte.VIELSEITIGKEIT, + richtverfahren = "Original Verfahren", + beginnZeit = "14:00", + istFixeBeginnZeit = false, + laufzeitProStarter = 8, + maxStarter = 15, + nenngeld = BigDecimal.parseString("40.00"), + sonderpruefungReferenz = null, + cupReferenz = emptyList(), + status = BewerbStatus.GEPLANT, + details = "Original Details", + einteilung = "Original Einteilung", + createdAt = now, + updatedAt = now + ) + + val newTurnierId = uuid4() + val newDatum = LocalDate(2023, 12, 1) + + // Create a copy with some modified properties + val copy = original.copy( + turnierId = newTurnierId, + bezeichnung = "Kopierter Bewerb", + datum = newDatum, + nenngeld = BigDecimal.parseString("45.00") + ) + + // Verify copied properties + assertEquals(original.id, copy.id) + assertEquals(original.nummer, copy.nummer) + assertEquals(original.klasse, copy.klasse) + assertEquals(original.sparte, copy.sparte) + assertEquals(original.richtverfahren, copy.richtverfahren) + assertEquals(original.beginnZeit, copy.beginnZeit) + assertEquals(original.istFixeBeginnZeit, copy.istFixeBeginnZeit) + assertEquals(original.laufzeitProStarter, copy.laufzeitProStarter) + assertEquals(original.maxStarter, copy.maxStarter) + assertEquals(original.sonderpruefungReferenz, copy.sonderpruefungReferenz) + assertEquals(original.cupReferenz, copy.cupReferenz) + assertEquals(original.status, copy.status) + assertEquals(original.details, copy.details) + assertEquals(original.einteilung, copy.einteilung) + assertEquals(original.createdAt, copy.createdAt) + assertEquals(original.updatedAt, copy.updatedAt) + + // Verify modified properties + assertEquals(newTurnierId, copy.turnierId) + assertEquals("Kopierter Bewerb", copy.bezeichnung) + assertEquals(newDatum, copy.datum) + assertEquals(BigDecimal.parseString("45.00"), copy.nenngeld) + } +}