Skip to content

Commit c2facad

Browse files
authored
Fix: Håndtere tilfeller hvor opphør ikke er lagt inn på siste periode i kjede (#5143)
[NAV-24387](https://favro.com/organization/98c34fb974ce445eac854de0/1844bbac3b6605eacc8f5543?card=NAV-24387) ### 💰 Hva skal gjøres, og hvorfor? Ved dry-run av konsistensavstemming fikk vi feil ved at samme periodeId dukket opp i flere forskjellige kjeder. Dette skal ikke forekomme. Fant ut at feilen skyldes at man i noen tilfeller ikke har lagt inn opphør på den siste perioden i kjeden, men en tidligere periode i kjeden. Legger her inn håndtering av "out of order"-perioder for en kjede ved å slå opp hvilken kjede perioden faller innenfor når periodens `forrigePeriodeId` ikke er den, så langt, siste perioden i kjeden. ### ✅ Checklist - [ ] Jeg har testet mine endringer i henhold til akseptansekriteriene 🕵️ - [ ] Jeg har config- eller sql-endringer. - [x] Jeg har skrevet tester.
1 parent 72f62c2 commit c2facad

File tree

2 files changed

+98
-12
lines changed

2 files changed

+98
-12
lines changed

Diff for: src/main/kotlin/no/nav/familie/ba/sak/integrasjoner/økonomi/UtbetalingsTidslinjeService.kt

+37-12
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class UtbetalingsTidslinjeService(
5353
val utbetalingsperioderPerKjede =
5454
utbetalingsperioderPerKjede(iverksatteUtbetalingsoppdrag = iverksatteUtbetalingsoppdrag)
5555

56-
val tidslinjePerKjede = genererTidslinjePerKjede(iverksatteUtbetalingsoppdrag = iverksatteUtbetalingsoppdrag)
56+
val tidslinjePerKjede = genererTidslinjePerKjede(iverksatteUtbetalingsoppdrag = iverksatteUtbetalingsoppdrag, utbetalingsperioderPerKjede = utbetalingsperioderPerKjede)
5757

5858
return tidslinjePerKjede.keys.map { sistePeriodeIdIKjede ->
5959
Utbetalingstidslinje(
@@ -80,14 +80,16 @@ class UtbetalingsTidslinjeService(
8080
val utbetalingsperidoerPerKjede =
8181
utbetalingsoppdrag.tilUtbetalingsperioderPerKjede().mapValues { (_, utbetalingsperioder) ->
8282
val opphørsPeriode = utbetalingsperioder.singleOrNull { it.opphør != null }
83-
val forrigePeriodeId = opphørsPeriode?.periodeId ?: utbetalingsperioder.minOfOrNull { it.forrigePeriodeId ?: -1 }
83+
val forrigePeriodeId = opphørsPeriode?.periodeId ?: utbetalingsperioder.minOfOrNull { it.forrigePeriodeId ?: -1 } ?: -1
8484
Pair(utbetalingsperioder, forrigePeriodeId)
8585
}
8686
kjederForFagsak.apply {
8787
utbetalingsperidoerPerKjede.forEach { periodeId, (utbetalingsperioder, forrigePeriodeId) ->
88-
put(periodeId, getOrDefault(forrigePeriodeId, emptySet()).plus(utbetalingsperioder))
89-
if (periodeId != forrigePeriodeId) {
90-
remove(forrigePeriodeId)
88+
val sistePeriodeIdIKjede = finnSistePeriodeIdIKjede(forrigePeriodeId, this)
89+
val nySistePeriodeIdIKjede = periodeId.takeIf { it > sistePeriodeIdIKjede } ?: sistePeriodeIdIKjede
90+
put(nySistePeriodeIdIKjede, getOrDefault(sistePeriodeIdIKjede, emptySet()).plus(utbetalingsperioder))
91+
if (nySistePeriodeIdIKjede != sistePeriodeIdIKjede) {
92+
remove(sistePeriodeIdIKjede)
9193
}
9294
}
9395
}
@@ -107,21 +109,28 @@ class UtbetalingsTidslinjeService(
107109
}
108110
}
109111

110-
private fun genererTidslinjePerKjede(iverksatteUtbetalingsoppdrag: List<Utbetalingsoppdrag>): Map<Long, Tidslinje<Utbetalingsperiode>> =
112+
private fun genererTidslinjePerKjede(
113+
iverksatteUtbetalingsoppdrag: List<Utbetalingsoppdrag>,
114+
utbetalingsperioderPerKjede: Map<Long, Set<Utbetalingsperiode>>,
115+
): Map<Long, Tidslinje<Utbetalingsperiode>> =
111116
iverksatteUtbetalingsoppdrag
112117
.fold(mutableMapOf()) { kjederForFagsak, utbetalingsoppdrag ->
113118
val kjederForUtbetalingsperioder =
114119
utbetalingsoppdrag.tilUtbetalingsperioderPerKjede().mapValues { (_, kjede) ->
115120
val opphørsperiode = kjede.singleOrNull { it.opphør != null }
116121
val nyePerioder = kjede.filter { it.opphør == null }.map { Periode(it, fom = it.vedtakdatoFom, tom = it.vedtakdatoTom) }
117-
val forrigePeriodeId = opphørsperiode?.periodeId ?: nyePerioder.minOfOrNull { it.verdi.forrigePeriodeId ?: -1 }
122+
val forrigePeriodeId = opphørsperiode?.periodeId ?: nyePerioder.minOfOrNull { it.verdi.forrigePeriodeId ?: -1 } ?: -1
118123
Triple(nyePerioder.tilTidslinje(), forrigePeriodeId, opphørsperiode)
119124
}
120125
kjederForFagsak.apply {
121126
kjederForUtbetalingsperioder.forEach { periodeId, (tidslinje, forrigePeriodeId, opphørsperiode) ->
127+
// I noen fagsaker har man lagt inn opphør på feil periode i kjede.
128+
// Opphør skal i utgangspunktet alltid legges inn på siste periode i kjede, men i noen fagsaker har opphør blitt lagt inn på en tidligere periode i kjeden.
129+
// Sørger her for at vi ikke oppretter nye kjeder når dette skjer, men heller finner ut hvilken kjede perioden faller inn under.
130+
val sistePeriodeIdIKjede = finnSistePeriodeIdIKjede(forrigePeriodeId, this, utbetalingsperioderPerKjede)
131+
val nySistePeriodeIdIKjede = periodeId.takeIf { it > sistePeriodeIdIKjede } ?: sistePeriodeIdIKjede
122132
val gjeldendeTidslinje =
123-
kjederForFagsak
124-
.getOrDefault(forrigePeriodeId, tomTidslinje())
133+
getOrDefault(sistePeriodeIdIKjede, tomTidslinje())
125134
.beskjærOgKorrigerPerioderVedOpphør(opphørsperiode)
126135
.beskjærTilOgMedEtterIkkeTomTidslinje(tidslinje)
127136

@@ -132,11 +141,11 @@ class UtbetalingsTidslinjeService(
132141
nyUtbetalingsperiode ?: gjeldendeUtbetalingsperiode
133142
}.tilPerioderIkkeNull()
134143
.tilTidslinje()
135-
put(periodeId, nyGjeldendeTidslinje)
144+
put(nySistePeriodeIdIKjede, nyGjeldendeTidslinje)
136145

137146
// Håndtering av opphør. Da vil periodeId være lik forrigePeriodeId, og vi må sørge for at vi ikke sletter tidslinja vi akkurat har oppdatert.
138-
if (periodeId != forrigePeriodeId) {
139-
remove(forrigePeriodeId)
147+
if (nySistePeriodeIdIKjede != sistePeriodeIdIKjede) {
148+
remove(sistePeriodeIdIKjede)
140149
}
141150
}
142151
}
@@ -168,4 +177,20 @@ class UtbetalingsTidslinjeService(
168177
}
169178
return this.beskjærTilOgMedEtter(tidslinje)
170179
}
180+
181+
private fun finnSistePeriodeIdIKjede(
182+
forrigePeriodeId: Long,
183+
kjederForFagsak: Map<Long, Set<Utbetalingsperiode>>,
184+
): Long = kjederForFagsak.entries.singleOrNull { (_, utbetalingsperioder) -> utbetalingsperioder.any { utbetalingsperiode -> utbetalingsperiode.periodeId == forrigePeriodeId } }?.key ?: -1
185+
186+
private fun finnSistePeriodeIdIKjede(
187+
forrigePeriodeId: Long,
188+
tidslinjerPerKjede: Map<Long, Tidslinje<Utbetalingsperiode>>,
189+
utbetalingsperioderPerKjede: Map<Long, Set<Utbetalingsperiode>>,
190+
): Long =
191+
tidslinjerPerKjede.keys.singleOrNull { sistePeriodeIdIKjede ->
192+
val kjedeForSistePeriodeIdIKjede = utbetalingsperioderPerKjede.entries.single { (_, utbetalingsperioder) -> utbetalingsperioder.any { it.periodeId == sistePeriodeIdIKjede } }.key
193+
val kjedeForForrigePeriodeId = utbetalingsperioderPerKjede.entries.singleOrNull { (_, utbetalingsperidoer) -> utbetalingsperidoer.any { it.periodeId == forrigePeriodeId } }?.key
194+
kjedeForSistePeriodeIdIKjede == kjedeForForrigePeriodeId
195+
} ?: -1
171196
}

Diff for: src/test/enhetstester/kotlin/no/nav/familie/ba/sak/integrasjoner/økonomi/UtbetalingsTidslinjeServiceTest.kt

+61
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import io.mockk.every
44
import io.mockk.mockk
55
import no.nav.familie.ba.sak.common.førsteDagIInneværendeMåned
66
import no.nav.familie.ba.sak.common.sisteDagIInneværendeMåned
7+
import no.nav.familie.ba.sak.common.sisteDagIMåned
78
import no.nav.familie.ba.sak.datagenerator.lagBehandling
89
import no.nav.familie.ba.sak.datagenerator.lagFagsak
910
import no.nav.familie.ba.sak.datagenerator.lagTilkjentYtelse
@@ -413,6 +414,66 @@ class UtbetalingsTidslinjeServiceTest {
413414
assertThat(perioderIAndreTidslinje[0].verdi.periodeId).isEqualTo(førstegangsbehandlingPeriode1Kjede2.periodeId)
414415
assertThat(perioderIAndreTidslinje[0].verdi.forrigePeriodeId).isEqualTo(førstegangsbehandlingPeriode1Kjede2.forrigePeriodeId)
415416
}
417+
418+
@Test
419+
fun `skal generere utbetalingstidslinjer for revurdering hvor man ikke bruker siste periode i kjede for opphør`() {
420+
// Arrange
421+
val fagsak = lagFagsak()
422+
val førstegangsbehandling = lagBehandling(fagsak)
423+
val revurderingOpphørFeilPeriodeId = lagBehandling(fagsak)
424+
425+
val revurderingOpphørFeilPeriodeIdPeriode1Kjede1 =
426+
lagUtbetalingsperiode(
427+
fom = førstegangsBehandlingPeriode1Kjede1.vedtakdatoFom,
428+
tom = førstegangsBehandlingPeriode1Kjede1.vedtakdatoTom,
429+
periodeId = 0,
430+
forrigePeriodeId = null,
431+
behandlingId = revurderingOpphørFeilPeriodeId.id,
432+
klassifisering = YtelseType.ORDINÆR_BARNETRYGD.klassifisering,
433+
beløp = BigDecimal.valueOf(1000L),
434+
opphør = Opphør(opphørDatoFom = førstegangsBehandlingPeriode1Kjede1.vedtakdatoFom.plusMonths(1)),
435+
)
436+
437+
val utbetalingsoppdragRevurderingOpphørFeilPeriodeId =
438+
lagUtbetalingsoppdrag(
439+
avstemmingTidspunkt = LocalDateTime.of(2025, 3, 1, 0, 0, 0),
440+
utbetalingsperiode =
441+
listOf(
442+
revurderingOpphørFeilPeriodeIdPeriode1Kjede1,
443+
),
444+
)
445+
446+
every { tilkjentYtelseRepository.findByFagsak(fagsak.id) } returns
447+
listOf(
448+
lagTilkjentYtelse(behandling = førstegangsbehandling, utbetalingsoppdrag = objectMapper.writeValueAsString(lagUtbetalingsoppdragFørstegangsbehandling())),
449+
lagTilkjentYtelse(behandling = revurderingOpphørFeilPeriodeId, utbetalingsoppdrag = objectMapper.writeValueAsString(utbetalingsoppdragRevurderingOpphørFeilPeriodeId)),
450+
)
451+
452+
// Act
453+
val utbetalingstidslinjer = utbetalingsTidslinjeService.genererUtbetalingstidslinjerForFagsak(fagsakId = fagsak.id)
454+
val førsteTidslinje = utbetalingsTidslinjeService.finnUtbetalingsTidslinjeForPeriodeId(førstePeriodeIdKjede1, utbetalingstidslinjer)
455+
val andreTidslinje = utbetalingsTidslinjeService.finnUtbetalingsTidslinjeForPeriodeId(førstePeriodeIdKjede2, utbetalingstidslinjer)
456+
457+
// Assert
458+
assertThat(utbetalingstidslinjer).hasSize(2)
459+
assertThat(førsteTidslinje.tidslinje).isNotNull
460+
val perioderIFørsteTidslinje = førsteTidslinje.tidslinje.tilPerioderIkkeNull()
461+
assertThat(perioderIFørsteTidslinje).hasSize(1)
462+
assertThat(perioderIFørsteTidslinje[0].fom).isEqualTo(førstegangsBehandlingPeriode1Kjede1.vedtakdatoFom)
463+
assertThat(perioderIFørsteTidslinje[0].tom).isEqualTo(førstegangsBehandlingPeriode1Kjede1.vedtakdatoFom.sisteDagIMåned())
464+
assertThat(perioderIFørsteTidslinje[0].verdi.behandlingId).isEqualTo(revurderingOpphørFeilPeriodeIdPeriode1Kjede1.behandlingId)
465+
assertThat(perioderIFørsteTidslinje[0].verdi.periodeId).isEqualTo(førstegangsBehandlingPeriode1Kjede1.periodeId)
466+
assertThat(perioderIFørsteTidslinje[0].verdi.forrigePeriodeId).isEqualTo(førstegangsBehandlingPeriode1Kjede1.forrigePeriodeId)
467+
468+
assertThat(andreTidslinje.tidslinje).isNotNull
469+
val perioderIAndreTidslinje = andreTidslinje.tidslinje.tilPerioderIkkeNull()
470+
assertThat(perioderIAndreTidslinje).hasSize(1)
471+
assertThat(perioderIAndreTidslinje[0].fom).isEqualTo(førstegangsbehandlingPeriode1Kjede2.vedtakdatoFom)
472+
assertThat(perioderIAndreTidslinje[0].tom).isEqualTo(førstegangsbehandlingPeriode1Kjede2.vedtakdatoTom)
473+
assertThat(perioderIAndreTidslinje[0].verdi.behandlingId).isEqualTo(førstegangsbehandlingPeriode1Kjede2.behandlingId)
474+
assertThat(perioderIAndreTidslinje[0].verdi.periodeId).isEqualTo(førstegangsbehandlingPeriode1Kjede2.periodeId)
475+
assertThat(perioderIAndreTidslinje[0].verdi.forrigePeriodeId).isEqualTo(førstegangsbehandlingPeriode1Kjede2.forrigePeriodeId)
476+
}
416477
}
417478

418479
private val førstegangsBehandlingPeriode1Kjede1 =

0 commit comments

Comments
 (0)