Skip to content

Commit b4b47dd

Browse files
authored
Merge pull request #1930 from navikt/annullering-kravgrunnlag
kan annullere et kravgrunnlag
2 parents c583965 + 4672f09 commit b4b47dd

File tree

33 files changed

+841
-36
lines changed

33 files changed

+841
-36
lines changed

hendelse/domain/src/main/kotlin/no/nav/su/se/bakover/hendelse/domain/Hendelse.kt

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import java.util.UUID
55

66
/**
77
* @property hendelseId unikt identifiserer denne hendelsen.
8+
* @property tidligereHendelseId en tidligere hendelse som denne nye hendelsen korrigerer / tillegger / annullerer
89
* @property entitetId Også kalt streamId. knytter et domeneområdet sammen (f.eks sak)
910
* @property versjon rekkefølgen hendelser skjer innenfor [entitetId]
1011
* @property hendelsestidspunkt Tidspunktet hendelsen skjedde fra domenet sin side.

test-common/src/main/kotlin/tilbakekreving/TilbakekrevingsklientStub.kt

+12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import arrow.core.Either
44
import arrow.core.right
55
import no.nav.su.se.bakover.common.ident.NavIdentBruker
66
import no.nav.su.se.bakover.common.tid.Tidspunkt
7+
import tilbakekreving.domain.kravgrunnlag.Kravgrunnlag
78
import tilbakekreving.domain.kravgrunnlag.rått.RåTilbakekrevingsvedtakForsendelse
9+
import tilbakekreving.domain.vedtak.KunneIkkeAnnullerePåbegynteVedtak
810
import tilbakekreving.domain.vedtak.KunneIkkeSendeTilbakekrevingsvedtak
911
import tilbakekreving.domain.vedtak.Tilbakekrevingsklient
1012
import tilbakekreving.domain.vurdering.VurderingerMedKrav
@@ -24,4 +26,14 @@ data class TilbakekrevingsklientStub(
2426
responseXml = "{\"responseJson\": \"stubbed\"}",
2527
).right()
2628
}
29+
30+
override fun annullerKravgrunnlag(
31+
annullertAv: NavIdentBruker.Saksbehandler,
32+
kravgrunnlagSomSkalAnnulleres: Kravgrunnlag,
33+
): Either<KunneIkkeAnnullerePåbegynteVedtak, RåTilbakekrevingsvedtakForsendelse> =
34+
RåTilbakekrevingsvedtakForsendelse(
35+
requestXml = "{\"requestJson\": \"stubbed\"}",
36+
tidspunkt = Tidspunkt.now(clock),
37+
responseXml = "{\"responseJson\": \"stubbed\"}",
38+
).right()
2739
}

tilbakekreving/application/src/main/kotlin/tilbakekreving/application/service/TilbakekrevingServices.kt

+11
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import tilbakekreving.application.service.forhåndsvarsel.ForhåndsvarsleTilbake
1818
import tilbakekreving.application.service.forhåndsvarsel.ForhåndsvisForhåndsvarselTilbakekrevingsbehandlingService
1919
import tilbakekreving.application.service.forhåndsvarsel.VisUtsendtForhåndsvarselbrevForTilbakekrevingService
2020
import tilbakekreving.application.service.iverksett.IverksettTilbakekrevingService
21+
import tilbakekreving.application.service.kravgrunnlag.AnnullerKravgrunnlagService
2122
import tilbakekreving.application.service.kravgrunnlag.OppdaterKravgrunnlagService
2223
import tilbakekreving.application.service.kravgrunnlag.RåttKravgrunnlagService
2324
import tilbakekreving.application.service.notat.NotatTilbakekrevingsbehandlingService
@@ -60,6 +61,7 @@ class TilbakekrevingServices(
6061
val oppdaterKravgrunnlagService: OppdaterKravgrunnlagService,
6162
val notatTilbakekrevingsbehandlingService: NotatTilbakekrevingsbehandlingService,
6263
val vedtaksbrevTilbakekrevingKonsument: GenererVedtaksbrevTilbakekrevingKonsument,
64+
val annullerKravgrunnlagService: AnnullerKravgrunnlagService,
6365
) {
6466
companion object {
6567
fun create(
@@ -210,6 +212,15 @@ class TilbakekrevingServices(
210212
sessionFactory = sessionFactory,
211213
clock = clock,
212214
),
215+
annullerKravgrunnlagService = AnnullerKravgrunnlagService(
216+
tilgangstyring = tilgangstyringService,
217+
tilbakekrevingsbehandlingRepo = tilbakekrevingsbehandlingRepo,
218+
sakService = sakService,
219+
kravgrunnlagRepo = kravgrunnlagRepo,
220+
tilbakekrevingsklient = tilbakekrevingsklient,
221+
sessionFactory = sessionFactory,
222+
clock = clock,
223+
),
213224
)
214225
}
215226
}

tilbakekreving/application/src/main/kotlin/tilbakekreving/application/service/consumer/KnyttKravgrunnlagTilSakOgUtbetalingKonsument.kt

+39-17
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
3838
override val konsumentId = HendelseskonsumentId("KnyttKravgrunnlagTilSakOgUtbetaling")
3939

4040
/**
41-
* Funksjonen logger feilene selv, men returnerer en throwable for testene sin del.
41+
* Funksjonen logger feilene selv, men returnerer for testene sin del.
4242
*/
4343
fun knyttKravgrunnlagTilSakOgUtbetaling(
4444
correlationId: CorrelationId,
45-
): Either<Nel<Throwable>, Unit> {
45+
): Either<Nel<Throwable>, List<HendelseId>> {
4646
return Either.catch {
4747
kravgrunnlagRepo.hentUprosesserteRåttKravgrunnlagHendelser(
4848
konsumentId = konsumentId,
@@ -56,14 +56,16 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
5656
)
5757
nonEmptyListOf(it)
5858
}.flatMap {
59-
it.flattenOrAccumulate().map { }
59+
it.flattenOrAccumulate().map {
60+
it.mapNotNull { it.knyttetKravgrunnlagPåSakHendelse }
61+
}
6062
}
6163
}
6264

6365
private fun prosesserEnHendelse(
6466
hendelseId: HendelseId,
6567
correlationId: CorrelationId,
66-
): Either<Throwable, Unit> {
68+
): Either<Throwable, ProsseserteHendelser> {
6769
return Either.catch {
6870
val (råttKravgrunnlagHendelse, meta) =
6971
kravgrunnlagRepo.hentRåttKravgrunnlagHendelseMedMetadataForHendelseId(hendelseId) ?: run {
@@ -93,20 +95,30 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
9395
hendelseId = hendelseId,
9496
konsumentId = konsumentId,
9597
)
96-
return Unit.right()
98+
return ProsseserteHendelser(hendelseId, null).right()
9799
}
98100
when (kravgrunnlagPåSakHendelse) {
99-
is KravgrunnlagDetaljerPåSakHendelse -> prosesserDetaljer(
100-
hendelseId = hendelseId,
101-
kravgrunnlagPåSakHendelse = kravgrunnlagPåSakHendelse,
102-
correlationId = correlationId,
103-
)
101+
is KravgrunnlagDetaljerPåSakHendelse -> {
102+
ProsseserteHendelser(
103+
hendelseId,
104+
prosesserDetaljer(
105+
hendelseId = hendelseId,
106+
kravgrunnlagPåSakHendelse = kravgrunnlagPåSakHendelse,
107+
correlationId = correlationId,
108+
),
109+
)
110+
}
104111

105-
is KravgrunnlagStatusendringPåSakHendelse -> prosesserStatus(
106-
hendelseId = hendelseId,
107-
kravgrunnlagPåSakHendelse = kravgrunnlagPåSakHendelse,
108-
correlationId = correlationId,
109-
)
112+
is KravgrunnlagStatusendringPåSakHendelse -> {
113+
ProsseserteHendelser(
114+
hendelseId,
115+
prosesserStatus(
116+
hendelseId = hendelseId,
117+
kravgrunnlagPåSakHendelse = kravgrunnlagPåSakHendelse,
118+
correlationId = correlationId,
119+
),
120+
)
121+
}
110122
}
111123
}.onLeft {
112124
log.error("Kunne ikke prosessere kravgrunnlag: Det ble kastet en exception for hendelsen $hendelseId", it)
@@ -117,7 +129,7 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
117129
hendelseId: HendelseId,
118130
kravgrunnlagPåSakHendelse: KravgrunnlagStatusendringPåSakHendelse,
119131
correlationId: CorrelationId,
120-
) {
132+
): HendelseId {
121133
// 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.
122134
sessionFactory.withTransactionContext { tx ->
123135
kravgrunnlagRepo.lagreKravgrunnlagPåSakHendelse(
@@ -131,13 +143,14 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
131143
context = tx,
132144
)
133145
}
146+
return kravgrunnlagPåSakHendelse.hendelseId
134147
}
135148

136149
private fun prosesserDetaljer(
137150
hendelseId: HendelseId,
138151
kravgrunnlagPåSakHendelse: KravgrunnlagDetaljerPåSakHendelse,
139152
correlationId: CorrelationId,
140-
) {
153+
): HendelseId {
141154
sessionFactory.withTransactionContext { tx ->
142155
kravgrunnlagRepo.lagreKravgrunnlagPåSakHendelse(
143156
hendelse = kravgrunnlagPåSakHendelse,
@@ -150,5 +163,14 @@ class KnyttKravgrunnlagTilSakOgUtbetalingKonsument(
150163
context = tx,
151164
)
152165
}
166+
return kravgrunnlagPåSakHendelse.hendelseId
153167
}
154168
}
169+
170+
private data class ProsseserteHendelser(
171+
/**
172+
* aka tidligere hendelseId for nye hendelsen som er blitt knyttet til saken
173+
*/
174+
val hendelsenSomErBlittProsessert: HendelseId,
175+
val knyttetKravgrunnlagPåSakHendelse: HendelseId?,
176+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package tilbakekreving.application.service.kravgrunnlag
2+
3+
import arrow.core.Either
4+
import arrow.core.getOrElse
5+
import arrow.core.left
6+
import no.nav.su.se.bakover.common.persistence.SessionFactory
7+
import no.nav.su.se.bakover.common.tid.Tidspunkt
8+
import no.nav.su.se.bakover.domain.sak.SakService
9+
import no.nav.su.se.bakover.hendelse.domain.HendelseId
10+
import org.slf4j.LoggerFactory
11+
import tilbakekreving.domain.AvbruttTilbakekrevingsbehandling
12+
import tilbakekreving.domain.KanAnnullere
13+
import tilbakekreving.domain.TilbakekrevingsbehandlingRepo
14+
import tilbakekreving.domain.kravgrunnlag.AnnullerKravgrunnlagCommand
15+
import tilbakekreving.domain.kravgrunnlag.Kravgrunnlagstatus
16+
import tilbakekreving.domain.kravgrunnlag.påsak.KravgrunnlagStatusendringPåSakHendelse
17+
import tilbakekreving.domain.kravgrunnlag.repo.AnnullerKravgrunnlagStatusEndringMeta
18+
import tilbakekreving.domain.kravgrunnlag.repo.KravgrunnlagRepo
19+
import tilbakekreving.domain.vedtak.Tilbakekrevingsklient
20+
import tilgangstyring.application.TilgangstyringService
21+
import java.time.Clock
22+
23+
class AnnullerKravgrunnlagService(
24+
private val tilgangstyring: TilgangstyringService,
25+
private val tilbakekrevingsbehandlingRepo: TilbakekrevingsbehandlingRepo,
26+
private val sakService: SakService,
27+
private val kravgrunnlagRepo: KravgrunnlagRepo,
28+
private val tilbakekrevingsklient: Tilbakekrevingsklient,
29+
private val sessionFactory: SessionFactory,
30+
private val clock: Clock,
31+
) {
32+
private val log = LoggerFactory.getLogger(this::class.java)
33+
34+
fun annuller(command: AnnullerKravgrunnlagCommand): Either<KunneIkkeAnnullereKravgrunnlag, AvbruttTilbakekrevingsbehandling?> {
35+
tilgangstyring.assertHarTilgangTilSak(command.sakId).onLeft {
36+
return KunneIkkeAnnullereKravgrunnlag.IkkeTilgang(it).left()
37+
}
38+
val sak = sakService.hentSak(command.sakId).getOrElse {
39+
throw IllegalStateException("Kunne ikke oppdatere kravgrunnlag for tilbakekrevingsbehandling, fant ikke sak. Command: $command")
40+
}
41+
if (sak.versjon != command.klientensSisteSaksversjon) {
42+
log.info("Oppdater kravgrunnlag - Sakens versjon (${sak.versjon}) er ulik saksbehandlers versjon. Command: $command")
43+
}
44+
val tilbakekrevingsbehandlingHendelser = tilbakekrevingsbehandlingRepo.hentForSak(command.sakId)
45+
val uteståendeKravgrunnlagPåSak = tilbakekrevingsbehandlingHendelser.hentUteståendeKravgrunnlag()
46+
?: return KunneIkkeAnnullereKravgrunnlag.SakenHarIkkeKravgrunnlagSomKanAnnulleres.left()
47+
val kravgrunnlag = tilbakekrevingsbehandlingHendelser.hentKravrunnlag(command.kravgrunnlagHendelseId)
48+
?: return KunneIkkeAnnullereKravgrunnlag.FantIkkeKravgrunnlag.left()
49+
50+
if (uteståendeKravgrunnlagPåSak.hendelseId != kravgrunnlag.hendelseId) {
51+
return KunneIkkeAnnullereKravgrunnlag.InnsendtHendelseIdErIkkeDenSistePåSaken.left()
52+
}
53+
54+
val behandling =
55+
tilbakekrevingsbehandlingHendelser.hentBehandlingForKravgrunnlag(uteståendeKravgrunnlagPåSak.hendelseId)
56+
57+
val (avbruttHendelse, avbruttBehandling) = behandling?.let {
58+
(it as? KanAnnullere)?.annuller(
59+
annulleringstidspunkt = Tidspunkt.now(clock),
60+
annullertAv = command.annullertAv,
61+
versjon = command.klientensSisteSaksversjon.inc(),
62+
) ?: return KunneIkkeAnnullereKravgrunnlag.BehandlingenErIFeilTilstandForÅAnnullere.left()
63+
} ?: (null to null)
64+
65+
return tilbakekrevingsklient.annullerKravgrunnlag(command.annullertAv, kravgrunnlag).mapLeft {
66+
KunneIkkeAnnullereKravgrunnlag.FeilMotTilbakekrevingskomponenten(it)
67+
}.map { råTilbakekrevingsvedtakForsendelse ->
68+
sessionFactory.withTransactionContext {
69+
kravgrunnlagRepo.lagreKravgrunnlagPåSakHendelse(
70+
KravgrunnlagStatusendringPåSakHendelse(
71+
hendelseId = HendelseId.generer(),
72+
versjon = if (avbruttHendelse == null) command.klientensSisteSaksversjon.inc() else command.klientensSisteSaksversjon.inc(2),
73+
sakId = sak.id,
74+
hendelsestidspunkt = Tidspunkt.now(clock),
75+
tidligereHendelseId = uteståendeKravgrunnlagPåSak.hendelseId,
76+
saksnummer = sak.saksnummer,
77+
eksternVedtakId = uteståendeKravgrunnlagPåSak.eksternVedtakId,
78+
status = Kravgrunnlagstatus.Annullert,
79+
eksternTidspunkt =TilbakekrevingsvedtakForsendelse.tidspunkt,
80+
),
81+
AnnullerKravgrunnlagStatusEndringMeta(
82+
correlationId = command.correlationId,
83+
ident = command.annullertAv,
84+
brukerroller = command.brukerroller,
85+
tilbakekrevingsvedtakForsendelse =TilbakekrevingsvedtakForsendelse,
86+
),
87+
it,
88+
)
89+
if (avbruttHendelse != null) {
90+
tilbakekrevingsbehandlingRepo.lagre(
91+
hendelse = avbruttHendelse,
92+
meta = command.toDefaultHendelsesMetadata(),
93+
sessionContext = it,
94+
)
95+
}
96+
}
97+
avbruttBehandling
98+
}
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package tilbakekreving.application.service.kravgrunnlag
2+
3+
import tilbakekreving.domain.vedtak.KunneIkkeAnnullerePåbegynteVedtak
4+
import tilgangstyring.domain.IkkeTilgangTilSak
5+
6+
sealed interface KunneIkkeAnnullereKravgrunnlag {
7+
data class IkkeTilgang(val underliggende: IkkeTilgangTilSak) : KunneIkkeAnnullereKravgrunnlag
8+
data object InnsendtHendelseIdErIkkeDenSistePåSaken : KunneIkkeAnnullereKravgrunnlag
9+
data object SakenHarIkkeKravgrunnlagSomKanAnnulleres : KunneIkkeAnnullereKravgrunnlag
10+
data object FantIkkeKravgrunnlag : KunneIkkeAnnullereKravgrunnlag
11+
data object BehandlingenErIFeilTilstandForÅAnnullere : KunneIkkeAnnullereKravgrunnlag
12+
data class FeilMotTilbakekrevingskomponenten(val underliggende: KunneIkkeAnnullerePåbegynteVedtak) :
13+
KunneIkkeAnnullereKravgrunnlag
14+
}

tilbakekreving/domain/src/main/kotlin/tilbakekreving/domain/KanEndres.kt

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package tilbakekreving.domain
77
* - oppdatere vedtaksbrev
88
* - oppdatere notat
99
* - oppdatere kravgrunnlag
10+
* - annullere kravgrunnlag
1011
*/
1112
sealed interface KanEndres : Tilbakekrevingsbehandling {
1213
override fun erÅpen() = true

tilbakekreving/domain/src/main/kotlin/tilbakekreving/domain/TilbakekrevingsbehandlingHendelser.kt

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import dokument.domain.DokumentHendelseSerie
44
import dokument.domain.DokumentHendelser
55
import dokument.domain.Dokumenttilstand
66
import no.nav.su.se.bakover.common.domain.Saksnummer
7+
import no.nav.su.se.bakover.common.domain.extensions.singleOrNullOrThrow
78
import no.nav.su.se.bakover.common.person.Fnr
89
import no.nav.su.se.bakover.hendelse.domain.HendelseId
910
import tilbakekreving.domain.kravgrunnlag.Kravgrunnlag
@@ -204,6 +205,15 @@ data class TilbakekrevingsbehandlingHendelser private constructor(
204205
hendelser = sorterteHendelser.filter { it.id == behandlingsid },
205206
)
206207

208+
fun hentKravrunnlag(kravgrunnlagHendelseId: HendelseId): Kravgrunnlag? {
209+
return kravgrunnlagPåSak.hentKravgrunnlagDetaljerPåSakHendelseForHendelseId(kravgrunnlagHendelseId)?.kravgrunnlag
210+
}
211+
212+
fun hentBehandlingForKravgrunnlag(kravgrunnlagHendelseId: HendelseId): Tilbakekrevingsbehandling? =
213+
this.currentState.behandlinger.singleOrNullOrThrow {
214+
it.kravgrunnlag.hendelseId == kravgrunnlagHendelseId && it.erÅpen()
215+
}
216+
207217
/**
208218
* Henter det siste utestående kravgrunnlaget, dersom det finnes et kravgrunnlag og det ikke er avsluttet.
209219
* Det er kun det siste mottatte kravgrunnlaget som kan være utestående.

tilbakekreving/domain/src/main/kotlin/tilbakekreving/domain/UnderBehandling.kt

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ sealed interface UnderBehandling :
2727
KanVurdere,
2828
KanForhåndsvarsle,
2929
KanOppdatereNotat,
30+
KanAnnullere,
3031
UnderBehandlingEllerTilAttestering {
3132

3233
override val vurderingerMedKrav: VurderingerMedKrav?
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@file:Suppress("PackageDirectoryMismatch")
2+
// Må ligge i samme pakke som Tilbakekrevingsbehandling (siden det er et sealed interface), men trenger ikke ligge i samme mappe.
3+
4+
package tilbakekreving.domain
5+
6+
import no.nav.su.se.bakover.common.ident.NavIdentBruker
7+
import no.nav.su.se.bakover.common.tid.Tidspunkt
8+
import no.nav.su.se.bakover.hendelse.domain.HendelseId
9+
import no.nav.su.se.bakover.hendelse.domain.Hendelsesversjon
10+
11+
sealed interface KanAnnullere : KanEndres {
12+
fun annuller(
13+
annulleringstidspunkt: Tidspunkt,
14+
annullertAv: NavIdentBruker.Saksbehandler,
15+
versjon: Hendelsesversjon,
16+
): Pair<AvbruttHendelse, AvbruttTilbakekrevingsbehandling> {
17+
val hendelse = AvbruttHendelse(
18+
hendelseId = HendelseId.generer(),
19+
id = this.id,
20+
utførtAv = annullertAv,
21+
tidligereHendelseId = this.hendelseId,
22+
hendelsestidspunkt = annulleringstidspunkt,
23+
sakId = this.sakId,
24+
versjon = versjon,
25+
begrunnelse = "Behandling er blitt avbrutt fordi kravgrunnlaget skal annulleres.",
26+
)
27+
return hendelse to hendelse.applyToState(this)
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package tilbakekreving.domain.kravgrunnlag
2+
3+
import no.nav.su.se.bakover.common.CorrelationId
4+
import no.nav.su.se.bakover.common.brukerrolle.Brukerrolle
5+
import no.nav.su.se.bakover.common.ident.NavIdentBruker
6+
import no.nav.su.se.bakover.hendelse.domain.DefaultHendelseMetadata
7+
import no.nav.su.se.bakover.hendelse.domain.HendelseId
8+
import no.nav.su.se.bakover.hendelse.domain.Hendelsesversjon
9+
import no.nav.su.se.bakover.hendelse.domain.SakshendelseCommand
10+
import java.util.UUID
11+
12+
data class AnnullerKravgrunnlagCommand(
13+
override val sakId: UUID,
14+
override val correlationId: CorrelationId?,
15+
override val brukerroller: List<Brukerrolle>,
16+
val annullertAv: NavIdentBruker.Saksbehandler,
17+
val kravgrunnlagHendelseId: HendelseId,
18+
val klientensSisteSaksversjon: Hendelsesversjon,
19+
) : SakshendelseCommand {
20+
override val utførtAv: NavIdentBruker = annullertAv
21+
22+
fun toDefaultHendelsesMetadata() = DefaultHendelseMetadata(
23+
correlationId = correlationId,
24+
ident = this.utførtAv,
25+
brukerroller = brukerroller,
26+
)
27+
}

0 commit comments

Comments
 (0)