Skip to content

Commit 43fd500

Browse files
committed
Reduserte muligheten for feilaktig avslutning ved feile stopp-på-veiene-av meldinger
1 parent 92a56b3 commit 43fd500

File tree

8 files changed

+368
-15
lines changed

8 files changed

+368
-15
lines changed

apps/bekreftelse-tjeneste/src/main/kotlin/no/nav/paw/bekreftelsetjeneste/tilstand/Bekreftelse.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package no.nav.paw.bekreftelsetjeneste.tilstand
22

3+
import org.apache.kafka.common.protocol.types.Field.Bool
34
import java.time.Instant
45
import java.util.*
56

@@ -8,7 +9,8 @@ data class Bekreftelse(
89
val tilstandsLogg: BekreftelseTilstandsLogg,
910
val bekreftelseId: UUID,
1011
val gjelderFra: Instant,
11-
val gjelderTil: Instant
12+
val gjelderTil: Instant,
13+
val dummy: Boolean = false //true -> Indikerer at dette ikke er en faktisk bekreftelse
1214
)
1315

1416
inline fun <reified T: BekreftelseTilstandStatus> Bekreftelse.tilstand(): T? = tilstandsLogg.get()

apps/bekreftelse-tjeneste/src/main/kotlin/no/nav/paw/bekreftelsetjeneste/topology/BekreftelsePunctuatorFunctions.kt

+44-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import no.nav.paw.bekreftelse.internehendelser.BekreftelseTilgjengelig
1010
import no.nav.paw.bekreftelse.internehendelser.LeveringsfristUtloept
1111
import no.nav.paw.bekreftelse.internehendelser.RegisterGracePeriodeGjenstaaendeTid
1212
import no.nav.paw.bekreftelse.internehendelser.RegisterGracePeriodeUtloept
13+
import no.nav.paw.bekreftelsetjeneste.logger
1314
import no.nav.paw.bekreftelsetjeneste.metrics.tellBekreftelseHandling
1415
import no.nav.paw.bekreftelsetjeneste.tilstand.Bekreftelse
1516
import no.nav.paw.bekreftelsetjeneste.tilstand.BekreftelseTilstand
@@ -19,6 +20,7 @@ import no.nav.paw.bekreftelsetjeneste.tilstand.GracePeriodeUtloept
1920
import no.nav.paw.bekreftelsetjeneste.tilstand.GracePeriodeVarselet
2021
import no.nav.paw.bekreftelsetjeneste.tilstand.IkkeKlarForUtfylling
2122
import no.nav.paw.bekreftelsetjeneste.tilstand.KlarForUtfylling
23+
import no.nav.paw.bekreftelsetjeneste.tilstand.Levert
2224
import no.nav.paw.bekreftelsetjeneste.tilstand.VenterPaaSvar
2325
import no.nav.paw.bekreftelsetjeneste.tilstand.VenterSvar
2426
import no.nav.paw.bekreftelsetjeneste.tilstand.erKlarForUtfylling
@@ -31,11 +33,14 @@ import no.nav.paw.bekreftelsetjeneste.tilstand.sisteTilstand
3133
import no.nav.paw.bekreftelsetjeneste.tilstand.sluttTidForBekreftelsePeriode
3234
import no.nav.paw.collections.PawNonEmptyList
3335
import no.nav.paw.collections.pawNonEmptyListOf
36+
import java.time.LocalDate
37+
import java.time.Month
3438
import java.util.*
3539

3640

3741
fun BekreftelseContext.prosesser(bekreftelseTilstand: BekreftelseTilstand): BekreftelseProsesseringsResultat =
3842
(::opprettInitielBekreftelse andThen
43+
::opprettSisteLeverteFoerMigrering andThen
3944
::opprettManglendeBekreftelser andThen
4045
::oppdaterBekreftelser andThen
4146
{ (bekreftelser, hendelser) ->
@@ -47,8 +52,46 @@ fun BekreftelseContext.prosesser(bekreftelseTilstand: BekreftelseTilstand): Bekr
4752
})(bekreftelseTilstand.bekreftelser)
4853

4954

55+
fun opprettSisteLeverteFoerMigrering(bekreftelser: PawNonEmptyList<Bekreftelse>): PawNonEmptyList<Bekreftelse> {
56+
val forsteBekreftelse = bekreftelser.minBy { it.gjelderFra }
57+
val dato = when (forsteBekreftelse.gjelderFra) {
58+
LocalDate.of(2025, Month.MARCH, 17)
59+
.atStartOfDay(norskTid).toInstant() -> LocalDate.of(2025, Month.MARCH, 3)
60+
LocalDate.of(2025, Month.MARCH, 10)
61+
.atStartOfDay(norskTid).toInstant() -> LocalDate.of(2025, Month.MARCH, 10)
62+
else -> null
63+
}
64+
return dato?.let { sisteLeverteBekreftelser ->
65+
val tidspunkt = sisteLeverteBekreftelser
66+
.atStartOfDay(norskTid)
67+
.toInstant()
68+
Bekreftelse(
69+
tilstandsLogg = BekreftelseTilstandsLogg(
70+
siste = Levert(tidspunkt),
71+
tidligere = emptyList()
72+
),
73+
bekreftelseId = UUID.randomUUID(),
74+
gjelderFra = sisteLeverteBekreftelser.minusWeeks(2).atStartOfDay(norskTid).toInstant(),
75+
gjelderTil = tidspunkt,
76+
dummy = true
77+
)
78+
}?.let {
79+
Span.current().addEvent(
80+
intern,
81+
Attributes.of(
82+
actionKey, bekreftelseOpprettetAction,
83+
initielBekreftelseKey, true,
84+
fraOgMedDagKey, it.gjelderFra.tilFraTilAttributeKeyValue(),
85+
tilDagKey, it.gjelderTil.tilFraTilAttributeKeyValue()
86+
)
87+
)
88+
bekreftelser + it
89+
} ?: bekreftelser
90+
}
91+
92+
5093
fun BekreftelseContext.opprettInitielBekreftelse(bekreftelser: List<Bekreftelse>): PawNonEmptyList<Bekreftelse> {
51-
val foerste = bekreftelser.firstOrNull()
94+
val foerste = bekreftelser.firstOrNull { !it.dummy }
5295
return if (foerste != null) {
5396
pawNonEmptyListOf(foerste, bekreftelser.drop(1))
5497
} else {

apps/bekreftelse-tjeneste/src/main/kotlin/no/nav/paw/bekreftelsetjeneste/topology/TraceAttributes.kt

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ val nyBekreftelseStatusKey = AttributeKey.stringKey("ny_bekreftelse_status")
3434
val gjeldeneBekreftelseStatusKey = AttributeKey.stringKey("gjeldene_bekreftelse_status")
3535
const val bekreftelseLevertAction = "bekreftelse_levert"
3636
const val bekreftelseOpprettetAction = "bekreftelse_opprettet"
37+
const val dummyBekreftelseOpprettetAction = "dummy_bekreftelse_opprettet"
3738
const val bekreftelseSattStatusAction = "bekreftelse_satt_status"
3839
const val bekreftelseHentUke = "bekreftelse_hent_uke"
3940

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package no.nav.paw.bekreftelsetjeneste.testcases
2+
3+
import io.kotest.core.spec.style.FreeSpec
4+
import io.kotest.matchers.collections.shouldBeEmpty
5+
import io.kotest.matchers.should
6+
import io.kotest.matchers.shouldBe
7+
import no.nav.paw.arbeidssoekerregisteret.testdata.KafkaKeyContext
8+
import no.nav.paw.arbeidssoekerregisteret.testdata.ValueWithKafkaKeyData
9+
import no.nav.paw.arbeidssoekerregisteret.testdata.bekreftelse.bekreftelseMelding
10+
import no.nav.paw.arbeidssoekerregisteret.testdata.bekreftelse.startPaaVegneAv
11+
import no.nav.paw.arbeidssoekerregisteret.testdata.bekreftelse.stoppPaaVegneAv
12+
import no.nav.paw.arbeidssoekerregisteret.testdata.mainavro.metadata
13+
import no.nav.paw.arbeidssoekerregisteret.testdata.mainavro.periode
14+
import no.nav.paw.bekreftelse.internehendelser.BaOmAaAvsluttePeriode
15+
import no.nav.paw.bekreftelse.internehendelser.BekreftelseMeldingMottatt
16+
import no.nav.paw.bekreftelse.internehendelser.BekreftelsePaaVegneAvStartet
17+
import no.nav.paw.bekreftelse.internehendelser.BekreftelseTilgjengelig
18+
import no.nav.paw.bekreftelse.internehendelser.LeveringsfristUtloept
19+
import no.nav.paw.bekreftelse.internehendelser.PeriodeAvsluttet
20+
import no.nav.paw.bekreftelse.internehendelser.RegisterGracePeriodeGjenstaaendeTid
21+
import no.nav.paw.bekreftelse.internehendelser.RegisterGracePeriodeUtloept
22+
import no.nav.paw.bekreftelse.internehendelser.RegisterGracePeriodeUtloeptEtterEksternInnsamling
23+
import no.nav.paw.bekreftelse.melding.v1.vo.Bekreftelsesloesning
24+
import no.nav.paw.bekreftelsetjeneste.testutils.dager
25+
import no.nav.paw.bekreftelsetjeneste.testutils.prettyPrint
26+
import no.nav.paw.bekreftelsetjeneste.testutils.run
27+
import no.nav.paw.bekreftelsetjeneste.testutils.setOppTest
28+
import no.nav.paw.bekreftelsetjeneste.testutils.timer
29+
import no.nav.paw.bekreftelsetjeneste.testutils.timestamp
30+
import no.nav.paw.bekreftelsetjeneste.tilstand.GracePeriodeVarselet
31+
import no.nav.paw.bekreftelsetjeneste.topology.DummyOddetallPartallMap
32+
import java.time.Duration
33+
import java.time.Instant
34+
import java.time.LocalDate
35+
import java.time.Month
36+
import java.util.*
37+
38+
class BrukerRegFoerMigreringKommerTilbakeUtenAaHaLevertNoe : FreeSpec({
39+
val identietsnummer = "12345678901"
40+
val periodeStartet = "01.01.2025 15:26".timestamp
41+
val interval = 14.dager
42+
val graceperiode = 7.dager
43+
val tilgjengeligOffset = 3.dager
44+
with(
45+
setOppTest(
46+
tidlistBekreftelsePeriodeStart = LocalDate.of(2025, Month.MARCH, 10),
47+
datoOgKlokkeslettVedStart = periodeStartet,
48+
bekreftelseIntervall = interval,
49+
tilgjengeligOffset = tilgjengeligOffset,
50+
innleveringsfrist = graceperiode + 4.timer,
51+
oddetallPartallMap = DummyOddetallPartallMap()
52+
)
53+
) {
54+
"Setter opp test med ${interval.toDays()} dagers intervall og ${graceperiode.toDays()} dagers graceperiode. Bekreftelser tilgjengeliggjøres ${tilgjengeligOffset.toDays()} dager før utløp av ${interval.toDays()} dagers perioden" {}
55+
val opploesning = Duration.ofSeconds(180)
56+
val stoppTid = "02.05.2025 00:00".timestamp
57+
val (hendelser, input) = with(KafkaKeyContext(this.kafkaKeysClient)) {
58+
val periode = periode(
59+
identitetsnummer = identietsnummer,
60+
startetMetadata = metadata(tidspunkt = periodeStartet)
61+
)
62+
val eksterneHendelser: List<Pair<Instant, ValueWithKafkaKeyData<*>>> = listOf(
63+
"01.01.2025 15:26".timestamp to periode,
64+
"15.03.2025 09:12".timestamp to ValueWithKafkaKeyData(periode.id, periode.key, startPaaVegneAv(
65+
periodeId = periode.value.id,
66+
bekreftelsesloesning = no.nav.paw.bekreftelse.paavegneav.v1.vo.Bekreftelsesloesning.DAGPENGER,
67+
grace = 7.dager,
68+
interval = 14.dager
69+
)),
70+
"15.03.2025 12:30".timestamp to ValueWithKafkaKeyData(periode.id, periode.key, stoppPaaVegneAv(
71+
periodeId = periode.value.id,
72+
bekreftelsesloesning = no.nav.paw.bekreftelse.paavegneav.v1.vo.Bekreftelsesloesning.DAGPENGER
73+
))
74+
)
75+
run(eksterneHendelser, stoppTid, opploesning) to eksterneHendelser
76+
}
77+
hendelser.map { (ts, hendelse) -> "${ts.prettyPrint}: ${hendelse.prettyPrint()}" }.forEach { println(it) }
78+
val kilde = mutableListOf(*hendelser.toTypedArray())
79+
val inputHendelser = input.toMutableList()
80+
forventer<BekreftelsePaaVegneAvStartet>(
81+
kilde,
82+
inputHendelser,
83+
fra = "15.03.2025 09:12".timestamp,
84+
til = "15.03.2025 09:18".timestamp
85+
)
86+
var bekreftelseId2803: UUID? = null
87+
forventer<BekreftelseTilgjengelig>(
88+
kilde,
89+
inputHendelser,
90+
fra = "21.03.2025 00:00".timestamp,
91+
til = "21.03.2025 06:00".timestamp,
92+
asserts = { publiserteBekreftelser ->
93+
publiserteBekreftelser.size shouldBe 1
94+
publiserteBekreftelser.first() should { bekreftelse ->
95+
bekreftelse.gjelderFra shouldBe "10.03.2025 00:00".timestamp
96+
bekreftelse.gjelderTil shouldBe "24.03.2025 00:00".timestamp
97+
}
98+
bekreftelseId2803 = publiserteBekreftelser.first().bekreftelseId
99+
}
100+
)
101+
forventer<LeveringsfristUtloept>(
102+
kilde,
103+
inputHendelser,
104+
fra = "24.03.2025 00:00".timestamp,
105+
til = "24.03.2025 00:10".timestamp,
106+
asserts = { fristUtloeptListe ->
107+
fristUtloeptListe.size shouldBe 1
108+
fristUtloeptListe.first() should { fristUtloept ->
109+
fristUtloept.leveringsfrist shouldBe "24.03.2025 00:00".timestamp
110+
fristUtloept.bekreftelseId shouldBe bekreftelseId2803
111+
}
112+
}
113+
)
114+
forventer<RegisterGracePeriodeGjenstaaendeTid>(
115+
kilde,
116+
inputHendelser,
117+
fra = "27.03.2025 00:30".timestamp,
118+
til = "27.03.2025 23:00".timestamp,
119+
)
120+
forventer<RegisterGracePeriodeUtloept>(
121+
kilde,
122+
inputHendelser,
123+
fra = "31.03.2025 00:00".timestamp,
124+
til = "31.03.2025 06:00".timestamp
125+
)
126+
forventer<PeriodeAvsluttet>(
127+
kilde,
128+
inputHendelser,
129+
fra = "31.03.2025 00:00".timestamp,
130+
til = "31.03.2025 06:00".timestamp
131+
)
132+
"Ingen flere hendelser inntraff" {
133+
kilde.shouldBeEmpty()
134+
}
135+
}
136+
})
137+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package no.nav.paw.bekreftelsetjeneste.testcases
2+
3+
import io.kotest.core.spec.style.FreeSpec
4+
import io.kotest.matchers.collections.shouldBeEmpty
5+
import io.kotest.matchers.should
6+
import io.kotest.matchers.shouldBe
7+
import no.nav.paw.arbeidssoekerregisteret.testdata.KafkaKeyContext
8+
import no.nav.paw.arbeidssoekerregisteret.testdata.ValueWithKafkaKeyData
9+
import no.nav.paw.arbeidssoekerregisteret.testdata.bekreftelse.bekreftelseMelding
10+
import no.nav.paw.arbeidssoekerregisteret.testdata.bekreftelse.startPaaVegneAv
11+
import no.nav.paw.arbeidssoekerregisteret.testdata.bekreftelse.stoppPaaVegneAv
12+
import no.nav.paw.arbeidssoekerregisteret.testdata.mainavro.metadata
13+
import no.nav.paw.arbeidssoekerregisteret.testdata.mainavro.periode
14+
import no.nav.paw.bekreftelse.internehendelser.BaOmAaAvsluttePeriode
15+
import no.nav.paw.bekreftelse.internehendelser.BekreftelseMeldingMottatt
16+
import no.nav.paw.bekreftelse.internehendelser.BekreftelsePaaVegneAvStartet
17+
import no.nav.paw.bekreftelse.internehendelser.BekreftelseTilgjengelig
18+
import no.nav.paw.bekreftelse.internehendelser.LeveringsfristUtloept
19+
import no.nav.paw.bekreftelse.internehendelser.PeriodeAvsluttet
20+
import no.nav.paw.bekreftelse.internehendelser.RegisterGracePeriodeGjenstaaendeTid
21+
import no.nav.paw.bekreftelse.internehendelser.RegisterGracePeriodeUtloept
22+
import no.nav.paw.bekreftelse.internehendelser.RegisterGracePeriodeUtloeptEtterEksternInnsamling
23+
import no.nav.paw.bekreftelse.melding.v1.vo.Bekreftelsesloesning
24+
import no.nav.paw.bekreftelsetjeneste.testutils.dager
25+
import no.nav.paw.bekreftelsetjeneste.testutils.prettyPrint
26+
import no.nav.paw.bekreftelsetjeneste.testutils.run
27+
import no.nav.paw.bekreftelsetjeneste.testutils.setOppTest
28+
import no.nav.paw.bekreftelsetjeneste.testutils.timer
29+
import no.nav.paw.bekreftelsetjeneste.testutils.timestamp
30+
import no.nav.paw.bekreftelsetjeneste.tilstand.GracePeriodeVarselet
31+
import no.nav.paw.bekreftelsetjeneste.topology.DummyOddetallPartallMap
32+
import java.time.Duration
33+
import java.time.Instant
34+
import java.time.LocalDate
35+
import java.time.Month
36+
import java.util.*
37+
38+
class PartallsBrukerRegFoerMigreringKommerTilbakeUtenAaHaLevertNoe : FreeSpec({
39+
val identietsnummer = "12345678902"
40+
val periodeStartet = "01.01.2025 15:26".timestamp
41+
val interval = 14.dager
42+
val graceperiode = 7.dager
43+
val tilgjengeligOffset = 3.dager - 4.timer
44+
with(
45+
setOppTest(
46+
tidlistBekreftelsePeriodeStart = LocalDate.of(2025, Month.MARCH, 10),
47+
datoOgKlokkeslettVedStart = periodeStartet,
48+
bekreftelseIntervall = interval,
49+
tilgjengeligOffset = tilgjengeligOffset,
50+
innleveringsfrist = graceperiode + 4.timer,
51+
oddetallPartallMap = DummyOddetallPartallMap()
52+
)
53+
) {
54+
"Setter opp test med ${interval.toDays()} dagers intervall og ${graceperiode.toDays()} dagers graceperiode. Bekreftelser tilgjengeliggjøres ${tilgjengeligOffset.toDays()} dager før utløp av ${interval.toDays()} dagers perioden" {}
55+
val opploesning = Duration.ofSeconds(180)
56+
val stoppTid = "02.05.2025 00:00".timestamp
57+
val (hendelser, input) = with(KafkaKeyContext(this.kafkaKeysClient)) {
58+
val periode = periode(
59+
identitetsnummer = identietsnummer,
60+
startetMetadata = metadata(tidspunkt = periodeStartet)
61+
)
62+
val eksterneHendelser: List<Pair<Instant, ValueWithKafkaKeyData<*>>> = listOf(
63+
"01.01.2025 15:26".timestamp to periode,
64+
"18.03.2025 09:12".timestamp to ValueWithKafkaKeyData(periode.id, periode.key, startPaaVegneAv(
65+
periodeId = periode.value.id,
66+
bekreftelsesloesning = no.nav.paw.bekreftelse.paavegneav.v1.vo.Bekreftelsesloesning.DAGPENGER,
67+
grace = 7.dager,
68+
interval = 14.dager
69+
)),
70+
"18.03.2025 12:30".timestamp to ValueWithKafkaKeyData(periode.id, periode.key, stoppPaaVegneAv(
71+
periodeId = periode.value.id,
72+
bekreftelsesloesning = no.nav.paw.bekreftelse.paavegneav.v1.vo.Bekreftelsesloesning.DAGPENGER
73+
))
74+
)
75+
run(eksterneHendelser, stoppTid, opploesning) to eksterneHendelser
76+
}
77+
hendelser.map { (ts, hendelse) -> "${ts.prettyPrint}: ${hendelse.prettyPrint()}" }.forEach { println(it) }
78+
val kilde = mutableListOf(*hendelser.toTypedArray())
79+
val inputHendelser = input.toMutableList()
80+
forventer<BekreftelsePaaVegneAvStartet>(
81+
kilde,
82+
inputHendelser,
83+
fra = "18.03.2025 09:12".timestamp,
84+
til = "18.03.2025 09:18".timestamp
85+
)
86+
var bekreftelseId2803: UUID? = null
87+
forventer<BekreftelseTilgjengelig>(
88+
kilde,
89+
inputHendelser,
90+
fra = "28.03.2025 00:00".timestamp,
91+
til = "28.03.2025 06:00".timestamp,
92+
asserts = { publiserteBekreftelser ->
93+
publiserteBekreftelser.size shouldBe 1
94+
publiserteBekreftelser.first() should { bekreftelse ->
95+
bekreftelse.gjelderFra shouldBe "17.03.2025 00:00".timestamp
96+
bekreftelse.gjelderTil shouldBe "31.03.2025 00:00".timestamp
97+
}
98+
bekreftelseId2803 = publiserteBekreftelser.first().bekreftelseId
99+
}
100+
)
101+
forventer<LeveringsfristUtloept>(
102+
kilde,
103+
inputHendelser,
104+
fra = "31.03.2025 00:00".timestamp,
105+
til = "31.03.2025 00:10".timestamp,
106+
asserts = { fristUtloeptListe ->
107+
fristUtloeptListe.size shouldBe 1
108+
fristUtloeptListe.first() should { fristUtloept ->
109+
fristUtloept.leveringsfrist shouldBe "31.03.2025 00:00".timestamp
110+
fristUtloept.bekreftelseId shouldBe bekreftelseId2803
111+
}
112+
}
113+
)
114+
forventer<RegisterGracePeriodeGjenstaaendeTid>(
115+
kilde,
116+
inputHendelser,
117+
fra = "03.04.2025 00:30".timestamp,
118+
til = "04.04.2025 23:00".timestamp,
119+
)
120+
forventer<RegisterGracePeriodeUtloept>(
121+
kilde,
122+
inputHendelser,
123+
fra = "07.04.2025 00:00".timestamp,
124+
til = "07.04.2025 06:00".timestamp
125+
)
126+
forventer<PeriodeAvsluttet>(
127+
kilde,
128+
inputHendelser,
129+
fra = "07.04.2025 00:00".timestamp,
130+
til = "07.04.2025 06:00".timestamp
131+
)
132+
"Ingen flere hendelser inntraff" {
133+
kilde.shouldBeEmpty()
134+
}
135+
}
136+
})
137+

0 commit comments

Comments
 (0)