Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Meldekort-korrigering del 1 (uten iverksetting) #873

Merged
merged 10 commits into from
Mar 18, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import no.nav.tiltakspenger.saksbehandling.meldekort.ports.MeldeperiodeRepo
import no.nav.tiltakspenger.saksbehandling.meldekort.service.IverksettMeldekortService
import no.nav.tiltakspenger.saksbehandling.meldekort.service.OppgaveMeldekortService
import no.nav.tiltakspenger.saksbehandling.meldekort.service.OpprettMeldekortBehandlingService
import no.nav.tiltakspenger.saksbehandling.meldekort.service.OpprettMeldekortKorrigeringService
import no.nav.tiltakspenger.saksbehandling.meldekort.service.SendMeldekortTilBeslutningService
import no.nav.tiltakspenger.saksbehandling.meldekort.service.SendMeldeperiodeTilBrukerService
import no.nav.tiltakspenger.saksbehandling.repository.meldekort.BrukersMeldekortPostgresRepo
Expand Down Expand Up @@ -86,6 +87,14 @@ open class MeldekortContext(
sessionFactory = sessionFactory,
)
}
val opprettMeldekortKorrigeringService by lazy {
OpprettMeldekortKorrigeringService(
meldekortBehandlingRepo = meldekortBehandlingRepo,
navkontorService = navkontorService,
sakService = sakService,
sessionFactory = sessionFactory,
)
}

private val meldekortApiHttpClient by lazy {
MeldekortApiHttpClient(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ sealed interface MeldekortBehandling {
val opprettet: LocalDateTime
val beregning: MeldeperiodeBeregning
val meldeperiode: Meldeperiode
val type: MeldekortBehandlingType

/** Vil kunne være null dersom vi ikke har mottatt et meldekort via vår digitale flate. Bør på sikt kunne være en liste? */
val brukersMeldekort: BrukersMeldekort?
Expand Down Expand Up @@ -125,6 +126,7 @@ sealed interface MeldekortBehandling {
override val ikkeRettTilTiltakspengerTidspunkt: LocalDateTime?,
override val brukersMeldekort: BrukersMeldekort?,
override val meldeperiode: Meldeperiode,
override val type: MeldekortBehandlingType,
) : MeldekortBehandling {

init {
Expand Down Expand Up @@ -204,6 +206,7 @@ sealed interface MeldekortBehandling {
ikkeRettTilTiltakspengerTidspunkt = ikkeRettTilTiltakspengerTidspunkt,
brukersMeldekort = brukersMeldekort,
meldeperiode = meldeperiode,
type = type,
)
}

Expand All @@ -229,6 +232,7 @@ sealed interface MeldekortBehandling {
override val brukersMeldekort: BrukersMeldekort?,
override val meldeperiode: Meldeperiode,
override val saksbehandler: String,
override val type: MeldekortBehandlingType,
) : MeldekortBehandling {
override val iverksattTidspunkt = null
override val sendtTilBeslutning = null
Expand Down Expand Up @@ -273,6 +277,7 @@ sealed interface MeldekortBehandling {
ikkeRettTilTiltakspengerTidspunkt = null,
brukersMeldekort = brukersMeldekort,
meldeperiode = meldeperiode,
type = type,
).right()
}

Expand Down Expand Up @@ -346,6 +351,7 @@ fun Sak.opprettMeldekortBehandling(
brukersMeldekort = brukersMeldekort,
meldeperiode = meldeperiode,
saksbehandler = saksbehandler.navIdent,
type = MeldekortBehandlingType.FØRSTE_BEHANDLING,
beregning = MeldeperiodeBeregning.IkkeUtfyltMeldeperiode.fraPeriode(
meldeperiode = meldeperiode,
meldekortId = meldekortId,
Expand All @@ -355,3 +361,44 @@ fun Sak.opprettMeldekortBehandling(
),
)
}

fun Sak.opprettMeldekortKorrigering(
saksbehandler: Saksbehandler,
kjedeId: MeldeperiodeKjedeId,
navkontor: Navkontor,
): MeldekortBehandling.MeldekortUnderBehandling {
val forrigeBehandling = hentSisteMeldekortBehandlingForKjede(kjedeId)

requireNotNull(forrigeBehandling) {
"Må ha en tidligere meldekortbehandling for å opprette korrigering (kjede $kjedeId på sak ${this.id})"
}
require(forrigeBehandling.status == GODKJENT) {
"Siste meldekortbehandling i kjeden må være godkjent for å opprette en korrigering (kjede $kjedeId på sak ${this.id})"
}

val meldekortId = MeldekortId.random()
val meldeperiode = hentSisteMeldeperiodeForKjede(kjedeId)
val brukersMeldekort = this.brukersMeldekort.find { it.kjedeId == kjedeId }

return MeldekortBehandling.MeldekortUnderBehandling(
id = meldekortId,
sakId = this.id,
saksnummer = this.saksnummer,
fnr = this.fnr,
opprettet = nå(),
navkontor = navkontor,
ikkeRettTilTiltakspengerTidspunkt = null,
brukersMeldekort = brukersMeldekort,
meldeperiode = meldeperiode,
saksbehandler = saksbehandler.navIdent,
type = MeldekortBehandlingType.KORRIGERING,
// TODO: forhåndsutfylle denne fra forrige meldekortbehandling
beregning = MeldeperiodeBeregning.IkkeUtfyltMeldeperiode.fraPeriode(
meldeperiode = meldeperiode,
meldekortId = meldekortId,
sakId = this.id,
maksDagerMedTiltakspengerForPeriode = meldeperiode.antallDagerForPeriode,
tiltakstypePerioder = this.vedtaksliste.tiltakstypeperioder,
),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package no.nav.tiltakspenger.saksbehandling.meldekort.domene

enum class MeldekortBehandlingType {
FØRSTE_BEHANDLING,
KORRIGERING,
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,24 @@ data class MeldekortBehandlinger(
}
}

fun hentMeldekortBehandlingForMeldekortBehandlingId(meldekortId: MeldekortId): MeldekortBehandling? {
fun hentMeldekortBehandling(meldekortId: MeldekortId): MeldekortBehandling? {
return verdi.singleOrNullOrThrow { it.id == meldekortId }
}

/** Flere behandlinger kan være knyttet til samme versjon av meldeperioden. */
fun hentMeldekortBehandlingForMeldeperiodeId(id: MeldeperiodeId): List<MeldekortBehandling> {
fun hentMeldekortBehandlingerForMeldeperiode(id: MeldeperiodeId): List<MeldekortBehandling> {
return this.filter { it.meldeperiode.id == id }
}

/** Flere behandlinger kan være knyttet til samme versjon av meldeperioden. */
fun hentMeldekortBehandlingForMeldeperiodeKjedeId(kjedeId: MeldeperiodeKjedeId): List<MeldekortBehandling> {
fun hentMeldekortBehandlingerForKjede(kjedeId: MeldeperiodeKjedeId): List<MeldekortBehandling> {
return verdi.filter { it.kjedeId == kjedeId }
}

fun hentSisteMeldekortBehandlingForKjede(kjedeId: MeldeperiodeKjedeId): MeldekortBehandling? {
return hentMeldekortBehandlingerForKjede(kjedeId).maxByOrNull { it.opprettet }
}

/**
* Løper igjennom alle ikke-avsluttede meldekortbehandlinger (også de som er sendt til beslutter), setter tilstanden til under behandling, oppdaterer meldeperioden og resetter utfyllinga.
*/
Expand All @@ -101,7 +105,7 @@ data class MeldekortBehandlinger(
): Pair<MeldekortBehandlinger, List<MeldekortBehandling>> {
return verdi.filter { it.erÅpen() }
.fold(Pair(this, emptyList())) { acc, meldekortBehandling ->
val meldeperiode = oppdaterteKjeder.hentSisteMeldeperiodeForKjedeId(
val meldeperiode = oppdaterteKjeder.hentSisteMeldeperiodeForKjede(
kjedeId = meldekortBehandling.meldeperiode.kjedeId,
)
meldekortBehandling.oppdaterMeldeperiode(meldeperiode, tiltakstypePerioder)?.let {
Expand All @@ -115,7 +119,7 @@ data class MeldekortBehandlinger(

val periode: Periode by lazy { Periode(verdi.first().fraOgMed, verdi.last().tilOgMed) }

val behandledeMeldekort: List<MeldekortBehandlet> by lazy { verdi.filterIsInstance<MeldekortBehandlet>() }
private val behandledeMeldekort: List<MeldekortBehandlet> by lazy { verdi.filterIsInstance<MeldekortBehandlet>() }

val godkjenteMeldekort: List<MeldekortBehandlet> by lazy { behandledeMeldekort.filter { it.status == MeldekortBehandlingStatus.GODKJENT } }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ data class MeldeperiodeKjeder(
return meldeperiodeKjeder.asSequence().flatten().find { it.id == id }
}

fun hentSisteMeldeperiodeForKjedeId(kjedeId: MeldeperiodeKjedeId): Meldeperiode {
fun hentSisteMeldeperiodeForKjede(kjedeId: MeldeperiodeKjedeId): Meldeperiode {
return meldeperiodeKjeder.single { it.kjedeId == kjedeId }.last()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import no.nav.tiltakspenger.saksbehandling.meldekort.domene.IverksettMeldekortKo
import no.nav.tiltakspenger.saksbehandling.meldekort.domene.KanIkkeIverksetteMeldekort
import no.nav.tiltakspenger.saksbehandling.meldekort.domene.MeldekortBehandling
import no.nav.tiltakspenger.saksbehandling.meldekort.domene.MeldekortBehandlingStatus
import no.nav.tiltakspenger.saksbehandling.meldekort.domene.Meldeperiode
import no.nav.tiltakspenger.saksbehandling.meldekort.domene.MeldekortBehandlingType
import no.nav.tiltakspenger.saksbehandling.meldekort.domene.opprettNesteMeldeperiode
import no.nav.tiltakspenger.saksbehandling.meldekort.ports.MeldekortBehandlingRepo
import no.nav.tiltakspenger.saksbehandling.meldekort.ports.MeldeperiodeRepo
import no.nav.tiltakspenger.saksbehandling.saksbehandling.domene.sak.Sak
import no.nav.tiltakspenger.saksbehandling.saksbehandling.ports.StatistikkStønadRepo
import no.nav.tiltakspenger.saksbehandling.saksbehandling.service.person.PersonService
import no.nav.tiltakspenger.saksbehandling.saksbehandling.service.sak.SakService
Expand Down Expand Up @@ -50,7 +51,7 @@ class IverksettMeldekortService(

val sak = sakService.hentForSakId(sakId, kommando.beslutter, kommando.correlationId)
.getOrElse { return KanIkkeIverksetteMeldekort.KunneIkkeHenteSak(it).left() }
val meldekortBehandling: MeldekortBehandling = sak.hentMeldekortBehandlingForMeldekortBehandlingId(meldekortId)
val meldekortBehandling: MeldekortBehandling = sak.hentMeldekortBehandling(meldekortId)
?: throw IllegalArgumentException("Fant ikke meldekort med id $meldekortId i sak $sakId")
meldekortBehandling as MeldekortBehandling.MeldekortBehandlet
require(meldekortBehandling.beslutter == null && meldekortBehandling.status == MeldekortBehandlingStatus.KLAR_TIL_BESLUTNING) {
Expand All @@ -61,34 +62,45 @@ class IverksettMeldekortService(
throw IllegalStateException("Kan ikke iverksette meldekortbehandling hvor meldeperioden (${meldeperiode.versjon}) ikke er siste versjon av meldeperioden i saken. sakId: $sakId, meldekortId: $meldekortId")
}

val nesteMeldeperiode: Meldeperiode? = sak.opprettNesteMeldeperiode()?.let {
if (meldekortBehandling.periode.tilOgMed.plusDays(1) != it.periode.fraOgMed) {
log.info { "Neste meldeperiode (${it.periode}) er ikke sammenhengende med det vedtatte meldekortet sin meldeperiode (${meldekortBehandling.periode}). Oppretter ikke ny meldeperiode. behandlingId: ${meldekortBehandling.id}, sakId: ${meldekortBehandling.sakId}, saksnummer: ${meldekortBehandling.saksnummer}" }
return meldekortBehandling.iverksettMeldekort(kommando.beslutter).onRight {
when (it.type) {
MeldekortBehandlingType.FØRSTE_BEHANDLING -> persisterFørsteBehandling(it, sak)
MeldekortBehandlingType.KORRIGERING -> persisterKorrigering(it, sak)
}
}
}

private fun persisterFørsteBehandling(meldekort: MeldekortBehandling.MeldekortBehandlet, sak: Sak) {
val eksisterendeUtbetalingsvedtak = sak.utbetalinger
val utbetalingsvedtak = meldekort.opprettUtbetalingsvedtak(
saksnummer = sak.saksnummer,
fnr = sak.fnr,
eksisterendeUtbetalingsvedtak.lastOrNull()?.id,
)
val utbetalingsstatistikk = utbetalingsvedtak.tilStatistikk()

val nesteMeldeperiode = sak.opprettNesteMeldeperiode()?.let {
if (meldekort.periode.tilOgMed.plusDays(1) != it.periode.fraOgMed) {
log.info { "Neste meldeperiode (${it.periode}) er ikke sammenhengende med det vedtatte meldekortet sin meldeperiode (${meldekort.periode}). Oppretter ikke ny meldeperiode. behandlingId: ${meldekort.id}, sakId: ${meldekort.sakId}" }
null
} else {
it
}
}

return meldekortBehandling.iverksettMeldekort(kommando.beslutter).onRight { iverksattMeldekort ->
val eksisterendeUtbetalingsvedtak = sak.utbetalinger
val utbetalingsvedtak = iverksattMeldekort.opprettUtbetalingsvedtak(
saksnummer = sak.saksnummer,
fnr = sak.fnr,
eksisterendeUtbetalingsvedtak.lastOrNull()?.id,
)
val utbetalingsstatistikk = utbetalingsvedtak.tilStatistikk()

sessionFactory.withTransactionContext { tx ->
meldekortBehandlingRepo.oppdater(iverksattMeldekort, tx)
// TODO John og Anders: På et tidspunkt bør vi kanskje flytte generering av meldeperioder ut i en jobb?
nesteMeldeperiode?.also { meldeperiodeRepo.lagre(it, tx) }
utbetalingsvedtakRepo.lagre(utbetalingsvedtak, tx)
statistikkStønadRepo.lagre(utbetalingsstatistikk, tx)
}
sessionFactory.withTransactionContext { tx ->
meldekortBehandlingRepo.oppdater(meldekort, tx)
// TODO John og Anders: På et tidspunkt bør vi kanskje flytte generering av meldeperioder ut i en jobb?
nesteMeldeperiode?.also { meldeperiodeRepo.lagre(it, tx) }
utbetalingsvedtakRepo.lagre(utbetalingsvedtak, tx)
statistikkStønadRepo.lagre(utbetalingsstatistikk, tx)
}
}

private fun persisterKorrigering(meldekort: MeldekortBehandling.MeldekortBehandlet, sak: Sak) {
TODO("Har ikke implementert iverksetting av korrigering ennå!")
}

private suspend fun kastHvisIkkeTilgangTilPerson(
saksbehandler: Saksbehandler,
meldekortId: MeldekortId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ class OpprettMeldekortBehandlingService(
logger.error { "Kunne ikke hente sak med id $sakId" }
return KanIkkeOppretteMeldekortBehandling.IkkeTilgangTilSak.left()
}.also {
if (it.hentMeldekortBehandlingForMeldeperiodeKjedeId(kjedeId).isNotEmpty()) {
if (it.hentMeldekortBehandlingerForKjede(kjedeId).isNotEmpty()) {
logger.error { "Det finnes allerede en behandling av $kjedeId: ${it.id}" }
return KanIkkeOppretteMeldekortBehandling.BehandlingFinnes.left()
}
}

val meldeperiode: Meldeperiode = sak.hentMeldeperiodeForKjedeId(kjedeId = kjedeId)
val meldeperiode: Meldeperiode = sak.hentSisteMeldeperiodeForKjede(kjedeId = kjedeId)

val navkontor = Either.catch {
navkontorService.hentOppfolgingsenhet(sak.fnr)
Expand Down Expand Up @@ -78,6 +78,5 @@ class OpprettMeldekortBehandlingService(
sealed interface KanIkkeOppretteMeldekortBehandling {
data object IkkeTilgangTilSak : KanIkkeOppretteMeldekortBehandling
data object BehandlingFinnes : KanIkkeOppretteMeldekortBehandling
data object IngenMeldeperiode : KanIkkeOppretteMeldekortBehandling
data object HenteNavkontorFeilet : KanIkkeOppretteMeldekortBehandling
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package no.nav.tiltakspenger.saksbehandling.meldekort.service

import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.left
import arrow.core.right
import mu.KotlinLogging
import no.nav.tiltakspenger.libs.common.CorrelationId
import no.nav.tiltakspenger.libs.common.MeldeperiodeKjedeId
import no.nav.tiltakspenger.libs.common.SakId
import no.nav.tiltakspenger.libs.common.Saksbehandler
import no.nav.tiltakspenger.libs.persistering.domene.SessionFactory
import no.nav.tiltakspenger.saksbehandling.felles.sikkerlogg
import no.nav.tiltakspenger.saksbehandling.meldekort.domene.MeldekortBehandling
import no.nav.tiltakspenger.saksbehandling.meldekort.domene.opprettMeldekortKorrigering
import no.nav.tiltakspenger.saksbehandling.meldekort.ports.MeldekortBehandlingRepo
import no.nav.tiltakspenger.saksbehandling.saksbehandling.service.sak.SakService
import no.nav.tiltakspenger.saksbehandling.utbetaling.service.NavkontorService

class OpprettMeldekortKorrigeringService(
val sakService: SakService,
val meldekortBehandlingRepo: MeldekortBehandlingRepo,
val navkontorService: NavkontorService,
val sessionFactory: SessionFactory,
) {
private val logger = KotlinLogging.logger {}

suspend fun opprettKorrigering(
kjedeId: MeldeperiodeKjedeId,
sakId: SakId,
saksbehandler: Saksbehandler,
correlationId: CorrelationId,
): Either<KanIkkeOppretteMeldekortKorrigering, MeldekortBehandling> {
val sak = sakService.hentForSakId(sakId, saksbehandler, correlationId).getOrElse {
logger.error { "Kunne ikke hente sak med id $sakId" }
return KanIkkeOppretteMeldekortKorrigering.IkkeTilgangTilSak.left()
}

val navkontor = Either.catch {
navkontorService.hentOppfolgingsenhet(sak.fnr)
}.getOrElse {
with("Kunne ikke hente navkontor for sak $sakId") {
logger.error { this }
sikkerlogg.error(it) { "$this - fnr ${sak.fnr.verdi}" }
}
return KanIkkeOppretteMeldekortKorrigering.HenteNavkontorFeilet.left()
}

val meldekortKorrigering = Either.catch {
sak.opprettMeldekortKorrigering(
saksbehandler = saksbehandler,
navkontor = navkontor,
kjedeId = kjedeId,
)
}.getOrElse {
return KanIkkeOppretteMeldekortKorrigering.KanIkkeKorrigerePåKjede.left()
}

sessionFactory.withTransactionContext { tx ->
meldekortBehandlingRepo.lagre(meldekortKorrigering, tx)
}

logger.info { "Opprettet korrigering av meldekort: ${meldekortKorrigering.id} for kjede $kjedeId på sak $sakId" }

return meldekortKorrigering.right()
}
}

sealed interface KanIkkeOppretteMeldekortKorrigering {
data object IkkeTilgangTilSak : KanIkkeOppretteMeldekortKorrigering
data object HenteNavkontorFeilet : KanIkkeOppretteMeldekortKorrigering
data object KanIkkeKorrigerePåKjede : KanIkkeOppretteMeldekortKorrigering
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class SendMeldekortTilBeslutningService(
val sak = sakService.hentForSakId(kommando.sakId, kommando.saksbehandler, kommando.correlationId)
.getOrElse { return KanIkkeSendeMeldekortTilBeslutning.KunneIkkeHenteSak(it).left() }

val meldekortbehandling = sak.hentMeldekortBehandlingForMeldekortBehandlingId(kommando.meldekortId)!!
val meldekortbehandling = sak.hentMeldekortBehandling(kommando.meldekortId)!!
val meldeperiode = meldekortbehandling.meldeperiode
if (!sak.erSisteVersjonAvMeldeperiode(meldeperiode)) {
throw IllegalStateException("Kan ikke iverksette meldekortbehandling hvor meldeperioden (${meldeperiode.versjon}) ikke er siste versjon av meldeperioden i saken. sakId: ${sak.id}, meldekortId: ${meldekortbehandling.id}")
Expand Down
Loading
Loading