feat(billing): introduce billing domain and service infrastructure
- **Billing Domain:** - Added Kotlin Multiplatform project with domain models (`TeilnehmerKonto`, `Buchung`, `BuchungsTyp`) to represent billing entities. - Defined serialization strategies using `InstantSerializer`. - **Service Implementation:** - Introduced `BillingServiceApplication` as the main entry point for the billing service. - Developed `TeilnehmerKontoService` for account management and transactions. - **Persistence Layer:** - Implemented Exposed repositories (`ExposedTeilnehmerKontoRepository`, `ExposedBillingRepositories`) for database interaction. - Added table definitions (`TeilnehmerKontoTable`, `BuchungTable`) with indexes for efficient querying. - **Build Configuration:** - Setup Gradle build files for billing domain and service modules with dependencies for Kotlin, Serialization, Spring Boot, and Exposed. - **Test Additions:** - Extended ZNS importer tests with new scenarios for qualification parsing
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
js(IR) {
|
||||
browser()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation(projects.core.coreDomain)
|
||||
implementation(projects.core.coreUtils)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
}
|
||||
}
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
@file:OptIn(ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.billing.domain.model
|
||||
|
||||
import at.mocode.core.domain.serialization.InstantSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Repräsentiert das Kassa-Konto eines Teilnehmers (Reiter oder Besitzer).
|
||||
* Ein Konto wird pro Veranstaltung/Turnier geführt, kann aber veranstaltungsübergreifend aggregiert werden.
|
||||
*/
|
||||
@Serializable
|
||||
data class TeilnehmerKonto constructor(
|
||||
val kontoId: Uuid = Uuid.random(),
|
||||
val veranstaltungId: Uuid,
|
||||
val personId: Uuid, // Referenz auf Reiter oder Besitzer
|
||||
val personName: String,
|
||||
val saldoCent: Long = 0L, // Aktueller Kontostand in Cent
|
||||
val bemerkungen: String? = null,
|
||||
@Serializable(with = InstantSerializer::class)
|
||||
val updatedAt: Instant = Clock.System.now()
|
||||
)
|
||||
|
||||
/**
|
||||
* Ein einzelner Buchungsvorgang (Zahlung, Gutschrift, Gebühr).
|
||||
*/
|
||||
@Serializable
|
||||
data class Buchung constructor(
|
||||
val buchungId: Uuid = Uuid.random(),
|
||||
val kontoId: Uuid,
|
||||
val betragCent: Long, // Positiv für Gutschrift/Zahlung, Negativ für Gebühr/Soll
|
||||
val typ: BuchungsTyp,
|
||||
val verwendungszweck: String,
|
||||
@Serializable(with = InstantSerializer::class)
|
||||
val gebuchtAm: Instant = Clock.System.now()
|
||||
)
|
||||
|
||||
@Serializable
|
||||
enum class BuchungsTyp {
|
||||
NENNGEBUEHR,
|
||||
STARTGEBUEHR,
|
||||
BOXENGEBUEHR,
|
||||
ZAHLUNG_BAR,
|
||||
ZAHLUNG_KARTE,
|
||||
GUTSCHRIFT,
|
||||
STORNIERUNG
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
@file:OptIn(ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.billing.domain.repository
|
||||
|
||||
import at.mocode.billing.domain.model.Buchung
|
||||
import at.mocode.billing.domain.model.TeilnehmerKonto
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Repository für den Zugriff auf Teilnehmer-Konten.
|
||||
*/
|
||||
interface TeilnehmerKontoRepository {
|
||||
fun findByVeranstaltungAndPerson(veranstaltungId: Uuid, personId: Uuid): TeilnehmerKonto?
|
||||
fun findById(kontoId: Uuid): TeilnehmerKonto?
|
||||
fun save(konto: TeilnehmerKonto): TeilnehmerKonto
|
||||
fun updateSaldo(kontoId: Uuid, saldoCent: Long): Long
|
||||
}
|
||||
|
||||
/**
|
||||
* Repository für den Zugriff auf Buchungen.
|
||||
*/
|
||||
interface BuchungRepository {
|
||||
fun findByKonto(kontoId: Uuid): List<Buchung>
|
||||
fun save(buchung: Buchung): Buchung
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.spring.boot)
|
||||
alias(libs.plugins.spring.dependencyManagement)
|
||||
alias(libs.plugins.kotlinSpring)
|
||||
}
|
||||
|
||||
springBoot {
|
||||
mainClass.set("at.mocode.billing.service.BillingServiceApplicationKt")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Interne Module
|
||||
implementation(projects.platform.platformDependencies)
|
||||
implementation(projects.core.coreUtils)
|
||||
implementation(projects.backend.services.billing.billingDomain)
|
||||
|
||||
// Spring Boot Starters
|
||||
implementation(libs.spring.boot.starter.web)
|
||||
implementation(libs.spring.boot.starter.validation)
|
||||
implementation(libs.spring.boot.starter.actuator)
|
||||
implementation(libs.jackson.module.kotlin)
|
||||
|
||||
// Datenbank-Abhängigkeiten
|
||||
implementation(libs.exposed.core)
|
||||
implementation(libs.exposed.dao)
|
||||
implementation(libs.exposed.jdbc)
|
||||
implementation(libs.exposed.kotlin.datetime)
|
||||
implementation(libs.hikari.cp)
|
||||
runtimeOnly(libs.postgresql.driver)
|
||||
testRuntimeOnly(libs.h2.driver)
|
||||
|
||||
// Testing
|
||||
testImplementation(projects.platform.platformTesting)
|
||||
testImplementation(libs.spring.boot.starter.test)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
@file:OptIn(ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.billing.service
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
|
||||
@SpringBootApplication
|
||||
class BillingServiceApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<BillingServiceApplication>(*args)
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
@file:OptIn(ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.billing.service
|
||||
|
||||
import at.mocode.billing.domain.model.Buchung
|
||||
import at.mocode.billing.domain.model.BuchungsTyp
|
||||
import at.mocode.billing.domain.model.TeilnehmerKonto
|
||||
import at.mocode.billing.domain.repository.BuchungRepository
|
||||
import at.mocode.billing.domain.repository.TeilnehmerKontoRepository
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import org.springframework.stereotype.Service
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
@Service
|
||||
class TeilnehmerKontoService(
|
||||
private val kontoRepository: TeilnehmerKontoRepository,
|
||||
private val buchungRepository: BuchungRepository
|
||||
) {
|
||||
|
||||
fun getOrCreateKonto(veranstaltungId: Uuid, personId: Uuid, personName: String): TeilnehmerKonto {
|
||||
return transaction {
|
||||
kontoRepository.findByVeranstaltungAndPerson(veranstaltungId, personId)
|
||||
?: kontoRepository.save(
|
||||
TeilnehmerKonto(
|
||||
veranstaltungId = veranstaltungId,
|
||||
personId = personId,
|
||||
personName = personName
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun bucheBetrag(kontoId: Uuid, betragCent: Long, typ: BuchungsTyp, verwendungszweck: String): Buchung {
|
||||
return transaction {
|
||||
val konto = kontoRepository.findById(kontoId) ?: throw IllegalArgumentException("Konto nicht gefunden: $kontoId")
|
||||
|
||||
val buchung = Buchung(
|
||||
kontoId = kontoId,
|
||||
betragCent = betragCent,
|
||||
typ = typ,
|
||||
verwendungszweck = verwendungszweck
|
||||
)
|
||||
|
||||
val neueBuchung = buchungRepository.save(buchung)
|
||||
kontoRepository.updateSaldo(kontoId, konto.saldoCent + betragCent)
|
||||
|
||||
neueBuchung
|
||||
}
|
||||
}
|
||||
|
||||
fun getBuchungen(kontoId: Uuid): List<Buchung> {
|
||||
return buchungRepository.findByKonto(kontoId)
|
||||
}
|
||||
|
||||
fun getKonto(kontoId: Uuid): TeilnehmerKonto? {
|
||||
return kontoRepository.findById(kontoId)
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
@file:OptIn(ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.billing.service.persistence
|
||||
|
||||
import org.jetbrains.exposed.v1.core.Table
|
||||
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
|
||||
import org.jetbrains.exposed.v1.datetime.timestamp
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
|
||||
/**
|
||||
* Exposed-Tabellendefinition für das Teilnehmer-Konto.
|
||||
*/
|
||||
object TeilnehmerKontoTable : Table("teilnehmer_konten") {
|
||||
val id = uuid("konto_id")
|
||||
val veranstaltungId = uuid("veranstaltung_id")
|
||||
val personId = uuid("person_id")
|
||||
val personName = varchar("person_name", 200)
|
||||
val saldoCent = long("saldo_cent").default(0L)
|
||||
val bemerkungen = text("bemerkungen").nullable()
|
||||
|
||||
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
|
||||
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
|
||||
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
|
||||
init {
|
||||
index("idx_konto_veranstaltung_person", isUnique = true, veranstaltungId, personId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposed-Tabellendefinition für Buchungen.
|
||||
*/
|
||||
object BuchungTable : Table("buchungen") {
|
||||
val id = uuid("buchung_id")
|
||||
val kontoId = uuid("konto_id")
|
||||
val betragCent = long("betrag_cent")
|
||||
val typ = varchar("typ", 50)
|
||||
val verwendungszweck = varchar("verwendungszweck", 500)
|
||||
val gebuchtAm = timestamp("gebucht_am").defaultExpression(CurrentTimestamp)
|
||||
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
|
||||
init {
|
||||
index("idx_buchung_konto", isUnique = false, kontoId)
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
@file:OptIn(ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.billing.service.persistence
|
||||
|
||||
import at.mocode.billing.domain.model.Buchung
|
||||
import at.mocode.billing.domain.model.BuchungsTyp
|
||||
import at.mocode.billing.domain.model.TeilnehmerKonto
|
||||
import at.mocode.billing.domain.repository.BuchungRepository
|
||||
import at.mocode.billing.domain.repository.TeilnehmerKontoRepository
|
||||
import org.jetbrains.exposed.v1.core.ResultRow
|
||||
import org.jetbrains.exposed.v1.core.and
|
||||
import org.jetbrains.exposed.v1.core.eq
|
||||
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
|
||||
import org.jetbrains.exposed.v1.jdbc.insert
|
||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||
import org.jetbrains.exposed.v1.jdbc.update
|
||||
import org.springframework.stereotype.Repository
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
@Repository
|
||||
class ExposedTeilnehmerKontoRepository : TeilnehmerKontoRepository {
|
||||
|
||||
override fun findByVeranstaltungAndPerson(veranstaltungId: Uuid, personId: Uuid): TeilnehmerKonto? {
|
||||
return TeilnehmerKontoTable
|
||||
.selectAll()
|
||||
.where { (TeilnehmerKontoTable.veranstaltungId eq veranstaltungId) and (TeilnehmerKontoTable.personId eq personId) }
|
||||
.singleOrNull()
|
||||
?.toModel()
|
||||
}
|
||||
|
||||
override fun findById(kontoId: Uuid): TeilnehmerKonto? {
|
||||
return TeilnehmerKontoTable
|
||||
.selectAll()
|
||||
.where { TeilnehmerKontoTable.id eq kontoId }
|
||||
.singleOrNull()
|
||||
?.toModel()
|
||||
}
|
||||
|
||||
override fun save(konto: TeilnehmerKonto): TeilnehmerKonto {
|
||||
val existing = findById(konto.kontoId)
|
||||
if (existing == null) {
|
||||
TeilnehmerKontoTable.insert {
|
||||
it[id] = konto.kontoId
|
||||
it[veranstaltungId] = konto.veranstaltungId
|
||||
it[personId] = konto.personId
|
||||
it[personName] = konto.personName
|
||||
it[saldoCent] = konto.saldoCent
|
||||
it[bemerkungen] = konto.bemerkungen
|
||||
}
|
||||
} else {
|
||||
TeilnehmerKontoTable.update({ TeilnehmerKontoTable.id eq konto.kontoId }) {
|
||||
it[personName] = konto.personName
|
||||
it[saldoCent] = konto.saldoCent
|
||||
it[bemerkungen] = konto.bemerkungen
|
||||
it[updatedAt] = CurrentTimestamp
|
||||
}
|
||||
}
|
||||
return findById(konto.kontoId)!!
|
||||
}
|
||||
|
||||
override fun updateSaldo(kontoId: Uuid, saldoCent: Long): Long {
|
||||
TeilnehmerKontoTable.update({ TeilnehmerKontoTable.id eq kontoId }) {
|
||||
it[this.saldoCent] = saldoCent
|
||||
it[updatedAt] = CurrentTimestamp
|
||||
}
|
||||
return saldoCent
|
||||
}
|
||||
|
||||
private fun ResultRow.toModel() = TeilnehmerKonto(
|
||||
kontoId = this[TeilnehmerKontoTable.id],
|
||||
veranstaltungId = this[TeilnehmerKontoTable.veranstaltungId],
|
||||
personId = this[TeilnehmerKontoTable.personId],
|
||||
personName = this[TeilnehmerKontoTable.personName],
|
||||
saldoCent = this[TeilnehmerKontoTable.saldoCent],
|
||||
bemerkungen = this[TeilnehmerKontoTable.bemerkungen],
|
||||
updatedAt = this[TeilnehmerKontoTable.updatedAt]
|
||||
)
|
||||
}
|
||||
|
||||
@Repository
|
||||
class ExposedBuchungRepository : BuchungRepository {
|
||||
|
||||
override fun findByKonto(kontoId: Uuid): List<Buchung> {
|
||||
return BuchungTable
|
||||
.selectAll()
|
||||
.where { BuchungTable.kontoId eq kontoId }
|
||||
.map { it.toModel() }
|
||||
}
|
||||
|
||||
override fun save(buchung: Buchung): Buchung {
|
||||
BuchungTable.insert {
|
||||
it[id] = buchung.buchungId
|
||||
it[kontoId] = buchung.kontoId
|
||||
it[betragCent] = buchung.betragCent
|
||||
it[typ] = buchung.typ.name
|
||||
it[verwendungszweck] = buchung.verwendungszweck
|
||||
it[gebuchtAm] = buchung.gebuchtAm
|
||||
}
|
||||
return buchung
|
||||
}
|
||||
|
||||
private fun ResultRow.toModel() = Buchung(
|
||||
buchungId = this[BuchungTable.id],
|
||||
kontoId = this[BuchungTable.kontoId],
|
||||
betragCent = this[BuchungTable.betragCent],
|
||||
typ = BuchungsTyp.valueOf(this[BuchungTable.typ]),
|
||||
verwendungszweck = this[BuchungTable.verwendungszweck],
|
||||
gebuchtAm = this[BuchungTable.gebuchtAm]
|
||||
)
|
||||
}
|
||||
+772
-5
@@ -8,15 +8,20 @@ servers:
|
||||
- url: http://localhost:8091
|
||||
description: Lokaler Entwicklungs-Server
|
||||
paths:
|
||||
/reiter/search:
|
||||
/reiter:
|
||||
get:
|
||||
summary: Sucht Reiter
|
||||
summary: Alle Reiter abrufen (paginiert)
|
||||
parameters:
|
||||
- name: q
|
||||
- name: limit
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
type: integer
|
||||
default: 100
|
||||
- name: offset
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
responses:
|
||||
'200':
|
||||
description: Liste von Reitern
|
||||
@@ -26,6 +31,450 @@ paths:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Reiter'
|
||||
post:
|
||||
summary: Neuen Reiter erstellen
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReiterCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Reiter erstellt
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Reiter'
|
||||
/reiter/{id}:
|
||||
get:
|
||||
summary: Reiter nach ID abrufen
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'200':
|
||||
description: Reiter Details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Reiter'
|
||||
'404':
|
||||
description: Nicht gefunden
|
||||
put:
|
||||
summary: Reiter aktualisieren
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReiterUpdateRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Reiter aktualisiert
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Reiter'
|
||||
'404':
|
||||
description: Nicht gefunden
|
||||
delete:
|
||||
summary: Reiter löschen
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'204':
|
||||
description: Erfolgreich gelöscht
|
||||
'404':
|
||||
description: Nicht gefunden
|
||||
/reiter/search:
|
||||
get:
|
||||
summary: Sucht Reiter nach Satznummer
|
||||
parameters:
|
||||
- name: q
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Liste von Reitern (Satznummer Match)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Reiter'
|
||||
/reiter/satznummer/{nr}:
|
||||
get:
|
||||
summary: Reiter nach Satznummer suchen
|
||||
parameters:
|
||||
- name: nr
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Reiter gefunden
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Reiter'
|
||||
'404':
|
||||
description: Nicht gefunden
|
||||
/horse:
|
||||
get:
|
||||
summary: Alle Pferde abrufen (paginiert)
|
||||
parameters:
|
||||
- name: jahrgang
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
- name: limit
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 100
|
||||
- name: offset
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
responses:
|
||||
'200':
|
||||
description: Liste von Pferden
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Horse'
|
||||
post:
|
||||
summary: Neues Pferd erstellen
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HorseCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Pferd erstellt
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Horse'
|
||||
/horse/{id}:
|
||||
get:
|
||||
summary: Pferd nach ID abrufen
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'200':
|
||||
description: Pferd Details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Horse'
|
||||
'404':
|
||||
description: Nicht gefunden
|
||||
put:
|
||||
summary: Pferd aktualisieren
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HorseUpdateRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Pferd aktualisiert
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Horse'
|
||||
delete:
|
||||
summary: Pferd löschen
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'204':
|
||||
description: Gelöscht
|
||||
/horse/search:
|
||||
get:
|
||||
summary: Sucht Pferde nach Lebensnummer
|
||||
parameters:
|
||||
- name: q
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Liste von Pferden
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Horse'
|
||||
/verein:
|
||||
get:
|
||||
summary: Alle Vereine abrufen (paginiert)
|
||||
parameters:
|
||||
- name: limit
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 100
|
||||
- name: offset
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
responses:
|
||||
'200':
|
||||
description: Liste von Vereinen
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Verein'
|
||||
post:
|
||||
summary: Neuen Verein erstellen
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/VereinCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Verein erstellt
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Verein'
|
||||
/verein/{id}:
|
||||
get:
|
||||
summary: Verein nach ID abrufen
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'200':
|
||||
description: Verein Details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Verein'
|
||||
'404':
|
||||
description: Nicht gefunden
|
||||
put:
|
||||
summary: Verein aktualisieren
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/VereinUpdateRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Verein aktualisiert
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Verein'
|
||||
delete:
|
||||
summary: Verein löschen
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'204':
|
||||
description: Gelöscht
|
||||
/funktionaer:
|
||||
get:
|
||||
summary: Alle Funktionäre abrufen (paginiert)
|
||||
parameters:
|
||||
- name: limit
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 100
|
||||
- name: offset
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
responses:
|
||||
'200':
|
||||
description: Liste von Funktionären
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Funktionaer'
|
||||
post:
|
||||
summary: Neuen Funktionär erstellen
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/FunktionaerCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Funktionär erstellt
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Funktionaer'
|
||||
/funktionaer/{id}:
|
||||
get:
|
||||
summary: Funktionär nach ID abrufen
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'200':
|
||||
description: Funktionär Details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Funktionaer'
|
||||
'404':
|
||||
description: Nicht gefunden
|
||||
put:
|
||||
summary: Funktionär aktualisieren
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/FunktionaerUpdateRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Funktionär aktualisiert
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Funktionaer'
|
||||
delete:
|
||||
summary: Funktionär löschen
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'204':
|
||||
description: Gelöscht
|
||||
/funktionaer/search:
|
||||
get:
|
||||
summary: Sucht Funktionäre nach SatzNummer
|
||||
parameters:
|
||||
- name: q
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: Liste von Funktionären
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Funktionaer'
|
||||
/funktionaer/satz/{satzId}/{satzNummer}:
|
||||
get:
|
||||
summary: Funktionär nach Satz-ID und Nummer suchen
|
||||
parameters:
|
||||
- name: satzId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: satzNummer
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: Funktionär gefunden
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Funktionaer'
|
||||
'404':
|
||||
description: Nicht gefunden
|
||||
/rules/turnierklassen:
|
||||
get:
|
||||
summary: Alle Turnierklassen abrufen
|
||||
@@ -58,9 +507,327 @@ components:
|
||||
reiterId:
|
||||
type: string
|
||||
format: uuid
|
||||
satznummer:
|
||||
type: string
|
||||
nachname:
|
||||
type: string
|
||||
vorname:
|
||||
type: string
|
||||
geburtsdatum:
|
||||
type: string
|
||||
format: date
|
||||
bundeslandNummer:
|
||||
type: integer
|
||||
vereinsName:
|
||||
type: string
|
||||
nation:
|
||||
type: string
|
||||
reiterLizenz:
|
||||
type: string
|
||||
startkarte:
|
||||
type: string
|
||||
fahrLizenz:
|
||||
type: string
|
||||
mitgliedsNummer:
|
||||
type: integer
|
||||
telefonNummer:
|
||||
type: string
|
||||
lastPayYear:
|
||||
type: integer
|
||||
feiId:
|
||||
type: string
|
||||
lizenzKlasse:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
ReiterCreateRequest:
|
||||
type: object
|
||||
required:
|
||||
- satznummer
|
||||
- nachname
|
||||
- vorname
|
||||
properties:
|
||||
satznummer:
|
||||
type: string
|
||||
nachname:
|
||||
type: string
|
||||
vorname:
|
||||
type: string
|
||||
geburtsdatum:
|
||||
type: string
|
||||
format: date
|
||||
bundeslandNummer:
|
||||
type: integer
|
||||
vereinsName:
|
||||
type: string
|
||||
nation:
|
||||
type: string
|
||||
reiterLizenz:
|
||||
type: string
|
||||
startkarte:
|
||||
type: string
|
||||
fahrLizenz:
|
||||
type: string
|
||||
mitgliedsNummer:
|
||||
type: integer
|
||||
telefonNummer:
|
||||
type: string
|
||||
lastPayYear:
|
||||
type: integer
|
||||
feiId:
|
||||
type: string
|
||||
lizenzKlasse:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
ReiterUpdateRequest:
|
||||
type: object
|
||||
properties:
|
||||
nachname:
|
||||
type: string
|
||||
vorname:
|
||||
type: string
|
||||
geburtsdatum:
|
||||
type: string
|
||||
format: date
|
||||
bundeslandNummer:
|
||||
type: integer
|
||||
vereinsName:
|
||||
type: string
|
||||
nation:
|
||||
type: string
|
||||
reiterLizenz:
|
||||
type: string
|
||||
startkarte:
|
||||
type: string
|
||||
fahrLizenz:
|
||||
type: string
|
||||
mitgliedsNummer:
|
||||
type: integer
|
||||
telefonNummer:
|
||||
type: string
|
||||
lastPayYear:
|
||||
type: integer
|
||||
feiId:
|
||||
type: string
|
||||
lizenzKlasse:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
Horse:
|
||||
type: object
|
||||
properties:
|
||||
pferdId:
|
||||
type: string
|
||||
format: uuid
|
||||
kopfnummer:
|
||||
type: string
|
||||
pferdeName:
|
||||
type: string
|
||||
lebensnummer:
|
||||
type: string
|
||||
geschlecht:
|
||||
type: string
|
||||
geburtsjahr:
|
||||
type: integer
|
||||
farbe:
|
||||
type: string
|
||||
satznummer:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
HorseCreateRequest:
|
||||
type: object
|
||||
required:
|
||||
- pferdeName
|
||||
- geschlecht
|
||||
properties:
|
||||
kopfnummer:
|
||||
type: string
|
||||
pferdeName:
|
||||
type: string
|
||||
lebensnummer:
|
||||
type: string
|
||||
geschlecht:
|
||||
type: string
|
||||
geburtsjahr:
|
||||
type: integer
|
||||
farbe:
|
||||
type: string
|
||||
satznummer:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
HorseUpdateRequest:
|
||||
type: object
|
||||
properties:
|
||||
kopfnummer:
|
||||
type: string
|
||||
pferdeName:
|
||||
type: string
|
||||
lebensnummer:
|
||||
type: string
|
||||
geschlecht:
|
||||
type: string
|
||||
geburtsjahr:
|
||||
type: integer
|
||||
farbe:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
Verein:
|
||||
type: object
|
||||
properties:
|
||||
vereinId:
|
||||
type: string
|
||||
format: uuid
|
||||
vereinsNummer:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
bundesland:
|
||||
type: string
|
||||
ort:
|
||||
type: string
|
||||
plz:
|
||||
type: string
|
||||
strasse:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
telefon:
|
||||
type: string
|
||||
website:
|
||||
type: string
|
||||
istVeranstalter:
|
||||
type: boolean
|
||||
istAktiv:
|
||||
type: boolean
|
||||
imageUrl:
|
||||
type: string
|
||||
bemerkungen:
|
||||
type: string
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
VereinCreateRequest:
|
||||
type: object
|
||||
required:
|
||||
- vereinsNummer
|
||||
- name
|
||||
properties:
|
||||
vereinsNummer:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
bundesland:
|
||||
type: string
|
||||
ort:
|
||||
type: string
|
||||
plz:
|
||||
type: string
|
||||
strasse:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
telefon:
|
||||
type: string
|
||||
website:
|
||||
type: string
|
||||
istVeranstalter:
|
||||
type: boolean
|
||||
istAktiv:
|
||||
type: boolean
|
||||
imageUrl:
|
||||
type: string
|
||||
bemerkungen:
|
||||
type: string
|
||||
VereinUpdateRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
bundesland:
|
||||
type: string
|
||||
ort:
|
||||
type: string
|
||||
plz:
|
||||
type: string
|
||||
strasse:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
telefon:
|
||||
type: string
|
||||
website:
|
||||
type: string
|
||||
istVeranstalter:
|
||||
type: boolean
|
||||
istAktiv:
|
||||
type: boolean
|
||||
imageUrl:
|
||||
type: string
|
||||
bemerkungen:
|
||||
type: string
|
||||
Funktionaer:
|
||||
type: object
|
||||
properties:
|
||||
funktionaerId:
|
||||
type: string
|
||||
format: uuid
|
||||
satzId:
|
||||
type: string
|
||||
satzNummer:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
qualifikationen:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
bemerkungen:
|
||||
type: string
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
FunktionaerCreateRequest:
|
||||
type: object
|
||||
required:
|
||||
- satzId
|
||||
- satzNummer
|
||||
properties:
|
||||
satzId:
|
||||
type: string
|
||||
satzNummer:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
qualifikationen:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
bemerkungen:
|
||||
type: string
|
||||
FunktionaerUpdateRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
qualifikationen:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
istAktiv:
|
||||
type: boolean
|
||||
bemerkungen:
|
||||
type: string
|
||||
|
||||
Reference in New Issue
Block a user