Skip to content

Commit

Permalink
Implementert tilgjengeliggjort og fristUtloept i Bekreftelse for Inte…
Browse files Browse the repository at this point in the history
…rnTilstand. Endret Tilstand til en sealed class med data objects, gjort nødvendig endringer KontrolerFrister.kt, RegisterInstillinger.kt og tester.
  • Loading branch information
robertkittilsen committed Sep 25, 2024
1 parent 6c27ae7 commit 0e5d031
Show file tree
Hide file tree
Showing 10 changed files with 428 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fun StreamsBuilder.processBekreftelseMeldingTopic() {
bekreftelse == null -> {
meldingsLogger.warn("Melding {} har ingen matchene bekreftelse", record.value().id)
}
bekreftelse.tilstand == VenterSvar || bekreftelse.tilstand == KlarForUtfylling -> {
bekreftelse.tilstand is VenterSvar || bekreftelse.tilstand is KlarForUtfylling -> {
val (hendelser, oppdatertBekreftelse) = behandleGyldigSvar(gjeldeneTilstand.periode.arbeidsoekerId, record, bekreftelse)
val oppdatertBekreftelser = gjeldeneTilstand.bekreftelser
.filterNot { t -> t.bekreftelseId == oppdatertBekreftelse.bekreftelseId } + oppdatertBekreftelse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import no.nav.paw.bekreftelsetjeneste.tilstand.InternTilstand
import no.nav.paw.bekreftelsetjeneste.tilstand.Tilstand
import no.nav.paw.bekreftelsetjeneste.tilstand.gjenstaendeGracePeriode
import no.nav.paw.bekreftelsetjeneste.tilstand.initBekreftelsePeriode
import no.nav.paw.bekreftelsetjeneste.tilstand.initNyBekreftelsePeriode
import no.nav.paw.bekreftelsetjeneste.tilstand.initNewBekreftelse
import org.apache.kafka.streams.KeyValue
import org.apache.kafka.streams.processor.api.ProcessorContext
import org.apache.kafka.streams.processor.api.Record
Expand Down Expand Up @@ -44,27 +44,26 @@ private fun processBekreftelser(
val existingBekreftelse = currentState.bekreftelser.firstOrNull()

val (tilstand, hendelse) = if (existingBekreftelse == null) {
currentState.handleNoExistingBekreftelse() to null
currentState.createInitialBekreftelse() to null
} else {
currentState.handleExistingBekreftelser(timestamp)
currentState.checkAndCreateNewBekreftelse(timestamp)
}

val (updatedTilstand, additionalHendelser) = tilstand.handleUpdateBekreftelser(timestamp)
val (updatedTilstand, additionalHendelse) = tilstand.handleUpdateBekreftelser(timestamp)

return updatedTilstand to (listOfNotNull(hendelse) + additionalHendelser)
return updatedTilstand to listOfNotNull(hendelse, additionalHendelse)
}

private fun InternTilstand.handleNoExistingBekreftelse(): InternTilstand =
private fun InternTilstand.createInitialBekreftelse(): InternTilstand =
copy(bekreftelser = listOf(initBekreftelsePeriode(periode)))


private fun InternTilstand.handleExistingBekreftelser(
private fun InternTilstand.checkAndCreateNewBekreftelse(
timestamp: Instant
): Pair<InternTilstand, BekreftelseHendelse?> {
val nonEmptyBekreftelser = bekreftelser.toNonEmptyListOrNull() ?: return this to null

return if (nonEmptyBekreftelser.skalLageNyBekreftelseTilgjengelig(timestamp)) {
val newBekreftelse = bekreftelser.initNyBekreftelsePeriode()
return if (nonEmptyBekreftelser.shouldCreateNewBekreftelse(timestamp)) {
val newBekreftelse = bekreftelser.initNewBekreftelse(tilgjengeliggjort = timestamp)
copy(bekreftelser = nonEmptyBekreftelser + newBekreftelse) to createNewBekreftelseTilgjengelig(newBekreftelse)
} else {
this to null
Expand All @@ -73,70 +72,80 @@ private fun InternTilstand.handleExistingBekreftelser(

private fun InternTilstand.handleUpdateBekreftelser(
timestamp: Instant,
): Pair<InternTilstand, List<BekreftelseHendelse>> =
bekreftelser.map { bekreftelse ->
when {
bekreftelse.tilstand == Tilstand.IkkeKlarForUtfylling && bekreftelse.erKlarForUtfylling(timestamp) -> {
val updatedBekreftelse = bekreftelse.copy(tilstand = Tilstand.KlarForUtfylling)
val hendelse = BekreftelseTilgjengelig(
hendelseId = UUID.randomUUID(),
periodeId = periode.periodeId,
arbeidssoekerId = periode.arbeidsoekerId,
bekreftelseId = bekreftelse.bekreftelseId,
gjelderFra = bekreftelse.gjelderFra,
gjelderTil = bekreftelse.gjelderTil,
hendelseTidspunkt = Instant.now()
)
updatedBekreftelse to hendelse
}
): Pair<InternTilstand, BekreftelseHendelse?> {
val updatedBekreftelser = bekreftelser.map { bekreftelse ->
generateSequence(bekreftelse to null as BekreftelseHendelse?) { (currentBekreftelse, _) ->
getProcessedBekreftelseTilstandAndHendelse(currentBekreftelse, timestamp).takeIf { it.second != null }
}.last().first
}

bekreftelse.tilstand == Tilstand.KlarForUtfylling && bekreftelse.harFristUtloept(timestamp) -> {
val updatedBekreftelse = bekreftelse.copy(tilstand = Tilstand.VenterSvar)
val hendelse = LeveringsfristUtloept(
hendelseId = UUID.randomUUID(),
periodeId = periode.periodeId,
arbeidssoekerId = periode.arbeidsoekerId,
bekreftelseId = bekreftelse.bekreftelseId,
hendelseTidspunkt = Instant.now(),
leveringsfrist = bekreftelse.gjelderTil
)
updatedBekreftelse to hendelse
}
val hendelse: BekreftelseHendelse? = bekreftelser.flatMap { bekreftelse ->
generateSequence(bekreftelse to null as BekreftelseHendelse?) { (currentBekreftelse, _) ->
getProcessedBekreftelseTilstandAndHendelse(currentBekreftelse, timestamp).takeIf { it.second != null }
}.mapNotNull { it.second }
}.lastOrNull()

bekreftelse.tilstand == Tilstand.VenterSvar && bekreftelse.erSisteVarselOmGjenstaaendeGraceTid(timestamp) -> {
val updatedBekreftelse = bekreftelse.copy(sisteVarselOmGjenstaaendeGraceTid = timestamp)
val hendelse = RegisterGracePeriodeGjendstaaendeTid(
hendelseId = UUID.randomUUID(),
periodeId = periode.periodeId,
arbeidssoekerId = periode.arbeidsoekerId,
bekreftelseId = bekreftelse.bekreftelseId,
gjenstaandeTid = gjenstaendeGracePeriode(timestamp, bekreftelse.gjelderTil),
hendelseTidspunkt = Instant.now()
)
updatedBekreftelse to hendelse
}
return copy(bekreftelser = updatedBekreftelser) to hendelse
}

bekreftelse.tilstand == Tilstand.VenterSvar && bekreftelse.harGracePeriodeUtloept(timestamp) -> {
val updatedBekreftelse = bekreftelse.copy(tilstand = Tilstand.GracePeriodeUtlopt)
val hendelse = RegisterGracePeriodeUtloept(
hendelseId = UUID.randomUUID(),
periodeId = periode.periodeId,
arbeidssoekerId = periode.arbeidsoekerId,
bekreftelseId = bekreftelse.bekreftelseId,
hendelseTidspunkt = Instant.now()
)
updatedBekreftelse to hendelse
}
private fun InternTilstand.getProcessedBekreftelseTilstandAndHendelse(
bekreftelse: Bekreftelse,
timestamp: Instant
): Pair<Bekreftelse, BekreftelseHendelse?> {
return when {
bekreftelse.tilstand is Tilstand.IkkeKlarForUtfylling && bekreftelse.erKlarForUtfylling(timestamp) -> {
val updatedBekreftelse = bekreftelse.copy(tilstand = Tilstand.KlarForUtfylling, tilgjengeliggjort = timestamp)
val hendelse = BekreftelseTilgjengelig(
hendelseId = UUID.randomUUID(),
periodeId = periode.periodeId,
arbeidssoekerId = periode.arbeidsoekerId,
bekreftelseId = bekreftelse.bekreftelseId,
gjelderFra = bekreftelse.gjelderFra,
gjelderTil = bekreftelse.gjelderTil,
hendelseTidspunkt = Instant.now())
updatedBekreftelse to hendelse
}

else -> {
bekreftelse to null
}
bekreftelse.tilstand is Tilstand.KlarForUtfylling && bekreftelse.harFristUtloept(timestamp) -> {
val updatedBekreftelse = bekreftelse.copy(tilstand = Tilstand.VenterSvar, fristUtloept = timestamp)
val hendelse = LeveringsfristUtloept(
hendelseId = UUID.randomUUID(),
periodeId = periode.periodeId,
arbeidssoekerId = periode.arbeidsoekerId,
bekreftelseId = bekreftelse.bekreftelseId,
hendelseTidspunkt = Instant.now(),
leveringsfrist = bekreftelse.gjelderTil)
updatedBekreftelse to hendelse
}

bekreftelse.tilstand == Tilstand.VenterSvar && bekreftelse.erSisteVarselOmGjenstaaendeGraceTid(timestamp) -> {
val updatedBekreftelse = bekreftelse.copy(sisteVarselOmGjenstaaendeGraceTid = timestamp)
val hendelse = RegisterGracePeriodeGjendstaaendeTid(
hendelseId = UUID.randomUUID(),
periodeId = periode.periodeId,
arbeidssoekerId = periode.arbeidsoekerId,
bekreftelseId = bekreftelse.bekreftelseId,
gjenstaandeTid = bekreftelse.gjenstaendeGracePeriode(timestamp),
hendelseTidspunkt = Instant.now())
updatedBekreftelse to hendelse
}

bekreftelse.tilstand == Tilstand.VenterSvar && bekreftelse.harGracePeriodeUtloept(timestamp) -> {
val updatedBekreftelse = bekreftelse.copy(tilstand = Tilstand.GracePeriodeUtloept)
val hendelse = RegisterGracePeriodeUtloept(
hendelseId = UUID.randomUUID(),
periodeId = periode.periodeId,
arbeidssoekerId = periode.arbeidsoekerId,
bekreftelseId = bekreftelse.bekreftelseId,
hendelseTidspunkt = Instant.now())
updatedBekreftelse to hendelse
}

else -> {
bekreftelse to null
}
}.let {
val updatedBekreftelser = it.map { it.first }
val hendelser = it.mapNotNull { it.second }
copy(bekreftelser = updatedBekreftelser) to hendelser
}
}

private fun InternTilstand.createNewBekreftelseTilgjengelig(newBekreftelse: Bekreftelse) =
BekreftelseTilgjengelig(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ fun Bekreftelse.erKlarForUtfylling(now: Instant): Boolean =
now.isAfter(gjelderTil.minus(BekreftelseConfig.bekreftelseTilgjengeligOffset))

fun Bekreftelse.harFristUtloept(now: Instant): Boolean =
now.isAfter(gjelderTil)
now.isAfter(tilgjengeliggjort?.plus(BekreftelseConfig.bekreftelseTilgjengeligOffset) ?: gjelderTil)

fun Bekreftelse.erSisteVarselOmGjenstaaendeGraceTid(now: Instant): Boolean =
sisteVarselOmGjenstaaendeGraceTid == null && now.isAfter(gjelderTil.plus(
sisteVarselOmGjenstaaendeGraceTid == null && now.isAfter(fristUtloept?.plus(BekreftelseConfig.varselFoerGracePeriodeUtloept) ?: gjelderTil.plus(
BekreftelseConfig.varselFoerGracePeriodeUtloept
))

fun Bekreftelse.harGracePeriodeUtloept(now: Instant): Boolean =
now.isAfter(gjelderTil.plus(BekreftelseConfig.gracePeriode))
now.isAfter(fristUtloept?.plus(BekreftelseConfig.gracePeriode) ?: gjelderTil.plus(BekreftelseConfig.gracePeriode))

fun NonEmptyList<Bekreftelse>.skalLageNyBekreftelseTilgjengelig(now: Instant): Boolean =
fun NonEmptyList<Bekreftelse>.shouldCreateNewBekreftelse(now: Instant): Boolean =
maxBy { it.gjelderTil }
.let {
now.isAfter(it.gjelderTil.plus(BekreftelseConfig.bekreftelseInterval.minus(BekreftelseConfig.bekreftelseTilgjengeligOffset)))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package no.nav.paw.bekreftelsetjeneste.tilstand

import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import no.nav.paw.arbeidssokerregisteret.api.v1.Periode
import java.time.Instant
import java.util.*
Expand All @@ -13,18 +15,32 @@ data class InternTilstand(
@JvmRecord
data class Bekreftelse(
val tilstand: Tilstand,
val tilgjengeliggjort: Instant?,
val fristUtloept: Instant?,
val sisteVarselOmGjenstaaendeGraceTid: Instant?,
val bekreftelseId: UUID,
val gjelderFra: Instant,
val gjelderTil: Instant
)

enum class Tilstand {
IkkeKlarForUtfylling,
KlarForUtfylling,
VenterSvar,
GracePeriodeUtlopt,
Levert
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes(
JsonSubTypes.Type(value = Tilstand.IkkeKlarForUtfylling::class, name = "IkkeKlarForUtfylling"),
JsonSubTypes.Type(value = Tilstand.KlarForUtfylling::class, name = "KlarForUtfylling"),
JsonSubTypes.Type(value = Tilstand.VenterSvar::class, name = "VenterSvar"),
JsonSubTypes.Type(value = Tilstand.GracePeriodeUtloept::class, name = "GracePeriodeUtloept"),
JsonSubTypes.Type(value = Tilstand.Levert::class, name = "Levert")
)
sealed class Tilstand {
data object IkkeKlarForUtfylling : Tilstand()
data object KlarForUtfylling : Tilstand()
data object VenterSvar : Tilstand()
data object GracePeriodeUtloept : Tilstand()
data object Levert : Tilstand()
}

@JvmRecord
Expand Down Expand Up @@ -62,16 +78,20 @@ fun initBekreftelsePeriode(
): Bekreftelse =
Bekreftelse(
tilstand = Tilstand.IkkeKlarForUtfylling,
tilgjengeliggjort = null,
fristUtloept = null,
sisteVarselOmGjenstaaendeGraceTid = null,
bekreftelseId = UUID.randomUUID(),
gjelderFra = periode.startet,
gjelderTil = fristForNesteBekreftelse(periode.startet, BekreftelseConfig.bekreftelseInterval)
)

fun List<Bekreftelse>.initNyBekreftelsePeriode(
fun List<Bekreftelse>.initNewBekreftelse(
tilgjengeliggjort: Instant,
): Bekreftelse =
maxBy { it.gjelderTil }.copy(
tilstand = Tilstand.KlarForUtfylling,
tilgjengeliggjort = tilgjengeliggjort,
sisteVarselOmGjenstaaendeGraceTid = null,
bekreftelseId = UUID.randomUUID(),
gjelderFra = maxBy { it.gjelderTil }.gjelderTil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,3 @@ object InternTilstandDeserializer : Deserializer<InternTilstand> {
private val internTilstandObjectMapper = ObjectMapper()
.registerKotlinModule()
.registerModules(JavaTimeModule())

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import java.time.temporal.TemporalAdjuster
import java.time.temporal.TemporalAdjusters

// Felles verdier for bekreftelse.
// TODO: Endre intervaller til dev-verdier
data object BekreftelseConfig {
val bekreftelseInterval:Duration = Duration.ofDays(14)
val gracePeriode: Duration = Duration.ofDays(7)
Expand All @@ -20,9 +21,9 @@ fun fristForNesteBekreftelse(forrige: Instant, interval: Duration): Instant {
return forrige.plus(interval)
}

fun gjenstaendeGracePeriode(timestamp: Instant, gjelderTil: Instant): Duration {
fun Bekreftelse.gjenstaendeGracePeriode(timestamp: Instant): Duration {
val gracePeriode = BekreftelseConfig.gracePeriode
val utvidetGjelderTil = gjelderTil.plus(gracePeriode)
val utvidetGjelderTil = fristUtloept?.plus(gracePeriode) ?: gjelderTil.plus(gracePeriode)

return if (timestamp.isAfter(utvidetGjelderTil)) {
Duration.ZERO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class ApplicationTestContext(initialWallClockTime: Instant = Instant.now()) {
bekreftelseSerde.serializer()
)

val hendelseLoggTopic = testDriver.createOutputTopic(
val hendelseLoggTopicOut = testDriver.createOutputTopic(
applicationConfiguration.bekreftelseHendelseloggTopic,
Serdes.Long().deserializer(),
hendelseLoggSerde.deserializer()
Expand Down
Loading

0 comments on commit 0e5d031

Please sign in to comment.