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

TB-140 Legg til nye endepunkter for arkivarisk historikk #214

Closed
Closed
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
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,11 @@
package no.kartverket.matrikkel.bygning.application.bygning

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

interface BygningRepository {
fun saveBruksenhet(bruksenhet: Bruksenhet)

fun getBruksenhetById(bruksenhetId: UUID, registreringstidspunkt: Instant): Bruksenhet?
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,54 @@ 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.applyEgenregistreringer
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
import java.time.Instant

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, registreringstidspunkt: Instant = Instant.now()): Result<Bygning, DomainError> {
return bygningClient.getBygningByBubbleId(bygningBubbleId).map { bygning ->
bygning.copy(
bruksenheter = bygning.bruksenheter.map { bruksenhet ->
bygningRepository.getBruksenhetById(bruksenhet.id.value, registreringstidspunkt) ?: 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,
registreringstidspunkt: Instant = Instant.now()
): 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, registreringstidspunkt) ?: bruksenhet
}
}

fun createBruksenhetSnapshotsOfEgenregistrering(bygning: Bygning, egenregistrering: Egenregistrering) {
egenregistrering.bygningRegistrering.bruksenhetRegistreringer.forEach { bruksenhetRegistrering ->
val bruksenhetInBygning =
bygning.bruksenheter.find { bruksenhet -> bruksenhet.bruksenhetBubbleId == bruksenhetRegistrering.bruksenhetBubbleId }

bruksenhetInBygning?.applyEgenregistreringer(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 @@ -29,17 +29,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 @@ -48,7 +49,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 @@ -68,7 +69,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 All @@ -81,7 +82,7 @@ class EgenregistreringValidator {
}
.map { invalidRegistrering ->
ValidationError(
message = "Bruksenhet med ID ${invalidRegistrering.bruksenhetId} har registrert BRA per etasje, men ikke totalt BRA. Totalt BRA er obligatorisk.",
message = "Bruksenhet med ID ${invalidRegistrering.bruksenhetBubbleId} har registrert BRA per etasje, men ikke totalt BRA. Totalt BRA er obligatorisk.",
)
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
package no.kartverket.matrikkel.bygning.application.models

import kotlinx.serialization.Serializable
import no.kartverket.matrikkel.bygning.application.models.Felt.Avlop
import no.kartverket.matrikkel.bygning.application.models.Felt.Bruksareal
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
import no.kartverket.matrikkel.bygning.application.models.kodelister.OppvarmingKode
import no.kartverket.matrikkel.bygning.application.models.kodelister.ProsessKode
import no.kartverket.matrikkel.bygning.application.models.kodelister.VannforsyningKode
import no.kartverket.matrikkel.bygning.application.serializers.InstantSerializer
import java.time.Instant

@Serializable
data class Bygning(
val bygningId: BygningId,
val id: BygningId,
val bygningBubbleId: BygningBubbleId,
val bygningsnummer: Long,
val etasjer: List<BygningEtasje>,
val bruksenheter: List<Bruksenhet>,
Expand All @@ -27,11 +35,14 @@ data class Bygning(
val avlop: Multikilde<Avlop> = Multikilde(),
)

@Serializable
data class Multikilde<T : Any>(val autoritativ: T? = null, val egenregistrert: T? = null) {
fun withEgenregistrert(verdi: T?): Multikilde<T> = copy(egenregistrert = verdi)
}

@Serializable
data class RegisterMetadata(
@Serializable(with = InstantSerializer::class)
val registreringstidspunkt: Instant,
val registrertAv: RegistreringAktoer,
val kildemateriale: KildematerialeKode? = null,
Expand All @@ -42,17 +53,25 @@ sealed interface Felt<T> {
val data: T?
val metadata: RegisterMetadata

@Serializable
data class Byggeaar(override val data: Int?, override val metadata: RegisterMetadata) : Felt<Int?>
@Serializable
data class Vannforsyning(override val data: VannforsyningKode?, override val metadata: RegisterMetadata) : Felt<VannforsyningKode?>
@Serializable
data class Bruksareal(override val data: Double?, override val metadata: RegisterMetadata) : Felt<Double?>
@Serializable
data class Avlop(override val data: AvlopKode?, override val metadata: RegisterMetadata) : Felt<AvlopKode?>
@Serializable
data class Energikilde(override val data: EnergikildeKode, override val metadata: RegisterMetadata) : Felt<EnergikildeKode?>
@Serializable
data class Oppvarming(override val data: OppvarmingKode, override val metadata: RegisterMetadata) : Felt<OppvarmingKode?>
}


@Serializable
data class Bruksenhet(
val bruksenhetId: BruksenhetId,
val id: BruksenhetId,
val bruksenhetBubbleId: BruksenhetBubbleId,
val bygningId: BygningId,
val etasjer: Multikilde<List<BruksenhetEtasje>> = Multikilde(),
val byggeaar: Multikilde<Byggeaar> = Multikilde(),
Expand All @@ -62,3 +81,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 @@ -13,19 +13,33 @@ import no.kartverket.matrikkel.bygning.application.models.kodelister.Kildemateri
* men ikke nødvendigvis andre steder?
*/

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

fun Bruksenhet.applyEgenregistreringer(egenregistrering: Egenregistrering): Bruksenhet {
return this.applyEgenregistreringer(listOf(egenregistrering))
}

private 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 @@ -82,7 +96,7 @@ private fun Bruksenhet.applyEgenregistrering(egenregistrering: Egenregistrering)

etasjer = this.etasjer.aggregate(
registrering = bruksenhetRegistrering.bruksarealRegistrering?.etasjeRegistreringer,
shouldMapRegistrering = !this.isEgenregistrertBruksarealRegistreringPresent(),
shouldRemove = !bruksenhetRegistrering.bruksarealRegistrering.isBothEtasjeAndTotalRegistrert(),
) {
it.map {
BruksenhetEtasje(
Expand All @@ -97,23 +111,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.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package no.kartverket.matrikkel.bygning.application.models

import kotlinx.serialization.Serializable
import no.kartverket.matrikkel.bygning.application.models.RegistreringAktoer.Foedselsnummer
import no.kartverket.matrikkel.bygning.application.models.ids.BruksenhetBubbleId
import no.kartverket.matrikkel.bygning.application.models.ids.BygningBubbleId
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 Down Expand Up @@ -75,13 +77,13 @@ data class OppvarmingRegistrering(

@Serializable
data class BygningRegistrering(
val bygningId: Long,
val bygningBubbleId: BygningBubbleId,
val bruksenhetRegistreringer: List<BruksenhetRegistrering>
)

@Serializable
data class BruksenhetRegistrering(
val bruksenhetId: Long,
val bruksenhetBubbleId: BruksenhetBubbleId,
val bruksarealRegistrering: BruksarealRegistrering?,
val byggeaarRegistrering: ByggeaarRegistrering?,
val vannforsyningRegistrering: VannforsyningRegistrering?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import kotlinx.serialization.Serializable
import no.kartverket.matrikkel.bygning.application.models.Felt.Bruksareal
import no.kartverket.matrikkel.bygning.application.models.kodelister.EtasjeplanKode

@Serializable
data class BygningEtasje(val etasjebetegnelse: Etasjebetegnelse, val etasjeId: Long)

@Serializable
data class BruksenhetEtasje(val etasjebetegnelse: Etasjebetegnelse, val bruksareal: Bruksareal?)

@ConsistentCopyVisibility
Expand Down
Loading