From 65338532fe4ddfb858747c05f6b2f4bee359c3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20N=C3=A6rland?= Date: Thu, 5 Oct 2023 09:23:02 +0200 Subject: [PATCH 1/4] =?UTF-8?q?Tjeneste=20til=20Pensjon=20for=20uthenting?= =?UTF-8?q?=20av=20perioder=20med=20barnetrygd=20for=20en=20person.=20Lage?= =?UTF-8?q?t=20etter=20modell=20fra=20bisys/skatt=20tjenestene,=20men=20ta?= =?UTF-8?q?r=20i=20tillegg=20med=20relevante=20perioder=20med=20ordin?= =?UTF-8?q?=C3=A6r=20barnetrygd?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ba/infotrygd/repository/SakRepository.kt | 14 +- .../rest/controller/PensjonController.kt | 83 +++++++++ .../ba/infotrygd/service/BarnetrygdService.kt | 165 ++++++++++++++++++ .../service/BarnetrygdServiceTest.kt | 62 ++++++- 4 files changed, 320 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt diff --git a/src/main/kotlin/no/nav/familie/ba/infotrygd/repository/SakRepository.kt b/src/main/kotlin/no/nav/familie/ba/infotrygd/repository/SakRepository.kt index 33ce2577..28259b50 100644 --- a/src/main/kotlin/no/nav/familie/ba/infotrygd/repository/SakRepository.kt +++ b/src/main/kotlin/no/nav/familie/ba/infotrygd/repository/SakRepository.kt @@ -47,6 +47,16 @@ interface SakRepository : JpaRepository { ) fun hentUtvidetBarnetrygdsakerForStønad(stonad: TrunkertStønad): List - - + @Query( + """ + SELECT s FROM Sak s + WHERE s.personKey = :#{#stonad.personKey} + AND s.kapittelNr = 'BA' + AND s.valg IN ('OR','UT') + AND s.saksblokk = :#{#stonad.saksblokk} + AND s.saksnummer = :#{#stonad.sakNr} + AND s.region = :#{#stonad.region} + AND s.type IN ('S', 'R', 'K', 'A', 'FL', 'AS')""" + ) + fun hentBarnetrygdsakerForStønad(stonad: TrunkertStønad): List } \ No newline at end of file diff --git a/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt b/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt new file mode 100644 index 00000000..4089e2a4 --- /dev/null +++ b/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt @@ -0,0 +1,83 @@ +package no.nav.familie.ba.infotrygd.rest.controller + +import com.fasterxml.jackson.annotation.JsonProperty +import io.micrometer.core.annotation.Timed +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.ExampleObject +import io.swagger.v3.oas.annotations.media.Schema +import no.nav.commons.foedselsnummer.FoedselsNr +import no.nav.familie.ba.infotrygd.service.BarnetrygdService +import no.nav.familie.ba.infotrygd.service.ClientValidator +import no.nav.security.token.support.core.api.Protected +import org.springframework.http.HttpStatus +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.server.ResponseStatusException +import java.time.YearMonth +import io.swagger.v3.oas.annotations.parameters.RequestBody as ApiRequestBody + +@Protected +@RestController +@Timed(value = "infotrygd_historikk_pensjon_controller", percentiles = [0.5, 0.95]) +@RequestMapping("/infotrygd/barnetrygd") +class PensjonController( + private val barnetrygdService: BarnetrygdService, + private val clientValidator: ClientValidator, +) { + + @Operation(summary = "Uttrekk barnetrygdperioder på en person fra en bestemet måned. Maks 2 år tilbake i tid") + @PostMapping(path = ["pensjon"], consumes = ["application/json"]) + @ApiRequestBody(content = [Content(examples = [ExampleObject(value = """{"personIdent": "12345678910", "fraDato": "2022-05"}""")])]) + fun hentBarnetrygd(@RequestBody request: BarnetrygdTilPensjonRequest): BarnetrygdTilPensjonResponse { + clientValidator.authorizeClient() + + if (request.fraDato.isBefore(YearMonth.now().minusYears(2))) { + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "fraDato kan ikke være lenger enn 2 år tilbake i tid") + } + + val bruker = FoedselsNr(request.personIdent) + + return BarnetrygdTilPensjonResponse( + saker = barnetrygdService.finnBarnetrygdForPensjon(bruker, request.fraDato) + ) + } + + data class BarnetrygdTilPensjonRequest( + val personIdent: String, + @Schema(implementation = String::class, example = "2020-05") val fraDato: YearMonth, + ) + + data class BarnetrygdTilPensjonResponse( + @JsonProperty("fagsaker") val saker: List + ) + + data class BarnetrygdTilPensjon( + @JsonProperty("fagsakEiersIdent") val fnr: String, + val barnetrygdPerioder: List, + ) + + data class BarnetrygdPeriode( + val personIdent: String, + val delingsprosentYtelse: YtelseProsent, + val ytelseTypeEkstern: YtelseTypeEkstern?, + val utbetaltPerMnd: Int, + val stønadFom: YearMonth, + val stønadTom: YearMonth, + val kildesystem: String = "Infotrygd" + ) + + enum class YtelseTypeEkstern { + ORDINÆR_BARNETRYGD, + UTVIDET_BARNETRYGD, + SMÅBARNSTILLEGG, + } + + enum class YtelseProsent { + FULL, + DELT, + USIKKER + } +} diff --git a/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt b/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt index e1e94fed..dd4d690e 100644 --- a/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt +++ b/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt @@ -20,6 +20,10 @@ import no.nav.familie.ba.infotrygd.rest.controller.BisysController.InfotrygdUtvi import no.nav.familie.ba.infotrygd.rest.controller.BisysController.Stønadstype.SMÅBARNSTILLEGG import no.nav.familie.ba.infotrygd.rest.controller.BisysController.Stønadstype.UTVIDET import no.nav.familie.ba.infotrygd.rest.controller.BisysController.UtvidetBarnetrygdPeriode +import no.nav.familie.ba.infotrygd.rest.controller.PensjonController.BarnetrygdPeriode +import no.nav.familie.ba.infotrygd.rest.controller.PensjonController.BarnetrygdTilPensjon +import no.nav.familie.ba.infotrygd.rest.controller.PensjonController.YtelseProsent +import no.nav.familie.ba.infotrygd.rest.controller.PensjonController.YtelseTypeEkstern import no.nav.familie.ba.infotrygd.utils.DatoUtils import no.nav.familie.ba.infotrygd.utils.DatoUtils.isSameOrAfter import no.nav.familie.eksterne.kontrakter.skatteetaten.SkatteetatenPeriode @@ -32,6 +36,7 @@ import org.springframework.core.env.Environment import org.springframework.data.domain.Page import org.springframework.data.domain.PageRequest import org.springframework.stereotype.Service +import java.time.LocalDate import java.time.LocalDateTime import java.time.YearMonth import java.time.format.DateTimeFormatter @@ -142,6 +147,31 @@ class BarnetrygdService( return personer.map { person -> vedtakRepository.tellAntallÅpneSakerPåPerson(person) }.sum() } + fun finnBarnetrygdForPensjon( + brukerFnr: FoedselsNr, + fraDato: YearMonth + ): List { + val barnetrygdStønader = stonadRepository.findStønadByFnr(listOf(brukerFnr)).filter { it.antallBarn > 0 } + .map { it.tilTrunkertStønad() } + .filter { erRelevantStønad(it) } + .filter { filtrerStønaderSomErFeilregistrert(it) } + + val perioder = konverterTilDtoForPensjon(barnetrygdStønader, fraDato.year).filter { + skalFiltreresPåDato(fraDato, it.stønadFom, it.stønadTom) + } + + if (perioder.isEmpty()) { + return emptyList() + } + + return listOf( + BarnetrygdTilPensjon( + fnr = brukerFnr.asString, + barnetrygdPerioder = perioder + ) + ) + } + fun finnUtvidetBarnetrygdBisys( brukerFnr: FoedselsNr, fraDato: YearMonth @@ -305,6 +335,27 @@ class BarnetrygdService( } } + private fun erRelevantStønad( + stønad: TrunkertStønad + ): Boolean { + return when (stønad.status.toLong()) { + 0L -> { // Manuell beregning ved Stønadsklasse BA OR/UT MB/MD/ME. + + if (stønad.fnr == null) { + logger.info("stønad.fnr var null for stønad med id ${stønad.id}") + return false + } + val undervalg = hentValgOgUndervalg(stønad).second + undervalg in arrayOf(MANUELL_BEREGNING, MANUELL_BEREGNING_DELT_BOSTED, MANUELL_BEREGNING_EØS) + } + 1L -> true // Ordinær barnetrygd - Maskinell beregning + 2L -> true // Utvidet barnetrygd - Maskinell beregning. + 3L -> false // Sykt barn (Ikke lenger i bruk, kan forekomme i gamle tilfeller), + 4L -> false // Ordinær barnetrygd - Institusjon + else -> false + } + } + private fun konverterTilDtoUtvidetBarnetrygdForSkatteetaten( brukerFnr: FoedselsNr, utvidetBarnetrygdStønader: List, år: Int @@ -356,6 +407,53 @@ class BarnetrygdService( } } + private fun konverterTilDtoForPensjon( + barnetrygdStønader: List, + år: Int + ): List { + if (barnetrygdStønader.isEmpty()) { + return emptyList() + } + + val allePerioder = mutableListOf() + + barnetrygdStønader.forEach { + val utbetalinger = utbetalingRepository.hentUtbetalingerByStønad(it) + allePerioder.addAll(utbetalinger.map { utbetaling -> + + val (valg, undervalg) = hentValgOgUndervalg(it) + + BarnetrygdPeriode( + ytelseTypeEkstern = when { + utbetaling.erSmåbarnstillegg() -> YtelseTypeEkstern.SMÅBARNSTILLEGG + valg == "UT" -> YtelseTypeEkstern.UTVIDET_BARNETRYGD + else -> YtelseTypeEkstern.ORDINÆR_BARNETRYGD + }, + stønadFom = utbetaling.fom()!!, + stønadTom = utbetaling.tom() ?: YearMonth.from(LocalDate.MAX), + utbetaltPerMnd = utbetaling.beløp.toInt(), + personIdent = utbetaling.fnr.asString, + delingsprosentYtelse = ytelseProsent(it, undervalg, år) + ) + }) + } + + val perioder = + allePerioder.filter { it.erOrdinærBarnetrygd }.groupBy { it.utbetaltPerMnd }.values + .flatMap(::slåSammenSammenhengende).toMutableList() + + perioder.addAll( + allePerioder.filter { it.erUtvidetBarnetrygd }.groupBy { it.utbetaltPerMnd }.values + .flatMap(::slåSammenSammenhengende) + ) + perioder.addAll( + allePerioder.filter { it.erSmåbarnstillegg }.groupBy { it.utbetaltPerMnd }.values + .flatMap(::slåSammenSammenhengende) + ) + + return perioder + } + private fun delingsprosent(stønad: TrunkertStønad, år: Int): SkatteetatenPeriode.Delingsprosent { val undervalg = hentUndervalg(stønad) var delingsprosent = SkatteetatenPeriode.Delingsprosent.usikker @@ -379,6 +477,27 @@ class BarnetrygdService( return delingsprosent } + private fun ytelseProsent(stønad: TrunkertStønad, undervalg: String?, år: Int): YtelseProsent { + if (stønad.status.toInt() != 0 ) { + return YtelseProsent.FULL + } else if (undervalg == MANUELL_BEREGNING_DELT_BOSTED) { + if (stønad.antallBarn == 1) { + return YtelseProsent.DELT + } else if (stønad.antallBarn < 7) { + val sumUtbetaltBeløp = utbetalingRepository.hentUtbetalingerByStønad(stønad).sumOf { it.beløp } + val gyldigeBeløp = utledListeMedGyldigeUtbetalingsbeløp(stønad.antallBarn, år) + + if (gyldigeBeløp.contains(sumUtbetaltBeløp.roundToInt())) { + return YtelseProsent.DELT + } else { + secureLogger.info("Ytelseprosent usikker, ident ${stønad.fnr}, sumUtbetaltBeløp: $sumUtbetaltBeløp, gyldigeBeløp: $gyldigeBeløp" + + ", antallBarn: ${stønad.antallBarn}, år: $år") + } + } + } + return YtelseProsent.USIKKER + } + fun utledListeMedGyldigeUtbetalingsbeløp(antallBarn: Int, år: Int): Set { val gyldigeBeløp = mutableSetOf() for (i in 0..antallBarn) { @@ -458,6 +577,30 @@ class BarnetrygdService( hentUtvidetBarnetrygdUndervalgFraDb2(stønad).filterNotNull() } + private fun hentValgOgUndervalg(stønad: TrunkertStønad) = + sakRepository.hentBarnetrygdsakerForStønad(stønad).map { + it.valg to it.undervalg + }.filter { it.second != null }.ifEmpty { + hentBarnetrygdValgOgUndervalgFraDb2(stønad) + }.distinct().singleOrNull() ?: (null to null) + + private fun slåSammenSammenhengende(perioderMedLiktBeløp: List): List { + require(perioderMedLiktBeløp.all { it.utbetaltPerMnd == perioderMedLiktBeløp.first().utbetaltPerMnd }) + + return perioderMedLiktBeløp.sortedBy { it.stønadFom } + .fold(mutableListOf()) { sammenslåttePerioder, nestePeriode -> + val forrigePeriode = sammenslåttePerioder.lastOrNull() + + if (forrigePeriode?.stønadTom?.isSameOrAfter(nestePeriode.stønadFom.minusMonths(1)) == true && + forrigePeriode.delingsprosentYtelse == nestePeriode.delingsprosentYtelse) { + + sammenslåttePerioder.apply { add(removeLast().copy(stønadTom = nestePeriode.stønadTom)) } + } else { + sammenslåttePerioder.apply { add(nestePeriode) } + } + } + } + private fun slåSammenSammenhengendePerioder(utbetalingerAvEtGittBeløp: List): List { return utbetalingerAvEtGittBeløp.sortedBy { it.fomMåned } .fold(mutableListOf()) { sammenslåttePerioder, nesteUtbetaling -> @@ -498,6 +641,19 @@ class BarnetrygdService( .map { it.kodeNivå3 } } ?: emptyList() + private fun hentBarnetrygdValgOgUndervalgFraDb2( + stønad: TrunkertStønad + ) = stønad.fnr?.let { + vedtakRepository.hentStønadsklassifisering( + fnr = stønad.fnr.asString, + tkNr = stønad.personKey.toString().padStart(15, '0').substring(0, 4), + saksblokk = stønad.saksblokk, + saksnummer = stønad.sakNr.toLong() + ).groupBy { stønadsklasse -> stønadsklasse.vedtakId }.values + .filter { !it.kodeNivå2.isNullOrBlank() } + .map { it.kodeNivå2!! to it.kodeNivå3 } + } ?: emptyList() + private val List.kodeNivå2: String? get() { return find { it.kodeNivaa == "02" }?.kodeKlasse // vil f.eks være "OR" for en sak av type BA OR OS @@ -522,3 +678,12 @@ class BarnetrygdService( const val PREPROD = "preprod" } } + +private val BarnetrygdPeriode.erOrdinærBarnetrygd: Boolean + get() = ytelseTypeEkstern == YtelseTypeEkstern.ORDINÆR_BARNETRYGD + +private val BarnetrygdPeriode.erUtvidetBarnetrygd: Boolean + get() = ytelseTypeEkstern == YtelseTypeEkstern.UTVIDET_BARNETRYGD + +private val BarnetrygdPeriode.erSmåbarnstillegg: Boolean + get() = ytelseTypeEkstern == YtelseTypeEkstern.SMÅBARNSTILLEGG \ No newline at end of file diff --git a/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt b/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt index 395d3859..c8e5898a 100644 --- a/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt +++ b/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt @@ -18,8 +18,10 @@ import no.nav.familie.ba.infotrygd.repository.StønadsklasseRepository import no.nav.familie.ba.infotrygd.repository.UtbetalingRepository import no.nav.familie.ba.infotrygd.repository.VedtakRepository import no.nav.familie.ba.infotrygd.rest.controller.BisysController +import no.nav.familie.ba.infotrygd.rest.controller.PensjonController +import no.nav.familie.ba.infotrygd.rest.controller.PensjonController.YtelseProsent +import no.nav.familie.ba.infotrygd.rest.controller.PensjonController.YtelseTypeEkstern import no.nav.familie.ba.infotrygd.testutil.TestData -import no.nav.familie.ba.infotrygd.testutil.TestData.foedselsNr import no.nav.familie.eksterne.kontrakter.skatteetaten.SkatteetatenPeriode import org.assertj.core.api.Assertions.assertThat import org.hibernate.exception.SQLGrammarException @@ -150,6 +152,54 @@ internal class BarnetrygdServiceTest { assertThat(barnetrygdService.tellAntallÅpneSaker(emptyList(), emptyList())).isEqualTo(0) } + @Test + fun `finn barnetrygd for pensjon - finner full ordniær barnetrygd`() { + val person = settOppLøpendeOrdinærBarnetrygd(ORDINÆR_BARNETRYGD_STATUS) + + val response = barnetrygdService.finnBarnetrygdForPensjon(person.fnr, YearMonth.now()).single() + assertThat(response.barnetrygdPerioder).contains( + PensjonController.BarnetrygdPeriode( + personIdent = person.fnr.asString, + delingsprosentYtelse = YtelseProsent.FULL, + ytelseTypeEkstern = YtelseTypeEkstern.ORDINÆR_BARNETRYGD, + utbetaltPerMnd = 1054, + stønadFom = YearMonth.of(2020, 5), + stønadTom = YearMonth.from(LocalDate.MAX), + kildesystem = "Infotrygd", + ) + ) + } + + @Test + fun `finn barnetrygd for pensjon - finner løpende småbarnstillegg, og løpende utvidet fra og med dato gitt av foregående periode`() { + val person = settOppLøpendeUtvidetBarnetrygd(MANUELT_BEREGNET_STATUS) + leggTilUtgåttUtvidetBarnetrygdSak(person) //2019-05 - 2020-04 + + + val response = barnetrygdService.finnBarnetrygdForPensjon(person.fnr, YearMonth.now()).single() + assertThat(response.barnetrygdPerioder).contains( + PensjonController.BarnetrygdPeriode( + personIdent = person.fnr.asString, + delingsprosentYtelse = YtelseProsent.USIKKER, + ytelseTypeEkstern = YtelseTypeEkstern.UTVIDET_BARNETRYGD, + utbetaltPerMnd = 1054, + stønadFom = YearMonth.of(2019, 5), + stønadTom = YearMonth.from(LocalDate.MAX), + kildesystem = "Infotrygd", + ) + ) + assertThat(response.barnetrygdPerioder).contains( + PensjonController.BarnetrygdPeriode( + personIdent = person.fnr.asString, + delingsprosentYtelse = YtelseProsent.USIKKER, + ytelseTypeEkstern = YtelseTypeEkstern.SMÅBARNSTILLEGG, + utbetaltPerMnd = 660, + stønadFom = YearMonth.of(2020, 5), + stønadTom = YearMonth.from(LocalDate.MAX), + kildesystem = "Infotrygd", + ) + ) + } @Test fun `hent utvidet barnetrygd for stønad med status 0, utvidet barnetrygdsak og inputdato med dato nå, som kun henter aktiv stønad, manuelt beregnet`() { @@ -664,6 +714,14 @@ internal class BarnetrygdServiceTest { assertThat(barnetrygdService.harSendtBrevForrigeMåned(listOf(person.fnr), listOf("B001"))).hasSize(1) } + private fun settOppLøpendeOrdinærBarnetrygd(stønadStatus: String): Person { + val person = personRepository.save(TestData.person()) + val løpendeStønad = stonadRepository.save(TestData.stønad(person, status = stønadStatus, opphørtFom = "000000")) + sakRepository.save(TestData.sak(person, løpendeStønad.saksblokk, løpendeStønad.sakNr, valg = "OR", undervalg = "OS")) + utbetalingRepository.saveAll(listOf(TestData.utbetaling(løpendeStønad))) + return person + + } private fun settOppLøpendeUtvidetBarnetrygd(stønadStatus: String): Person { val person = personRepository.save(TestData.person()) @@ -716,7 +774,7 @@ internal class BarnetrygdServiceTest { companion object { const val MANUELT_BEREGNET_STATUS = "0" - const val UTVIDET_BARNETRYGD_STATUS = "2" + const val ORDINÆR_BARNETRYGD_STATUS = "1" const val SATS_BARNETRYGD_OVER_6 = 1054.0 const val SATS_BARNETRYGD_UNDER_6_2021 = 1654.0 const val SATS_BARNETRYGD_UNDER_6_2022 = 1676.0 From 5cbacad18966148311d4fd2febcd16af1281d289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20N=C3=A6rland?= Date: Thu, 5 Oct 2023 10:38:25 +0200 Subject: [PATCH 2/4] Fikser kompileringsfeil etter merge med main --- .../no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt b/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt index 8cd650f9..9589c988 100644 --- a/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt +++ b/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt @@ -34,6 +34,7 @@ import org.springframework.core.env.Environment import org.springframework.test.context.ActiveProfiles import org.springframework.test.context.junit4.SpringRunner import java.sql.SQLException +import java.time.LocalDate import java.time.LocalDateTime import java.time.YearMonth import java.time.format.DateTimeFormatter From 3e2db5817e405859dbc98b9d54e19e045c3c5864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20N=C3=A6rland?= Date: Thu, 5 Oct 2023 11:43:34 +0200 Subject: [PATCH 3/4] Fjerner utbetaltPrMnd da den ikke brukes til noe --- .../rest/controller/PensjonController.kt | 1 - .../ba/infotrygd/service/BarnetrygdService.kt | 22 +++++++++---------- .../service/BarnetrygdServiceTest.kt | 3 --- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt b/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt index 4089e2a4..b2129188 100644 --- a/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt +++ b/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt @@ -63,7 +63,6 @@ class PensjonController( val personIdent: String, val delingsprosentYtelse: YtelseProsent, val ytelseTypeEkstern: YtelseTypeEkstern?, - val utbetaltPerMnd: Int, val stønadFom: YearMonth, val stønadTom: YearMonth, val kildesystem: String = "Infotrygd" diff --git a/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt b/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt index 2c411f8c..b99eb697 100644 --- a/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt +++ b/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt @@ -440,7 +440,6 @@ class BarnetrygdService( }, stønadFom = utbetaling.fom()!!, stønadTom = utbetaling.tom() ?: YearMonth.from(LocalDate.MAX), - utbetaltPerMnd = utbetaling.beløp.toInt(), personIdent = utbetaling.fnr.asString, delingsprosentYtelse = ytelseProsent(it, undervalg, år) ) @@ -448,15 +447,15 @@ class BarnetrygdService( } val perioder = - allePerioder.filter { it.erOrdinærBarnetrygd }.groupBy { it.utbetaltPerMnd }.values + allePerioder.filter { it.erOrdinærBarnetrygd }.groupBy { it.delingsprosentYtelse }.values .flatMap(::slåSammenSammenhengende).toMutableList() perioder.addAll( - allePerioder.filter { it.erUtvidetBarnetrygd }.groupBy { it.utbetaltPerMnd }.values + allePerioder.filter { it.erUtvidetBarnetrygd }.groupBy { it.delingsprosentYtelse }.values .flatMap(::slåSammenSammenhengende) ) perioder.addAll( - allePerioder.filter { it.erSmåbarnstillegg }.groupBy { it.utbetaltPerMnd }.values + allePerioder.filter { it.erSmåbarnstillegg }.groupBy { it.delingsprosentYtelse }.values .flatMap(::slåSammenSammenhengende) ) @@ -591,18 +590,19 @@ class BarnetrygdService( it.valg to it.undervalg }.filter { it.second != null }.ifEmpty { hentBarnetrygdValgOgUndervalgFraDb2(stønad) - }.distinct().singleOrNull() ?: (null to null) + }.distinct().singleOrNull() ?: run { + secureLogger.info("Manglende/tvetydig stønadsklassifisering for stønad $stønad") + (null to null) + } - private fun slåSammenSammenhengende(perioderMedLiktBeløp: List): List { - require(perioderMedLiktBeløp.all { it.utbetaltPerMnd == perioderMedLiktBeløp.first().utbetaltPerMnd }) + private fun slåSammenSammenhengende(perioderMedLikProsentandel: List): List { + require(perioderMedLikProsentandel.all { it.delingsprosentYtelse == perioderMedLikProsentandel.first().delingsprosentYtelse }) - return perioderMedLiktBeløp.sortedBy { it.stønadFom } + return perioderMedLikProsentandel.sortedBy { it.stønadFom } .fold(mutableListOf()) { sammenslåttePerioder, nestePeriode -> val forrigePeriode = sammenslåttePerioder.lastOrNull() - if (forrigePeriode?.stønadTom?.isSameOrAfter(nestePeriode.stønadFom.minusMonths(1)) == true && - forrigePeriode.delingsprosentYtelse == nestePeriode.delingsprosentYtelse) { - + if (forrigePeriode?.stønadTom?.isSameOrAfter(nestePeriode.stønadFom.minusMonths(1)) == true) { sammenslåttePerioder.apply { add(removeLast().copy(stønadTom = nestePeriode.stønadTom)) } } else { sammenslåttePerioder.apply { add(nestePeriode) } diff --git a/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt b/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt index 9589c988..a6e35fab 100644 --- a/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt +++ b/src/test/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdServiceTest.kt @@ -173,7 +173,6 @@ internal class BarnetrygdServiceTest { personIdent = person.fnr.asString, delingsprosentYtelse = YtelseProsent.FULL, ytelseTypeEkstern = YtelseTypeEkstern.ORDINÆR_BARNETRYGD, - utbetaltPerMnd = 1054, stønadFom = YearMonth.of(2020, 5), stønadTom = YearMonth.from(LocalDate.MAX), kildesystem = "Infotrygd", @@ -193,7 +192,6 @@ internal class BarnetrygdServiceTest { personIdent = person.fnr.asString, delingsprosentYtelse = YtelseProsent.USIKKER, ytelseTypeEkstern = YtelseTypeEkstern.UTVIDET_BARNETRYGD, - utbetaltPerMnd = 1054, stønadFom = YearMonth.of(2019, 5), stønadTom = YearMonth.from(LocalDate.MAX), kildesystem = "Infotrygd", @@ -204,7 +202,6 @@ internal class BarnetrygdServiceTest { personIdent = person.fnr.asString, delingsprosentYtelse = YtelseProsent.USIKKER, ytelseTypeEkstern = YtelseTypeEkstern.SMÅBARNSTILLEGG, - utbetaltPerMnd = 660, stønadFom = YearMonth.of(2020, 5), stønadTom = YearMonth.from(LocalDate.MAX), kildesystem = "Infotrygd", From 29f925e8cd40780f357c533567d206ff36aa9c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20N=C3=A6rland?= Date: Fri, 6 Oct 2023 09:04:57 +0200 Subject: [PATCH 4/4] =?UTF-8?q?Legger=20til=20endepunkt=20for=20henting=20?= =?UTF-8?q?av=20alle=20personer=20med=20barnetrygd=20et=20bestemt=20=C3=A5?= =?UTF-8?q?r=20til=20pensjon=20(for=20det=20meste=20en=20kopi=20av=20skatt?= =?UTF-8?q?-versjonen).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Endrer fraDato-typen i perioder-requesten til LocalDate, i samsvar med request-objektet i BA-sak. --- .../rest/controller/PensjonController.kt | 26 ++++++++++++++----- .../ba/infotrygd/service/BarnetrygdService.kt | 21 +++++++++++++-- .../St\303\270nadRepositoryTest.kt" | 20 ++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt b/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt index b2129188..a06d97d4 100644 --- a/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt +++ b/src/main/kotlin/no/nav/familie/ba/infotrygd/rest/controller/PensjonController.kt @@ -3,6 +3,7 @@ package no.nav.familie.ba.infotrygd.rest.controller import com.fasterxml.jackson.annotation.JsonProperty import io.micrometer.core.annotation.Timed import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema @@ -11,11 +12,14 @@ import no.nav.familie.ba.infotrygd.service.BarnetrygdService import no.nav.familie.ba.infotrygd.service.ClientValidator import no.nav.security.token.support.core.api.Protected 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.RequestMapping +import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import org.springframework.web.server.ResponseStatusException +import java.time.LocalDate import java.time.YearMonth import io.swagger.v3.oas.annotations.parameters.RequestBody as ApiRequestBody @@ -30,24 +34,34 @@ class PensjonController( @Operation(summary = "Uttrekk barnetrygdperioder på en person fra en bestemet måned. Maks 2 år tilbake i tid") @PostMapping(path = ["pensjon"], consumes = ["application/json"]) - @ApiRequestBody(content = [Content(examples = [ExampleObject(value = """{"personIdent": "12345678910", "fraDato": "2022-05"}""")])]) + @ApiRequestBody(content = [Content(examples = [ExampleObject(value = """{"ident": "12345678910", "fraDato": "2022-12-01"}""")])]) fun hentBarnetrygd(@RequestBody request: BarnetrygdTilPensjonRequest): BarnetrygdTilPensjonResponse { clientValidator.authorizeClient() - if (request.fraDato.isBefore(YearMonth.now().minusYears(2))) { + val fraDato = YearMonth.of(request.fraDato.year, request.fraDato.month) + + if (fraDato.isBefore(YearMonth.now().minusYears(2))) { throw ResponseStatusException(HttpStatus.BAD_REQUEST, "fraDato kan ikke være lenger enn 2 år tilbake i tid") } - val bruker = FoedselsNr(request.personIdent) + val bruker = FoedselsNr(request.ident) return BarnetrygdTilPensjonResponse( - saker = barnetrygdService.finnBarnetrygdForPensjon(bruker, request.fraDato) + saker = barnetrygdService.finnBarnetrygdForPensjon(bruker, fraDato) ) } + @Operation(summary = "Finner alle personer med barnetrygd innenfor et bestemt år på vegne av Psys") + @GetMapping(path = ["pensjon"]) + fun personerMedBarnetrygd(@Parameter(name = "aar") @RequestParam("aar") år: String): List { + clientValidator.authorizeClient() + return barnetrygdService.finnPersonerBarnetrygdPensjon(år) + } + + data class BarnetrygdTilPensjonRequest( - val personIdent: String, - @Schema(implementation = String::class, example = "2020-05") val fraDato: YearMonth, + val ident: String, + @Schema(implementation = String::class, example = "2020-12-01") val fraDato: LocalDate, ) data class BarnetrygdTilPensjonResponse( diff --git a/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt b/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt index b99eb697..21eb378e 100644 --- a/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt +++ b/src/main/kotlin/no/nav/familie/ba/infotrygd/service/BarnetrygdService.kt @@ -162,7 +162,7 @@ class BarnetrygdService( ): List { val barnetrygdStønader = stonadRepository.findStønadByFnr(listOf(brukerFnr)).filter { it.antallBarn > 0 } .map { it.tilTrunkertStønad() } - .filter { erRelevantStønad(it) } + .filter { erRelevantStønadForPensjon(it) } .filter { filtrerStønaderSomErFeilregistrert(it) } val perioder = konverterTilDtoForPensjon(barnetrygdStønader, fraDato.year).filter { @@ -249,6 +249,23 @@ class BarnetrygdService( } } + @Cacheable(cacheManager = "personerCacheManager", value = ["pensjon_personer"], unless = "#result == null") + fun finnPersonerBarnetrygdPensjon(år: String): List { + val stønaderMedAktuelleKoder = stonadRepository.findStønadByÅrAndStatusKoder(år.toInt(), "00", "01", "02") + .filter { erRelevantStønadForPensjon(it) } + .filter { filtrerStønaderSomErFeilregistrert(it) } + .filter { + val sisteMåned = DatoUtils.stringDatoMMyyyyTilYearMonth(it.opphørtFom)?.minusMonths(1) + sisteMåned == null || sisteMåned.year >= år.toInt() + } + .filter { + utbetalingRepository.hentUtbetalingerByStønad(it).any { it.tom() == null || it.tom()!!.year >= år.toInt() } + } + + return stønaderMedAktuelleKoder.mapNotNull { + it.fnr + } + } fun listUtvidetStønadstyperForPerson(år: Int, fnr:String): List { val utvidetBarnetrygdStønader = stonadRepository.findStønadByÅrAndStatusKoderAndFnr(FoedselsNr(fnr), år, "00", "02", "03").map { it.tilTrunkertStønad() } @@ -344,7 +361,7 @@ class BarnetrygdService( } } - private fun erRelevantStønad( + private fun erRelevantStønadForPensjon( stønad: TrunkertStønad ): Boolean { return when (stønad.status.toLong()) { diff --git "a/src/test/kotlin/no/nav/familie/ba/infotrygd/repository/St\303\270nadRepositoryTest.kt" "b/src/test/kotlin/no/nav/familie/ba/infotrygd/repository/St\303\270nadRepositoryTest.kt" index 126aaf28..3f4061fa 100644 --- "a/src/test/kotlin/no/nav/familie/ba/infotrygd/repository/St\303\270nadRepositoryTest.kt" +++ "b/src/test/kotlin/no/nav/familie/ba/infotrygd/repository/St\303\270nadRepositoryTest.kt" @@ -49,6 +49,26 @@ class StønadRepositoryTest { ) } + @Test + fun `sjekk at antall personer med barnetrygd til pensjon er riktig innenfor hvert av årene 2021, 2022 og 2023`() { + stønadRepository.saveAll(listOf( + TestData.stønad(TestData.person(), opphørtFom = "122021", status = "01"), // ordinær barnetrygd opphørt 2021 + TestData.stønad(TestData.person(), opphørtFom = "122022", status = "02"), // utvidet opphørt 2022 + TestData.stønad(TestData.person(), status = "02") // løpende utvidet + )).also { stønader -> + utbetalingRepository.saveAll(stønader.map { TestData.utbetaling(it) }) + } + barnetrygdService.finnPersonerBarnetrygdPensjon("2021").also { + assertThat(it).hasSize(3) + } + barnetrygdService.finnPersonerBarnetrygdPensjon("2022").also { + assertThat(it).hasSize(2) + } + barnetrygdService.finnPersonerBarnetrygdPensjon("2023").also { + assertThat(it).hasSize(1) + } + } + @Test fun `sjekk at antall personer med utvidet barnetrygd er riktig innenfor hvert av årene 2019, 2020 og 2021`() { val personFraInneværendeÅr = TestData.person()