Skip to content

Commit

Permalink
EY-4847 plukk opp manglende avslag statistikk (#6595)
Browse files Browse the repository at this point in the history
* Korrigerer mappingen for behandlingsresultat saksbehandlingsstatistikk

* Rydder i gamle utfall som kan ha blitt feil / misvisende

* Rydder opp mellom tester

* Fikser linje som ble fjernet ved en glipp

* Fjerner ekstra t
  • Loading branch information
oyvindsh authored Dec 13, 2024
1 parent cedceb1 commit 33d4811
Show file tree
Hide file tree
Showing 16 changed files with 448 additions and 68 deletions.
5 changes: 5 additions & 0 deletions apps/etterlatte-statistikk/.nais/dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,18 @@ spec:
value: api://dev-gcp.etterlatte.etterlatte-behandling/.default
- name: BEREGNING_AZURE_SCOPE
value: api://dev-gcp.etterlatte.etterlatte-beregning/.default
- name: ETTERLATTE_VEDTAK_CLIENT_ID
value: dev-gcp.etterlatte.etterlatte-vedtaksvurdering
- name: ETTERLATTE_VEDTAK_URL
value: http://etterlatte-vedtaksvurdering
envFrom:
- secret: my-application-unleash-api-token
accessPolicy:
outbound:
rules:
- application: etterlatte-behandling
- application: etterlatte-beregning
- application: etterlatte-vedtaksvurdering # TODO tilgangen er midlertidig for å rydde i resultat for vedtak
external:
- host: etterlatte-unleash-api.nav.cloud.nais.io
inbound:
Expand Down
6 changes: 6 additions & 0 deletions apps/etterlatte-statistikk/.nais/prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,18 @@ spec:
value: api://prod-gcp.etterlatte.etterlatte-behandling/.default
- name: BEREGNING_AZURE_SCOPE
value: api://prod-gcp.etterlatte.etterlatte-beregning/.default
- name: ETTERLATTE_VEDTAK_CLIENT_ID
value: prod-gcp.etterlatte.etterlatte-vedtaksvurdering
- name: ETTERLATTE_VEDTAK_URL
value: http://etterlatte-vedtaksvurdering
envFrom:
- secret: my-application-unleash-api-token
accessPolicy:
outbound:
rules:
- application: etterlatte-behandling
- application: etterlatte-beregning
# Denne tilgangen er midlertidig og skal fjernes når vedtaksresultat er fikset bakover i tid
- application: etterlatte-vedtaksvurdering
external:
- host: etterlatte-unleash-api.nav.cloud.nais.io
1 change: 1 addition & 0 deletions apps/etterlatte-statistikk/src/main/kotlin/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import no.nav.etterlatte.statistikk.config.ApplicationContext
fun main() =
with(ApplicationContext()) {
maanedligStatistikkJob.schedule().also { addShutdownHook(it) }
ryddVedtakResultatJob.schedule().also { addShutdownHook(it) }
initRapidsConnection()
sikkerLoggOppstart("etterlatte-statistikk")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package no.nav.etterlatte.statistikk.clients

import com.fasterxml.jackson.module.kotlin.readValue
import com.github.michaelbull.result.mapBoth
import com.typesafe.config.Config
import io.ktor.client.HttpClient
import kotlinx.coroutines.runBlocking
import no.nav.etterlatte.libs.common.objectMapper
import no.nav.etterlatte.libs.common.vedtak.VedtakDto
import no.nav.etterlatte.libs.ktor.ktor.ktorobo.AzureAdClient
import no.nav.etterlatte.libs.ktor.ktor.ktorobo.DownstreamResourceClient
import no.nav.etterlatte.libs.ktor.ktor.ktorobo.Resource
import no.nav.etterlatte.libs.ktor.token.Systembruker
import java.util.UUID

class VedtakKlient(
config: Config,
httpClient: HttpClient,
) {
private val azureAdClient = AzureAdClient(config)
private val downstreamResourceClient = DownstreamResourceClient(azureAdClient, httpClient)

private val clientId = config.getString("vedtak.client.id")
private val resourceUrl = config.getString("vedtak.resource.url")

fun hentVedtak(
behandlingId: UUID,
systembruker: Systembruker,
): VedtakDto =
runBlocking {
downstreamResourceClient
.get(
Resource(
clientId = clientId,
url = "$resourceUrl/api/vedtak/$behandlingId",
),
systembruker,
).mapBoth(
success = { resource -> resource.response.let { objectMapper.readValue(it.toString()) } },
failure = { errorResponse -> throw errorResponse },
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package no.nav.etterlatte.statistikk.config

import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import io.ktor.client.HttpClient
import no.nav.etterlatte.EnvKey.BEHANDLING_AZURE_SCOPE
import no.nav.etterlatte.EnvKey.BEREGNING_AZURE_SCOPE
Expand All @@ -11,16 +13,20 @@ import no.nav.etterlatte.libs.ktor.AppConfig.ELECTOR_PATH
import no.nav.etterlatte.libs.ktor.AzureEnums.AZURE_APP_CLIENT_ID
import no.nav.etterlatte.libs.ktor.AzureEnums.AZURE_APP_JWK
import no.nav.etterlatte.libs.ktor.AzureEnums.AZURE_APP_WELL_KNOWN_URL
import no.nav.etterlatte.libs.ktor.httpClient
import no.nav.etterlatte.libs.ktor.httpClientClientCredentials
import no.nav.etterlatte.statistikk.clients.BehandlingKlient
import no.nav.etterlatte.statistikk.clients.BehandlingKlientImpl
import no.nav.etterlatte.statistikk.clients.BeregningKlient
import no.nav.etterlatte.statistikk.clients.BeregningKlientImpl
import no.nav.etterlatte.statistikk.clients.VedtakKlient
import no.nav.etterlatte.statistikk.database.AktivitetspliktRepo
import no.nav.etterlatte.statistikk.database.RyddVedtakResultatDao
import no.nav.etterlatte.statistikk.database.SakRepository
import no.nav.etterlatte.statistikk.database.SoeknadStatistikkRepository
import no.nav.etterlatte.statistikk.database.StoenadRepository
import no.nav.etterlatte.statistikk.jobs.MaanedligStatistikkJob
import no.nav.etterlatte.statistikk.jobs.RyddVedtakResultatJob
import no.nav.etterlatte.statistikk.river.AktivitetspliktHendelseRiver
import no.nav.etterlatte.statistikk.river.AvbruttOpprettetBehandlinghendelseRiver
import no.nav.etterlatte.statistikk.river.BehandlingPaaVentHendelseRiver
Expand Down Expand Up @@ -96,6 +102,23 @@ class ApplicationContext {
)
}

private val ryddVedtakResultatDao: RyddVedtakResultatDao by lazy {
RyddVedtakResultatDao(datasource)
}

val config: Config = ConfigFactory.load()
private val vedtakKlient: VedtakKlient by lazy {
VedtakKlient(config, httpClient())
}

val ryddVedtakResultatJob: RyddVedtakResultatJob by lazy {
RyddVedtakResultatJob(
ryddVedtakResultatDao,
vedtakKlient,
leaderElection,
)
}

private val leaderElection: LeaderElection by lazy {
LeaderElection(env[ELECTOR_PATH])
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package no.nav.etterlatte.statistikk.database

import no.nav.etterlatte.libs.common.behandling.BehandlingType
import no.nav.etterlatte.libs.database.toList
import no.nav.etterlatte.statistikk.domain.BehandlingResultat
import java.util.UUID
import javax.sql.DataSource

class RyddVedtakResultatDao(
private val datasource: DataSource,
) {
fun hentRaderMedPotensiellFeil(): List<RadMedKanskjeFeilResultat> {
datasource.connection.use { connection ->
val statement =
connection.prepareStatement(
"""
select id, behandling_id, behandling_type, fikset from sak_rader_med_potensielt_feil_resultat
where fikset = false order by behandling_id limit 100
""".trimIndent(),
)

return statement.executeQuery().toList {
RadMedKanskjeFeilResultat(
id = getLong("id"),
behandlingId = getObject("behandling_id") as UUID,
behandlingType = enumValueOf(getString("behandling_type")),
fikset = getBoolean("fikset"),
)
}
}
}

fun oppdaterResultat(
rad: RadMedKanskjeFeilResultat,
resultat: BehandlingResultat,
) {
datasource.connection.use { connection ->
connection.autoCommit = false
val stmntOppdaterSak =
connection.prepareStatement(
"""
update sak set behandling_resultat = ? where id = ? and behandling_id = ?
""".trimIndent(),
)

stmntOppdaterSak.setString(1, resultat.name)
stmntOppdaterSak.setLong(2, rad.id)
stmntOppdaterSak.setObject(3, rad.behandlingId)
stmntOppdaterSak.executeUpdate()

val stmntOppdaterRydderad =
connection.prepareStatement(
"""
update sak_rader_med_potensielt_feil_resultat set fikset = true where id = ? and behandling_id = ?
""".trimIndent(),
)

stmntOppdaterRydderad.setLong(1, rad.id)
stmntOppdaterRydderad.setObject(2, rad.behandlingId)
stmntOppdaterRydderad.executeUpdate()

connection.commit()
}
}
}

data class RadMedKanskjeFeilResultat(
val id: Long,
val behandlingId: UUID,
val behandlingType: BehandlingType,
val fikset: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ enum class BehandlingResultat {
INNVILGELSE,
AVBRUTT,
OPPHOER,
ENDRING,
AVSLAG,
}

enum class SakYtelsesgruppe {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package no.nav.etterlatte.statistikk.jobs

import no.nav.etterlatte.jobs.LoggerInfo
import no.nav.etterlatte.jobs.fixedRateCancellableTimer
import no.nav.etterlatte.libs.common.TimerJob
import no.nav.etterlatte.libs.common.behandling.BehandlingStatus
import no.nav.etterlatte.libs.common.feilhaandtering.InternfeilException
import no.nav.etterlatte.libs.common.vedtak.VedtakKafkaHendelseHendelseType
import no.nav.etterlatte.libs.jobs.LeaderElection
import no.nav.etterlatte.libs.ktor.token.HardkodaSystembruker
import no.nav.etterlatte.statistikk.clients.VedtakKlient
import no.nav.etterlatte.statistikk.database.RyddVedtakResultatDao
import no.nav.etterlatte.statistikk.service.behandlingResultatFraVedtak
import org.slf4j.LoggerFactory
import java.time.Duration
import java.time.temporal.ChronoUnit
import java.util.Timer

class RyddVedtakResultatJob(
private val dao: RyddVedtakResultatDao,
private val vedtakKlient: VedtakKlient,
private val leaderElection: LeaderElection,
) : TimerJob {
private val logger = LoggerFactory.getLogger(this::class.java)
private val jobbNavn = this::class.simpleName
private val periode = Duration.of(5, ChronoUnit.MINUTES)
private val initialDelay = Duration.of(2, ChronoUnit.MINUTES).toMillis()

override fun schedule(): Timer {
logger.info("$jobbNavn er satt til å kjøre med periode $periode etter $initialDelay ms")

return fixedRateCancellableTimer(
name = jobbNavn,
period = periode.toMillis(),
initialDelay = initialDelay,
loggerInfo = LoggerInfo(logger = logger, loggTilSikkerLogg = false),
) {
OppdaterResultatSakRad(
leaderElection = leaderElection,
dao = dao,
klient = vedtakKlient,
).run()
}
}

class OppdaterResultatSakRad(
val leaderElection: LeaderElection,
val dao: RyddVedtakResultatDao,
val klient: VedtakKlient,
) {
private val logger = LoggerFactory.getLogger(this::class.java)

fun run() {
if (!leaderElection.isLeader()) {
logger.info("Er ikke leader, kjører ikke oppdater sak resultat jobb")
return
}

try {
val saker = dao.hentRaderMedPotensiellFeil().groupBy { it.behandlingId }
saker.entries.forEach { (behandlingId, rader) ->
val vedtak =
try {
klient.hentVedtak(behandlingId, HardkodaSystembruker.statistikk)
} catch (e: Exception) {
logger.warn(
"Feilet i henting / oppdatering av behandling resultat " +
"for vedtak til behandling med id = $behandlingId",
)
return@forEach
}
val resultat =
behandlingResultatFraVedtak(
vedtak,
VedtakKafkaHendelseHendelseType.ATTESTERT,
behandligStatus = BehandlingStatus.ATTESTERT,
) ?: throw InternfeilException(
"Fikk ikke utledet resultat fra vedtak til " +
"behandling med id = $behandlingId",
)
rader.forEach {
try {
dao.oppdaterResultat(it, resultat)
} catch (e: Exception) {
logger.warn(
"Kunne ikke oppdatere resulatet for sak rad med id = ${it.id} for " +
"behandling med id = $behandlingId",
)
}
}
}
} catch (e: Exception) {
logger.warn("Feilet i uthenting av rader med potensiell feil", e)
}
}
}
}
Loading

0 comments on commit 33d4811

Please sign in to comment.