Skip to content

Commit

Permalink
PEK-715 hent SPK tjenestepensjon-simulering
Browse files Browse the repository at this point in the history
  • Loading branch information
antonfofanov committed Nov 5, 2024
1 parent 8a73130 commit 980a7ba
Show file tree
Hide file tree
Showing 24 changed files with 981 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ 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.aggregerRespons
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.TpOrdningStoettesIkkeException
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.TjenestepensjonV2025Service
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
Expand All @@ -22,20 +20,12 @@ 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)
}
return tjenestepensjonV2025Service.simuler(request).fold(
onSuccess = { aggregerRespons(it) },
onFailure = { e ->
log.error(e) { "Simulering feilet: ${e.message}" }
SimulerTjenestepensjonResponseDto(ResultatTypeDto.ERROR, e.message)
})
}

@GetMapping("/v2025/tjenestepensjon/ping")
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,17 @@
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(),
)

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(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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 aggregerRespons(simulertTjenestepensjon: SimulertTjenestepensjonMedMaanedsUtbetalinger) =
SimulerTjenestepensjonResponseDto(
simuleringsResultatStatus = SimuleringsResultatStatusDto(ResultatTypeDto.SUCCESS),
simuleringsResultat = SimuleringsResultatDto(
tpLeverandoer = simulertTjenestepensjon.tpLeverandoer,
utbetalingsperioder = aggregerTilAarligePerioder(simulertTjenestepensjon.utbetalingsperioder),
)
)

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,26 @@ package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.response

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

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

enum class SimuleringsResultatTypeDto { SUCCESS, ERROR }
enum class ResultatTypeDto { SUCCESS, ERROR }

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

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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
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.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): Result<SimulertTjenestepensjonMedMaanedsUtbetalinger> {
val response = tp.findTPForhold(request.pid)
val tpOrdningNavn = response.flatMap { it.alias }.firstOrNull()
?: "spk" //TODO før prodsetting -> throw BrukerErIkkeMedlemException()
log.info { "Fant aktive tp-ordninger for bruker: $response, skal bruke $tpOrdningNavn for å simulere" }

return when (tpOrdningNavn.lowercase()) {
"spk" -> spk.simuler(request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,37 @@ import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.Ordning
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.SimulertTjenestepensjon
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.Utbetalingsperiode
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.request.SimulerTjenestepensjonRequestDto
import java.time.LocalDate

object KLPMapper {

private const val LEVERANDOER = "Kommunal landspensjonskasse"

fun mapToRequest(request: SimulerTjenestepensjonRequestDto) =
KLPSimulerTjenestepensjonRequest(
personId = request.fnr,
uttaksListe = request.uttaksListe.map { uttakDto ->
Uttak(
ytelseType = uttakDto.ytelseType,
fraOgMedDato = uttakDto.fraOgMedDato,
uttaksgrad = uttakDto.uttaksgrad
personId = request.pid,
uttaksListe = listOf(Uttak(
ytelseType = "ALLE",
fraOgMedDato = request.uttaksdato,
uttaksgrad = 100
)
},
fremtidigInntektsListe = request.fremtidigInntektListe.map { fremtidigInntektDto ->
),
fremtidigInntektsListe = listOf(
FremtidigInntekt(
fraOgMedDato = fremtidigInntektDto.fraOgMedDato,
arligInntekt = fremtidigInntektDto.aarligInntekt
fraOgMedDato = aarUtenRegistrertInntektHosSkatteetaten(),
arligInntekt = request.sisteInntekt
)
},
),
arIUtlandetEtter16 = request.aarIUtlandetEtter16,
epsPensjon = request.epsPensjon,
eps2G = request.eps2G,
)

private fun aarUtenRegistrertInntektHosSkatteetaten(): LocalDate = LocalDate.now().minusYears(2).withDayOfYear(1)

fun mapToResponse(response: KLPSimulerTjenestepensjonResponse) =
SimulertTjenestepensjon(
tpLeverandoer = LEVERANDOER,
ordningsListe = response.inkludertOrdningListe.map { Ordning(it.tpnr) },
utbetalingsperioder = response.utbetalingsListe.map { Utbetalingsperiode(it.fraOgMedDato, it.manedligUtbetaling, it.ytelseType) },
aarsakIngenUtbetaling = response.arsakIngenUtbetaling
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.klp

import no.nav.tjenestepensjon.simulering.ping.Pingable
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.SimulertTjenestepensjonMedMaanedsUtbetalinger
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.request.SimulerTjenestepensjonRequestDto
import org.springframework.stereotype.Service

@Service
class KLPTjenestepensjonService(private val client: KLPTjenestepensjonClient) : Pingable {

fun simuler(request: SimulerTjenestepensjonRequestDto): Result<SimulertTjenestepensjonMedMaanedsUtbetalinger> {
return Result.failure(RuntimeException("Aggregation is not implemented for KLP"))
}

override fun ping() = client.ping()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,45 @@ import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.Ordning
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.SimulertTjenestepensjon
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.domain.Utbetalingsperiode
import no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.dto.request.SimulerTjenestepensjonRequestDto
import java.time.LocalDate

object SPKMapper {

const val LEVERANDOER = "Statens pensjonskasse"

fun mapToRequest(request: SimulerTjenestepensjonRequestDto) =
SPKSimulerTjenestepensjonRequest(
personId = request.fnr,
uttaksListe = request.uttaksListe.map { uttakDto ->
Uttak(
ytelseType = uttakDto.ytelseType,
fraOgMedDato = uttakDto.fraOgMedDato,
uttaksgrad = uttakDto.uttaksgrad
)
},
fremtidigInntektListe = request.fremtidigInntektListe.map { fremtidigInntektDto ->
personId = request.pid,
uttaksListe = opprettUttaksliste(request),
fremtidigInntektListe = listOf(
FremtidigInntekt(
fraOgMedDato = fremtidigInntektDto.fraOgMedDato,
aarligInntekt = fremtidigInntektDto.aarligInntekt
fraOgMedDato = LocalDate.now().withDayOfYear(1),
aarligInntekt = request.sisteInntekt
)
},
),
aarIUtlandetEtter16 = request.aarIUtlandetEtter16,
epsPensjon = request.epsPensjon,
eps2G = request.eps2G,
)

fun mapToResponse(response: SPKSimulerTjenestepensjonResponse) =
SimulertTjenestepensjon(
tpLeverandoer = LEVERANDOER,
ordningsListe = response.inkludertOrdningListe.map { Ordning(it.tpnr) },
utbetalingsperioder = response.utbetalingListe.flatMap { periode ->
val fraOgMed = periode.fraOgMedDato
periode.delytelseListe.map { Utbetalingsperiode(fraOgMed, it.maanedligBelop, it.ytelseType) }
},
aarsakIngenUtbetaling = response.aarsakIngenUtbetaling.map { it.statusBeskrivelse + ": " + it.ytelseType }
)

fun opprettUttaksliste(request: SimulerTjenestepensjonRequestDto) =
mutableListOf("PAASLAG", "APOF2020", "OAFP", "OT6370", "SAERALDERSPAASLAG", if (request.brukerBaOmAfp) "AFP" else "BTP")
.map {
Uttak(
ytelseType = it,
fraOgMedDato = request.uttaksdato,
uttaksgrad = null
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package no.nav.tjenestepensjon.simulering.v2025.tjenestepensjon.v1.service.spk

import com.fasterxml.jackson.annotation.JsonFormat
import java.time.LocalDate

data class SPKSimulerTjenestepensjonResponse(
Expand All @@ -13,6 +14,7 @@ data class InkludertOrdning(
)

data class Utbetaling(
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
val fraOgMedDato: LocalDate,
val delytelseListe: List<Delytelse>,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class SPKTjenestepensjonClient(private val spkWebClient: WebClient) : Tjenestepe
}

companion object {
private const val SIMULER_PATH = "/nav/v2/tjenestepensjon/simuler/3010"
const val SIMULER_PATH = "/nav/v2/tjenestepensjon/simuler/3010"
private const val PING_PATH = "/nav/admin/ping"
private const val PROVIDER = "SPK"
}
Expand Down
Loading

0 comments on commit 980a7ba

Please sign in to comment.