Remove domain models and services related to Abteilung, AbteilungsRegelService, and Bewerb: cleanup unnecessary entities, validation logic, and tests across backend modules.

This commit is contained in:
2026-04-13 21:58:06 +02:00
parent 76d7019d30
commit fb1c1ee4ce
76 changed files with 1091 additions and 267 deletions
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Dieses Modul kapselt die Gebühren-Logik und Abrechnungs-Features (Billing-Sync).
*/
@@ -13,11 +17,24 @@ version = "1.0.0"
kotlin {
jvm()
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
commonMain.dependencies {
implementation(projects.frontend.core.designSystem)
@@ -42,4 +42,8 @@ class DefaultBillingRepository(
override suspend fun getRechnungPdf(kontoId: String): Result<ByteArray> = runCatching {
client.get(ApiRoutes.Billing.rechnung(kontoId)).body()
}
override suspend fun getOffenePosten(veranstaltungId: String): Result<List<TeilnehmerKontoDto>> = runCatching {
client.get(ApiRoutes.Billing.offenePosten(veranstaltungId)).body()
}
}
@@ -61,4 +61,8 @@ class FakeBillingRepository : BillingRepository {
override suspend fun getRechnungPdf(kontoId: String): Result<ByteArray> {
return Result.success("MOCK PDF CONTENT".encodeToByteArray())
}
override suspend fun getOffenePosten(veranstaltungId: String): Result<List<TeilnehmerKontoDto>> {
return Result.success(konten.filter { it.saldoCent < 0 })
}
}
@@ -38,4 +38,11 @@ interface BillingRepository {
suspend fun getRechnungPdf(
kontoId: String
): Result<ByteArray>
/**
* Holt alle Konten mit negativem Saldo für eine Veranstaltung.
*/
suspend fun getOffenePosten(
veranstaltungId: String
): Result<List<TeilnehmerKontoDto>>
}
@@ -37,7 +37,34 @@ fun BillingScreen(
Spacer(Modifier.width(8.dp))
Text("Teilnehmer-Abrechnung", style = MaterialTheme.typography.headlineSmall)
Spacer(Modifier.weight(1f))
IconButton(onClick = { viewModel.loadKonten(veranstaltungId.toString()) }) {
FilterChip(
selected = !state.isOffenePostenMode,
onClick = { viewModel.loadKonten(veranstaltungId.toString()) },
label = { Text("Alle") },
leadingIcon = if (!state.isOffenePostenMode) {
{ Icon(Icons.Default.People, contentDescription = null, modifier = Modifier.size(18.dp)) }
} else null
)
Spacer(Modifier.width(8.dp))
FilterChip(
selected = state.isOffenePostenMode,
onClick = { viewModel.loadOffenePosten(veranstaltungId.toString()) },
label = { Text("Offen") },
leadingIcon = if (state.isOffenePostenMode) {
{ Icon(Icons.Default.Warning, contentDescription = null, modifier = Modifier.size(18.dp), tint = MaterialTheme.colorScheme.error) }
} else null,
colors = FilterChipDefaults.filterChipColors(
selectedContainerColor = MaterialTheme.colorScheme.errorContainer,
selectedLabelColor = MaterialTheme.colorScheme.error
)
)
Spacer(Modifier.width(16.dp))
IconButton(onClick = {
if (state.isOffenePostenMode) viewModel.loadOffenePosten(veranstaltungId.toString())
else viewModel.loadKonten(veranstaltungId.toString())
}) {
Icon(Icons.Default.Refresh, contentDescription = "Aktualisieren")
}
}
@@ -51,15 +78,22 @@ fun BillingScreen(
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Column(modifier = Modifier.padding(8.dp)) {
Text("Teilnehmer", fontWeight = FontWeight.Bold, fontSize = 14.sp)
Text(
if (state.isOffenePostenMode) "Offene Posten" else "Teilnehmer",
fontWeight = FontWeight.Bold,
fontSize = 14.sp,
color = if (state.isOffenePostenMode) MaterialTheme.colorScheme.error else Color.Unspecified
)
HorizontalDivider(Modifier.padding(vertical = 4.dp))
if (state.isLoading && state.konten.isEmpty()) {
if (state.isLoading && (state.konten.isEmpty() && state.offenePosten.isEmpty())) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.CenterHorizontally).padding(16.dp))
}
val displayList = if (state.isOffenePostenMode) state.offenePosten else state.konten
LazyColumn {
items(state.konten) { konto ->
items(displayList) { konto ->
KontoItem(
konto = konto,
isSelected = state.selectedKonto?.id == konto.id,
@@ -16,6 +16,8 @@ data class BillingUiState(
val konten: List<TeilnehmerKontoDto> = emptyList(),
val selectedKonto: TeilnehmerKontoDto? = null,
val buchungen: List<BuchungDto> = emptyList(),
val offenePosten: List<TeilnehmerKontoDto> = emptyList(),
val isOffenePostenMode: Boolean = false,
val pdfData: ByteArray? = null,
val error: String? = null
)
@@ -29,7 +31,7 @@ class BillingViewModel(
fun loadKonten(veranstaltungId: String) {
viewModelScope.launch {
_uiState.value = _uiState.value.copy(isLoading = true, error = null)
_uiState.value = _uiState.value.copy(isLoading = true, error = null, isOffenePostenMode = false)
try {
repository.getKonten(veranstaltungId)
.onSuccess { konten ->
@@ -50,6 +52,22 @@ class BillingViewModel(
}
}
fun loadOffenePosten(veranstaltungId: String) {
viewModelScope.launch {
_uiState.value = _uiState.value.copy(isLoading = true, error = null, isOffenePostenMode = true)
repository.getOffenePosten(veranstaltungId)
.onSuccess { konten ->
_uiState.value = _uiState.value.copy(offenePosten = konten, isLoading = false, error = null)
}
.onFailure {
_uiState.value = _uiState.value.copy(
isLoading = false,
error = "Fehler beim Laden der offenen Posten: ${it.message ?: "Unbekannter Fehler"}"
)
}
}
}
fun loadKonto(veranstaltungId: String, personId: String, personName: String) {
viewModelScope.launch {
_uiState.value = _uiState.value.copy(isLoading = true, error = null)
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Feature-Modul: Funktionärs-Verwaltung (Desktop-only)
*/
@@ -13,21 +17,53 @@ version = "1.0.0"
kotlin {
jvm()
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
jvmMain.dependencies {
commonMain.dependencies {
implementation(projects.frontend.core.designSystem)
implementation(projects.frontend.core.network)
implementation(projects.frontend.core.domain)
implementation(projects.frontend.core.navigation)
implementation(compose.desktop.currentOs)
implementation(projects.core.coreDomain)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
implementation(libs.bundles.kmp.common)
implementation(libs.bundles.compose.common)
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
}
jvmMain.dependencies {
implementation(compose.uiTooling)
}
}
}
@@ -1,3 +1,5 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
@@ -15,9 +17,23 @@ version = "1.0.0"
kotlin {
jvm()
@OptIn(ExperimentalWasmDsl::class)
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
browser()
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
@@ -25,13 +41,16 @@ kotlin {
implementation(projects.frontend.core.designSystem)
implementation(projects.frontend.core.domain)
implementation(libs.kotlinx.datetime)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.materialIconsExtended)
implementation(libs.bundles.kmp.common)
implementation(libs.bundles.compose.common)
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Feature-Modul: Pferde-Verwaltung (Desktop-only)
*/
@@ -12,21 +16,53 @@ version = "1.0.0"
kotlin {
jvm()
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
jvmMain.dependencies {
commonMain.dependencies {
implementation(projects.frontend.core.designSystem)
implementation(projects.frontend.core.network)
implementation(projects.frontend.core.domain)
implementation(projects.frontend.core.navigation)
implementation(compose.desktop.currentOs)
implementation(projects.core.coreDomain)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
implementation(libs.bundles.kmp.common)
implementation(libs.bundles.compose.common)
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
}
jvmMain.dependencies {
implementation(compose.uiTooling)
}
}
}
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Dieses Modul kapselt die gesamte UI und Logik für das Ping-Feature.
*/
@@ -13,7 +17,17 @@ version = "1.0.0"
kotlin {
jvm()
js {
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
binaries.library()
browser {
testTask {
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Dieses Modul kapselt die UI und Logik für die Profil-Verwaltung und den ZNS-Link.
*/
@@ -14,6 +18,24 @@ version = "1.0.0"
kotlin {
jvm()
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
commonMain.dependencies {
implementation(projects.frontend.core.designSystem)
@@ -1,3 +1,5 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
@@ -12,27 +14,53 @@ group = "at.mocode.clients"
version = "1.0.0"
kotlin {
jvm()
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
commonMain.dependencies {
implementation(projects.frontend.core.designSystem)
implementation(projects.frontend.core.network)
implementation(projects.frontend.core.domain)
implementation(projects.frontend.core.navigation)
implementation(projects.core.coreDomain)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
implementation(libs.bundles.kmp.common)
implementation(libs.bundles.compose.common)
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
}
jvmMain.dependencies {
implementation(compose.desktop.currentOs)
implementation(compose.uiTooling)
}
}
}
@@ -1,8 +1,10 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Feature-Modul: Turnier-Verwaltung (Desktop-only)
* Kapselt alle Screens und Tabs für Turnier-Detail, -Neuanlage und alle Turnier-Tabs
* kapselt alle Screens und Tabs für Turnier-Detail, -Neuanlage und alle Turnier-Tabs
* (Stammdaten, Organisation, Bewerbe, Artikel, Abrechnung, Nennungen, Startlisten, Ergebnislisten).
*/
plugins {
@@ -14,9 +16,23 @@ group = "at.mocode.clients"
version = "1.0.0"
kotlin {
jvm()
@OptIn(ExperimentalWasmDsl::class)
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
browser()
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
@@ -27,16 +43,20 @@ kotlin {
implementation(projects.frontend.core.navigation)
implementation(projects.frontend.features.billingFeature)
implementation(projects.core.znsParser)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.materialIconsExtended)
implementation(libs.bundles.kmp.common)
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
implementation(libs.ktor.client.core)
implementation(libs.bundles.kmp.common)
}
jvmMain.dependencies {
@@ -1,5 +1,7 @@
package at.mocode.turnier.feature.domain
import at.mocode.zns.parser.ZnsBewerb
data class Bewerb(
val id: Long,
val turnierId: Long,
@@ -44,5 +46,5 @@ interface BewerbRepository {
suspend fun getAuditLog(bewerbId: Long): Result<List<AuditLogEntry>>
suspend fun exportZnsBSatz(turnierId: Long): Result<String>
suspend fun delete(id: Long): Result<Unit>
suspend fun importBewerbe(turnierId: Long, bewerbe: List<at.mocode.zns.parser.ZnsBewerb>): Result<Unit>
suspend fun importBewerbe(turnierId: Long, bewerbe: List<ZnsBewerb>): Result<Unit>
}
@@ -0,0 +1,7 @@
package at.mocode.turnier.feature.di
import org.koin.dsl.module
actual val turnierFeatureModule = module {
// No-op or minimal for JS/Web
}
@@ -14,6 +14,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.sun.tools.javac.code.Type
import java.time.LocalDate
private val PrimaryBlue = Color(0xFF1E3A8A)
@@ -27,6 +28,7 @@ private val AccentBlue = Color(0xFF3B82F6)
* - Turnier-Beschreibung: Titel, Sub-Titel
* - Sponsoren
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun StammdatenTabContent(
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Feature-Modul: Veranstalter-Verwaltung (Desktop-only)
* Kapselt alle Screens und Logik für Veranstalter-Auswahl, -Detail und -Neuanlage.
@@ -11,31 +15,53 @@ group = "at.mocode.clients"
version = "1.0.0"
kotlin {
jvm()
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
browser()
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
commonMain.dependencies {
implementation(projects.frontend.core.designSystem)
implementation(projects.frontend.core.domain)
implementation(projects.frontend.core.network)
implementation(projects.frontend.core.navigation)
implementation(projects.frontend.core.domain)
implementation(projects.core.coreDomain)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
implementation(libs.bundles.kmp.common)
implementation(libs.bundles.compose.common)
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
implementation(libs.ktor.client.core)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
}
jvmMain.dependencies {
implementation(compose.desktop.currentOs)
implementation(compose.uiTooling)
}
}
}
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Feature-Modul: Veranstaltungs-Verwaltung (Desktop-only)
* Kapselt alle Screens und Logik für Veranstaltungs-Übersicht, -Detail und -Neuanlage.
@@ -11,29 +15,53 @@ group = "at.mocode.clients"
version = "1.0.0"
kotlin {
jvm()
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
browser()
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
commonMain.dependencies {
implementation(projects.frontend.core.designSystem)
implementation(projects.frontend.core.network)
implementation(projects.frontend.core.domain)
implementation(projects.frontend.core.navigation)
implementation(projects.core.coreDomain)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
implementation(libs.bundles.kmp.common)
implementation(libs.bundles.compose.common)
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
}
jvmMain.dependencies {
implementation(compose.desktop.currentOs)
implementation(compose.uiTooling)
}
}
}
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Feature-Modul: Vereins-Verwaltung (Desktop-only)
*/
@@ -12,23 +16,47 @@ version = "1.0.0"
kotlin {
jvm()
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
jvmMain.dependencies {
commonMain.dependencies {
implementation(projects.frontend.core.designSystem)
implementation(projects.frontend.core.domain)
implementation(projects.frontend.core.navigation)
implementation(projects.frontend.core.network)
implementation(compose.desktop.currentOs)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.materialIconsExtended)
implementation(libs.bundles.kmp.common)
implementation(libs.bundles.ktor.client.common)
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
}
jvmMain.dependencies {
implementation(compose.desktop.currentOs)
}
}
}
@@ -1,3 +1,7 @@
@file:OptIn(ExperimentalWasmDsl::class)
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
/**
* Feature-Modul: ZNS-Stammdaten-Import (Desktop-only)
* Kapselt ViewModel, State, API-Kommunikation und UI-Screen für den ZNS-Import.
@@ -12,27 +16,55 @@ version = "1.0.0"
kotlin {
jvm()
js(IR) {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
wasmJs {
binaries.library()
browser {
testTask {
enabled = false
}
}
}
sourceSets {
jvmMain.dependencies {
implementation(projects.frontend.core.designSystem)
implementation(projects.frontend.core.network)
implementation(projects.frontend.core.auth)
implementation(projects.frontend.core.domain)
implementation(projects.frontend.core.navigation)
implementation(compose.desktop.currentOs)
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.materialIconsExtended)
implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel)
implementation(libs.bundles.kmp.common)
implementation(libs.koin.core)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.contentNegotiation)
implementation(libs.ktor.client.serialization.kotlinx.json)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.bundles.kmp.common)
}
}
}
@@ -18,6 +18,7 @@ import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.io.File
import kotlin.time.Duration.Companion.milliseconds
data class ZnsImportState(
val selectedFilePath: String? = null,
@@ -123,7 +124,7 @@ class ZnsImportViewModel(
state = state.copy(errorMessage = "Polling-Fehler: ${e.message}", isFinished = true)
break
}
delay(POLLING_INTERVAL_MS)
delay(POLLING_INTERVAL_MS.milliseconds)
}
}
}