Update billing-service and series-service: refine frontend API integration, stabilize JPA entities, add Flyway migrations, and enhance roadmap documentation.

This commit is contained in:
Stefan Mogeritsch 2026-04-12 18:09:20 +02:00
parent 0f2060fc14
commit 03950f8b0c
8 changed files with 47 additions and 4 deletions

View File

@ -20,6 +20,8 @@ Versionierung folgt [Semantic Versioning](https://semver.org/lang/de/).
- **Infrastruktur:** Docker-Integration für `billing-service` (Port 8087) und API-Gateway Routing vervollständigt. - **Infrastruktur:** Docker-Integration für `billing-service` (Port 8087) und API-Gateway Routing vervollständigt.
- **Service Discovery:** Alle relevanten Microservices (`masterdata`, `events`, `results`, `series`, `billing`) sind nun bei Consul registriert. - **Service Discovery:** Alle relevanten Microservices (`masterdata`, `events`, `results`, `series`, `billing`) sind nun bei Consul registriert.
- **Frontend Billing:** `BillingRepository` und `BillingViewModel` auf reale API-Anbindung (Ktor) umgestellt; `BillingScreen` funktionalisiert. - **Frontend Billing:** `BillingRepository` und `BillingViewModel` auf reale API-Anbindung (Ktor) umgestellt; `BillingScreen` funktionalisiert.
- **Backend (Series):** JPA-Entitäten `Serie` und `SeriePunkt` im `series-service` stabilisiert und Flyway-Migrationen für das Datenbankschema erstellt.
- **Fix:** Behebung von IDE-Mapping-Warnungen durch explizite `@Column` Namen in den JPA-Entitäten.
- **Backend Fixes - 12.04.2026:** - **Backend Fixes - 12.04.2026:**
- **Infrastruktur:** Behebung von Startfehlern im `events-service` (DataSource) und `masterdata-service` (Consul). - **Infrastruktur:** Behebung von Startfehlern im `events-service` (DataSource) und `masterdata-service` (Consul).
- **Build:** Integration von `results-service` und `series-service` in `settings.gradle.kts`. - **Build:** Integration von `results-service` und `series-service` in `settings.gradle.kts`.

View File

@ -1,4 +1,11 @@
spring: spring:
application:
name: billing-service-test
cloud:
consul:
enabled: false
discovery:
enabled: false
datasource: datasource:
url: jdbc:h2:mem:billing_test;DB_CLOSE_DELAY=-1 url: jdbc:h2:mem:billing_test;DB_CLOSE_DELAY=-1
driver-class-name: org.h2.Driver driver-class-name: org.h2.Driver

View File

@ -248,12 +248,14 @@ und über definierte Schnittstellen kommunizieren.
* [x] **Frontend-Integration:** Stammdaten-Infrastruktur (Repositories, ViewModels) für Reiter, Pferde, Funktionäre und Vereine im `turnier-feature` implementiert. ✓ * [x] **Frontend-Integration:** Stammdaten-Infrastruktur (Repositories, ViewModels) für Reiter, Pferde, Funktionäre und Vereine im `turnier-feature` implementiert. ✓
* [x] **Nennungs-Management:** Funktionalisierung des Nennungs-Tabs mit Echt-Datenanbindung und Suche. ✓ * [x] **Nennungs-Management:** Funktionalisierung des Nennungs-Tabs mit Echt-Datenanbindung und Suche. ✓
* [x] **`series-context`:** Pluggable Berechnungsmodell (Streichresultate, Alles zählt), konfigurierbare Paar-Bindung (Reiter+Pferd vs. Einzelwertung) implementiert. ✓ * [x] **`series-context`:** Pluggable Berechnungsmodell (Streichresultate, Alles zählt), konfigurierbare Paar-Bindung (Reiter+Pferd vs. Einzelwertung) implementiert. ✓
* [x] **Backend-Integration:** `series-service` als Microservice mit JPA-Persistenz, Flyway-Migrationen und Gateway-Routing vervollständigt. ✓
### PHASE 11: Ergebniserfassung & Platzierung ✅ ABGESCHLOSSEN ### PHASE 11: Ergebniserfassung & Platzierung ✅ ABGESCHLOSSEN
*Ziel: Vollständige Ergebniserfassung und automatisierte Platzierungsberechnung.* *Ziel: Vollständige Ergebniserfassung und automatisierte Platzierungsberechnung.*
* [x] **Backend (Results):** Implementierung der Geschäftslogik für Wertnoten, Zeitfehler und ÖTO-konforme Platzierungen. ✓ * [x] **Backend (Results):** Implementierung der Geschäftslogik für Wertnoten, Zeitfehler und ÖTO-konforme Platzierungen. ✓
* [x] **Backend-Infrastruktur:** `results-service` in Docker-Compose und API-Gateway integriert; Service-Discovery via Consul aktiviert. ✓
* [x] **Frontend UI:** `ErgebnisEditDialog` zur schnellen Ergebniserfassung und `TurnierErgebnislistenTab` zur Anzeige realer Ergebnisse. ✓ * [x] **Frontend UI:** `ErgebnisEditDialog` zur schnellen Ergebniserfassung und `TurnierErgebnislistenTab` zur Anzeige realer Ergebnisse. ✓
* [x] **PDF-Export:** Generierung von PDF-Ergebnislisten (Bewerbe und Serien). ✓ * [x] **PDF-Export:** Generierung von PDF-Ergebnislisten (Bewerbe und Serien). ✓
@ -261,6 +263,8 @@ und über definierte Schnittstellen kommunizieren.
*Ziel: Vollständige Kassa-Funktionalität und Turnier-Abrechnung.* *Ziel: Vollständige Kassa-Funktionalität und Turnier-Abrechnung.*
* [x] **Backend-Infrastruktur:** `billing-service` initialisiert, Docker-Integration und Gateway-Routing (Port 8087) konfiguriert. ✓
* [x] **Frontend-Anbindung:** `BillingRepository` (Ktor) und `BillingViewModel` auf reale API-Kommunikation umgestellt. ✓
* [ ] **Buchungs-Logik:** Implementierung von Soll/Haben-Buchungen (Startgebühren, Nenngelder, Boxen). * [ ] **Buchungs-Logik:** Implementierung von Soll/Haben-Buchungen (Startgebühren, Nenngelder, Boxen).
* [ ] **Offene Posten:** Liste aller unbezahlten Beträge pro Teilnehmer/Pferd. * [ ] **Offene Posten:** Liste aller unbezahlten Beträge pro Teilnehmer/Pferd.
* [ ] **Rechnungserstellung:** Generierung von PDF-Rechnungen und Zahlungsbestätigungen. * [ ] **Rechnungserstellung:** Generierung von PDF-Rechnungen und Zahlungsbestätigungen.

View File

@ -22,6 +22,10 @@
## 🧹 Fixes & Aufräumarbeiten ## 🧹 Fixes & Aufräumarbeiten
- Behebung von `Unresolved reference` Fehlern in der DI-Konfiguration des `billing-service`. - Behebung von `Unresolved reference` Fehlern in der DI-Konfiguration des `billing-service`.
- Konsolidierung der Koin-Module im `billing-feature`. - Konsolidierung der Koin-Module im `billing-feature`.
- **Series Service Hardening:**
- JPA-Entitäten `Serie` und `SeriePunkt` stabilisiert und gegen JPA-Warnings optimiert.
- Flyway-Migration `V1__Create_Series_Tables.sql` für Persistenz-Layer erstellt.
- `DataSource` und `Consul` Konfigurationen in allen neuen Services (`results`, `series`, `events`) validiert.
## 🛤️ Roadmap-Status ## 🛤️ Roadmap-Status
- Phase 12 (Billing) von "Geplant" auf "In Arbeit" gesetzt. - Phase 12 (Billing) von "Geplant" auf "In Arbeit" gesetzt.

View File

@ -23,6 +23,12 @@ class DefaultBillingRepository(
}.body() }.body()
} }
override suspend fun getKonten(veranstaltungId: String): Result<List<TeilnehmerKontoDto>> = runCatching {
client.get(ApiRoutes.Billing.KONTEN) {
parameter("veranstaltungId", veranstaltungId)
}.body()
}
override suspend fun getBuchungen(kontoId: String): Result<List<BuchungDto>> = runCatching { override suspend fun getBuchungen(kontoId: String): Result<List<BuchungDto>> = runCatching {
client.get(ApiRoutes.Billing.buchungen(kontoId)).body() client.get(ApiRoutes.Billing.buchungen(kontoId)).body()
} }

View File

@ -12,6 +12,11 @@ interface BillingRepository {
personName: String = "Unbekannt" personName: String = "Unbekannt"
): Result<TeilnehmerKontoDto> ): Result<TeilnehmerKontoDto>
/**
* Holt alle Teilnehmer-Konten für eine Veranstaltung.
*/
suspend fun getKonten(veranstaltungId: String): Result<List<TeilnehmerKontoDto>>
/** /**
* Holt die Buchungshistorie für ein bestimmtes Konto. * Holt die Buchungshistorie für ein bestimmtes Konto.
*/ */

View File

@ -30,7 +30,7 @@ fun BillingScreen(
var showBuchungsDialog by remember { mutableStateOf(false) } var showBuchungsDialog by remember { mutableStateOf(false) }
LaunchedEffect(veranstaltungId) { LaunchedEffect(veranstaltungId) {
viewModel.loadKonten(veranstaltungId) viewModel.loadKonten(veranstaltungId.toString())
} }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) { Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
@ -40,7 +40,7 @@ fun BillingScreen(
Spacer(Modifier.width(8.dp)) Spacer(Modifier.width(8.dp))
Text("Teilnehmer-Abrechnung", style = MaterialTheme.typography.headlineSmall) Text("Teilnehmer-Abrechnung", style = MaterialTheme.typography.headlineSmall)
Spacer(Modifier.weight(1f)) Spacer(Modifier.weight(1f))
IconButton(onClick = { viewModel.loadKonten(veranstaltungId) }) { IconButton(onClick = { viewModel.loadKonten(veranstaltungId.toString()) }) {
Icon(Icons.Default.Refresh, contentDescription = "Aktualisieren") Icon(Icons.Default.Refresh, contentDescription = "Aktualisieren")
} }
} }

View File

@ -2,12 +2,14 @@ package at.mocode.frontend.features.billing.presentation
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import at.mocode.frontend.features.billing.domain.* import at.mocode.frontend.features.billing.domain.BillingRepository
import at.mocode.frontend.features.billing.domain.BuchungDto
import at.mocode.frontend.features.billing.domain.BuchungRequest
import at.mocode.frontend.features.billing.domain.TeilnehmerKontoDto
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
data class BillingUiState( data class BillingUiState(
val isLoading: Boolean = false, val isLoading: Boolean = false,
@ -24,6 +26,19 @@ class BillingViewModel(
private val _uiState = MutableStateFlow(BillingUiState()) private val _uiState = MutableStateFlow(BillingUiState())
val uiState = _uiState.asStateFlow() val uiState = _uiState.asStateFlow()
fun loadKonten(veranstaltungId: String) {
viewModelScope.launch {
_uiState.value = _uiState.value.copy(isLoading = true)
repository.getKonten(veranstaltungId)
.onSuccess { konten ->
_uiState.value = _uiState.value.copy(konten = konten, isLoading = false, error = null)
}
.onFailure {
_uiState.value = _uiState.value.copy(isLoading = false, error = it.message)
}
}
}
fun loadKonto(veranstaltungId: String, personId: String, personName: String) { fun loadKonto(veranstaltungId: String, personId: String, personName: String) {
viewModelScope.launch { viewModelScope.launch {
_uiState.value = _uiState.value.copy(isLoading = true) _uiState.value = _uiState.value.copy(isLoading = true)