Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Materialisering av bruksenhet ved innkommende egenregistreringer #207

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions application/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED

plugins {
kotlin("jvm")
kotlin("plugin.serialization").version(libs.versions.kotlinVersion)

`jvm-test-suite`
}
Expand All @@ -15,8 +14,7 @@ dependencies {
api(libs.kotlin.result)

// Serialization
// TODO: Bør helst ikke måtte ligge i application (skyldes lagring i databasen)
implementation(libs.ktor.serialization.kotlinx)
implementation(libs.fasterxml.jackson.kotlin)

// Norwegian Commons
implementation(libs.norwegian.commons)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import no.kartverket.matrikkel.bygning.application.models.Bygning
import no.kartverket.matrikkel.bygning.application.models.error.DomainError

interface BygningClient {
fun getBygningById(id: Long): Result<Bygning, DomainError>
fun getBygningByBubbleId(bygningBubbleId: Long): Result<Bygning, DomainError>

fun getBygningByBygningsnummer(bygningsnummer: Long): Result<Bygning, DomainError>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package no.kartverket.matrikkel.bygning.application.bygning

import no.kartverket.matrikkel.bygning.application.models.Bruksenhet
import java.util.*

interface BygningRepository {
fun saveBruksenhet(bruksenhet: Bruksenhet)

fun getBruksenhetById(bruksenhetId: UUID): Bruksenhet?
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,48 @@ import com.github.michaelbull.result.Result
import com.github.michaelbull.result.andThen
import com.github.michaelbull.result.map
import com.github.michaelbull.result.toResultOr
import no.kartverket.matrikkel.bygning.application.egenregistrering.EgenregistreringService
import no.kartverket.matrikkel.bygning.application.models.Bruksenhet
import no.kartverket.matrikkel.bygning.application.models.Bygning
import no.kartverket.matrikkel.bygning.application.models.Egenregistrering
import no.kartverket.matrikkel.bygning.application.models.applyEgenregistrering
import no.kartverket.matrikkel.bygning.application.models.error.BruksenhetNotFound
import no.kartverket.matrikkel.bygning.application.models.error.DomainError
import no.kartverket.matrikkel.bygning.application.models.withEgenregistrertData

class BygningService(
private val bygningClient: BygningClient,
private val egenregistreringService: EgenregistreringService
private val bygningRepository: BygningRepository,
) {
fun getBygning(bygningId: Long): Result<Bygning, DomainError> {
return bygningClient.getBygningById(bygningId)
fun getBygningByBubbleId(bygningBubbleId: Long): Result<Bygning, DomainError> {
return bygningClient.getBygningByBubbleId(bygningBubbleId).map { bygning ->
bygning.copy(
bruksenheter = bygning.bruksenheter.map { bruksenhet ->
bygningRepository.getBruksenhetById(bruksenhet.id.value) ?: bruksenhet
},
)
}
}

fun getBygningWithEgenregistrertData(bygningId: Long): Result<Bygning, DomainError> {
return getBygning(bygningId)
.map { bygning ->
val egenregistreringerForBygning = egenregistreringService
.findAllEgenregistreringerForBygning(bygningId)

bygning.withEgenregistrertData(egenregistreringerForBygning)
}
}

fun getBruksenhetWithEgenregistrertData(bygningId: Long, bruksenhetId: Long): Result<Bruksenhet, DomainError> {
return getBygning(bygningId)
fun getBruksenhetByBubbleId(bygningBubbleId: Long, bruksenhetBubbleId: Long): Result<Bruksenhet, DomainError> {
return bygningClient.getBygningByBubbleId(bygningBubbleId)
.andThen { bygning ->
val egenregistreringerForBygning = egenregistreringService.findAllEgenregistreringerForBygning(bygningId)

bygning.bruksenheter
.find { it.bruksenhetId.value == bruksenhetId }
?.withEgenregistrertData(egenregistreringerForBygning)
.firstOrNull { bruksenhet -> bruksenhet.bruksenhetBubbleId.value == bruksenhetBubbleId }
.toResultOr {
BruksenhetNotFound(message = "Bruksenhet finnes ikke på bygningen")
BruksenhetNotFound("Fant ikke bruksenhet med id $bruksenhetBubbleId i bygning med id $bygningBubbleId")
}

}
.map { bruksenhet ->
bygningRepository.getBruksenhetById(bruksenhet.id.value) ?: bruksenhet
}
}

fun createBruksenhetSnapshotsOfEgenregistrering(bygning: Bygning, egenregistrering: Egenregistrering) {
egenregistrering.bygningRegistrering.bruksenhetRegistreringer.forEach { bruksenhetRegistrering ->
bygning.bruksenheter.find { bruksenhet -> bruksenhet.bruksenhetBubbleId == bruksenhetRegistrering.bruksenhetBubbleId }
?.applyEgenregistrering(egenregistrering)
?.let { bruksenhet ->
bygningRepository.saveBruksenhet(bruksenhet)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ package no.kartverket.matrikkel.bygning.application.egenregistrering
import no.kartverket.matrikkel.bygning.application.models.Egenregistrering

interface EgenregistreringRepository {
fun getAllEgenregistreringerForBygning(bygningId: Long): List<Egenregistrering>
fun saveEgenregistrering(egenregistrering: Egenregistrering)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,23 @@ package no.kartverket.matrikkel.bygning.application.egenregistrering

import com.github.michaelbull.result.Result
import com.github.michaelbull.result.andThen
import com.github.michaelbull.result.onSuccess
import no.kartverket.matrikkel.bygning.application.bygning.BygningClient
import com.github.michaelbull.result.map
import no.kartverket.matrikkel.bygning.application.bygning.BygningService
import no.kartverket.matrikkel.bygning.application.models.Egenregistrering
import no.kartverket.matrikkel.bygning.application.models.error.DomainError

class EgenregistreringService(
private val bygningClient: BygningClient,
private val bygningService: BygningService,
private val egenregistreringRepository: EgenregistreringRepository,
) {
fun addEgenregistrering(egenregistrering: Egenregistrering): Result<Unit, DomainError> {
return bygningClient
.getBygningById(egenregistrering.bygningRegistrering.bygningId)
.andThen {
EgenregistreringValidator.validateEgenregistrering(egenregistrering, it)
return bygningService.getBygningByBubbleId(egenregistrering.bygningRegistrering.bygningBubbleId.value)
.andThen { bygning ->
EgenregistreringValidator.validateEgenregistrering(egenregistrering, bygning).map { bygning }
}
.onSuccess {
.map { bygning ->
egenregistreringRepository.saveEgenregistrering(egenregistrering)
bygningService.createBruksenhetSnapshotsOfEgenregistrering(bygning, egenregistrering)
}
}

fun findAllEgenregistreringerForBygning(bygningId: Long): List<Egenregistrering> {
return egenregistreringRepository.getAllEgenregistreringerForBygning(bygningId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@ class EgenregistreringValidator {
egenregistrering: Egenregistrering, bygning: Bygning
): ValidationError? {
val invalidBruksenheter = egenregistrering.bygningRegistrering.bruksenhetRegistreringer.mapNotNull { bruksenhetRegistering ->
val bruksenhet = bygning.bruksenheter.find { it.bruksenhetId.value == bruksenhetRegistering.bruksenhetId }
val bruksenhet = bygning.bruksenheter.find { it.bruksenhetBubbleId == bruksenhetRegistering.bruksenhetBubbleId }

if (bruksenhet == null) {
bruksenhetRegistering.bruksenhetId
bruksenhetRegistering.bruksenhetBubbleId
} else {
null
}
}

if (invalidBruksenheter.isNotEmpty()) {
return ValidationError(
message = "Bruksenhet${if (invalidBruksenheter.size > 1) "er" else ""} med ID ${invalidBruksenheter.joinToString()} finnes ikke i bygning med ID ${bygning.bygningId}",
message = "Bruksenhet${if (invalidBruksenheter.size > 1) "er" else ""} med ID ${invalidBruksenheter.joinToString()} finnes ikke i bygning med ID ${bygning.bygningBubbleId}",
)
}

Expand All @@ -47,7 +48,7 @@ class EgenregistreringValidator {

private fun validateRepeatedBruksenheter(egenregistrering: Egenregistrering): ValidationError? {
val repeatedBruksenheter =
egenregistrering.bygningRegistrering.bruksenhetRegistreringer.groupBy { it.bruksenhetId }.filter { it.value.size > 1 }
egenregistrering.bygningRegistrering.bruksenhetRegistreringer.groupBy { it.bruksenhetBubbleId }.filter { it.value.size > 1 }
.map { it.key }


Expand All @@ -67,7 +68,7 @@ class EgenregistreringValidator {
}
.map { invalidRegistrering ->
ValidationError(
message = "Bruksenhet med ID ${invalidRegistrering.bruksenhetId} har registrert totalt BRA og BRA per etasje, men totalt BRA stemmer ikke overens med totalen av BRA per etasje",
message = "Bruksenhet med ID ${invalidRegistrering.bruksenhetBubbleId} har registrert totalt BRA og BRA per etasje, men totalt BRA stemmer ikke overens med totalen av BRA per etasje",
)
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import no.kartverket.matrikkel.bygning.application.models.Felt.Byggeaar
import no.kartverket.matrikkel.bygning.application.models.Felt.Energikilde
import no.kartverket.matrikkel.bygning.application.models.Felt.Oppvarming
import no.kartverket.matrikkel.bygning.application.models.Felt.Vannforsyning
import no.kartverket.matrikkel.bygning.application.models.ids.BruksenhetBubbleId
import no.kartverket.matrikkel.bygning.application.models.ids.BruksenhetId
import no.kartverket.matrikkel.bygning.application.models.ids.BygningBubbleId
import no.kartverket.matrikkel.bygning.application.models.ids.BygningId
import no.kartverket.matrikkel.bygning.application.models.kodelister.AvlopKode
import no.kartverket.matrikkel.bygning.application.models.kodelister.EnergikildeKode
import no.kartverket.matrikkel.bygning.application.models.kodelister.KildematerialeKode
Expand All @@ -16,7 +20,8 @@ import no.kartverket.matrikkel.bygning.application.models.kodelister.Vannforsyni
import java.time.Instant

data class Bygning(
val bygningId: BygningId,
val id: BygningId,
val bygningBubbleId: BygningBubbleId,
val bygningsnummer: Long,
val etasjer: List<BygningEtasje>,
val bruksenheter: List<Bruksenhet>,
Expand Down Expand Up @@ -52,9 +57,9 @@ sealed interface Felt<T> {
data class Oppvarming(override val data: List<OppvarmingKode>, override val metadata: RegisterMetadata) : Felt<List<OppvarmingKode>>
}


data class Bruksenhet(
val bruksenhetId: BruksenhetId,
val id: BruksenhetId,
val bruksenhetBubbleId: BruksenhetBubbleId,
val bygningId: BygningId,
val etasjer: Multikilde<BruksenhetEtasjer> = Multikilde(),
val byggeaar: Multikilde<Byggeaar> = Multikilde(),
Expand All @@ -64,3 +69,4 @@ data class Bruksenhet(
val vannforsyning: Multikilde<Vannforsyning> = Multikilde(),
val avlop: Multikilde<Avlop> = Multikilde(),
)

Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,29 @@ import no.kartverket.matrikkel.bygning.application.models.Felt.Oppvarming
import no.kartverket.matrikkel.bygning.application.models.Felt.Vannforsyning
import no.kartverket.matrikkel.bygning.application.models.kodelister.KildematerialeKode

/**
* Burde vi kanskje sortere egenregistreringer her, da vi er avhengig av at egenregistreringene er sortert her,
* men ikke nødvendigvis andre steder?
*/
fun Bygning.applyEgenregistreringer(egenregistreringer: List<Egenregistrering>): Bygning {
return egenregistreringer
.sortedBy { it.registreringstidspunkt }
.fold(this) { bygningAggregate, egenregistrering ->
bygningAggregate.copy(
bruksenheter = bygningAggregate.bruksenheter.map {
it.applyEgenregistrering(egenregistrering)
},
)
}
}

fun Bygning.withEgenregistrertData(egenregistreringer: List<Egenregistrering>): Bygning {
return egenregistreringer.fold(this) { bygningAggregate, egenregistrering ->
bygningAggregate.copy(
bruksenheter = bygningAggregate.bruksenheter.map {
it.applyEgenregistrering(egenregistrering)
},
)
}
fun Bruksenhet.applyEgenregistreringer(egenregistreringer: List<Egenregistrering>): Bruksenhet {
return egenregistreringer
.sortedBy { it.registreringstidspunkt }
.fold(this) { bruksenhetAggregate, egenregistrering ->
bruksenhetAggregate.applyEgenregistrering(egenregistrering)
}
}

private fun Bruksenhet.applyEgenregistrering(egenregistrering: Egenregistrering): Bruksenhet {
fun Bruksenhet.applyEgenregistrering(egenregistrering: Egenregistrering): Bruksenhet {
val bruksenhetRegistrering =
egenregistrering.bygningRegistrering.bruksenhetRegistreringer.firstOrNull { it.bruksenhetId == this.bruksenhetId.value }
egenregistrering.bygningRegistrering.bruksenhetRegistreringer.firstOrNull { it.bruksenhetBubbleId == this.bruksenhetBubbleId }
if (bruksenhetRegistrering == null) {
return this
}
Expand Down Expand Up @@ -79,7 +84,7 @@ private fun Bruksenhet.applyEgenregistrering(egenregistrering: Egenregistrering)

etasjer = this.etasjer.aggregate(
registrering = bruksenhetRegistrering.bruksarealRegistrering?.etasjeRegistreringer,
shouldMapRegistrering = !this.isEgenregistrertBruksarealRegistreringPresent(),
shouldRemove = !bruksenhetRegistrering.bruksarealRegistrering.isBothEtasjeAndTotalRegistrert(),
) { etasjeBruksarealRegistreringer ->
BruksenhetEtasjer(
data = etasjeBruksarealRegistreringer.map {
Expand All @@ -94,23 +99,21 @@ private fun Bruksenhet.applyEgenregistrering(egenregistrering: Egenregistrering)
)
}

private fun Bruksenhet.isEgenregistrertBruksarealRegistreringPresent(): Boolean =
this.etasjer.egenregistrert != null || this.totaltBruksareal.egenregistrert != null

fun Bruksenhet.withEgenregistrertData(egenregistreringer: List<Egenregistrering>): Bruksenhet {
return egenregistreringer.fold(this) { bruksenhetAggregate, egenregistrering ->
bruksenhetAggregate.applyEgenregistrering(egenregistrering)
}
}
private fun BruksarealRegistrering?.isBothEtasjeAndTotalRegistrert(): Boolean =
this?.totaltBruksareal != null && etasjeRegistreringer?.isNotEmpty() == true

private fun <T : Any, V : Any> Multikilde<T>.aggregate(
registrering: V?, shouldMapRegistrering: Boolean = true, mapper: (V) -> T?
registrering: V?, shouldRemove: Boolean = false, mapper: (V) -> T?
): Multikilde<T> {
if (this.egenregistrert != null || registrering == null) {
if (shouldRemove) {
return withEgenregistrert(null)
}

if (registrering == null) {
return this
}

return withEgenregistrert(if (shouldMapRegistrering) mapper(registrering) else null)
return withEgenregistrert(mapper(registrering))
}

private fun RegisterMetadata.withKildemateriale(kildemateriale: KildematerialeKode?): RegisterMetadata {
Expand Down

This file was deleted.

Loading
Loading