Skip to content

Commit

Permalink
NAV-22995: Ny klassekode for utvidet barnetrygd (BAUTV-OP) (#4852)
Browse files Browse the repository at this point in the history
Favro:
[NAV-22995](https://favro.com/organization/98c34fb974ce445eac854de0/1844bbac3b6605eacc8f5543?card=NAV-22995)

### 💰 Hva skal gjøres, og hvorfor?
Bruker nå ny klassekode `BAUTV-OP` for utvidet barnetrygd fremfor `BATR`
som ble brukt tidligere. Endringen er lagt bak feature toggle som vi vil
skru på for enkelte fagsaker til å begynne med.

Det er laget skreddersydd håndtering dersom utvidet barnetrygd opphører
i fagsaker som ikke er over på ny klassekode for utvidet. I disse
tilfellene vil vi fortsette å bruke `BATR`. Ved opphør av utvidet
barnetrygd i fagsaker som er over på ny klassekode vil vi fortsette å
bruke den nye klassekoden `BAUTV-OP`.

### 🔎️ Er det noe spesielt du ønsker tilbakemelding om?
Vi har også omstrukturert koden rundt generering av utbetalingsoppdrag
og oppdatering av tilkjent ytelse. Kun strukturelle endringer.

### ✅ Checklist
- [x] Jeg har testet mine endringer i henhold til akseptansekriteriene
🕵️
- [ ] Jeg har config- eller sql-endringer. 
- [x] Jeg har skrevet tester.

### 💬 Ønsker du en muntlig gjennomgang?
- [ ] Ja
- [x] Nei, men tar gjerne en gjennomgang om ønskelig.

Detaljer for siste utbetaling på Min side -> Utbetalinger:

![image](https://github.com/user-attachments/assets/a01f0654-d56c-4488-887d-eac254ba41fe)

---------

Co-authored-by: thoalm <[email protected]>
Co-authored-by: Thomas Alm <[email protected]>
  • Loading branch information
3 people authored Nov 13, 2024
1 parent ab4c4f5 commit 637f705
Show file tree
Hide file tree
Showing 37 changed files with 2,974 additions and 1,214 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ class FeatureToggleConfig {
// NAV-22311
const val OPPRETT_SAK_PÅ_RIKTIG_ENHET_OG_SAKSBEHANDLER = "familie-ba-ks-sak.opprett-sak-paa-riktig-enhet-og-saksbehandler"

// NAV-22995
const val SKAL_BRUKE_NY_KLASSEKODE_FOR_UTVIDET_BARNETRYGD = "familie-ba-sak.skal-bruke-ny-klassekode-for-utvidet-barnetrygd"

// satsendring
// Oppretter satsendring-tasker for de som ikke har fått ny task
const val SATSENDRING_ENABLET: String = "familie-ba-sak.satsendring-enablet"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package no.nav.familie.ba.sak.integrasjoner.økonomi.utbetalingsoppdrag

import no.nav.familie.ba.sak.common.ClockProvider
import no.nav.familie.ba.sak.kjerne.beregning.domene.AndelTilkjentYtelse
import no.nav.familie.ba.sak.kjerne.beregning.domene.TilkjentYtelse
import no.nav.familie.ba.sak.kjerne.fagsak.Fagsak
import no.nav.familie.ba.sak.kjerne.fagsak.FagsakType
import no.nav.familie.ba.sak.kjerne.vedtak.Vedtak
import no.nav.familie.felles.utbetalingsgenerator.domain.Behandlingsinformasjon
import no.nav.familie.felles.utbetalingsgenerator.domain.IdentOgType
import org.springframework.stereotype.Component
import java.time.LocalDate
import java.time.YearMonth

@Component
class BehandlingsinformasjonUtleder(
private val endretMigreringsdatoUtleder: EndretMigreringsdatoUtleder,
private val clockProvider: ClockProvider,
) {
fun utled(
saksbehandlerId: String,
vedtak: Vedtak,
forrigeTilkjentYtelse: TilkjentYtelse?,
sisteAndelPerKjede: Map<IdentOgType, AndelTilkjentYtelse>,
erSimulering: Boolean,
): Behandlingsinformasjon {
val behandling = vedtak.behandling
val fagsak = behandling.fagsak
val endretMigreringsdato = endretMigreringsdatoUtleder.utled(fagsak, forrigeTilkjentYtelse)
return Behandlingsinformasjon(
saksbehandlerId = saksbehandlerId,
behandlingId = behandling.id.toString(),
eksternBehandlingId = behandling.id,
eksternFagsakId = fagsak.id,
fagsystem = FagsystemBA.BARNETRYGD,
personIdent = fagsak.aktør.aktivFødselsnummer(),
vedtaksdato = vedtak.vedtaksdato?.toLocalDate() ?: LocalDate.now(clockProvider.get()),
opphørAlleKjederFra = finnOpphørsdatoForAlleKjeder(forrigeTilkjentYtelse, sisteAndelPerKjede, endretMigreringsdato),
utbetalesTil = finnUtebetalesTil(fagsak),
opphørKjederFraFørsteUtbetaling = finnOpphørKjederFraFørsteUtbetaling(endretMigreringsdato, erSimulering),
)
}

private fun finnOpphørsdatoForAlleKjeder(
forrigeTilkjentYtelse: TilkjentYtelse?,
sisteAndelPerKjede: Map<IdentOgType, AndelTilkjentYtelse>,
endretMigreringsdato: YearMonth?,
): YearMonth? =
if (forrigeTilkjentYtelse == null || sisteAndelPerKjede.isEmpty()) {
null
} else {
endretMigreringsdato
}

private fun finnUtebetalesTil(fagsak: Fagsak): String =
when (fagsak.type) {
FagsakType.NORMAL,
FagsakType.BARN_ENSLIG_MINDREÅRIG,
-> fagsak.aktør.aktivFødselsnummer()

FagsakType.INSTITUSJON,
-> {
fagsak.institusjon?.tssEksternId ?: throw IllegalStateException(
"Fagsak ${fagsak.id} er av type institusjon og mangler informasjon om institusjonen",
)
}
}

private fun finnOpphørKjederFraFørsteUtbetaling(
endretMigreringsdato: YearMonth?,
erSimulering: Boolean,
) =
if (endretMigreringsdato != null) {
false
} else {
// Ved simulering når migreringsdato er endret, skal vi opphøre fra den nye datoen og ikke fra første utbetaling per kjede.
erSimulering
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package no.nav.familie.ba.sak.integrasjoner.økonomi.utbetalingsoppdrag

import no.nav.familie.ba.sak.common.toYearMonth
import no.nav.familie.ba.sak.kjerne.behandling.BehandlingHentOgPersisterService
import no.nav.familie.ba.sak.kjerne.behandling.BehandlingService
import no.nav.familie.ba.sak.kjerne.behandling.domene.BehandlingType
import no.nav.familie.ba.sak.kjerne.beregning.domene.TilkjentYtelse
import no.nav.familie.ba.sak.kjerne.fagsak.Fagsak
import org.springframework.stereotype.Component
import java.time.YearMonth

@Component
class EndretMigreringsdatoUtleder(
private val behandlingHentOgPersisterService: BehandlingHentOgPersisterService,
private val behandlingService: BehandlingService,
) {
fun utled(
fagsak: Fagsak,
forrigeTilkjentYtelse: TilkjentYtelse?,
): YearMonth? {
val forrigeTilstandFraDato = forrigeTilkjentYtelse?.andelerTilkjentYtelse?.minOfOrNull { it.stønadFom }

if (forrigeTilstandFraDato == null) {
return null
}

val erMigrertSak =
behandlingHentOgPersisterService
.hentBehandlinger(fagsak.id)
.any { it.type == BehandlingType.MIGRERING_FRA_INFOTRYGD }

if (!erMigrertSak) {
return null
}

val migreringsdatoPåFagsak = behandlingService.hentMigreringsdatoPåFagsak(fagsakId = fagsak.id)

if (migreringsdatoPåFagsak == null) {
return null
}

val nyTilstandFraDato = migreringsdatoPåFagsak.toYearMonth().plusMonths(1)

if (nyTilstandFraDato.isAfter(forrigeTilstandFraDato)) {
throw IllegalStateException("Ny migreringsdato kan ikke være etter forrige migreringsdato")
}

return if (forrigeTilstandFraDato.isAfter(nyTilstandFraDato)) {
nyTilstandFraDato
} else {
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum class FagsystemBA(
setOf(
YtelsetypeBA.ORDINÆR_BARNETRYGD,
YtelsetypeBA.UTVIDET_BARNETRYGD,
YtelsetypeBA.UTVIDET_BARNETRYGD_GAMMEL,
YtelsetypeBA.SMÅBARNSTILLEGG,
),
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package no.nav.familie.ba.sak.integrasjoner.økonomi.utbetalingsoppdrag

import no.nav.familie.ba.sak.config.FeatureToggleConfig
import no.nav.familie.ba.sak.config.featureToggle.UnleashNextMedContextService
import no.nav.familie.ba.sak.kjerne.behandling.domene.Behandling
import no.nav.familie.ba.sak.kjerne.beregning.domene.TilkjentYtelseRepository
import no.nav.familie.felles.utbetalingsgenerator.domain.BeregnetUtbetalingsoppdragLongId
import org.springframework.stereotype.Component

@Component
class KlassifiseringKorrigerer(
private val tilkjentYtelseRepository: TilkjentYtelseRepository,
private val unleashNextMedContextService: UnleashNextMedContextService,
) {
fun korrigerKlassifiseringVedBehov(
beregnetUtbetalingsoppdrag: BeregnetUtbetalingsoppdragLongId,
behandling: Behandling,
): BeregnetUtbetalingsoppdragLongId {
// For fagsaker vi ikke har skrudd på ny klassekode for, returnerer vi det originale utbetalingsoppdraget.
if (!unleashNextMedContextService.isEnabled(
toggleId = FeatureToggleConfig.SKAL_BRUKE_NY_KLASSEKODE_FOR_UTVIDET_BARNETRYGD,
behandlingId = behandling.id,
)
) {
return beregnetUtbetalingsoppdrag
}

val erFagsakOverPåNyKlassekodeForUtvidetBarnetrygd =
tilkjentYtelseRepository.harFagsakTattIBrukNyKlassekodeForUtvidetBarnetrygd(
fagsakId = behandling.fagsak.id,
)

// Fagsak er over på ny klassekode for utvidet barnetrygd. Trenger ikke gjøre noen justeringer.
if (erFagsakOverPåNyKlassekodeForUtvidetBarnetrygd) {
return beregnetUtbetalingsoppdrag
}

val utvidetBarnetrygdErOpphørt =
beregnetUtbetalingsoppdrag
.utbetalingsoppdrag
.utbetalingsperiode
.any { it.opphør != null && it.klassifisering == YtelsetypeBA.UTVIDET_BARNETRYGD.klassifisering }

// Fagsak er ikke over på ny klassekode for utvidet barnetrygd, men det finnes heller ikke noe
// opphør på en utvidet-kjede. Trenger ikke gjøre noen justeringer.
if (!utvidetBarnetrygdErOpphørt) {
return beregnetUtbetalingsoppdrag
}

// Når fagsak ikke er over på ny klassekode for utvidet barnetrygd og vi opphører en utvidet kjede,
// må vi bruke gammel klassekode.
return beregnetUtbetalingsoppdrag.copy(
utbetalingsoppdrag =
beregnetUtbetalingsoppdrag.utbetalingsoppdrag.copy(
utbetalingsperiode =
beregnetUtbetalingsoppdrag.utbetalingsoppdrag.utbetalingsperiode.map {
if (it.opphør != null && it.klassifisering == YtelsetypeBA.UTVIDET_BARNETRYGD.klassifisering) {
it.copy(klassifisering = YtelsetypeBA.UTVIDET_BARNETRYGD_GAMMEL.klassifisering)
} else {
it
}
},
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package no.nav.familie.ba.sak.integrasjoner.økonomi.utbetalingsoppdrag

import no.nav.familie.ba.sak.common.ClockProvider
import no.nav.familie.ba.sak.common.secureLogger
import no.nav.familie.ba.sak.common.toYearMonth
import no.nav.familie.ba.sak.kjerne.beregning.domene.AndelTilkjentYtelse
import no.nav.familie.ba.sak.kjerne.beregning.domene.TilkjentYtelse
import no.nav.familie.ba.sak.kjerne.beregning.domene.TilkjentYtelseRepository
import no.nav.familie.ba.sak.kjerne.beregning.domene.tilAndelerTilkjentYtelseMedEndreteUtbetalinger
import no.nav.familie.ba.sak.kjerne.endretutbetaling.EndretUtbetalingAndelHentOgPersisterService
import no.nav.familie.ba.sak.kjerne.endretutbetaling.domene.EndretUtbetalingAndel
import no.nav.familie.ba.sak.kjerne.endretutbetaling.domene.førerTilOpphør
import no.nav.familie.felles.utbetalingsgenerator.domain.AndelMedPeriodeIdLongId
import no.nav.familie.felles.utbetalingsgenerator.domain.BeregnetUtbetalingsoppdragLongId
import no.nav.familie.felles.utbetalingsgenerator.domain.Utbetalingsoppdrag
import no.nav.familie.kontrakter.felles.objectMapper
import org.springframework.stereotype.Service
import java.time.LocalDate
import java.time.YearMonth

@Service
class OppdaterTilkjentYtelseService(
private val endretUtbetalingAndelHentOgPersisterService: EndretUtbetalingAndelHentOgPersisterService,
private val tilkjentYtelseRepository: TilkjentYtelseRepository,
private val clockProvider: ClockProvider,
) {
fun oppdaterTilkjentYtelseMedUtbetalingsoppdrag(
tilkjentYtelse: TilkjentYtelse,
beregnetUtbetalingsoppdrag: BeregnetUtbetalingsoppdragLongId,
) {
secureLogger.info(
"Oppdaterer TilkjentYtelse med utbetalingsoppdrag og offsets på andeler for behandling ${tilkjentYtelse.behandling.id}",
)

oppdaterTilkjentYtelseMedUtbetalingsoppdrag(
tilkjentYtelse = tilkjentYtelse,
utbetalingsoppdrag = beregnetUtbetalingsoppdrag.utbetalingsoppdrag,
endretUtbetalingAndeler = endretUtbetalingAndelHentOgPersisterService.hentForBehandling(tilkjentYtelse.behandling.id),
)

oppdaterAndelerMedPeriodeOffset(
tilkjentYtelse = tilkjentYtelse,
andelerMedPeriodeId = beregnetUtbetalingsoppdrag.andeler,
)

tilkjentYtelseRepository.save(tilkjentYtelse)
}

private fun oppdaterTilkjentYtelseMedUtbetalingsoppdrag(
tilkjentYtelse: TilkjentYtelse,
utbetalingsoppdrag: Utbetalingsoppdrag,
endretUtbetalingAndeler: List<EndretUtbetalingAndel>,
) {
val opphør = Opphør.opprettFor(utbetalingsoppdrag, tilkjentYtelse.behandling)
tilkjentYtelse.utbetalingsoppdrag = objectMapper.writeValueAsString(utbetalingsoppdrag)
tilkjentYtelse.stønadTom = utledStønadTom(tilkjentYtelse.andelerTilkjentYtelse, endretUtbetalingAndeler)
tilkjentYtelse.stønadFom = if (opphør.erRentOpphør) null else tilkjentYtelse.andelerTilkjentYtelse.minOf { it.stønadFom }
tilkjentYtelse.endretDato = LocalDate.now(clockProvider.get())
tilkjentYtelse.opphørFom = opphør.opphørsdato?.toYearMonth()
}

private fun utledStønadTom(
andelerTilkjentYtelse: Set<AndelTilkjentYtelse>,
endretUtbetalingAndeler: List<EndretUtbetalingAndel>,
): YearMonth? {
val andelerMedEndringer = andelerTilkjentYtelse.tilAndelerTilkjentYtelseMedEndreteUtbetalinger(endretUtbetalingAndeler)

val andelerMedRelevantUtbetaling =
andelerMedEndringer.filterNot { andelTilkjentYtelseMedEndreteUtbetalinger ->
andelTilkjentYtelseMedEndreteUtbetalinger.endreteUtbetalinger.any { endretUtbetaling ->
endretUtbetaling.førerTilOpphør()
}
}

return andelerMedRelevantUtbetaling.maxOfOrNull { it.stønadTom }
}

private fun oppdaterAndelerMedPeriodeOffset(
tilkjentYtelse: TilkjentYtelse,
andelerMedPeriodeId: List<AndelMedPeriodeIdLongId>,
) {
val andelerPåId = andelerMedPeriodeId.associateBy { it.id }
val andelerTilkjentYtelse = tilkjentYtelse.andelerTilkjentYtelse
val andelerSomSkalSendesTilOppdrag = andelerTilkjentYtelse.filter { it.erAndelSomSkalSendesTilOppdrag() }
if (andelerMedPeriodeId.size != andelerSomSkalSendesTilOppdrag.size) {
throw IllegalStateException(
"Antallet andeler med oppdatert periodeOffset, forrigePeriodeOffset og kildeBehandlingId fra ny generator skal være likt antallet andeler med kalkulertUtbetalingsbeløp != 0. Generator gir ${andelerMedPeriodeId.size} andeler men det er ${andelerSomSkalSendesTilOppdrag.size} andeler med kalkulertUtbetalingsbeløp != 0",
)
}
andelerSomSkalSendesTilOppdrag.forEach { andel ->
val andelMedOffset = andelerPåId[andel.id]
if (andelMedOffset == null) {
throw IllegalStateException(
"Feil ved oppdaterig av offset på andeler. Finner ikke andel med id ${andel.id} blandt andelene med oppdatert offset fra ny generator. Ny generator returnerer andeler med ider ${andelerPåId.values.map { it.id }}",
)
}
andel.periodeOffset = andelMedOffset.periodeId
andel.forrigePeriodeOffset = andelMedOffset.forrigePeriodeId
andel.kildeBehandlingId = andelMedOffset.kildeBehandlingId
}
}
}
Loading

0 comments on commit 637f705

Please sign in to comment.