Skip to content

Commit

Permalink
Merge pull request #1930 from navikt/annullering-kravgrunnlag
Browse files Browse the repository at this point in the history
kan annullere et kravgrunnlag
  • Loading branch information
ramnav990 authored Oct 17, 2024
2 parents c583965 + 4672f09 commit b4b47dd
Show file tree
Hide file tree
Showing 33 changed files with 841 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import java.util.UUID

/**
* @property hendelseId unikt identifiserer denne hendelsen.
* @property tidligereHendelseId en tidligere hendelse som denne nye hendelsen korrigerer / tillegger / annullerer
* @property entitetId Også kalt streamId. knytter et domeneområdet sammen (f.eks sak)
* @property versjon rekkefølgen hendelser skjer innenfor [entitetId]
* @property hendelsestidspunkt Tidspunktet hendelsen skjedde fra domenet sin side.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import arrow.core.Either
import arrow.core.right
import no.nav.su.se.bakover.common.ident.NavIdentBruker
import no.nav.su.se.bakover.common.tid.Tidspunkt
import tilbakekreving.domain.kravgrunnlag.Kravgrunnlag
import tilbakekreving.domain.kravgrunnlag.rått.RåTilbakekrevingsvedtakForsendelse
import tilbakekreving.domain.vedtak.KunneIkkeAnnullerePåbegynteVedtak
import tilbakekreving.domain.vedtak.KunneIkkeSendeTilbakekrevingsvedtak
import tilbakekreving.domain.vedtak.Tilbakekrevingsklient
import tilbakekreving.domain.vurdering.VurderingerMedKrav
Expand All @@ -24,4 +26,14 @@ data class TilbakekrevingsklientStub(
responseXml = "{\"responseJson\": \"stubbed\"}",
).right()
}

override fun annullerKravgrunnlag(
annullertAv: NavIdentBruker.Saksbehandler,
kravgrunnlagSomSkalAnnulleres: Kravgrunnlag,
): Either<KunneIkkeAnnullerePåbegynteVedtak, RåTilbakekrevingsvedtakForsendelse> =
RåTilbakekrevingsvedtakForsendelse(
requestXml = "{\"requestJson\": \"stubbed\"}",
tidspunkt = Tidspunkt.now(clock),
responseXml = "{\"responseJson\": \"stubbed\"}",
).right()
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import tilbakekreving.application.service.forhåndsvarsel.ForhåndsvarsleTilbake
import tilbakekreving.application.service.forhåndsvarsel.ForhåndsvisForhåndsvarselTilbakekrevingsbehandlingService
import tilbakekreving.application.service.forhåndsvarsel.VisUtsendtForhåndsvarselbrevForTilbakekrevingService
import tilbakekreving.application.service.iverksett.IverksettTilbakekrevingService
import tilbakekreving.application.service.kravgrunnlag.AnnullerKravgrunnlagService
import tilbakekreving.application.service.kravgrunnlag.OppdaterKravgrunnlagService
import tilbakekreving.application.service.kravgrunnlag.RåttKravgrunnlagService
import tilbakekreving.application.service.notat.NotatTilbakekrevingsbehandlingService
Expand Down Expand Up @@ -60,6 +61,7 @@ class TilbakekrevingServices(
val oppdaterKravgrunnlagService: OppdaterKravgrunnlagService,
val notatTilbakekrevingsbehandlingService: NotatTilbakekrevingsbehandlingService,
val vedtaksbrevTilbakekrevingKonsument: GenererVedtaksbrevTilbakekrevingKonsument,
val annullerKravgrunnlagService: AnnullerKravgrunnlagService,
) {
companion object {
fun create(
Expand Down Expand Up @@ -210,6 +212,15 @@ class TilbakekrevingServices(
sessionFactory = sessionFactory,
clock = clock,
),
annullerKravgrunnlagService = AnnullerKravgrunnlagService(
tilgangstyring = tilgangstyringService,
tilbakekrevingsbehandlingRepo = tilbakekrevingsbehandlingRepo,
sakService = sakService,
kravgrunnlagRepo = kravgrunnlagRepo,
tilbakekrevingsklient = tilbakekrevingsklient,
sessionFactory = sessionFactory,
clock = clock,
),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
override val konsumentId = HendelseskonsumentId("KnyttKravgrunnlagTilSakOgUtbetaling")

/**
* Funksjonen logger feilene selv, men returnerer en throwable for testene sin del.
* Funksjonen logger feilene selv, men returnerer for testene sin del.
*/
fun knyttKravgrunnlagTilSakOgUtbetaling(
correlationId: CorrelationId,
): Either<Nel<Throwable>, Unit> {
): Either<Nel<Throwable>, List<HendelseId>> {
return Either.catch {
kravgrunnlagRepo.hentUprosesserteRåttKravgrunnlagHendelser(
konsumentId = konsumentId,
Expand All @@ -56,14 +56,16 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
)
nonEmptyListOf(it)
}.flatMap {
it.flattenOrAccumulate().map { }
it.flattenOrAccumulate().map {
it.mapNotNull { it.knyttetKravgrunnlagPåSakHendelse }
}
}
}

private fun prosesserEnHendelse(
hendelseId: HendelseId,
correlationId: CorrelationId,
): Either<Throwable, Unit> {
): Either<Throwable, ProsseserteHendelser> {
return Either.catch {
val (råttKravgrunnlagHendelse, meta) =
kravgrunnlagRepo.hentRåttKravgrunnlagHendelseMedMetadataForHendelseId(hendelseId) ?: run {
Expand Down Expand Up @@ -93,20 +95,30 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
hendelseId = hendelseId,
konsumentId = konsumentId,
)
return Unit.right()
return ProsseserteHendelser(hendelseId, null).right()
}
when (kravgrunnlagPåSakHendelse) {
is KravgrunnlagDetaljerPåSakHendelse -> prosesserDetaljer(
hendelseId = hendelseId,
kravgrunnlagPåSakHendelse = kravgrunnlagPåSakHendelse,
correlationId = correlationId,
)
is KravgrunnlagDetaljerPåSakHendelse -> {
ProsseserteHendelser(
hendelseId,
prosesserDetaljer(
hendelseId = hendelseId,
kravgrunnlagPåSakHendelse = kravgrunnlagPåSakHendelse,
correlationId = correlationId,
),
)
}

is KravgrunnlagStatusendringPåSakHendelse -> prosesserStatus(
hendelseId = hendelseId,
kravgrunnlagPåSakHendelse = kravgrunnlagPåSakHendelse,
correlationId = correlationId,
)
is KravgrunnlagStatusendringPåSakHendelse -> {
ProsseserteHendelser(
hendelseId,
prosesserStatus(
hendelseId = hendelseId,
kravgrunnlagPåSakHendelse = kravgrunnlagPåSakHendelse,
correlationId = correlationId,
),
)
}
}
}.onLeft {
log.error("Kunne ikke prosessere kravgrunnlag: Det ble kastet en exception for hendelsen $hendelseId", it)
Expand All @@ -117,7 +129,7 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
hendelseId: HendelseId,
kravgrunnlagPåSakHendelse: KravgrunnlagStatusendringPåSakHendelse,
correlationId: CorrelationId,
) {
): HendelseId {
// Statusendringene har ikke noen unik indikator i seg selv, annet enn JMS-meldingen sin id. Siden vi ikke får til noen god dedup. så vi aksepterer alle statusendringer.
sessionFactory.withTransactionContext { tx ->
kravgrunnlagRepo.lagreKravgrunnlagPåSakHendelse(
Expand All @@ -131,13 +143,14 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
context = tx,
)
}
return kravgrunnlagPåSakHendelse.hendelseId
}

private fun prosesserDetaljer(
hendelseId: HendelseId,
kravgrunnlagPåSakHendelse: KravgrunnlagDetaljerPåSakHendelse,
correlationId: CorrelationId,
) {
): HendelseId {
sessionFactory.withTransactionContext { tx ->
kravgrunnlagRepo.lagreKravgrunnlagPåSakHendelse(
hendelse = kravgrunnlagPåSakHendelse,
Expand All @@ -150,5 +163,14 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
context = tx,
)
}
return kravgrunnlagPåSakHendelse.hendelseId
}
}

private data class ProsseserteHendelser(
/**
* aka tidligere hendelseId for nye hendelsen som er blitt knyttet til saken
*/
val hendelsenSomErBlittProsessert: HendelseId,
val knyttetKravgrunnlagPåSakHendelse: HendelseId?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package tilbakekreving.application.service.kravgrunnlag

import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.left
import no.nav.su.se.bakover.common.persistence.SessionFactory
import no.nav.su.se.bakover.common.tid.Tidspunkt
import no.nav.su.se.bakover.domain.sak.SakService
import no.nav.su.se.bakover.hendelse.domain.HendelseId
import org.slf4j.LoggerFactory
import tilbakekreving.domain.AvbruttTilbakekrevingsbehandling
import tilbakekreving.domain.KanAnnullere
import tilbakekreving.domain.TilbakekrevingsbehandlingRepo
import tilbakekreving.domain.kravgrunnlag.AnnullerKravgrunnlagCommand
import tilbakekreving.domain.kravgrunnlag.Kravgrunnlagstatus
import tilbakekreving.domain.kravgrunnlag.påsak.KravgrunnlagStatusendringPåSakHendelse
import tilbakekreving.domain.kravgrunnlag.repo.AnnullerKravgrunnlagStatusEndringMeta
import tilbakekreving.domain.kravgrunnlag.repo.KravgrunnlagRepo
import tilbakekreving.domain.vedtak.Tilbakekrevingsklient
import tilgangstyring.application.TilgangstyringService
import java.time.Clock

class AnnullerKravgrunnlagService(
private val tilgangstyring: TilgangstyringService,
private val tilbakekrevingsbehandlingRepo: TilbakekrevingsbehandlingRepo,
private val sakService: SakService,
private val kravgrunnlagRepo: KravgrunnlagRepo,
private val tilbakekrevingsklient: Tilbakekrevingsklient,
private val sessionFactory: SessionFactory,
private val clock: Clock,
) {
private val log = LoggerFactory.getLogger(this::class.java)

fun annuller(command: AnnullerKravgrunnlagCommand): Either<KunneIkkeAnnullereKravgrunnlag, AvbruttTilbakekrevingsbehandling?> {
tilgangstyring.assertHarTilgangTilSak(command.sakId).onLeft {
return KunneIkkeAnnullereKravgrunnlag.IkkeTilgang(it).left()
}
val sak = sakService.hentSak(command.sakId).getOrElse {
throw IllegalStateException("Kunne ikke oppdatere kravgrunnlag for tilbakekrevingsbehandling, fant ikke sak. Command: $command")
}
if (sak.versjon != command.klientensSisteSaksversjon) {
log.info("Oppdater kravgrunnlag - Sakens versjon (${sak.versjon}) er ulik saksbehandlers versjon. Command: $command")
}
val tilbakekrevingsbehandlingHendelser = tilbakekrevingsbehandlingRepo.hentForSak(command.sakId)
val uteståendeKravgrunnlagPåSak = tilbakekrevingsbehandlingHendelser.hentUteståendeKravgrunnlag()
?: return KunneIkkeAnnullereKravgrunnlag.SakenHarIkkeKravgrunnlagSomKanAnnulleres.left()
val kravgrunnlag = tilbakekrevingsbehandlingHendelser.hentKravrunnlag(command.kravgrunnlagHendelseId)
?: return KunneIkkeAnnullereKravgrunnlag.FantIkkeKravgrunnlag.left()

if (uteståendeKravgrunnlagPåSak.hendelseId != kravgrunnlag.hendelseId) {
return KunneIkkeAnnullereKravgrunnlag.InnsendtHendelseIdErIkkeDenSistePåSaken.left()
}

val behandling =
tilbakekrevingsbehandlingHendelser.hentBehandlingForKravgrunnlag(uteståendeKravgrunnlagPåSak.hendelseId)

val (avbruttHendelse, avbruttBehandling) = behandling?.let {
(it as? KanAnnullere)?.annuller(
annulleringstidspunkt = Tidspunkt.now(clock),
annullertAv = command.annullertAv,
versjon = command.klientensSisteSaksversjon.inc(),
) ?: return KunneIkkeAnnullereKravgrunnlag.BehandlingenErIFeilTilstandForÅAnnullere.left()
} ?: (null to null)

return tilbakekrevingsklient.annullerKravgrunnlag(command.annullertAv, kravgrunnlag).mapLeft {
KunneIkkeAnnullereKravgrunnlag.FeilMotTilbakekrevingskomponenten(it)
}.map { råTilbakekrevingsvedtakForsendelse ->
sessionFactory.withTransactionContext {
kravgrunnlagRepo.lagreKravgrunnlagPåSakHendelse(
KravgrunnlagStatusendringPåSakHendelse(
hendelseId = HendelseId.generer(),
versjon = if (avbruttHendelse == null) command.klientensSisteSaksversjon.inc() else command.klientensSisteSaksversjon.inc(2),
sakId = sak.id,
hendelsestidspunkt = Tidspunkt.now(clock),
tidligereHendelseId = uteståendeKravgrunnlagPåSak.hendelseId,
saksnummer = sak.saksnummer,
eksternVedtakId = uteståendeKravgrunnlagPåSak.eksternVedtakId,
status = Kravgrunnlagstatus.Annullert,
eksternTidspunkt =TilbakekrevingsvedtakForsendelse.tidspunkt,
),
AnnullerKravgrunnlagStatusEndringMeta(
correlationId = command.correlationId,
ident = command.annullertAv,
brukerroller = command.brukerroller,
tilbakekrevingsvedtakForsendelse =TilbakekrevingsvedtakForsendelse,
),
it,
)
if (avbruttHendelse != null) {
tilbakekrevingsbehandlingRepo.lagre(
hendelse = avbruttHendelse,
meta = command.toDefaultHendelsesMetadata(),
sessionContext = it,
)
}
}
avbruttBehandling
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package tilbakekreving.application.service.kravgrunnlag

import tilbakekreving.domain.vedtak.KunneIkkeAnnullerePåbegynteVedtak
import tilgangstyring.domain.IkkeTilgangTilSak

sealed interface KunneIkkeAnnullereKravgrunnlag {
data class IkkeTilgang(val underliggende: IkkeTilgangTilSak) : KunneIkkeAnnullereKravgrunnlag
data object InnsendtHendelseIdErIkkeDenSistePåSaken : KunneIkkeAnnullereKravgrunnlag
data object SakenHarIkkeKravgrunnlagSomKanAnnulleres : KunneIkkeAnnullereKravgrunnlag
data object FantIkkeKravgrunnlag : KunneIkkeAnnullereKravgrunnlag
data object BehandlingenErIFeilTilstandForÅAnnullere : KunneIkkeAnnullereKravgrunnlag
data class FeilMotTilbakekrevingskomponenten(val underliggende: KunneIkkeAnnullerePåbegynteVedtak) :
KunneIkkeAnnullereKravgrunnlag
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package tilbakekreving.domain
* - oppdatere vedtaksbrev
* - oppdatere notat
* - oppdatere kravgrunnlag
* - annullere kravgrunnlag
*/
sealed interface KanEndres : Tilbakekrevingsbehandling {
override fun erÅpen() = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import dokument.domain.DokumentHendelseSerie
import dokument.domain.DokumentHendelser
import dokument.domain.Dokumenttilstand
import no.nav.su.se.bakover.common.domain.Saksnummer
import no.nav.su.se.bakover.common.domain.extensions.singleOrNullOrThrow
import no.nav.su.se.bakover.common.person.Fnr
import no.nav.su.se.bakover.hendelse.domain.HendelseId
import tilbakekreving.domain.kravgrunnlag.Kravgrunnlag
Expand Down Expand Up @@ -204,6 +205,15 @@ data class TilbakekrevingsbehandlingHendelser private constructor(
hendelser = sorterteHendelser.filter { it.id == behandlingsid },
)

fun hentKravrunnlag(kravgrunnlagHendelseId: HendelseId): Kravgrunnlag? {
return kravgrunnlagPåSak.hentKravgrunnlagDetaljerPåSakHendelseForHendelseId(kravgrunnlagHendelseId)?.kravgrunnlag
}

fun hentBehandlingForKravgrunnlag(kravgrunnlagHendelseId: HendelseId): Tilbakekrevingsbehandling? =
this.currentState.behandlinger.singleOrNullOrThrow {
it.kravgrunnlag.hendelseId == kravgrunnlagHendelseId && it.erÅpen()
}

/**
* 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ sealed interface UnderBehandling :
KanVurdere,
KanForhåndsvarsle,
KanOppdatereNotat,
KanAnnullere,
UnderBehandlingEllerTilAttestering {

override val vurderingerMedKrav: VurderingerMedKrav?
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@file:Suppress("PackageDirectoryMismatch")
// Må ligge i samme pakke som Tilbakekrevingsbehandling (siden det er et sealed interface), men trenger ikke ligge i samme mappe.

package tilbakekreving.domain

import no.nav.su.se.bakover.common.ident.NavIdentBruker
import no.nav.su.se.bakover.common.tid.Tidspunkt
import no.nav.su.se.bakover.hendelse.domain.HendelseId
import no.nav.su.se.bakover.hendelse.domain.Hendelsesversjon

sealed interface KanAnnullere : KanEndres {
fun annuller(
annulleringstidspunkt: Tidspunkt,
annullertAv: NavIdentBruker.Saksbehandler,
versjon: Hendelsesversjon,
): Pair<AvbruttHendelse, AvbruttTilbakekrevingsbehandling> {
val hendelse = AvbruttHendelse(
hendelseId = HendelseId.generer(),
id = this.id,
utførtAv = annullertAv,
tidligereHendelseId = this.hendelseId,
hendelsestidspunkt = annulleringstidspunkt,
sakId = this.sakId,
versjon = versjon,
begrunnelse = "Behandling er blitt avbrutt fordi kravgrunnlaget skal annulleres.",
)
return hendelse to hendelse.applyToState(this)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package tilbakekreving.domain.kravgrunnlag

import no.nav.su.se.bakover.common.CorrelationId
import no.nav.su.se.bakover.common.brukerrolle.Brukerrolle
import no.nav.su.se.bakover.common.ident.NavIdentBruker
import no.nav.su.se.bakover.hendelse.domain.DefaultHendelseMetadata
import no.nav.su.se.bakover.hendelse.domain.HendelseId
import no.nav.su.se.bakover.hendelse.domain.Hendelsesversjon
import no.nav.su.se.bakover.hendelse.domain.SakshendelseCommand
import java.util.UUID

data class AnnullerKravgrunnlagCommand(
override val sakId: UUID,
override val correlationId: CorrelationId?,
override val brukerroller: List<Brukerrolle>,
val annullertAv: NavIdentBruker.Saksbehandler,
val kravgrunnlagHendelseId: HendelseId,
val klientensSisteSaksversjon: Hendelsesversjon,
) : SakshendelseCommand {
override val utførtAv: NavIdentBruker = annullertAv

fun toDefaultHendelsesMetadata() = DefaultHendelseMetadata(
correlationId = correlationId,
ident = this.utførtAv,
brukerroller = brukerroller,
)
}
Loading

0 comments on commit b4b47dd

Please sign in to comment.