Skip to content

Commit

Permalink
hentUteståendeKravgrunnlag tar høyde for iverksatte tilbakekrevingsbe…
Browse files Browse the repository at this point in the history
…handlinger
  • Loading branch information
hestad committed Dec 18, 2023
1 parent d64fbd8 commit 3c1bd74
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ internal class SakPostgresRepo(
// Siden vi ikke har migrert SAK_OPPRETTET-hendelser, vil vi ikke alltid ha en hendelse knyttet til denne saken. Vi reserverer da den aller første hendelsesversjonen til SAK_OPPRETTET.
// Det betyr at etter hvert som vi migrerer sak/søknad osv. til hendelser vil versjonene kunne være out of order. En mulighet er da og bumpe alle versjoner tilsvarende med antall hendelser vi migrerer. Dette fungerer bare så lenge ingen andre tabeller/systemer har lagret hendelsesversjonene våre.
versjon = max(hendelseRepo.hentSisteVersjonFraEntitetId(sakId, sessionContext), Hendelsesversjon(1)),
uteståendeKravgrunnlag = kravgrunnlagRepo.hentKravgrunnlagPåSakHendelser(sakId, sessionContext).hentUteståendeKravgrunnlag(),
uteståendeKravgrunnlag = tilbakekrevingsbehandlingHendelser.hentUteståendeKravgrunnlag(),
)
}
}
Expand Down
1 change: 0 additions & 1 deletion test-common/src/main/kotlin/persistence/TestDataHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1871,7 +1871,6 @@ class TestDataHelper(
),
clock = fixedClock,
kravgrunnlagPåSak = KravgrunnlagPåSakHendelser(listOf(it.sixth)),
oppgaveHendelser = listOf(it.eighth),
dokumentHendelser = DokumentHendelser.empty(it.first.id),
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ class IverksettTilbakekrevingService(
)

/**
* TODO: det kan være slik at sending av vedtak til oppdrag får fint, men ting feiler under iverksetting
* hos oss.
* TODO tilbakekreving: At least once idempotency - det kan være slik at sending av vedtak til oppdrag går fint, men vi får ikke persistert hendelsen.
* Vi må finne ut hva slags feilmelding oppdrag sender oss når vi sender samme vedtak to ganger og persistere hendelsen når dette skjer.
*/
return iverksettelse.let {
val tilbakekrevingsvedtakForsendelse = tilbakekrevingsklient.sendTilbakekrevingsvedtak(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,20 @@ package tilbakekreving.domain
import dokument.domain.DokumentHendelseSerie
import dokument.domain.DokumentHendelser
import dokument.domain.Dokumenttilstand
import no.nav.su.se.bakover.common.domain.oppgave.OppgaveId
import no.nav.su.se.bakover.common.extensions.pickByCondition
import no.nav.su.se.bakover.common.extensions.whenever
import no.nav.su.se.bakover.hendelse.domain.HendelseId
import no.nav.su.se.bakover.oppgave.domain.OppgaveHendelse
import tilbakekreving.domain.iverksett.VedtakTilbakekrevingsbehandling
import tilbakekreving.domain.kravgrunnlag.Kravgrunnlag
import tilbakekreving.domain.kravgrunnlag.KravgrunnlagPåSakHendelser
import java.time.Clock
import java.util.UUID

/**
* @param tilhørendeOgSorterteOppgaveHendelser - oppgavehendelsene må ha en tilbakekrevingshendelse i sin relaterteHendelser
* @param tilhørendeOgSorterteDokumentHendelser - Dokumenthendelsen må ha en tilbakekrevingshendelse i sin relaterteHendelser
*/
data class TilbakekrevingsbehandlingHendelser private constructor(
private val sakId: UUID,
private val sorterteHendelser: List<TilbakekrevingsbehandlingHendelse>,
private val kravgrunnlagPåSak: KravgrunnlagPåSakHendelser,
private val tilhørendeOgSorterteOppgaveHendelser: List<OppgaveHendelse>,
private val tilhørendeOgSorterteDokumentHendelser: DokumentHendelser,
private val clock: Clock,
) : List<TilbakekrevingsbehandlingHendelse> by sorterteHendelser {
Expand Down Expand Up @@ -64,18 +59,6 @@ data class TilbakekrevingsbehandlingHendelser private constructor(
sorterteHendelser.map { it.entitetId }.distinct()
}"
}
require(tilhørendeOgSorterteOppgaveHendelser.sorted() == tilhørendeOgSorterteOppgaveHendelser) {
"tilhørendeOgSorterteOppgaveHendelser må være sortert etter stigende versjon."
}

require(
tilhørendeOgSorterteOppgaveHendelser.all { oppgaveHendelse ->
sorterteHendelser.any { opprettetHendelse ->
oppgaveHendelse.relaterteHendelser.contains(opprettetHendelse.hendelseId)
}
},
) { "Oppgavehendelsene må være relatert til minst 1 tilbakekrevingsbehandlingHendelse" }

require(
tilhørendeOgSorterteDokumentHendelser.all { dokumentHendelse ->
sorterteHendelser.any { opprettetHendelse ->
Expand All @@ -89,23 +72,28 @@ data class TilbakekrevingsbehandlingHendelser private constructor(
if (sorterteHendelser.isEmpty()) {
Tilbakekrevingsbehandlinger.empty(sakId)
} else {
toCurrentState()
toCurrentState().also {
it.behandlinger.filterIsInstance<IverksattTilbakekrevingsbehandling>().let {
if (it.size > 1) {
throw IllegalStateException("Kun én iverksatt tilbakekrevingsbehandling kan referere til ett kravgrunnlag, men fant disse IDene: ${it.map { it.id }}")
}
}
}
}
}

private fun toCurrentState(): Tilbakekrevingsbehandlinger {
return this.fold(mapOf<HendelseId, Tilbakekrevingsbehandling>()) { acc, hendelse ->
val hendelseId = hendelse.hendelseId
when (hendelse) {
// Dette gjelder kun første hendelsen og er et spesialtilfelle.
is OpprettetTilbakekrevingsbehandlingHendelse -> {
val kravgrunnlagsDetaljer =
this.kravgrunnlagPåSak.hentKravgrunnlagDetaljerPåSakHendelseForEksternKravgrunnlagId(hendelse.kravgrunnlagPåSakHendelseId)!!

this.kravgrunnlagPåSak.hentKravgrunnlagDetaljerPåSakHendelseForHendelseId(hendelse.kravgrunnlagPåSakHendelseId)!!
// opprettet er alltid den første hendelsen i serien, så derfor trenger vi ikke trekke fra tidligereHendelseId.
acc.plus(
hendelseId to hendelse.toDomain(
kravgrunnlagPåSakHendelse = kravgrunnlagsDetaljer,
erKravgrunnlagUtdatert = this.kravgrunnlagPåSak.hentUteståendeKravgrunnlag() != kravgrunnlagsDetaljer.kravgrunnlag,
erKravgrunnlagUtdatert = this.kravgrunnlagPåSak.hentSisteKravgrunnlag() != kravgrunnlagsDetaljer.kravgrunnlag,
),
)
}
Expand Down Expand Up @@ -144,8 +132,10 @@ data class TilbakekrevingsbehandlingHendelser private constructor(

is OppdatertKravgrunnlagPåTilbakekrevingHendelse -> acc.plus(
hendelseId to hendelse.applyToState(
acc[hendelse.tidligereHendelseId]!!,
this.kravgrunnlagPåSak.hentKravgrunnlagDetaljerPåSakHendelseForEksternKravgrunnlagId(hendelse.kravgrunnlagPåSakHendelseId)!!.kravgrunnlag,
behandling = acc[hendelse.tidligereHendelseId]!!,
kravgrunnlag = this.kravgrunnlagPåSak.hentKravgrunnlagDetaljerPåSakHendelseForHendelseId(
hendelse.kravgrunnlagPåSakHendelseId,
)!!.kravgrunnlag,
),
).minus(hendelse.tidligereHendelseId)
}
Expand Down Expand Up @@ -179,20 +169,6 @@ data class TilbakekrevingsbehandlingHendelser private constructor(
}
}

fun hentOppgaveIdForBehandling(id: TilbakekrevingsbehandlingId): Pair<OppgaveHendelse, OppgaveId>? {
val hendelsesIderForBehandling = sorterteHendelser.filter { it.id == id }.map { it.hendelseId }

val oppgaveHendelserForBehandling =
tilhørendeOgSorterteOppgaveHendelser.pickByCondition(hendelsesIderForBehandling) { oppgaveHendelse, hendelseId ->
oppgaveHendelse.relaterteHendelser.contains(hendelseId)
}

return oppgaveHendelserForBehandling.whenever(
isEmpty = { null },
isNotEmpty = { it.max() to it.distinctBy { it.oppgaveId }.single().oppgaveId },
)
}

/**
* @throws IllegalArgumentException dersom et av init-kravene feiler.
*/
Expand All @@ -213,6 +189,26 @@ data class TilbakekrevingsbehandlingHendelser private constructor(
hendelser = sorterteHendelser.filter { it.id == behandlingsid },
)

/**
* Henter det siste utestående kravgrunnlaget, dersom det finnes et kravgrunnlag og det ikke er avsluttet.
* Det er kun det siste mottatte kravgrunnlaget som kan være utestående.
* Et kravgrunnlag er avsluttet dersom vi har iverksatt en tilbakekrevingsbehandling eller kravgrunnlaget har blitt annullert på annen måte (statuser fra oppdrag).
* Merk at et kravgrunnlag vil være utestående helt til behandlingen er iverksatt eller det er overskrevet av et nyere kravgrunnlag.
*
* @return null dersom det ikke finnet et kravgrunnlag eller kravgrunnlaget ikke er utestående.
*/
fun hentUteståendeKravgrunnlag(): Kravgrunnlag? {
val sisteKravgrunnlag = kravgrunnlagPåSak.hentSisteKravgrunnlag() ?: return null
if (this.currentState.behandlinger
.filterIsInstance<IverksattTilbakekrevingsbehandling>()
.any { it.kravgrunnlag == sisteKravgrunnlag }
) {
return null
}
return sisteKravgrunnlag
// TODO jah: Vi må ta høyde for statusene. Det finnes noen statuser som betyr at kravgrunnlaget er avsluttet eksternt. Kan f.eks. være vi har revurdert på nytt.
}

companion object {

fun empty(sakId: UUID, clock: Clock): TilbakekrevingsbehandlingHendelser {
Expand All @@ -221,7 +217,6 @@ data class TilbakekrevingsbehandlingHendelser private constructor(
clock = clock,
sorterteHendelser = emptyList(),
kravgrunnlagPåSak = KravgrunnlagPåSakHendelser(emptyList()),
tilhørendeOgSorterteOppgaveHendelser = emptyList(),
tilhørendeOgSorterteDokumentHendelser = DokumentHendelser.empty(sakId),
)
}
Expand All @@ -231,15 +226,13 @@ data class TilbakekrevingsbehandlingHendelser private constructor(
clock: Clock,
hendelser: List<TilbakekrevingsbehandlingHendelse>,
kravgrunnlagPåSak: KravgrunnlagPåSakHendelser,
oppgaveHendelser: List<OppgaveHendelse>,
dokumentHendelser: DokumentHendelser,
): TilbakekrevingsbehandlingHendelser {
return TilbakekrevingsbehandlingHendelser(
sakId = sakId,
clock = clock,
sorterteHendelser = hendelser.sorted(),
kravgrunnlagPåSak = kravgrunnlagPåSak,
tilhørendeOgSorterteOppgaveHendelser = oppgaveHendelser.sorted(),
tilhørendeOgSorterteDokumentHendelser = dokumentHendelser,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,14 @@ data class IverksattTilbakekrevingsbehandling(
override val hendelseId: HendelseId,
override val versjon: Hendelsesversjon,
override val attesteringer: Attesteringshistorikk,
) : ErUtfylt by forrigeSteg
) : ErUtfylt by forrigeSteg {
init {
require(attesteringer.hentSisteIverksatteAttesteringOrNull() != null) {
"Kan ikke opprette en iverksatt tilbakekrevingsbehandling uten en iverksatt attestering"
}
require(!erKravgrunnlagUtdatert) {
// Nye kravgrunnlag etter dette vil få en annen eksternVedtakId og eksternKravgrunnlagId og skal ikke knyttes til denne behandlingen.
"En iverksatt tilbakekrevingsbehandling sitt kravgrunnlag kan ikke være utdatert"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,24 @@ data class KravgrunnlagPåSakHendelser(
.filterIsInstance<KravgrunnlagStatusendringPåSakHendelse>()
.sortedBy { it.eksternTidspunkt.instant }

fun hentSisteKravgrunnagforEksternVedtakId(eksternVedtakId: String): Kravgrunnlag? {
return detaljerSortert
.filter { it.kravgrunnlag.eksternVedtakId == eksternVedtakId }
.map { it.kravgrunnlag }
.maxByOrNull { it.eksternTidspunkt.instant }
?.let { kravgrunnlag ->
hentSisteStatusEtterTidspunkt(kravgrunnlag)?.let {
kravgrunnlag.copy(status = it)
} ?: kravgrunnlag
}
}

/**
* TODO - må ta stilling til om den er svart på
* Henter det siste kravgrunnlaget vi har mottatt og siste status.
*
* Merk at vi ikke filtrerer bort kravgrunnlag som allerede er behandlet.
*/
fun hentUteståendeKravgrunnlag(): Kravgrunnlag? {
fun hentSisteKravgrunnlag(): Kravgrunnlag? {
return detaljerSortert
.map { it.kravgrunnlag }
.maxByOrNull { it.eksternTidspunkt.instant }
Expand All @@ -31,7 +45,7 @@ data class KravgrunnlagPåSakHendelser(
}
}

fun hentKravgrunnlagDetaljerPåSakHendelseForEksternKravgrunnlagId(
fun hentKravgrunnlagDetaljerPåSakHendelseForHendelseId(
kravgrunnlagPåSakHendelseId: HendelseId,
): KravgrunnlagDetaljerPåSakHendelse? {
return detaljerSortert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,6 @@ class TilbakekrevingsbehandlingPostgresRepo(
hendelser = tilbakekrevingsHendelser,
clock = clock,
kravgrunnlagPåSak = kravgrunnlagRepo.hentKravgrunnlagPåSakHendelser(sakId, openSessionContext),
oppgaveHendelser = oppgaveRepo.hentForSak(sakId, openSessionContext).filter { oppgaveHendelse ->
tilbakekrevingsHendelser.any { oppgaveHendelse.relaterteHendelser.contains(it.hendelseId) }
}.sorted(),
dokumentHendelser = dokumentHendelseRepo.hentForSak(sakId, openSessionContext)
.filter { dokumentHendelseSerie ->
tilbakekrevingsHendelser.any { dokumentHendelseSerie.relatertHendelse == it.hendelseId }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class OpprettTilbakekrevingsbehandlingRepoTest {
withMigratedDb { dataSource ->
val testDataHelper = TestDataHelper(dataSource = dataSource, clock = clock)

val (sak, _, _, _, _, _, hendelse, oppgaveHendelse) = testDataHelper.persisterOpprettetTilbakekrevingsbehandlingHendelse()
val (sak, _, _, _, _, _, hendelse) = testDataHelper.persisterOpprettetTilbakekrevingsbehandlingHendelse()

val actual = testDataHelper.tilbakekrevingHendelseRepo.hentForSak(sak.id)
val actualKravgrunnlag =
Expand All @@ -35,7 +35,6 @@ class OpprettTilbakekrevingsbehandlingRepoTest {
clock = fixedClock,
hendelser = listOf(hendelse),
kravgrunnlagPåSak = actualKravgrunnlag,
oppgaveHendelser = listOf(oppgaveHendelse),
dokumentHendelser = DokumentHendelser.empty(sak.id),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ internal fun AppComponents.iverksettTilbakekrevingsbehandling(
// kun hendelsen
saksversjonEtter shouldBe saksversjon + 1
}
sakEtterKallJson.shouldBeSimilarJsonTo(sakFørKallJson, "versjon", "tilbakekrevinger", "vedtak")
sakEtterKallJson.shouldBeSimilarJsonTo(sakFørKallJson, "versjon", "tilbakekrevinger", "vedtak", "uteståendeKravgrunnlag")
JSONObject(sakEtterKallJson).isNull("uteståendeKravgrunnlag")
verifiserTilbakekrevingsVedtak(
tilbakekrevingsbehandlingId,
JSONObject(sakEtterKallJson).getJSONArray("vedtak"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,7 @@ internal class TilbakekrevingsbehandlingIT {
verifiserFritekst = fritekst,
tidligereAttesteringer = underkjentAttestering,
)
// TODO tilbakekreving jah: Denne skal snues til false. Vi forventer ikke kravgrunnlaget etter vi har iverksatt tilbakekrevingsbehandlingen.
verifiserKravgrunnlagPåSak(sakId, client, true, versjonEtterIverksetting.toInt())
verifiserKravgrunnlagPåSak(sakId, client, false, versjonEtterIverksetting.toInt())
}
}

Expand Down Expand Up @@ -272,4 +271,6 @@ internal class TilbakekrevingsbehandlingIT {
)
}
}

// TODO tilbakekreving jah: Skriv en test som sjekker at vi ikke kan åpne en tilbakekreving på en sak som har en tilbakekreving som er til behandling. Men dersom behandlingen avsluttes, kan vi åpne en ny tilbakekreving.
}

0 comments on commit 3c1bd74

Please sign in to comment.