Skip to content

Commit

Permalink
Merge pull request #171 from navikt/PEK-715-hente-simulert-tjenestepe…
Browse files Browse the repository at this point in the history
…nsjon-spk

Pek 715 hente simulert tjenestepensjon spk
  • Loading branch information
antonfofanov authored Nov 27, 2024
2 parents c273da8 + 1017265 commit d606dc2
Show file tree
Hide file tree
Showing 38 changed files with 1,207 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ class WebClientConfig {
@Bean
fun client(): HttpClient =
HttpClient.create().option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECT_TIMEOUT_MILLIS)
.doOnConnected { it.addHandlerLast(ReadTimeoutHandler(READ_TIMEOUT_MILLIS / 1000)) }
.compress(true)
.followRedirect(true)
.doOnConnected { it.addHandlerLast(ReadTimeoutHandler(30)) }
.doOnConnected { it.addHandlerLast(ReadTimeoutHandler(READ_TIMEOUT_SECONDS)) }
.wiretap("reactor.netty.http.client.HttpClient", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL)

@Bean
Expand Down Expand Up @@ -154,7 +153,7 @@ class WebClientConfig {

companion object {
private const val CONNECT_TIMEOUT_MILLIS = 3000
const val READ_TIMEOUT_MILLIS = 5000
const val READ_TIMEOUT_SECONDS = 45

fun addCorrelationId(
next: ExchangeFunction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import no.nav.tjenestepensjon.simulering.v2.models.response.SimulerOffentligTjen
import no.nav.tjenestepensjon.simulering.v2.models.response.SimulerOffentligTjenestepensjonResponse.Companion.tpOrdningStoettesIkke
import no.nav.tjenestepensjon.simulering.v2.rest.RestClient
import no.nav.tjenestepensjon.simulering.v2.service.SimuleringServiceV2
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.TpregisteretException
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.http.HttpStatus
import org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR
Expand Down Expand Up @@ -103,6 +104,9 @@ class SimuleringEndpoint(
log.debug { "Returning response: ${filterFnr(response.toString())}" }
ResponseEntity(response, OK)
}
} catch (e: TpregisteretException) {
log.error (e) { """Request with nav-call-id ${getHeaderFromRequestContext(NAV_CALL_ID)}. failed.""" }
ResponseEntity.internalServerError().build()
} catch (e: NoTpOrdningerFoundException) {
log.debug { """Request with nav-call-id ${getHeaderFromRequestContext(NAV_CALL_ID)}. No TP-forhold found for person.""" }
ResponseEntity.ok(SimulerOffentligTjenestepensjonResponse.ikkeMedlem())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@ package no.nav.tjenestepensjon.simulering.rest

import io.github.oshai.kotlinlogging.KotlinLogging
import no.nav.tjenestepensjon.simulering.ping.PingResponse
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.Tjenestepensjon2025Mapper.mapToVellykketTjenestepensjonSimuleringResponse
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.Tjenestepensjon2025Aggregator.aggregerVellykketRespons
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.request.SimulerTjenestepensjonRequestDto
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.response.ResultatTypeDto
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.response.SimulerTjenestepensjonResponseDto
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.response.SimuleringsResultatTypeDto
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.BrukerErIkkeMedlemException
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.TjenestepensjonSimuleringException
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.TpOrdningStoettesIkkeException
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.TpregisteretException
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.TjenestepensjonV2025Service
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ResponseStatusException
import java.lang.RuntimeException

@RestController
class TjenestepensjonSimuleringV2025Controller(
Expand All @@ -22,20 +27,31 @@ class TjenestepensjonSimuleringV2025Controller(

@PostMapping("/v2025/tjenestepensjon/v1/simulering")
fun simuler(@RequestBody request: SimulerTjenestepensjonRequestDto): SimulerTjenestepensjonResponseDto {
try {
return tjenestepensjonV2025Service.simuler(request).fold(
onSuccess = { data ->
mapToVellykketTjenestepensjonSimuleringResponse(data)
},
onFailure = { e ->
log.error(e) { "Simulering feilet: ${e.message}" }
SimulerTjenestepensjonResponseDto(SimuleringsResultatTypeDto.ERROR, "Simulering feilet")
})
} catch (e: BrukerErIkkeMedlemException) {
return SimulerTjenestepensjonResponseDto(SimuleringsResultatTypeDto.ERROR, e.message)
} catch (e: TpOrdningStoettesIkkeException) {
return SimulerTjenestepensjonResponseDto(SimuleringsResultatTypeDto.ERROR, e.message)
}
val simuleringsresultat = tjenestepensjonV2025Service.simuler(request)
val relevanteTpOrdninger = simuleringsresultat.first
return simuleringsresultat.second.fold(
onSuccess = {
if (it.utbetalingsperioder.isNotEmpty()) {
aggregerVellykketRespons(it, relevanteTpOrdninger)
} else {
log.info { "Simulering fra ${it.tpLeverandoer} inneholder ingen utbetalingsperioder" }
SimulerTjenestepensjonResponseDto(ResultatTypeDto.INGEN_UTBETALINGSPERIODER_FRA_TP_ORDNING, "Simulering fra ${it.tpLeverandoer} inneholder ingen utbetalingsperioder", relevanteTpOrdninger)
}
},
onFailure = { e ->
when (e) {
is BrukerErIkkeMedlemException -> SimulerTjenestepensjonResponseDto(ResultatTypeDto.BRUKER_ER_IKKE_MEDLEM_HOS_TP_ORDNING, e.message, relevanteTpOrdninger)
is TpOrdningStoettesIkkeException -> SimulerTjenestepensjonResponseDto(ResultatTypeDto.TP_ORDNING_ER_IKKE_STOTTET, e.message, relevanteTpOrdninger)
is TjenestepensjonSimuleringException -> loggOgReturnerTekniskFeil(e)
is TpregisteretException -> loggOgReturnerTekniskFeil(e)
else -> loggOgReturnerTekniskFeil(RuntimeException(e))
}
})
}

private fun loggOgReturnerTekniskFeil(e: RuntimeException): SimulerTjenestepensjonResponseDto {
log.error(e) { "Simulering feilet: ${e.message}" }
throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.message)
}

@GetMapping("/v2025/tjenestepensjon/ping")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@ import no.nav.tjenestepensjon.simulering.model.domain.HateoasWrapper
import no.nav.tjenestepensjon.simulering.model.domain.TPOrdningIdDto
import no.nav.tjenestepensjon.simulering.ping.PingResponse
import no.nav.tjenestepensjon.simulering.ping.Pingable
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.TjenestepensjonV2025Client
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.spk.SPKTjenestepensjonClient
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.spk.SPKTjenestepensjonClient.Companion
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.TpregisteretException
import org.springframework.beans.factory.annotation.Value
import org.springframework.cache.annotation.Cacheable
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.*
import org.springframework.web.server.ResponseStatusException
Expand Down Expand Up @@ -100,14 +97,16 @@ class TpClient(
when (it.statusCode().value()) {
200 -> it.bodyToMono<List<TpOrdningDto>>()
404 -> Mono.empty()
else -> Mono.error(handleRemoteError(null))
else -> Mono.error(handleRemoteError("Received status code ${it.statusCode()} fra tpregisteret")) //TODO bedre feilhåndtering i alle funksjonene
}
}.block() ?: emptyList()
}
.onErrorMap { handleRemoteError(it.message) }
.block() ?: emptyList()
}

fun handleRemoteError(logMessage: String?): ResponseStatusException {
fun handleRemoteError(logMessage: String?): TpregisteretException {
log.error { "Error fetching data from TP: $logMessage" }
return ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR)
return TpregisteretException("Error fetching data from TP")
}

override fun ping(): PingResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ object AlderForDelingstallBeregner {
return listOf(AlderForDelingstall(bestemAlderVedDato(fodselsdato, uttaksdato), uttaksdato))
}

private fun bestemAlderVedDato(fodselsdato: LocalDate, date: LocalDate): Alder {
fun bestemAlderVedDato(fodselsdato: LocalDate, date: LocalDate): Alder {
val periode = Period.between(fodselsdato, date)
return Alder(periode.years, periode.months)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain

import no.nav.tjenestepensjon.simulering.model.domain.pen.Alder
import java.time.LocalDate

data class Maanedsutbetaling(
val fraOgMedDato: LocalDate,
val fraOgMedAlder: Alder,
var maanedsBeloep: Int,
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain

data class SimulertTjenestepensjon(
open class SimulertTjenestepensjon(
val tpLeverandoer: String,
var ordningsListe: List<Ordning> = emptyList(),
var utbetalingsperioder: List<Utbetalingsperiode> = emptyList(),
var aarsakIngenUtbetaling: List<String> = emptyList(),
val betingetTjenestepensjonErInkludert: Boolean
)

data class Ordning(val tpNummer: String)
data class Ordning(val tpNummer: String)

open class SimulertTjenestepensjonMedMaanedsUtbetalinger(
val tpLeverandoer: String,
var ordningsListe: List<Ordning> = emptyList(),
var utbetalingsperioder: List<Maanedsutbetaling> = emptyList(),
var aarsakIngenUtbetaling: List<String> = emptyList(),
val betingetTjenestepensjonErInkludert: Boolean = false
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto

import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.Maanedsutbetaling
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.SimulertTjenestepensjonMedMaanedsUtbetalinger
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.response.*

object Tjenestepensjon2025Aggregator {

fun aggregerVellykketRespons(simulertTjenestepensjon: SimulertTjenestepensjonMedMaanedsUtbetalinger, tpOrdninger: List<String>) =
SimulerTjenestepensjonResponseDto(
relevanteTpOrdninger = tpOrdninger,
simuleringsResultatStatus = SimuleringsResultatStatusDto(ResultatTypeDto.SUCCESS),
simuleringsResultat = SimuleringsResultatDto(
tpLeverandoer = simulertTjenestepensjon.tpLeverandoer,
utbetalingsperioder = aggregerTilAarligePerioder(simulertTjenestepensjon.utbetalingsperioder),
betingetTjenestepensjonErInkludert = simulertTjenestepensjon.betingetTjenestepensjonErInkludert
)
)

fun aggregerTilAarligePerioder(maanedsutbetalinger: List<Maanedsutbetaling>): List<UtbetalingPerAar> {
val aarligeUtbetalinger = mutableMapOf<Int, MutableMap<Int, Int>>() //år -> månedsnummer(1-12) -> beløp for måneden

maanedsutbetalinger.forEach { maanedsutbetaling ->
val (startAar, startMaaned) = maanedsutbetaling.fraOgMedAlder.let { it.aar to it.maaneder + 1 }

// Bruk beløp for start år-måned og fremtidige år
(startAar..SISTE_UTBETALINGSAAR).forEach { aar ->
val maanedFra = if (aar == startAar) startMaaned else 1
aarligeUtbetalinger
.getOrPut(aar) { mutableMapOf() }
.putAll((maanedFra..MAANEDER_I_AAR).associateWith { maanedsutbetaling.maanedsBeloep })
}
}

// Summer beløp per år
return aarligeUtbetalinger
.map { (aar, maanedToBeloep) -> UtbetalingPerAar(aar, maanedToBeloep.values.sum()) }
.sortedBy { it.aar }
}

const val MAANEDER_I_AAR = 12
const val SISTE_UTBETALINGSAAR = 85
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.request

import java.time.LocalDate

data class SimulerTjenestepensjonRequestDto(
val fnr: String,
val uttaksListe: List<UttakDto>,
val fremtidigInntektListe: List<FremtidigInntektDto>,
val pid: String,
val foedselsdato: LocalDate,
val uttaksdato: LocalDate,
val sisteInntekt: Int,
val aarIUtlandetEtter16: Int,
val brukerBaOmAfp: Boolean,
val epsPensjon: Boolean,
val eps2G: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,33 @@ package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.response

data class SimulerTjenestepensjonResponseDto(
val simuleringsResultatStatus: SimuleringsResultatStatusDto,
val simuleringsResultatDto: SimuleringsResultatDto? = null,
){
constructor(simuleringsResultatTypeDto: SimuleringsResultatTypeDto, feilmelding: String) : this(
SimuleringsResultatStatusDto(simuleringsResultatTypeDto, feilmelding)
val simuleringsResultat: SimuleringsResultatDto? = null,
val relevanteTpOrdninger: List<String> = emptyList(),
) {
constructor(resultatTypeDto: ResultatTypeDto, feilmelding: String?, tpOrdninger: List<String>) : this(
SimuleringsResultatStatusDto(resultatTypeDto, feilmelding), null, tpOrdninger
)
}

data class SimuleringsResultatStatusDto(
val simuleringsResultatStatus: SimuleringsResultatTypeDto,
val resultatType: ResultatTypeDto,
val feilmelding: String? = null,
)

enum class SimuleringsResultatTypeDto { SUCCESS, ERROR }
enum class ResultatTypeDto {
SUCCESS,
BRUKER_ER_IKKE_MEDLEM_HOS_TP_ORDNING,
TP_ORDNING_ER_IKKE_STOTTET,
INGEN_UTBETALINGSPERIODER_FRA_TP_ORDNING,
}

data class SimuleringsResultatDto(
val utbetalingsperioder: List<UtbetalingsperiodeDto>,
val aarsakIngenUtbetaling: List<String>,
val tpLeverandoer: String,
val utbetalingsperioder: List<UtbetalingPerAar>,
val betingetTjenestepensjonErInkludert: Boolean,
)

data class UtbetalingPerAar(
val aar: Int,
val beloep: Int,
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception

class TpregisteretException(message: String) : RuntimeException(message)
Original file line number Diff line number Diff line change
@@ -1,31 +1,47 @@
package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service

import io.github.oshai.kotlinlogging.KotlinLogging
import no.nav.tjenestepensjon.simulering.ping.PingResponse
import no.nav.tjenestepensjon.simulering.service.TpClient
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.SimulertTjenestepensjon
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.SimulertTjenestepensjonMedMaanedsUtbetalinger
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.request.SimulerTjenestepensjonRequestDto
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.BrukerErIkkeMedlemException
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.TpOrdningStoettesIkkeException
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.klp.KLPTjenestepensjonClient
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.spk.SPKTjenestepensjonClient
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.exception.TpregisteretException
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.klp.KLPTjenestepensjonService
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.spk.SPKTjenestepensjonService
import org.springframework.stereotype.Service

@Service
class TjenestepensjonV2025Service(
private val tp: TpClient,
private val spk: SPKTjenestepensjonClient,
private val klp: KLPTjenestepensjonClient,
private val spk: SPKTjenestepensjonService,
private val klp: KLPTjenestepensjonService,
) {
private val log = KotlinLogging.logger {}

@Throws(BrukerErIkkeMedlemException::class, TpOrdningStoettesIkkeException::class)
fun simuler(request: SimulerTjenestepensjonRequestDto): Result<SimulertTjenestepensjon> {
val tpOrdningNavn = tp.findTPForhold(request.fnr).flatMap { it.alias }.firstOrNull()
?: "spk" //TODO throw BrukerErIkkeMedlemException()
fun simuler(request: SimulerTjenestepensjonRequestDto): Pair<List<String>, Result<SimulertTjenestepensjonMedMaanedsUtbetalinger>> {
val tpOrdninger = try {
tp.findTPForhold(request.pid)
}
catch (e: TpregisteretException) {
return emptyList<String>() to Result.failure(e)
}

val sisteTpOrdningNavn = tpOrdninger.flatMap { it.alias }.firstOrNull() //avventer siste ordning fra SPK

if (sisteTpOrdningNavn == null) {
return emptyList<String>() to Result.failure(BrukerErIkkeMedlemException())
}

log.info { "Fant aktive tp-ordninger for bruker: $tpOrdninger, skal bruke $sisteTpOrdningNavn for å simulere" }

val tpOrdningerNavn = tpOrdninger.map { it.navn }

return when (tpOrdningNavn.lowercase()) {
"spk" -> spk.simuler(request)
"klp" -> klp.simuler(request)
else -> throw TpOrdningStoettesIkkeException(tpOrdningNavn)
return when (sisteTpOrdningNavn.lowercase()) {
"spk" -> tpOrdningerNavn to spk.simuler(request)
//"klp" -> tpOrdningerNavn to klp.simuler(request)
else -> tpOrdningerNavn to Result.failure(TpOrdningStoettesIkkeException(sisteTpOrdningNavn))
}
}

Expand Down
Loading

0 comments on commit d606dc2

Please sign in to comment.