From 9cb3310e0a5cd5eaf98ff049e0442bbdf4a5d5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Golberg?= Date: Fri, 22 Nov 2024 15:28:45 +0100 Subject: [PATCH 1/4] =?UTF-8?q?=C3=85rlig=20inntektsjusteringsjobb=20oppre?= =?UTF-8?q?tter=20avkorting=20med=20tidligere=20opph=C3=B8r=20f=C3=B8r=20b?= =?UTF-8?q?eregner=20fra=201.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AarligInntektsjusteringService.kt | 3 + .../AvkortingReparerAarsoppgjoeret.kt | 86 ++++++++++++++++++ .../kotlin/avkorting/AvkortingRepository.kt | 19 ++++ .../main/kotlin/avkorting/AvkortingService.kt | 25 ++++-- .../main/kotlin/config/ApplicationContext.kt | 5 ++ .../BeregningOgAvkortingBrevService.kt | 6 +- .../kotlin/avkorting/AvkortingServiceTest.kt | 89 ++++++++++++++++--- 7 files changed, 215 insertions(+), 18 deletions(-) create mode 100644 apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt diff --git a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AarligInntektsjusteringService.kt b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AarligInntektsjusteringService.kt index c900a14d92b..a07c540e459 100644 --- a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AarligInntektsjusteringService.kt +++ b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AarligInntektsjusteringService.kt @@ -62,6 +62,9 @@ class AarligInntektsjusteringService( fom = YearMonth.of(aar, 1), ) + // Avkorting opprettes her med tidligere årsoppgjør + avkortingService.hentOpprettEllerReberegnAvkorting(behandlingId, brukerTokenInfo) + avkortingService.beregnAvkortingMedNyttGrunnlag(behandlingId, brukerTokenInfo, nyttGrunnlag) return avkortingRepository.hentAvkorting(behandlingId) ?: throw AvkortingFinnesIkkeException(behandlingId) diff --git a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt new file mode 100644 index 00000000000..077a0b88d4c --- /dev/null +++ b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt @@ -0,0 +1,86 @@ +package no.nav.etterlatte.avkorting + +import no.nav.etterlatte.libs.common.feilhaandtering.InternfeilException +import no.nav.etterlatte.libs.common.sak.SakId +import no.nav.etterlatte.libs.common.vedtak.VedtakSammendragDto +import no.nav.etterlatte.libs.common.vedtak.VedtakType +import java.time.YearMonth + +/* +* Inntektsjobb for 2025 innførte en feil i alle behandlinger som ble gjort automatisk som kompanseres for her. +* Alle behandlinger skal inneholde alle tidligere årsoppgjør men de automatiske behandlingene i jobben består kun av 2025. +* Det medfører at revurdering tilbake til 2024 mangler inntekten for 2024 når forrige behandling/avkorting kopieres. +* +* For å reparere dette gjøres det ekstra håndtering for å flette forrige avkorting med forrige avkorting i 2024. +* Denne må kjøre helt til alle saker har lagd en ny revurdering. +* +* Når alle saker har en ny revurdering hver (f.eks ved regulering eller etteroppgjør) +* kan dette fjernes og kun kopiere forrige avkorting. +* +*/ +class AvkortingReparerAarsoppgjoeret( + val avkortingRepository: AvkortingRepository, +) { + fun hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting: Avkorting, + virkningstidspunkt: YearMonth, + sakId: SakId, + alleVedtak: List, + ): Avkorting { + val alleAarMedAarsoppgjoer = avkortingRepository.hentAlleAarsoppgjoer(sakId).map { it.aar }.distinct() + val manglerAar = alleAarMedAarsoppgjoer != forrigeAvkorting.aarsoppgjoer.map { it.aar } + + if (manglerAar) { + val sisteAarsoppgjoer = forrigeAvkorting.aarsoppgjoer.maxBy { it.aar } + if (sisteAarsoppgjoer.aar < virkningstidspunkt.year) { + // TODO to unittester + if (virkningstidspunkt != YearMonth.of(virkningstidspunkt.year, 1)) { + throw FoersteRevurderingSenereEnnJanuar() + } + return forrigeAvkorting + } + + // TODO en unittester - mock liste med vedtak som har opphør i mellom + val sisteBehandlingSammeAar = alleVedtak.sisteLoependeVedtakForAar(virkningstidspunkt.year).behandlingId + + val forrigeAvkortingSammeAar = + avkortingRepository.hentAvkorting(sisteBehandlingSammeAar) + ?: throw TidligereAvkortingFinnesIkkeException(sisteBehandlingSammeAar) + + // TODO to unittester + val forrigeAvkortingHarAarsoppgjoerForVirk = + forrigeAvkortingSammeAar.aarsoppgjoer.map { it.aar }.contains(virkningstidspunkt.year) + return forrigeAvkortingSammeAar.copy( + aarsoppgjoer = + if (forrigeAvkortingHarAarsoppgjoerForVirk) { + val nyttAarsoppgjoer = + forrigeAvkorting.aarsoppgjoer.single { + it.aar == virkningstidspunkt.year + } + forrigeAvkortingSammeAar.aarsoppgjoer.erstattEtAarsoppgjoer(nyttAarsoppgjoer) + } else { + forrigeAvkortingSammeAar.aarsoppgjoer + forrigeAvkorting.aarsoppgjoer + }, + ) + } else { + // TODO en unittester + return forrigeAvkorting + } + } +} + +fun List.erstattEtAarsoppgjoer(nyttAarsoppgjoer: Aarsoppgjoer) = + map { + when (it.aar) { + nyttAarsoppgjoer.aar -> nyttAarsoppgjoer + else -> it + } + } + +fun List.sisteLoependeVedtakForAar(aar: Int) = + filter { + val vedtakAar = it.virkningstidspunkt?.year ?: throw InternfeilException("Vedtak mangler virk") + it.vedtakType != VedtakType.OPPHOER && (vedtakAar) != aar + }.maxBy { + it.datoAttestert ?: throw InternfeilException("Iverksatt vedtak mangler dato attestert") + } diff --git a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingRepository.kt b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingRepository.kt index 55497006b4f..3265c8ca334 100644 --- a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingRepository.kt +++ b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingRepository.kt @@ -501,4 +501,23 @@ class AvkortingRepository( sanksjonId = uuid("sanksjon_id"), sanksjonType = enumValueOf(string("sanksjon_type")), ) + + fun hentAlleAarsoppgjoer(sakId: SakId): List = + dataSource.transaction { tx -> + queryOf( + "SELECT * FROM avkorting_aarsoppgjoer WHERE sak_id= ? ORDER BY aar ASC", + sakId, + ).let { query -> + tx.run( + query + .map { row -> + Aarsoppgjoer( + id = row.uuid("id"), + aar = row.int("aar"), + fom = row.sqlDate("fom").let { YearMonth.from(it.toLocalDate()) }, + ) + }.asList, + ) + } + } } diff --git a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingService.kt b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingService.kt index 14f222c56f1..368e2f6d8c6 100644 --- a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingService.kt +++ b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingService.kt @@ -22,6 +22,7 @@ import no.nav.etterlatte.libs.common.vedtak.VedtakType import no.nav.etterlatte.libs.ktor.token.BrukerTokenInfo import no.nav.etterlatte.sanksjon.SanksjonService import org.slf4j.LoggerFactory +import java.time.YearMonth import java.util.UUID enum class AvkortingToggles( @@ -40,6 +41,7 @@ class AvkortingService( private val sanksjonService: SanksjonService, private val grunnlagKlient: GrunnlagKlient, private val vedtakKlient: VedtaksvurderingKlient, + private val avkortingReparerAarsoppgjoeret: AvkortingReparerAarsoppgjoeret, private val featureToggleService: FeatureToggleService, ) { private val logger = LoggerFactory.getLogger(this::class.java) @@ -69,7 +71,8 @@ class AvkortingService( } } - val forrigeAvkorting = hentAvkortingForrigeBehandling(behandling.sak, brukerTokenInfo) + val forrigeAvkorting = + hentAvkortingForrigeBehandling(behandling.sak, brukerTokenInfo, behandling.virkningstidspunkt().dato) return if (eksisterendeAvkorting == null) { val nyAvkorting = kopierOgReberegnAvkorting(behandling, forrigeAvkorting, brukerTokenInfo) @@ -148,7 +151,12 @@ class AvkortingService( if (behandling.behandlingType == BehandlingType.FØRSTEGANGSBEHANDLING) { avkortingMedTillegg(lagretAvkorting, behandling) } else { - val forrigeAvkorting = hentAvkortingForrigeBehandling(behandling.sak, brukerTokenInfo) + val forrigeAvkorting = + hentAvkortingForrigeBehandling( + behandling.sak, + brukerTokenInfo, + behandling.virkningstidspunkt().dato, + ) avkortingMedTillegg( lagretAvkorting, behandling, @@ -240,16 +248,23 @@ class AvkortingService( suspend fun hentAvkortingForrigeBehandling( sakId: SakId, brukerTokenInfo: BrukerTokenInfo, + virkningstidspunkt: YearMonth, ): Avkorting { + val alleVedtak = vedtakKlient.hentIverksatteVedtak(sakId, brukerTokenInfo) val forrigeBehandlingId = - vedtakKlient - .hentIverksatteVedtak(sakId, brukerTokenInfo) + alleVedtak .filter { it.vedtakType != VedtakType.OPPHOER }.maxBy { it.datoAttestert ?: throw InternfeilException("Iverksatt vedtak mangler dato attestert") }.behandlingId - return hentForrigeAvkorting(forrigeBehandlingId) + val forrigeAvkorting = hentForrigeAvkorting(forrigeBehandlingId) + return avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + virkningstidspunkt, + sakId, + alleVedtak, + ) } fun hentForrigeAvkorting(forrigeBehandlingId: UUID): Avkorting = diff --git a/apps/etterlatte-beregning/src/main/kotlin/config/ApplicationContext.kt b/apps/etterlatte-beregning/src/main/kotlin/config/ApplicationContext.kt index 89640570d14..095611c4f2e 100644 --- a/apps/etterlatte-beregning/src/main/kotlin/config/ApplicationContext.kt +++ b/apps/etterlatte-beregning/src/main/kotlin/config/ApplicationContext.kt @@ -3,6 +3,7 @@ package no.nav.etterlatte.config import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import no.nav.etterlatte.avkorting.AarligInntektsjusteringService +import no.nav.etterlatte.avkorting.AvkortingReparerAarsoppgjoeret import no.nav.etterlatte.avkorting.AvkortingRepository import no.nav.etterlatte.avkorting.AvkortingService import no.nav.etterlatte.avkorting.AvkortingTidligAlderspensjonService @@ -105,6 +106,9 @@ class ApplicationContext { sanksjonService = sanksjonService, ) val avkortingRepository = AvkortingRepository(dataSource) + + val avkortingReparerAarsoppgjoeret = AvkortingReparerAarsoppgjoeret(avkortingRepository) + val avkortingService = AvkortingService( behandlingKlient = behandlingKlient, @@ -113,6 +117,7 @@ class ApplicationContext { sanksjonService = sanksjonService, grunnlagKlient = grunnlagKlient, vedtakKlient = vedtaksvurderingKlient, + avkortingReparerAarsoppgjoeret = avkortingReparerAarsoppgjoeret, featureToggleService = featureToggleService, ) val avkortingTidligAlderspensjonService = diff --git a/apps/etterlatte-beregning/src/main/kotlin/ytelseMedGrunnlag/BeregningOgAvkortingBrevService.kt b/apps/etterlatte-beregning/src/main/kotlin/ytelseMedGrunnlag/BeregningOgAvkortingBrevService.kt index 6007dd62541..5f23de2858d 100644 --- a/apps/etterlatte-beregning/src/main/kotlin/ytelseMedGrunnlag/BeregningOgAvkortingBrevService.kt +++ b/apps/etterlatte-beregning/src/main/kotlin/ytelseMedGrunnlag/BeregningOgAvkortingBrevService.kt @@ -72,7 +72,11 @@ class BeregningOgAvkortingBrevService( BehandlingType.FØRSTEGANGSBEHANDLING -> false else -> { val forrigeAvkorting = - avkortingService.hentAvkortingForrigeBehandling(behandling.sak, brukerTokenInfo) + avkortingService.hentAvkortingForrigeBehandling( + behandling.sak, + brukerTokenInfo, + behandling.virkningstidspunkt().dato, + ) val sisteBeloep = forrigeAvkorting .toDto() diff --git a/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingServiceTest.kt b/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingServiceTest.kt index 6283acd8d5d..4b75fee19b0 100644 --- a/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingServiceTest.kt +++ b/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingServiceTest.kt @@ -42,6 +42,9 @@ internal class AvkortingServiceTest { private val sanksjonService: SanksjonService = mockk() private val grunnlagKlient: GrunnlagKlient = mockk() private val vedtaksvurderingKlient: VedtaksvurderingKlient = mockk() + + private val avkortingReparerAarsoppgjoeret: AvkortingReparerAarsoppgjoeret = mockk() + private val featureToggleService: FeatureToggleService = mockk(relaxed = true) { every { isEnabled(AvkortingToggles.VALIDERE_AARSINNTEKT_NESTE_AAR, any(), any()) } returns false @@ -55,6 +58,7 @@ internal class AvkortingServiceTest { sanksjonService, grunnlagKlient, vedtaksvurderingKlient, + avkortingReparerAarsoppgjoeret, featureToggleService, ) @@ -187,12 +191,22 @@ internal class AvkortingServiceTest { val eksisterendeAvkorting = mockk() val forrigeAvkorting = mockk() val avkortingFrontend = mockk() - - coEvery { behandlingKlient.hentBehandling(any(), any()) } returns behandling - coEvery { vedtaksvurderingKlient.hentIverksatteVedtak(any(), any()) } returns + val alleVedtak = listOf( vedtakSammendragDto(behandlingId = forrigeBehandlingId), ) + + coEvery { behandlingKlient.hentBehandling(any(), any()) } returns behandling + coEvery { vedtaksvurderingKlient.hentIverksatteVedtak(any(), any()) } returns alleVedtak + + every { + avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + any(), + any(), + any(), + any(), + ) + } returns forrigeAvkorting every { avkortingRepository.hentAvkorting(behandlingId) } returns eksisterendeAvkorting every { avkortingRepository.hentAvkorting(forrigeBehandlingId) } returns forrigeAvkorting every { eksisterendeAvkorting.toFrontend(any(), any(), any()) } returns avkortingFrontend @@ -205,6 +219,12 @@ internal class AvkortingServiceTest { behandlingKlient.hentBehandling(behandlingId, bruker) avkortingRepository.hentAvkorting(behandlingId) vedtaksvurderingKlient.hentIverksatteVedtak(behandling.sak, bruker) + avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + YearMonth.of(2024, 1), + behandling.sak, + alleVedtak, + ) avkortingRepository.hentAvkorting(forrigeBehandlingId) eksisterendeAvkorting.toFrontend(YearMonth.of(2024, 1), forrigeAvkorting, BehandlingStatus.AVKORTET) } @@ -228,12 +248,21 @@ internal class AvkortingServiceTest { val beregnetAvkorting = mockk() val lagretAvkorting = mockk() val avkortingFrontend = mockk() - - coEvery { behandlingKlient.hentBehandling(any(), any()) } returns behandling - coEvery { vedtaksvurderingKlient.hentIverksatteVedtak(any(), any()) } returns + val alleVedtak = listOf( vedtakSammendragDto(behandlingId = forrigeBehandlingId), ) + + coEvery { behandlingKlient.hentBehandling(any(), any()) } returns behandling + coEvery { vedtaksvurderingKlient.hentIverksatteVedtak(any(), any()) } returns alleVedtak + every { + avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + any(), + any(), + any(), + any(), + ) + } returns forrigeAvkorting every { avkortingRepository.hentAvkorting(forrigeBehandlingId) } returns forrigeAvkorting every { avkortingRepository.hentAvkorting(behandlingId) } returns null andThen lagretAvkorting every { beregningService.hentBeregningNonnull(any()) } returns beregning @@ -252,6 +281,12 @@ internal class AvkortingServiceTest { behandlingKlient.avkort(behandlingId, bruker, false) behandlingKlient.hentBehandling(behandlingId, bruker) vedtaksvurderingKlient.hentIverksatteVedtak(behandling.sak, bruker) + avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + YearMonth.of(2024, 1), + behandling.sak, + alleVedtak, + ) avkortingRepository.hentAvkorting(forrigeBehandlingId) beregningService.hentBeregningNonnull(behandlingId) sanksjonService.hentSanksjon(behandlingId) @@ -286,12 +321,21 @@ internal class AvkortingServiceTest { val reberegnetAvkorting = mockk() val lagretAvkorting = mockk() val avkortingFrontend = mockk() - - coEvery { behandlingKlient.hentBehandling(any(), any()) } returns behandling - coEvery { vedtaksvurderingKlient.hentIverksatteVedtak(any(), any()) } returns + val alleVedtak = listOf( vedtakSammendragDto(behandlingId = forrigeBehandlingId), ) + + coEvery { behandlingKlient.hentBehandling(any(), any()) } returns behandling + coEvery { vedtaksvurderingKlient.hentIverksatteVedtak(any(), any()) } returns alleVedtak + every { + avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + any(), + any(), + any(), + any(), + ) + } returns forrigeAvkorting every { avkortingRepository.hentAvkorting(behandlingId) } returns eksisterendeAvkorting andThen lagretAvkorting every { avkortingRepository.hentAvkorting(forrigeBehandlingId) } returns forrigeAvkorting every { beregningService.hentBeregningNonnull(any()) } returns beregning @@ -309,6 +353,12 @@ internal class AvkortingServiceTest { behandlingKlient.avkort(behandlingId, bruker, false) behandlingKlient.hentBehandling(behandlingId, bruker) vedtaksvurderingKlient.hentIverksatteVedtak(behandling.sak, bruker) + avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + YearMonth.of(2024, 1), + behandling.sak, + alleVedtak, + ) avkortingRepository.hentAvkorting(forrigeBehandlingId) beregningService.hentBeregningNonnull(behandlingId) sanksjonService.hentSanksjon(behandlingId) @@ -408,6 +458,10 @@ internal class AvkortingServiceTest { ) val forrigeBehandling = UUID.randomUUID() val forrigeAvkorting = mockk() + val alleVedtak = + listOf( + vedtakSammendragDto(behandlingId = forrigeBehandling), + ) every { avkortingRepository.hentAvkorting(revurderingId) } returns eksisterendeAvkorting andThen lagretAvkorting coEvery { behandlingKlient.hentBehandling(any(), any()) } returns revurdering @@ -421,10 +475,15 @@ internal class AvkortingServiceTest { eksisterendeAvkorting.beregnAvkortingMedNyttGrunnlag(any(), any(), any(), any(), any()) } returns beregnetAvkorting every { avkortingRepository.lagreAvkorting(any(), any(), any()) } returns Unit - coEvery { vedtaksvurderingKlient.hentIverksatteVedtak(any(), any()) } returns - listOf( - vedtakSammendragDto(behandlingId = forrigeBehandling), + coEvery { vedtaksvurderingKlient.hentIverksatteVedtak(any(), any()) } returns alleVedtak + every { + avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + any(), + any(), + any(), + any(), ) + } returns forrigeAvkorting every { avkortingRepository.hentAvkorting(forrigeBehandling) } returns forrigeAvkorting every { lagretAvkorting.toFrontend(any(), any(), any()) } returns avkortingFrontend coEvery { behandlingKlient.avkort(any(), any(), any()) } returns true @@ -454,6 +513,12 @@ internal class AvkortingServiceTest { ) avkortingRepository.lagreAvkorting(revurderingId, sakId, beregnetAvkorting) vedtaksvurderingKlient.hentIverksatteVedtak(sakId, bruker) + avkortingReparerAarsoppgjoeret.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + YearMonth.of(2024, 3), + revurdering.sak, + alleVedtak, + ) avkortingRepository.hentAvkorting(forrigeBehandling) lagretAvkorting.toFrontend(YearMonth.of(2024, 3), forrigeAvkorting, BehandlingStatus.BEREGNET) behandlingKlient.avkort(revurderingId, bruker, true) From bfc1538cdaa2ac8c655d6a7f4d8c78e6671f7562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Golberg?= Date: Mon, 25 Nov 2024 14:12:49 +0100 Subject: [PATCH 2/4] Unittester --- .../AvkortingReparerAarsoppgjoeret.kt | 45 +--- .../AvkortingReparerAarsoppgjoeretTest.kt | 249 ++++++++++++++++++ 2 files changed, 263 insertions(+), 31 deletions(-) create mode 100644 apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingReparerAarsoppgjoeretTest.kt diff --git a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt index 077a0b88d4c..65f4e226b1c 100644 --- a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt +++ b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt @@ -28,59 +28,42 @@ class AvkortingReparerAarsoppgjoeret( alleVedtak: List, ): Avkorting { val alleAarMedAarsoppgjoer = avkortingRepository.hentAlleAarsoppgjoer(sakId).map { it.aar }.distinct() - val manglerAar = alleAarMedAarsoppgjoer != forrigeAvkorting.aarsoppgjoer.map { it.aar } + val alleAarNyAvkortng = forrigeAvkorting.aarsoppgjoer.map { it.aar } + val manglerAar = alleAarMedAarsoppgjoer != alleAarNyAvkortng if (manglerAar) { val sisteAarsoppgjoer = forrigeAvkorting.aarsoppgjoer.maxBy { it.aar } if (sisteAarsoppgjoer.aar < virkningstidspunkt.year) { - // TODO to unittester if (virkningstidspunkt != YearMonth.of(virkningstidspunkt.year, 1)) { throw FoersteRevurderingSenereEnnJanuar() } return forrigeAvkorting } - // TODO en unittester - mock liste med vedtak som har opphør i mellom - val sisteBehandlingSammeAar = alleVedtak.sisteLoependeVedtakForAar(virkningstidspunkt.year).behandlingId + val manglendeAar = + when (alleAarNyAvkortng.contains(virkningstidspunkt.year)) { + true -> virkningstidspunkt.year.minus(1) + false -> virkningstidspunkt.year + } - val forrigeAvkortingSammeAar = - avkortingRepository.hentAvkorting(sisteBehandlingSammeAar) - ?: throw TidligereAvkortingFinnesIkkeException(sisteBehandlingSammeAar) + val sisteBehandlingManglendeAar = alleVedtak.sisteLoependeVedtakForAar(manglendeAar).behandlingId + val sisteAvkortingManglendeAar = + avkortingRepository.hentAvkorting(sisteBehandlingManglendeAar) + ?: throw TidligereAvkortingFinnesIkkeException(sisteBehandlingManglendeAar) - // TODO to unittester - val forrigeAvkortingHarAarsoppgjoerForVirk = - forrigeAvkortingSammeAar.aarsoppgjoer.map { it.aar }.contains(virkningstidspunkt.year) - return forrigeAvkortingSammeAar.copy( - aarsoppgjoer = - if (forrigeAvkortingHarAarsoppgjoerForVirk) { - val nyttAarsoppgjoer = - forrigeAvkorting.aarsoppgjoer.single { - it.aar == virkningstidspunkt.year - } - forrigeAvkortingSammeAar.aarsoppgjoer.erstattEtAarsoppgjoer(nyttAarsoppgjoer) - } else { - forrigeAvkortingSammeAar.aarsoppgjoer + forrigeAvkorting.aarsoppgjoer - }, + return sisteAvkortingManglendeAar.copy( + aarsoppgjoer = sisteAvkortingManglendeAar.aarsoppgjoer + forrigeAvkorting.aarsoppgjoer, ) } else { - // TODO en unittester return forrigeAvkorting } } } -fun List.erstattEtAarsoppgjoer(nyttAarsoppgjoer: Aarsoppgjoer) = - map { - when (it.aar) { - nyttAarsoppgjoer.aar -> nyttAarsoppgjoer - else -> it - } - } - fun List.sisteLoependeVedtakForAar(aar: Int) = filter { val vedtakAar = it.virkningstidspunkt?.year ?: throw InternfeilException("Vedtak mangler virk") - it.vedtakType != VedtakType.OPPHOER && (vedtakAar) != aar + it.vedtakType != VedtakType.OPPHOER && vedtakAar == aar }.maxBy { it.datoAttestert ?: throw InternfeilException("Iverksatt vedtak mangler dato attestert") } diff --git a/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingReparerAarsoppgjoeretTest.kt b/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingReparerAarsoppgjoeretTest.kt new file mode 100644 index 00000000000..71090393025 --- /dev/null +++ b/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingReparerAarsoppgjoeretTest.kt @@ -0,0 +1,249 @@ +package avkorting + +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import no.nav.etterlatte.avkorting.Avkorting +import no.nav.etterlatte.avkorting.AvkortingReparerAarsoppgjoeret +import no.nav.etterlatte.avkorting.AvkortingRepository +import no.nav.etterlatte.avkorting.FoersteRevurderingSenereEnnJanuar +import no.nav.etterlatte.beregning.regler.aarsoppgjoer +import no.nav.etterlatte.libs.common.sak.SakId +import no.nav.etterlatte.libs.common.vedtak.VedtakSammendragDto +import no.nav.etterlatte.libs.common.vedtak.VedtakType +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.time.YearMonth +import java.time.ZoneId +import java.time.ZonedDateTime +import java.util.UUID + +class AvkortingReparerAarsoppgjoeretTest { + private val repo = mockk() + private val service = AvkortingReparerAarsoppgjoeret(repo) + + @Test + fun `hvis det ikke mangler tidligere aarsoppgjoer paa forrige avkorting skal den returneres`() { + val sakId = SakId(123L) + val forrigeAvkorting = + mockk { + every { aarsoppgjoer } returns + listOf( + aarsoppgjoer(aar = 2024), + aarsoppgjoer(aar = 2025), + ) + } + val virk = YearMonth.of(2024, 12) + val alleVedtak = emptyList() + + every { repo.hentAlleAarsoppgjoer(sakId) } returns + listOf( + aarsoppgjoer(aar = 2024), + aarsoppgjoer(aar = 2025), + ) + + val reparertAvkorting = + service.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + virk, + sakId, + alleVedtak, + ) + + reparertAvkorting shouldBe forrigeAvkorting + } + + @Test + fun `hvis det mangler aarsoppgjoer men det er fordi nytt aarsoppgjoer er et nytt aar skal forrige avkorting returneres`() { + val sakId = SakId(123L) + val forrigeAvkorting = + mockk { + every { aarsoppgjoer } returns + listOf( + aarsoppgjoer(aar = 2024), + ) + } + val virk = YearMonth.of(2025, 1) + val alleVedtak = emptyList() + + every { repo.hentAlleAarsoppgjoer(sakId) } returns + listOf( + aarsoppgjoer(aar = 2024), + aarsoppgjoer(aar = 2025), + ) + + val reparertAvkorting = + service.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + virk, + sakId, + alleVedtak, + ) + + reparertAvkorting shouldBe forrigeAvkorting + } + + @Test + fun `hvis det mangler aarsoppgjoer men det er fordi nytt aarsoppgjoer er et nytt aar skal det feile hvis virk ikke er januar`() { + val sakId = SakId(123L) + val forrigeAvkorting = + mockk { + every { aarsoppgjoer } returns + listOf( + aarsoppgjoer(aar = 2024), + ) + } + val virk = YearMonth.of(2025, 2) + val alleVedtak = emptyList() + + every { repo.hentAlleAarsoppgjoer(sakId) } returns + listOf( + aarsoppgjoer(aar = 2024), + aarsoppgjoer(aar = 2025), + ) + + assertThrows { + service.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + virk, + sakId, + alleVedtak, + ) + } + } + + @Test + fun `hvis det mangler aarsoppgjoer for aar samme som virk skal det tidligere avkorting hentes for kopiering`() { + val sakId = SakId(123L) + val forrigeAvkorting = + Avkorting( + aarsoppgjoer = listOf(aarsoppgjoer(aar = 2025)), + ) + val virk = YearMonth.of(2024, 11) + + val sistebehandlingIdManglendeAar = UUID.randomUUID() + val sisteAvkortingMangelndeAar = + Avkorting( + aarsoppgjoer = + listOf( + aarsoppgjoer(aar = 2024), + ), + ) + + val alleVedtak = + listOf( + vedtakSammendragDto(virk = YearMonth.of(2025, 1), datoAttestert = YearMonth.of(2024, 11)), + vedtakSammendragDto( + behandlingId = sistebehandlingIdManglendeAar, + virk = YearMonth.of(2024, 10), + datoAttestert = YearMonth.of(2024, 9), + ), + vedtakSammendragDto( + type = VedtakType.INNVILGELSE, + virk = YearMonth.of(2024, 3), + datoAttestert = YearMonth.of(2024, 2), + ), + ) + + every { repo.hentAlleAarsoppgjoer(sakId) } returns + listOf( + aarsoppgjoer(aar = 2024), + aarsoppgjoer(aar = 2025), + ) + every { repo.hentAvkorting(sistebehandlingIdManglendeAar) } returns sisteAvkortingMangelndeAar + + val reparertAvkorting = + service.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + virk, + sakId, + alleVedtak, + ) + + reparertAvkorting.aarsoppgjoer.size shouldBe 2 + reparertAvkorting.aarsoppgjoer[0].aar shouldBe 2024 + reparertAvkorting.aarsoppgjoer[1].aar shouldBe 2025 + } + + @Test + fun `hvis det mangler aarsoppgjoer for tidligere aar enn virk skal disse hentes og legges til`() { + val sakId = SakId(123L) + val forrigeAvkorting = + Avkorting( + aarsoppgjoer = listOf(aarsoppgjoer(aar = 2025)), + ) + val virk = YearMonth.of(2025, 2) + + val sistebehandlingIdManglendeAar = UUID.randomUUID() + val sisteAvkortingManglendeAar = + Avkorting( + aarsoppgjoer = + listOf( + aarsoppgjoer(aar = 2024), + ), + ) + + val alleVedtak = + listOf( + vedtakSammendragDto(virk = YearMonth.of(2025, 1), datoAttestert = YearMonth.of(2024, 11)), + vedtakSammendragDto( + behandlingId = sistebehandlingIdManglendeAar, + virk = YearMonth.of(2024, 10), + datoAttestert = YearMonth.of(2024, 9), + ), + vedtakSammendragDto( + type = VedtakType.INNVILGELSE, + virk = YearMonth.of(2024, 3), + datoAttestert = YearMonth.of(2024, 2), + ), + ) + + every { repo.hentAlleAarsoppgjoer(sakId) } returns + listOf( + aarsoppgjoer(aar = 2024), + aarsoppgjoer(aar = 2025), + ) + every { repo.hentAvkorting(sistebehandlingIdManglendeAar) } returns sisteAvkortingManglendeAar + + val reparertAvkorting = + service.hentSisteAvkortingMedReparertAarsoppgjoer( + forrigeAvkorting, + virk, + sakId, + alleVedtak, + ) + + reparertAvkorting.aarsoppgjoer.size shouldBe 2 + reparertAvkorting.aarsoppgjoer[0].aar shouldBe 2024 + reparertAvkorting.aarsoppgjoer[1].aar shouldBe 2025 + } + + companion object { + fun vedtakSammendragDto( + behandlingId: UUID = UUID.randomUUID(), + type: VedtakType = VedtakType.ENDRING, + datoAttestert: YearMonth, + virk: YearMonth, + ) = VedtakSammendragDto( + id = "id", + behandlingId = behandlingId, + vedtakType = type, + behandlendeSaksbehandler = null, + datoFattet = null, + attesterendeSaksbehandler = null, + datoAttestert = + ZonedDateTime.of( + datoAttestert.year, + datoAttestert.monthValue, + 1, + 1, + 1, + 1, + 1, + ZoneId.of("Europe/Oslo"), + ), + virkningstidspunkt = virk, + opphoerFraOgMed = null, + ) + } +} From f5eb74a1116839e122ce42e8ccf266fbb08c8967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Golberg?= Date: Mon, 25 Nov 2024 15:32:06 +0100 Subject: [PATCH 3/4] =?UTF-8?q?Legger=20til=20varsellogging=20n=C3=A5r=20k?= =?UTF-8?q?lasse=20kan=20fjernes=20etter=20regulering=20for=20=C3=A5=20sik?= =?UTF-8?q?re=20at=20det=20ikke=20glemmes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt index 65f4e226b1c..ddc39dde5a1 100644 --- a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt +++ b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingReparerAarsoppgjoeret.kt @@ -4,6 +4,7 @@ import no.nav.etterlatte.libs.common.feilhaandtering.InternfeilException import no.nav.etterlatte.libs.common.sak.SakId import no.nav.etterlatte.libs.common.vedtak.VedtakSammendragDto import no.nav.etterlatte.libs.common.vedtak.VedtakType +import org.slf4j.LoggerFactory import java.time.YearMonth /* @@ -21,12 +22,18 @@ import java.time.YearMonth class AvkortingReparerAarsoppgjoeret( val avkortingRepository: AvkortingRepository, ) { + private val logger = LoggerFactory.getLogger(this::class.java) + fun hentSisteAvkortingMedReparertAarsoppgjoer( forrigeAvkorting: Avkorting, virkningstidspunkt: YearMonth, sakId: SakId, alleVedtak: List, ): Avkorting { + if (YearMonth.now() > YearMonth.of(2025, 5)) { + logger.warn("AvkortingReparerAarsoppgjoeret.kt har nå med sikkerhet blitt kjørt på alle saker etter regulering og kan fjernes!") + } + val alleAarMedAarsoppgjoer = avkortingRepository.hentAlleAarsoppgjoer(sakId).map { it.aar }.distinct() val alleAarNyAvkortng = forrigeAvkorting.aarsoppgjoer.map { it.aar } val manglerAar = alleAarMedAarsoppgjoer != alleAarNyAvkortng From c25a12a46f7eb194d00cc35ad535385e9c194bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Golberg?= Date: Mon, 25 Nov 2024 16:14:41 +0100 Subject: [PATCH 4/4] Fiks feil i repo --- .../kotlin/avkorting/AvkortingRepository.kt | 2 +- .../avkorting/AvkortingRepositoryTest.kt | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingRepository.kt b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingRepository.kt index 3265c8ca334..ee92f662f7c 100644 --- a/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingRepository.kt +++ b/apps/etterlatte-beregning/src/main/kotlin/avkorting/AvkortingRepository.kt @@ -506,7 +506,7 @@ class AvkortingRepository( dataSource.transaction { tx -> queryOf( "SELECT * FROM avkorting_aarsoppgjoer WHERE sak_id= ? ORDER BY aar ASC", - sakId, + sakId.sakId, ).let { query -> tx.run( query diff --git a/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingRepositoryTest.kt b/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingRepositoryTest.kt index da56b8cca9c..7c309538d03 100644 --- a/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingRepositoryTest.kt +++ b/apps/etterlatte-beregning/src/test/kotlin/avkorting/AvkortingRepositoryTest.kt @@ -151,6 +151,24 @@ internal class AvkortingRepositoryTest( } } + @Test + fun `hent alle aarsoppgjoer`() { + val sakId = randomSakId() + avkortingRepository.lagreAvkorting( + UUID.randomUUID(), + sakId, + Avkorting( + aarsoppgjoer = listOf(nyAvkorting(2024), nyAvkorting(2025)), + ), + ) + + val alle = avkortingRepository.hentAlleAarsoppgjoer(sakId) + + alle.size shouldBe 2 + alle[0].aar shouldBe 2024 + alle[1].aar shouldBe 2025 + } + private fun nyAvkorting( aar: Int, forventaInnvilgaMaaneder: Int = 12,