diff --git a/src/main/kotlin/no/nav/k9/los/aksjonspunktbehandling/K9sakEventHandler.kt b/src/main/kotlin/no/nav/k9/los/aksjonspunktbehandling/K9sakEventHandler.kt index a1505b51c..7d3b9a329 100644 --- a/src/main/kotlin/no/nav/k9/los/aksjonspunktbehandling/K9sakEventHandler.kt +++ b/src/main/kotlin/no/nav/k9/los/aksjonspunktbehandling/K9sakEventHandler.kt @@ -8,6 +8,7 @@ import no.nav.k9.los.domene.modell.* import no.nav.k9.los.domene.modell.reportMetrics import no.nav.k9.los.domene.repository.* import no.nav.k9.los.integrasjon.kafka.dto.BehandlingProsessEventDto +import no.nav.k9.los.integrasjon.kafka.dto.EventHendelse import no.nav.k9.los.integrasjon.sakogbehandling.SakOgBehandlingProducer import no.nav.k9.los.nyoppgavestyring.domeneadaptere.k9.saktillos.K9SakTilLosAdapterTjeneste import no.nav.k9.los.tjenester.avdelingsleder.nokkeltall.AlleOppgaverNyeOgFerdigstilte @@ -40,8 +41,12 @@ class K9sakEventHandler constructor( ) fun prosesser( - event: BehandlingProsessEventDto + eventInn: BehandlingProsessEventDto ) { + + val event = håndterVaskeevent(eventInn) + if (event == null) return + var skalSkippe = false val modell = behandlingProsessEventK9Repository.lagre(event.eksternId!!) { k9SakModell -> if (k9SakModell == null) { @@ -80,6 +85,30 @@ class K9sakEventHandler constructor( k9SakTilLosAdapterTjeneste.oppdaterOppgaveForBehandlingUuid(event.eksternId) } + fun håndterVaskeevent(event: BehandlingProsessEventDto): BehandlingProsessEventDto? { + if (event.eventHendelse != EventHendelse.VASKEEVENT) { + return event + } + + // Gjøres utenfor transaksjon fordi den ikke muterer data. + // Det er ikke mulig å unngå lagring selv om eventet skal ignoreres hvis den skulle ha vært i samme transaksjon (pga on conflict(id) update.. ) i lagre-metoden + val eksisterendeEventModell = behandlingProsessEventK9Repository.hent(event.eksternId!!) + if (eksisterendeEventModell.eventer.any { tidligereEvent -> tidligereEvent.behandlingStatus == BehandlingStatus.AVSLUTTET.kode }) { + return null + } + + if (eksisterendeEventModell.eventer.isEmpty()) { + log.info("Vaskeeventfiltrering gjelder behandling som ikke tidligere finnes i los ${event.eksternId}") + return event + } + + log.info("Vaskeeventfiltrering ${event.behandlingStatus} - ${event.eventTid} - ${event.eksternId}") + return eksisterendeEventModell.sisteEvent().eventTid + .takeIf { sisteEventTid -> sisteEventTid.isAfter(event.eventTid) } + ?.let { sisteEventTid -> event.copy(eventTid = sisteEventTid.plusNanos(100_1000)) } + ?: event + } + private fun nyFerdigstilltAvSaksbehandler(oppgave: Oppgave) { if (tillatteYtelseTyper.contains(oppgave.fagsakYtelseType)) { diff --git a/src/main/kotlin/no/nav/k9/los/integrasjon/kafka/dto/EventHendelse.kt b/src/main/kotlin/no/nav/k9/los/integrasjon/kafka/dto/EventHendelse.kt index 662aba6a2..4a2ce282c 100644 --- a/src/main/kotlin/no/nav/k9/los/integrasjon/kafka/dto/EventHendelse.kt +++ b/src/main/kotlin/no/nav/k9/los/integrasjon/kafka/dto/EventHendelse.kt @@ -7,5 +7,6 @@ enum class EventHendelse { AKSJONSPUNKT_TILBAKEFØR, AKSJONSPUNKT_AVBRUTT, AKSJONSPUNKT_HAR_ENDRET_BEHANDLENDE_ENHET, - BEHANDLINGSKONTROLL_EVENT + BEHANDLINGSKONTROLL_EVENT, + VASKEEVENT } diff --git a/src/test/kotlin/no/nav/k9/los/aksjonspunktbehandling/K9sakEventHandlerTest.kt b/src/test/kotlin/no/nav/k9/los/aksjonspunktbehandling/K9sakEventHandlerTest.kt index 96689e1da..173baf1e1 100644 --- a/src/test/kotlin/no/nav/k9/los/aksjonspunktbehandling/K9sakEventHandlerTest.kt +++ b/src/test/kotlin/no/nav/k9/los/aksjonspunktbehandling/K9sakEventHandlerTest.kt @@ -1,23 +1,26 @@ package no.nav.k9.los.aksjonspunktbehandling import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isSuccess +import assertk.assertions.* +import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.PropertyNamingStrategy import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import kotlinx.coroutines.runBlocking import no.nav.helse.dusseldorf.ktor.jackson.dusseldorfConfigured import no.nav.k9.los.AbstractK9LosIntegrationTest +import no.nav.k9.los.domene.modell.BehandlingStatus import no.nav.k9.los.domene.modell.Enhet import no.nav.k9.los.domene.modell.KøSortering import no.nav.k9.los.domene.modell.OppgaveKø import no.nav.k9.los.domene.repository.OppgaveKøRepository import no.nav.k9.los.domene.repository.OppgaveRepository import no.nav.k9.los.integrasjon.kafka.dto.BehandlingProsessEventDto +import no.nav.k9.los.integrasjon.kafka.dto.EventHendelse import org.intellij.lang.annotations.Language import org.junit.jupiter.api.Test import org.koin.test.get import java.time.LocalDate +import java.time.LocalDateTime import java.util.* import kotlin.test.assertFalse import kotlin.test.assertSame @@ -25,6 +28,9 @@ import kotlin.test.assertTrue class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { + val objectMapper = jacksonObjectMapper() + .dusseldorfConfigured().setPropertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE) + @Test fun `Skal lukke oppgave dersom den ikke har noen aktive aksjonspunkter`() { @@ -56,8 +62,6 @@ class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { "aksjonspunktKoderMedStatusListe": {} } """.trimIndent() - val objectMapper = jacksonObjectMapper() - .dusseldorfConfigured().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE) val event = objectMapper.readValue(json, BehandlingProsessEventDto::class.java) @@ -96,8 +100,6 @@ class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { "7030": "OPPR" } }""" - val objectMapper = jacksonObjectMapper() - .dusseldorfConfigured().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE) val event = objectMapper.readValue(json, BehandlingProsessEventDto::class.java) @@ -138,9 +140,6 @@ class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { "5080": "OPPR" } }""" - val objectMapper = jacksonObjectMapper() - .dusseldorfConfigured().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE) - val event = objectMapper.readValue(json, BehandlingProsessEventDto::class.java) k9sakEventHandler.prosesser(event) @@ -183,9 +182,6 @@ class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { "5016": "OPPR" } }""" - val objectMapper = jacksonObjectMapper() - .dusseldorfConfigured().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE) - val event = objectMapper.readValue(json, BehandlingProsessEventDto::class.java) k9sakEventHandler.prosesser(event) @@ -231,9 +227,6 @@ class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { "relatertPartAktørId" : "9906098522415" }""" - val objectMapper = jacksonObjectMapper() - .dusseldorfConfigured().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE) - val event = objectMapper.readValue(json, BehandlingProsessEventDto::class.java) assertThat { event.fagsakPeriode?.fom }.isSuccess().isEqualTo(LocalDate.of(2020, 2, 20)) @@ -312,9 +305,6 @@ class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { "5080": "OPPR" } }""" - val objectMapper = jacksonObjectMapper() - .dusseldorfConfigured().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE) - val event = objectMapper.readValue(json, BehandlingProsessEventDto::class.java) k9sakEventHandler.prosesser(event) @@ -395,8 +385,6 @@ class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { "5009": "OPPR" } }""" - val objectMapper = jacksonObjectMapper() - .dusseldorfConfigured().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE) val event = objectMapper.readValue(json, BehandlingProsessEventDto::class.java) @@ -434,4 +422,85 @@ class K9sakEventHandlerTest : AbstractK9LosIntegrationTest() { } assertSame(1, i[0].oppgaverOgDatoer.size) } + + @Test + fun `Vaskeevent skal ignoreres hvis det allerede finnes event med avsluttet behandling`() { + val k9sakEventHandler = get() + + val eksternId = UUID.randomUUID().toString() + val eventTid = LocalDateTime.now().minusDays(1) + k9sakEventHandler.prosesser(lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.OPPRETTET, eventTid)) + k9sakEventHandler.prosesser(lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.UTREDES, eventTid.plusHours(1))) + k9sakEventHandler.prosesser(lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.AVSLUTTET, eventTid.plusHours(2))) + + val vaskeevent = lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.AVSLUTTET, LocalDateTime.now(), EventHendelse.VASKEEVENT) + assertThat(k9sakEventHandler.håndterVaskeevent(vaskeevent)).isNull() + } + + @Test + fun `Vaskeevent skal brukes hvis det ikke finnes event med avsluttet behandling`() { + val k9sakEventHandler = get() + + val eksternId = UUID.randomUUID().toString() + val eventTid = LocalDateTime.now().minusDays(1) + k9sakEventHandler.prosesser(lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.OPPRETTET, eventTid)) + k9sakEventHandler.prosesser(lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.UTREDES, eventTid.plusHours(1))) + + val vaskeevent = lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.AVSLUTTET, eventTid.plusHours(2), EventHendelse.VASKEEVENT) + val håndtertEvent = k9sakEventHandler.håndterVaskeevent(vaskeevent) + + assertThat(håndtertEvent).isNotNull() + assertThat(håndtertEvent!!.eventTid).isEqualTo(eventTid.plusHours(2)) + } + + @Test + fun `Vaskeevent skal brukes hvis det ikke finnes event med avsluttet behandling, og utsetter ikke eventtid eventtid 100 mikrosekunder hvis tidligere eller lik siste event`() { + val k9sakEventHandler = get() + + val eksternId = UUID.randomUUID().toString() + val eventTid = LocalDateTime.now().minusDays(1) + k9sakEventHandler.prosesser(lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.OPPRETTET, eventTid)) + k9sakEventHandler.prosesser(lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.UTREDES, eventTid.plusHours(1))) + + val vaskeevent = lagBehandlingprosessEventMedStatus(eksternId, BehandlingStatus.AVSLUTTET, eventTid.plusMinutes(30), EventHendelse.VASKEEVENT) + val håndtertEvent = k9sakEventHandler.håndterVaskeevent(vaskeevent) + + assertThat(håndtertEvent).isNotNull() + assertThat(håndtertEvent!!.eventTid).isGreaterThan(eventTid.plusHours(1)) + } + + private fun lagBehandlingprosessEventMedStatus( + eksternId: String, + behandlingStatus: BehandlingStatus, + eventTid: LocalDateTime = LocalDateTime.now(), + eventHendelse: EventHendelse = EventHendelse.BEHANDLINGSKONTROLL_EVENT + ): BehandlingProsessEventDto { + + @Language("JSON") val json = + """{ + "eksternId": "$eksternId", + "fagsystem": { + "kode": "K9SAK", + "kodeverk": "FAGSYSTEM" + }, + "saksnummer": "5YC4K", + "aktørId": "9906098522415", + "behandlingId": 1000001, + "eventTid": "$eventTid", + "eventHendelse": "$eventHendelse", + "behandlinStatus": "${behandlingStatus.kode}", + "behandlingstidFrist": "2020-03-31", + "behandlingStatus": "${behandlingStatus.kode}", + "behandlingSteg": "INREG_AVSL", + "behandlendeEnhet": "0300", + "ytelseTypeKode": "OMP", + "behandlingTypeKode": "BT-002", + "opprettetBehandling": "2020-02-20T07:38:49", + "aksjonspunktKoderMedStatusListe": { + "5009": "OPPR" + } + }""" + + return objectMapper.readValue(json, BehandlingProsessEventDto::class.java) + } }