Skip to content

Commit

Permalink
Ny utbetalingsoppdrag-generator: Oppdatering av TilkjentYtelse/Andele…
Browse files Browse the repository at this point in the history
…r og lagt til tester (#3909)

### 💰 Hva skal gjøres, og hvorfor?
* Lagt til oppdatering av `AndelTilkjentYtelse` med offsets fra ny
utbetalingsoppdrag-generator. Oppdatering av andeler ligger bak ny
feature toggle `BRUK_NY_UTBETALINGSGENERATOR`.
* Lagt til Cucumber tester for ny utbetalingsoppdrag-generator, basert
på [Johan sin
branch](main...utbetalingsgenerator-ny-cucumber)
* Laget enhetstester for `UtbetalingsoppdragGeneratorService`.
* Lagt bruk av ny utbetalingsgenerator bak feature-toggle i
`ØkonomiService` og `SimuleringService`. Skrevet tester for å verifisere
at feature toggles fungerer som forventet.

### ✅ Checklist
- [ ] Jeg har testet mine endringer i henhold til akseptansekriteriene
🕵️
- [ ] Jeg har config- eller sql-endringer. I så fall, husk manuell
deploy til miljø for å verifisere endringene.
- [x] Jeg har skrevet tester. 

### 💬 Ønsker du en muntlig gjennomgang?
- [ ] Ja
- [x] Nei

---------

Co-authored-by: Stig Strøm <[email protected]>
  • Loading branch information
bragejahren and stigebil authored Sep 21, 2023
1 parent 751bbf1 commit 197bde1
Show file tree
Hide file tree
Showing 24 changed files with 1,977 additions and 169 deletions.
6 changes: 5 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<felles-kontrakter.version>3.0_20230911102049_85cefe7</felles-kontrakter.version>
<familie.kontrakter.saksstatistikk>2.0_20230214104704_706e9c0</familie.kontrakter.saksstatistikk>
<familie.kontrakter.stønadsstatistikk>2.0_20230912090318_2267c05</familie.kontrakter.stønadsstatistikk>
<utbetalingsgenerator.version>1.0_20230816154126_e551e82</utbetalingsgenerator.version>
<utbetalingsgenerator.version>1.0_20230919124039_4b3660d</utbetalingsgenerator.version>
<familie.kontrakter.skatteetaten>2.0_20230214104704_706e9c0</familie.kontrakter.skatteetaten>
<cucumber.version>7.14.0</cucumber.version>
<mockk.version>1.13.5</mockk.version>
Expand Down Expand Up @@ -274,6 +274,10 @@
<groupId>no.nav.familie.felles</groupId>
<artifactId>valutakurs-klient</artifactId>
</dependency>
<dependency>
<groupId>no.nav.familie.felles</groupId>
<artifactId>unleash</artifactId>
</dependency>
<dependency>
<groupId>no.nav.familie.kontrakter</groupId>
<artifactId>felles</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class FeatureToggleConfig {

// Ny utbetalingsgenerator
const val KONTROLLER_NY_UTBETALINGSGENERATOR = "familie.ba.sak.kontroller-ny-utbetalingsgenerator"
const val BRUK_NY_UTBETALINGSGENERATOR = "familie.ba.sak.bruk-ny-utbetalingsgenerator"

// Unleash Next toggles
const val ENDRET_EØS_REGELVERKFILTER_FOR_BARN = "familie-ba-sak.endret-eos-regelverkfilter-for-barn"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import no.nav.familie.felles.utbetalingsgenerator.Utbetalingsgenerator
import no.nav.familie.felles.utbetalingsgenerator.domain.AndelDataLongId
import no.nav.familie.felles.utbetalingsgenerator.domain.Behandlingsinformasjon
import no.nav.familie.felles.utbetalingsgenerator.domain.BeregnetUtbetalingsoppdragLongId
import no.nav.familie.felles.utbetalingsgenerator.domain.Fagsystem
import no.nav.familie.felles.utbetalingsgenerator.domain.IdentOgType
import no.nav.familie.kontrakter.felles.oppdrag.Opphør
import no.nav.familie.kontrakter.felles.oppdrag.Utbetalingsoppdrag
import no.nav.familie.kontrakter.felles.oppdrag.Utbetalingsperiode
import no.nav.familie.kontrakter.felles.tilbakekreving.Ytelsestype
import org.springframework.stereotype.Component
import java.time.LocalDate
import java.time.YearMonth
Expand All @@ -46,20 +47,25 @@ class UtbetalingsoppdragGenerator(
behandlingId = vedtak.behandling.id.toString(),
eksternBehandlingId = vedtak.behandling.id,
eksternFagsakId = vedtak.behandling.fagsak.id,
ytelse = Ytelsestype.BARNETRYGD,
fagsystem = FagsystemBA.BARNETRYGD,
personIdent = vedtak.behandling.fagsak.aktør.aktivFødselsnummer(),
vedtaksdato = vedtak.vedtaksdato?.toLocalDate() ?: LocalDate.now(),
opphørFra = opphørFra(forrigeTilkjentYtelse, erSimulering, endretMigreringsDato),
opphørFra = opphørFra(
forrigeTilkjentYtelse = forrigeTilkjentYtelse,
sisteAndelPerKjede = sisteAndelPerKjede,
endretMigreringsDato = endretMigreringsDato,
),
utbetalesTil = hentUtebetalesTil(vedtak.behandling.fagsak),
opphørKjederFraFørsteUtbetaling = if (endretMigreringsDato != null) false else erSimulering, // Ved simulering når migreringsdato er endret, skal vi opphøre fra den nye datoen og ikke fra første utbetaling per kjede.
),
forrigeAndeler = forrigeTilkjentYtelse?.tilAndelDataMedUtbetaling() ?: emptyList(),
nyeAndeler = nyTilkjentYtelse.tilAndelDataMedUtbetaling(),
forrigeAndeler = forrigeTilkjentYtelse?.tilAndelData() ?: emptyList(),
nyeAndeler = nyTilkjentYtelse.tilAndelData(),
sisteAndelPerKjede = sisteAndelPerKjede.mapValues { it.value.tilAndelDataLongId() },
)
}

private fun TilkjentYtelse.tilAndelDataMedUtbetaling(): List<AndelDataLongId> =
this.andelerTilkjentYtelse.map { it.tilAndelDataLongId() }.filter { it.beløp > 0 }
private fun TilkjentYtelse.tilAndelData(): List<AndelDataLongId> =
this.andelerTilkjentYtelse.map { it.tilAndelDataLongId() }

private fun AndelTilkjentYtelse.tilAndelDataLongId(): AndelDataLongId =
AndelDataLongId(
Expand All @@ -76,14 +82,11 @@ class UtbetalingsoppdragGenerator(

private fun opphørFra(
forrigeTilkjentYtelse: TilkjentYtelse?,
erSimulering: Boolean,
sisteAndelPerKjede: Map<IdentOgType, AndelTilkjentYtelse>,
endretMigreringsDato: YearMonth?,
): YearMonth? {
if (forrigeTilkjentYtelse == null) return null
if (forrigeTilkjentYtelse == null || sisteAndelPerKjede.isEmpty()) return null
if (endretMigreringsDato != null) return endretMigreringsDato
if (erSimulering) {
return forrigeTilkjentYtelse.andelerTilkjentYtelse.minOfOrNull { it.periode.fom }
}
return null
}

Expand Down Expand Up @@ -338,3 +341,51 @@ class AndelTilkjentYtelseForIverksettingFactory : AndelTilkjentYtelseForUtbetali
fun Collection<AndelTilkjentYtelse>.pakkInnForUtbetaling(
andelTilkjentYtelseForUtbetalingsoppdragFactory: AndelTilkjentYtelseForUtbetalingsoppdragFactory,
) = andelTilkjentYtelseForUtbetalingsoppdragFactory.pakkInnForUtbetaling(this)

enum class YtelsetypeBA(
override val klassifisering: String,
override val satsType: no.nav.familie.felles.utbetalingsgenerator.domain.Utbetalingsperiode.SatsType = no.nav.familie.felles.utbetalingsgenerator.domain.Utbetalingsperiode.SatsType.MND,
) : no.nav.familie.felles.utbetalingsgenerator.domain.Ytelsestype {
ORDINÆR_BARNETRYGD("BATR"),
UTVIDET_BARNETRYGD("BATR"),
SMÅBARNSTILLEGG("BATRSMA"),
}

enum class FagsystemBA(
override val kode: String,
override val gyldigeSatstyper: Set<YtelsetypeBA>,
) : Fagsystem {
BARNETRYGD(
"BA",
setOf(YtelsetypeBA.ORDINÆR_BARNETRYGD, YtelsetypeBA.UTVIDET_BARNETRYGD, YtelsetypeBA.SMÅBARNSTILLEGG),
),
}

fun no.nav.familie.felles.utbetalingsgenerator.domain.Utbetalingsoppdrag.tilRestUtbetalingsoppdrag(): Utbetalingsoppdrag =
Utbetalingsoppdrag(
kodeEndring = Utbetalingsoppdrag.KodeEndring.valueOf(this.kodeEndring.name),
fagSystem = this.fagSystem,
saksnummer = this.saksnummer,
aktoer = this.aktoer,
saksbehandlerId = this.saksbehandlerId,
avstemmingTidspunkt = this.avstemmingTidspunkt,
utbetalingsperiode = this.utbetalingsperiode.map { it.tilRestUtbetalingsperiode() },
gOmregning = this.gOmregning,
)

fun no.nav.familie.felles.utbetalingsgenerator.domain.Utbetalingsperiode.tilRestUtbetalingsperiode(): Utbetalingsperiode =
Utbetalingsperiode(
erEndringPåEksisterendePeriode = this.erEndringPåEksisterendePeriode,
opphør = this.opphør?.let { Opphør(it.opphørDatoFom) },
periodeId = this.periodeId,
forrigePeriodeId = this.forrigePeriodeId,
datoForVedtak = this.datoForVedtak,
klassifisering = this.klassifisering,
vedtakdatoFom = this.vedtakdatoFom,
vedtakdatoTom = this.vedtakdatoTom,
sats = this.sats,
satsType = Utbetalingsperiode.SatsType.valueOf(this.satsType.name),
utbetalesTil = this.utbetalesTil,
behandlingId = this.behandlingId,
utbetalingsgrad = this.utbetalingsgrad,
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package no.nav.familie.ba.sak.integrasjoner.økonomi

import no.nav.familie.ba.sak.common.secureLogger
import no.nav.familie.ba.sak.common.toYearMonth
import no.nav.familie.ba.sak.config.FeatureToggleConfig
import no.nav.familie.ba.sak.integrasjoner.økonomi.ØkonomiUtils.grupperAndeler
import no.nav.familie.ba.sak.integrasjoner.økonomi.ØkonomiUtils.oppdaterBeståendeAndelerMedOffset
import no.nav.familie.ba.sak.kjerne.behandling.BehandlingHentOgPersisterService
Expand All @@ -14,11 +16,16 @@ 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.fagsak.Fagsak
import no.nav.familie.ba.sak.kjerne.vedtak.Vedtak
import no.nav.familie.felles.utbetalingsgenerator.domain.AndelMedPeriodeIdLongId
import no.nav.familie.felles.utbetalingsgenerator.domain.BeregnetUtbetalingsoppdragLongId
import no.nav.familie.felles.utbetalingsgenerator.domain.IdentOgType
import no.nav.familie.kontrakter.felles.objectMapper
import no.nav.familie.kontrakter.felles.oppdrag.Utbetalingsoppdrag
import no.nav.familie.unleash.UnleashContextFields
import no.nav.familie.unleash.UnleashService
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDate
import java.time.YearMonth

@Service
Expand All @@ -29,9 +36,11 @@ class UtbetalingsoppdragGeneratorService(
private val andelTilkjentYtelseRepository: AndelTilkjentYtelseRepository,
private val utbetalingsoppdragGenerator: UtbetalingsoppdragGenerator,
private val beregningService: BeregningService,
private val unleashService: UnleashService,
) {

fun genererUtbetalingsoppdrag(
@Transactional
fun genererUtbetalingsoppdragOgOppdaterTilkjentYtelse(
vedtak: Vedtak,
saksbehandlerId: String,
erSimulering: Boolean = false,
Expand All @@ -43,7 +52,7 @@ class UtbetalingsoppdragGeneratorService(
forrigeTilkjentYtelse?.andelerTilkjentYtelse?.minByOrNull { it.stønadFom }?.stønadFom,
)
val sisteAndelPerKjede = hentSisteAndelTilkjentYtelse(vedtak.behandling.fagsak)
return utbetalingsoppdragGenerator.lagUtbetalingsoppdrag(
val beregnetUtbetalingsoppdrag = utbetalingsoppdragGenerator.lagUtbetalingsoppdrag(
saksbehandlerId = saksbehandlerId,
vedtak = vedtak,
forrigeTilkjentYtelse = forrigeTilkjentYtelse,
Expand All @@ -52,6 +61,33 @@ class UtbetalingsoppdragGeneratorService(
erSimulering = erSimulering,
endretMigreringsDato = endretMigreringsDato,
)

if (!erSimulering && unleashService.isEnabled(
FeatureToggleConfig.BRUK_NY_UTBETALINGSGENERATOR,
mapOf(UnleashContextFields.FAGSAK_ID to vedtak.behandling.fagsak.id.toString()),
)
) {
oppdaterTilkjentYtelse(nyTilkjentYtelse, beregnetUtbetalingsoppdrag)
}

return beregnetUtbetalingsoppdrag
}

private fun oppdaterTilkjentYtelse(
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,
)
oppdaterAndelerMedPeriodeOffset(
tilkjentYtelse = tilkjentYtelse,
andelerMedPeriodeId = beregnetUtbetalingsoppdrag.andeler,
)
tilkjentYtelseRepository.save(tilkjentYtelse)
}

private fun hentForrigeTilkjentYtelse(behandling: Behandling): TilkjentYtelse? =
Expand Down Expand Up @@ -168,4 +204,59 @@ class UtbetalingsoppdragGeneratorService(
null
}
}

private fun utledOpphør(
utbetalingsoppdrag: no.nav.familie.felles.utbetalingsgenerator.domain.Utbetalingsoppdrag,
behandling: Behandling,
): Opphør {
val erRentOpphør =
utbetalingsoppdrag.utbetalingsperiode.isNotEmpty() && utbetalingsoppdrag.utbetalingsperiode.all { it.opphør != null }
var opphørsdato: LocalDate? = null
if (erRentOpphør) {
opphørsdato = utbetalingsoppdrag.utbetalingsperiode.minOf { it.opphør!!.opphørDatoFom }
}

if (behandling.type == BehandlingType.REVURDERING) {
val opphørPåRevurdering = utbetalingsoppdrag.utbetalingsperiode.filter { it.opphør != null }
if (opphørPåRevurdering.isNotEmpty()) {
opphørsdato = opphørPåRevurdering.maxOfOrNull { it.opphør!!.opphørDatoFom }
}
}
return Opphør(erRentOpphør = erRentOpphør, opphørsdato = opphørsdato)
}

private fun oppdaterTilkjentYtelseMedUtbetalingsoppdrag(
tilkjentYtelse: TilkjentYtelse,
utbetalingsoppdrag: no.nav.familie.felles.utbetalingsgenerator.domain.Utbetalingsoppdrag,
) {
val opphør = utledOpphør(utbetalingsoppdrag, tilkjentYtelse.behandling)

tilkjentYtelse.utbetalingsoppdrag = objectMapper.writeValueAsString(utbetalingsoppdrag)
tilkjentYtelse.stønadTom = tilkjentYtelse.andelerTilkjentYtelse.maxOfOrNull { it.stønadTom }
tilkjentYtelse.stønadFom =
if (opphør.erRentOpphør) null else tilkjentYtelse.andelerTilkjentYtelse.minOfOrNull { it.stønadFom }
tilkjentYtelse.endretDato = LocalDate.now()
tilkjentYtelse.opphørFom = opphør.opphørsdato?.toYearMonth()
}

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) {
error("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]
?: error("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
}
}

data class Opphør(val erRentOpphør: Boolean, val opphørsdato: LocalDate?)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package no.nav.familie.ba.sak.integrasjoner.økonomi

import io.micrometer.core.instrument.Metrics
import no.nav.familie.ba.sak.config.FeatureToggleConfig
import no.nav.familie.ba.sak.kjerne.beregning.BeregningService
import no.nav.familie.ba.sak.kjerne.beregning.TilkjentYtelseValideringService
import no.nav.familie.ba.sak.kjerne.beregning.domene.TilkjentYtelse
Expand All @@ -12,6 +13,8 @@ import no.nav.familie.http.client.RessursException
import no.nav.familie.kontrakter.felles.oppdrag.OppdragId
import no.nav.familie.kontrakter.felles.oppdrag.OppdragStatus
import no.nav.familie.kontrakter.felles.oppdrag.Utbetalingsoppdrag
import no.nav.familie.unleash.UnleashContextFields
import no.nav.familie.unleash.UnleashService
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
Expand All @@ -24,6 +27,7 @@ class ØkonomiService(
private val tilkjentYtelseRepository: TilkjentYtelseRepository,
private val kontrollerNyUtbetalingsgeneratorService: KontrollerNyUtbetalingsgeneratorService,
private val utbetalingsoppdragGeneratorService: UtbetalingsoppdragGeneratorService,
private val unleashService: UnleashService,

) {
private val sammeOppdragSendtKonflikt = Metrics.counter("familie.ba.sak.samme.oppdrag.sendt.konflikt")
Expand All @@ -35,18 +39,36 @@ class ØkonomiService(
): Utbetalingsoppdrag {
val oppdatertBehandling = vedtak.behandling

kontrollerNyUtbetalingsgeneratorService.kontrollerNyUtbetalingsgenerator(
vedtak = vedtak,
saksbehandlerId = saksbehandlerId,
val brukNyUtbetalingsoppdragGenerator = unleashService.isEnabled(
FeatureToggleConfig.BRUK_NY_UTBETALINGSGENERATOR,
mapOf(UnleashContextFields.FAGSAK_ID to vedtak.behandling.fagsak.id.toString()),
)

val utbetalingsoppdrag = utbetalingsoppdragGeneratorService.genererUtbetalingsoppdragOgOppdaterTilkjentYtelse(
vedtak,
saksbehandlerId,
andelTilkjentYtelseForUtbetalingsoppdragFactory,
)
if (!brukNyUtbetalingsoppdragGenerator) {
kontrollerNyUtbetalingsgeneratorService.kontrollerNyUtbetalingsgenerator(
vedtak = vedtak,
saksbehandlerId = saksbehandlerId,
)
}

beregningService.oppdaterTilkjentYtelseMedUtbetalingsoppdrag(oppdatertBehandling, utbetalingsoppdrag)
val utbetalingsoppdrag: Utbetalingsoppdrag =
if (brukNyUtbetalingsoppdragGenerator) {
logger.info("Bruker ny utbetalingsgenerator for behandling ${vedtak.behandling.id}")
utbetalingsoppdragGeneratorService.genererUtbetalingsoppdragOgOppdaterTilkjentYtelse(
vedtak,
saksbehandlerId,
).utbetalingsoppdrag.tilRestUtbetalingsoppdrag()
} else {
val utbetalingsoppdrag =
utbetalingsoppdragGeneratorService.genererUtbetalingsoppdragOgOppdaterTilkjentYtelse(
vedtak,
saksbehandlerId,
andelTilkjentYtelseForUtbetalingsoppdragFactory,
)

beregningService.oppdaterTilkjentYtelseMedUtbetalingsoppdrag(oppdatertBehandling, utbetalingsoppdrag)
utbetalingsoppdrag
}

tilkjentYtelseValideringService.validerIngenAndelerTilkjentYtelseMedSammeOffsetIBehandling(behandlingId = vedtak.behandling.id)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import no.nav.familie.ba.sak.common.YearMonthConverter
import no.nav.familie.ba.sak.common.førsteDagIInneværendeMåned
import no.nav.familie.ba.sak.common.sisteDagIInneværendeMåned
import no.nav.familie.ba.sak.common.toYearMonth
import no.nav.familie.ba.sak.integrasjoner.økonomi.YtelsetypeBA
import no.nav.familie.ba.sak.kjerne.beregning.AndelTilkjentYtelseForVedtaksperioderTidslinje
import no.nav.familie.ba.sak.kjerne.beregning.AndelTilkjentYtelseTidslinje
import no.nav.familie.ba.sak.kjerne.grunnlag.personopplysninger.Person
Expand Down Expand Up @@ -263,10 +264,10 @@ enum class YtelseType(val klassifisering: String) {
SMÅBARNSTILLEGG -> listOf(SatsType.SMA)
}

fun tilYtelseType(): no.nav.familie.felles.utbetalingsgenerator.domain.YtelseType = when (this) {
ORDINÆR_BARNETRYGD -> no.nav.familie.felles.utbetalingsgenerator.domain.YtelseType.ORDINÆR_BARNETRYGD
UTVIDET_BARNETRYGD -> no.nav.familie.felles.utbetalingsgenerator.domain.YtelseType.UTVIDET_BARNETRYGD
SMÅBARNSTILLEGG -> no.nav.familie.felles.utbetalingsgenerator.domain.YtelseType.SMÅBARNSTILLEGG
fun tilYtelseType(): YtelsetypeBA = when (this) {
ORDINÆR_BARNETRYGD -> YtelsetypeBA.ORDINÆR_BARNETRYGD
UTVIDET_BARNETRYGD -> YtelsetypeBA.UTVIDET_BARNETRYGD
SMÅBARNSTILLEGG -> YtelsetypeBA.SMÅBARNSTILLEGG
}

fun tilSatsType(person: Person, ytelseDato: LocalDate) = when (this) {
Expand Down
Loading

0 comments on commit 197bde1

Please sign in to comment.