Skip to content

Commit da178e4

Browse files
authored
Merge pull request #872 from navikt/to-behandlinger-v2
Mulighet for å innvilge flere vedtak
2 parents 69c3997 + b86b3f3 commit da178e4

File tree

64 files changed

+1437
-425
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1437
-425
lines changed

app/src/main/kotlin/no/nav/tiltakspenger/saksbehandling/App.kt

+4
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ internal fun start(
8585
applicationContext.meldekortContext.sendMeldeperiodeTilBrukerService.send()
8686
applicationContext.utbetalingContext.oppdaterUtbetalingsstatusService.oppdaterUtbetalingsstatus()
8787
}
88+
// Tester denne kun i dev til å begynne med
89+
if (!Configuration.isProd()) {
90+
applicationContext.genererMeldeperioderService.genererMeldeperioderForSaker()
91+
}
8892
},
8993
)
9094

app/src/main/kotlin/no/nav/tiltakspenger/saksbehandling/context/ApplicationContext.kt

+9
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import no.nav.tiltakspenger.saksbehandling.kafka.tiltaksdeltakelser.arena.Tiltak
2424
import no.nav.tiltakspenger.saksbehandling.kafka.tiltaksdeltakelser.jobb.EndretTiltaksdeltakerJobb
2525
import no.nav.tiltakspenger.saksbehandling.kafka.tiltaksdeltakelser.komet.TiltaksdeltakerKometConsumer
2626
import no.nav.tiltakspenger.saksbehandling.kafka.tiltaksdeltakelser.repository.TiltaksdeltakerKafkaRepository
27+
import no.nav.tiltakspenger.saksbehandling.meldekort.service.GenererMeldeperioderService
2728
import no.nav.tiltakspenger.saksbehandling.meldekort.service.MottaBrukerutfyltMeldekortService
2829
import no.nav.tiltakspenger.saksbehandling.saksbehandling.ports.OppgaveGateway
2930
import no.nav.tiltakspenger.saksbehandling.saksbehandling.ports.VeilarboppfolgingGateway
@@ -203,4 +204,12 @@ open class ApplicationContext(
203204
sessionFactory = sessionFactory,
204205
)
205206
}
207+
208+
val genererMeldeperioderService by lazy {
209+
GenererMeldeperioderService(
210+
sakRepo = sakContext.sakRepo,
211+
meldeperiodeRepo = meldekortContext.meldeperiodeRepo,
212+
sessionFactory = sessionFactory,
213+
)
214+
}
206215
}

app/src/main/kotlin/no/nav/tiltakspenger/saksbehandling/meldekort/domene/BeregnMeldeperiode.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ private data class MeldekortBeregning(
4949
fun beregn(
5050
kommando: SendMeldekortTilBeslutningKommando,
5151
eksisterendeMeldekortPåSaken: MeldekortBehandlinger,
52-
barnetilleggsPerioder: Periodisering<AntallBarn>,
53-
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett>,
52+
barnetilleggsPerioder: Periodisering<AntallBarn?>,
53+
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett?>,
5454
): NonEmptyList<MeldeperiodeBeregningDag.Utfylt> {
5555
val meldekortId = kommando.meldekortId
5656

@@ -469,8 +469,8 @@ private enum class SykTilstand {
469469

470470
fun SendMeldekortTilBeslutningKommando.beregn(
471471
eksisterendeMeldekortBehandlinger: MeldekortBehandlinger,
472-
barnetilleggsPerioder: Periodisering<AntallBarn>,
473-
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett>,
472+
barnetilleggsPerioder: Periodisering<AntallBarn?>,
473+
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett?>,
474474
): NonEmptyList<MeldeperiodeBeregningDag.Utfylt> {
475475
return MeldekortBeregning(
476476
utløsendeMeldekortId = this.meldekortId,

app/src/main/kotlin/no/nav/tiltakspenger/saksbehandling/meldekort/domene/MeldekortBehandling.kt

+2-7
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ sealed interface MeldekortBehandling {
7575
/** Oppdaterer meldeperioden til [meldeperiode] dersom den har samme kjede id, den er nyere enn den eksisterende og dette ikke er avsluttet meldekortbehandling. */
7676
fun oppdaterMeldeperiode(
7777
meldeperiode: Meldeperiode,
78-
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett>,
78+
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett?>,
7979
): MeldekortBehandling? {
8080
require(meldeperiode.kjedeId == kjedeId) {
8181
"MeldekortBehandling: Kan ikke oppdatere meldeperiode med annen kjede id. ${meldeperiode.kjedeId} != $kjedeId"
@@ -98,7 +98,6 @@ sealed interface MeldekortBehandling {
9898
meldeperiode = meldeperiode,
9999
meldekortId = this.id,
100100
sakId = this.sakId,
101-
maksDagerMedTiltakspengerForPeriode = meldeperiode.antallDagerForPeriode,
102101
tiltakstypePerioder = tiltakstypePerioder,
103102
),
104103
)
@@ -187,7 +186,7 @@ sealed interface MeldekortBehandling {
187186
fun tilUnderBehandling(
188187
nyMeldeperiode: Meldeperiode?,
189188
ikkeRettTilTiltakspengerTidspunkt: LocalDateTime? = null,
190-
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett>,
189+
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett?>,
191190
): MeldekortUnderBehandling {
192191
val meldeperiode = nyMeldeperiode ?: this.meldeperiode
193192
return MeldekortUnderBehandling(
@@ -201,7 +200,6 @@ sealed interface MeldekortBehandling {
201200
tiltakstypePerioder = tiltakstypePerioder,
202201
meldekortId = this.id,
203202
sakId = this.sakId,
204-
maksDagerMedTiltakspengerForPeriode = meldeperiode.antallDagerForPeriode,
205203
),
206204
saksbehandler = saksbehandler,
207205
navkontor = this.navkontor,
@@ -335,7 +333,6 @@ fun Sak.opprettMeldekortBehandling(
335333
"Forrige meldekortbehandling i kjeden må være godkjent for å opprette en ny behandling/korrigering (kjede $kjedeId på sak ${this.id})"
336334
}
337335
}
338-
339336
val meldekortId = MeldekortId.random()
340337
val meldeperiode = hentSisteMeldeperiodeForKjede(kjedeId)
341338

@@ -367,8 +364,6 @@ fun Sak.opprettMeldekortBehandling(
367364
meldeperiode = meldeperiode,
368365
meldekortId = meldekortId,
369366
sakId = this.id,
370-
// TODO jah: Behandlingen må ta inn periodisert antall dager og ikke bruke tidligere vedtak her. Tror ikke maksDagerMedTiltakspengerForPeriode brukes til noe; kanskje den bør bort fra beregningen?
371-
maksDagerMedTiltakspengerForPeriode = meldeperiode.antallDagerForPeriode,
372367
tiltakstypePerioder = this.vedtaksliste.tiltakstypeperioder,
373368
),
374369
)

app/src/main/kotlin/no/nav/tiltakspenger/saksbehandling/meldekort/domene/MeldekortBehandlinger.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ data class MeldekortBehandlinger(
3838
*/
3939
fun sendTilBeslutter(
4040
kommando: SendMeldekortTilBeslutningKommando,
41-
barnetilleggsPerioder: Periodisering<AntallBarn>,
42-
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett>,
41+
barnetilleggsPerioder: Periodisering<AntallBarn?>,
42+
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett?>,
4343
): Either<KanIkkeSendeMeldekortTilBeslutning, Pair<MeldekortBehandlinger, MeldekortBehandlet>> {
4444
val meldekortId = kommando.meldekortId
4545

@@ -108,7 +108,7 @@ data class MeldekortBehandlinger(
108108
*/
109109
fun oppdaterMedNyeKjeder(
110110
oppdaterteKjeder: MeldeperiodeKjeder,
111-
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett>,
111+
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett?>,
112112
): Pair<MeldekortBehandlinger, List<MeldekortBehandling>> {
113113
return verdi.filter { it.erÅpen() }
114114
.fold(Pair(this, emptyList())) { acc, meldekortBehandling ->

app/src/main/kotlin/no/nav/tiltakspenger/saksbehandling/meldekort/domene/Meldeperiode.kt

+55-65
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ import no.nav.tiltakspenger.libs.common.SakId
88
import no.nav.tiltakspenger.libs.periodisering.Periode
99
import no.nav.tiltakspenger.libs.periodisering.Periodisering
1010
import no.nav.tiltakspenger.saksbehandling.felles.nå
11-
import no.nav.tiltakspenger.saksbehandling.saksbehandling.domene.sak.Sak
1211
import no.nav.tiltakspenger.saksbehandling.saksbehandling.domene.sak.Saksnummer
1312
import no.nav.tiltakspenger.saksbehandling.saksbehandling.domene.vilkår.Utfallsperiode
14-
import java.time.DayOfWeek
1513
import java.time.LocalDate
1614
import java.time.LocalDateTime
17-
import java.time.temporal.TemporalAdjusters
1815

1916
data class Meldeperiode(
2017
val id: MeldeperiodeId,
@@ -29,7 +26,10 @@ data class Meldeperiode(
2926
val antallDagerForPeriode: Int,
3027
val girRett: Map<LocalDate, Boolean>,
3128
val sendtTilMeldekortApi: LocalDateTime?,
32-
) {
29+
) : Comparable<Meldeperiode> {
30+
val antallDagerSomGirRett = girRett.values.count { it }
31+
val ingenDagerGirRett = antallDagerSomGirRett == 0
32+
3333
fun helePeriodenErSperret(): Boolean {
3434
return girRett.values.toList().all { !it }
3535
}
@@ -39,70 +39,60 @@ data class Meldeperiode(
3939
return periode.fraOgMed <= nå().toLocalDate()
4040
}
4141

42-
val ingenDagerGirRett = girRett.values.none { it }
43-
}
44-
45-
fun Sak.opprettFørsteMeldeperiode(): Meldeperiode {
46-
requireNotNull(this.vedtaksliste.førstegangsvedtak) { "Kan ikke opprette første meldeperiode uten førstegangsvedtak" }
47-
requireNotNull(this.vedtaksliste.innvilgelsesperioder) { "Kan ikke opprette første meldeperiode uten minst én periode som gir rett til tiltakspenger" }
48-
// TODO John + Anders: Denne fungerer ikke når vi får 2 førstegangsbehandlinger.
49-
val periode = finnFørsteMeldekortsperiode(this.vedtaksliste.innvilgelsesperioder.single())
50-
val utfallsperioder = this.vedtaksliste.førstegangsvedtak!!.utfallsperioder
51-
52-
return this.opprettMeldeperiode(periode, utfallsperioder!!)
53-
}
54-
55-
/**
56-
* Dersom vi kan opprette en ny meldeperiode, returnerer vi denne. Dersom vi ikke, returnerer vi null.
57-
* Hvis ingen av dagene i neste meldeperiode
58-
* Denne funksjonen tar ikke høyde for om det er "for tidlig" og opprette neste meldeperiode. Dette må håndteres av kaller.
59-
*
60-
* @return null dersom vi ikke skal opprette en ny meldeperiode (dvs. at vi har nådd slutten av vedtaksperioden)
61-
* @throws IllegalStateException hvis det ikke finnes noen vedtak
62-
*/
63-
fun Sak.opprettNesteMeldeperiode(): Meldeperiode? {
64-
check(this.vedtaksliste.isNotEmpty()) { "Vedtaksliste kan ikke være tom når man prøver opprette neste meldeperiode" }
65-
66-
val siste: Meldeperiode = this.meldeperiodeKjeder.hentSisteMeldeperiode()
67-
// Kommentar jah: Dersom vi har hull mellom meldeperiodene, så vil ikke dette være godt nok.
68-
val nestePeriode = Periode(siste.periode.fraOgMed.plusDays(14), siste.periode.tilOgMed.plusDays(14))
69-
70-
val utfallsperioder = this.vedtaksliste.utfallsperioder
71-
if (nestePeriode.fraOgMed.isAfter(utfallsperioder.totalePeriode.tilOgMed)) {
72-
return null
42+
fun erLik(meldeperiode: Meldeperiode): Boolean {
43+
// feltene vi har lyst til å ignorere
44+
return this == meldeperiode.copy(
45+
id = this.id,
46+
opprettet = this.opprettet,
47+
versjon = this.versjon,
48+
)
7349
}
7450

75-
val nesteMeldeperiode = this.opprettMeldeperiode(nestePeriode, utfallsperioder)
76-
if (nesteMeldeperiode.ingenDagerGirRett) return null
77-
return nesteMeldeperiode
78-
}
79-
80-
private fun Sak.opprettMeldeperiode(
81-
periode: Periode,
82-
utfallsperioder: Periodisering<Utfallsperiode>,
83-
): Meldeperiode {
84-
val meldeperiode = Meldeperiode(
85-
kjedeId = MeldeperiodeKjedeId.fraPeriode(periode),
86-
id = MeldeperiodeId.random(),
87-
fnr = this.fnr,
88-
saksnummer = this.saksnummer,
89-
sakId = this.id,
90-
antallDagerForPeriode = this.hentAntallDager()!!,
91-
periode = periode,
92-
opprettet = nå(),
93-
versjon = HendelseVersjon.ny(),
94-
girRett = periode.tilDager().associateWith {
95-
(utfallsperioder.hentVerdiForDag(it) == Utfallsperiode.RETT_TIL_TILTAKSPENGER)
96-
},
97-
sendtTilMeldekortApi = null,
98-
)
51+
override fun compareTo(other: Meldeperiode): Int {
52+
require(!this.periode.overlapperMed(other.periode)) { "Meldeperiodene kan ikke overlappe" }
53+
return this.periode.fraOgMed.compareTo(other.periode.fraOgMed)
54+
}
9955

100-
return meldeperiode
101-
}
56+
init {
57+
if (ingenDagerGirRett) {
58+
require(antallDagerForPeriode == 0) { "Dersom ingen dager gir rett, må antallDagerForPeriode være 0" }
59+
}
60+
require(antallDagerForPeriode <= antallDagerSomGirRett) {
61+
"""
62+
Antall dager som gir rett kan ikke være mindre enn antall dager for periode
63+
antallDagerForPeriode: $antallDagerForPeriode
64+
antallDagerSomGirRett: $antallDagerSomGirRett
65+
""".trimIndent()
66+
}
67+
}
10268

103-
private fun finnFørsteMeldekortsperiode(periode: Periode): Periode {
104-
val førsteMandagIMeldekortsperiode = periode.fraOgMed.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
105-
val sisteSøndagIMeldekortsperiode = førsteMandagIMeldekortsperiode.plusDays(13)
69+
companion object {
70+
fun opprettMeldeperiode(
71+
periode: Periode,
72+
utfallsperioder: Periodisering<Utfallsperiode?>,
73+
fnr: Fnr,
74+
saksnummer: Saksnummer,
75+
sakId: SakId,
76+
antallDagerForPeriode: Int,
77+
versjon: HendelseVersjon = HendelseVersjon.ny(),
78+
): Meldeperiode {
79+
val meldeperiode = Meldeperiode(
80+
kjedeId = MeldeperiodeKjedeId.fraPeriode(periode),
81+
id = MeldeperiodeId.random(),
82+
fnr = fnr,
83+
saksnummer = saksnummer,
84+
sakId = sakId,
85+
antallDagerForPeriode = antallDagerForPeriode,
86+
periode = periode,
87+
opprettet = nå(),
88+
versjon = versjon,
89+
girRett = periode.tilDager().associateWith {
90+
(utfallsperioder.hentVerdiForDag(it) == Utfallsperiode.RETT_TIL_TILTAKSPENGER)
91+
},
92+
sendtTilMeldekortApi = null,
93+
)
10694

107-
return Periode(førsteMandagIMeldekortsperiode, sisteSøndagIMeldekortsperiode)
95+
return meldeperiode
96+
}
97+
}
10898
}

app/src/main/kotlin/no/nav/tiltakspenger/saksbehandling/meldekort/domene/MeldeperiodeBeregning.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,7 @@ sealed interface MeldeperiodeBeregning : List<MeldeperiodeBeregningDag> {
125125
meldeperiode: Meldeperiode,
126126
meldekortId: MeldekortId,
127127
sakId: SakId,
128-
maksDagerMedTiltakspengerForPeriode: Int,
129-
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett>,
128+
tiltakstypePerioder: Periodisering<TiltakstypeSomGirRett?>,
130129
): IkkeUtfyltMeldeperiode {
131130
val dager =
132131
meldeperiode.periode.tilDager().map { dag ->
@@ -144,7 +143,7 @@ sealed interface MeldeperiodeBeregning : List<MeldeperiodeBeregningDag> {
144143
}
145144
}
146145
return if (dager.any { it is MeldeperiodeBeregningDag.IkkeUtfylt }) {
147-
IkkeUtfyltMeldeperiode(sakId, maksDagerMedTiltakspengerForPeriode, dager.toNonEmptyListOrNull()!!)
146+
IkkeUtfyltMeldeperiode(sakId, meldeperiode.antallDagerForPeriode, dager.toNonEmptyListOrNull()!!)
148147
} else {
149148
throw IllegalStateException("Alle dagene i en meldekortperiode er SPERRET. Dette har vi ikke støtte for i MVP.")
150149
}
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package no.nav.tiltakspenger.saksbehandling.meldekort.domene
22

33
import arrow.core.NonEmptyList
4+
import arrow.core.nonEmptyListOf
45
import no.nav.tiltakspenger.libs.common.Fnr
5-
import no.nav.tiltakspenger.libs.common.MeldeperiodeId
6+
import no.nav.tiltakspenger.libs.common.HendelseVersjon
67
import no.nav.tiltakspenger.libs.common.MeldeperiodeKjedeId
78
import no.nav.tiltakspenger.libs.common.SakId
89
import no.nav.tiltakspenger.libs.common.nonDistinctBy
9-
import no.nav.tiltakspenger.libs.common.nå
1010
import no.nav.tiltakspenger.libs.periodisering.Periode
1111
import no.nav.tiltakspenger.saksbehandling.saksbehandling.domene.sak.Saksnummer
1212

1313
data class MeldeperiodeKjede(
1414
private val meldeperioder: NonEmptyList<Meldeperiode>,
15-
) : List<Meldeperiode> by meldeperioder {
15+
) : List<Meldeperiode> by meldeperioder,
16+
Comparable<MeldeperiodeKjede> {
17+
constructor(meldeperiode: Meldeperiode) : this(nonEmptyListOf(meldeperiode))
1618

1719
// Disse fungerer også som validering, hvis du fjerner må du legge de inn som init.
1820
val sakId: SakId = meldeperioder.map { it.sakId }.distinct().single()
@@ -21,7 +23,8 @@ data class MeldeperiodeKjede(
2123
val fnr: Fnr = meldeperioder.map { it.fnr }.distinct().single()
2224
val kjedeId: MeldeperiodeKjedeId = meldeperioder.map { it.kjedeId }.distinct().single()
2325

24-
val siste = meldeperioder.last()
26+
val siste: Meldeperiode = meldeperioder.last()
27+
val sisteVersjon = siste.versjon
2528

2629
init {
2730
meldeperioder.nonDistinctBy { it.id }.also {
@@ -35,44 +38,36 @@ data class MeldeperiodeKjede(
3538
"Meldeperiodene må være sortert på versjon - ${a.id} og ${b.id} var i feil rekkefølge"
3639
}
3740
require(a.id != b.id)
41+
require(!a.erLik(b)) {
42+
"Meldeperiodene må være unike - ${a.id} og ${b.id} var like"
43+
}
3844
}
3945
}
4046

47+
fun hentSisteMeldeperiode(): Meldeperiode {
48+
return meldeperioder.last()
49+
}
50+
51+
fun erLikSiste(meldeperiode: Meldeperiode): Boolean {
52+
return siste.erLik(meldeperiode)
53+
}
54+
4155
/**
42-
* Legger til en ny meldeperiode i kjeden dersom den overlapper med stansperioden.
43-
* Setter [Meldeperiode.antallDagerForPeriode] til 0 dersom ingen av dagene i meldeperioden gir rett.
44-
* Oppdaterer [Meldeperiode.girRett] basert på [stansperiode]
45-
* Inkrementerer [Meldeperiode.versjon] med 1.
56+
* Endrer bare kjeden dersom siste meldeperiode i kjeden har en differense med nye meldeperioden.
57+
* @return Par av [MeldeperiodeKjede] med [Meldeperiode] hvis kjeden har blitt endret, ellers nåværende kjede og null.
4658
*/
47-
fun oppdaterMedNyStansperiode(stansperiode: Periode): Pair<MeldeperiodeKjede, Meldeperiode?> {
48-
val erFullstendigStans = stansperiode.inneholderHele(this.periode)
49-
return if (stansperiode.overlapperMed(this.periode)) {
50-
val oppdatertMeldeperiode = Meldeperiode(
51-
kjedeId = kjedeId,
52-
id = MeldeperiodeId.random(),
53-
versjon = siste.versjon.inc(),
54-
periode = this.periode,
55-
opprettet = nå(),
56-
sakId = sakId,
57-
saksnummer = saksnummer,
58-
fnr = fnr,
59-
// Kommentar jah: Småplukk. Dersom dager som gir rett < siste.antallDagerForPeriode, bør vi krympet antallDagerForPeriode?
60-
// Meldeperiode burde isåfall ha noe i init-en sin dersom det er en slik avhengighet mellom typene.
61-
antallDagerForPeriode = if (erFullstendigStans) 0 else siste.antallDagerForPeriode,
62-
girRett = siste.girRett.mapValues { (dag, girRett) -> if (stansperiode.inneholder(dag)) false else girRett },
63-
sendtTilMeldekortApi = null,
64-
)
65-
Pair(this.leggTilMeldeperiode(oppdatertMeldeperiode), oppdatertMeldeperiode)
66-
} else {
67-
Pair(this, null)
59+
fun leggTilMeldeperiode(meldeperiode: Meldeperiode): Pair<MeldeperiodeKjede, Meldeperiode?> {
60+
require(meldeperiode.versjon == sisteVersjon.inc()) { "Den innkommende meldeperioden sin versjon må være 1 versjon høyere enn kjedens siste versjon" }
61+
if (erLikSiste(meldeperiode)) {
62+
return this to null
6863
}
64+
return MeldeperiodeKjede(meldeperioder + meldeperiode) to meldeperiode
6965
}
7066

71-
fun hentSisteMeldeperiode(): Meldeperiode {
72-
return meldeperioder.last()
73-
}
67+
fun nesteVersjon(): HendelseVersjon = this.meldeperioder.last().versjon.inc()
7468

75-
fun leggTilMeldeperiode(meldeperiode: Meldeperiode): MeldeperiodeKjede {
76-
return MeldeperiodeKjede(meldeperioder + meldeperiode)
69+
override fun compareTo(other: MeldeperiodeKjede): Int {
70+
require(!this.periode.overlapperMed(other.periode)) { "Meldeperiodekjedene kan ikke overlappe" }
71+
return this.periode.fraOgMed.compareTo(other.periode.fraOgMed)
7772
}
7873
}

0 commit comments

Comments
 (0)