diff --git a/apps/hendelselogg-backup/nais/nais-dev.yaml b/apps/hendelselogg-backup/nais/nais-dev.yaml index 965250f8..bf50aa57 100644 --- a/apps/hendelselogg-backup/nais/nais-dev.yaml +++ b/apps/hendelselogg-backup/nais/nais-dev.yaml @@ -45,6 +45,7 @@ spec: gcp: sqlInstances: - type: POSTGRES_15 + tier: db-custom-1-3840 databases: - name: hendelselogg accessPolicy: diff --git a/apps/utgang-pdl/build.gradle.kts b/apps/utgang-pdl/build.gradle.kts index 98f01edc..d2035bf1 100644 --- a/apps/utgang-pdl/build.gradle.kts +++ b/apps/utgang-pdl/build.gradle.kts @@ -18,12 +18,15 @@ dependencies { implementation(project(":domain:main-avro-schema")) implementation(project(":domain:interne-hendelser")) implementation(project(":domain:arbeidssoekerregisteret-kotlin")) + implementation(project(":domain:arbeidssoeker-regler")) implementation(project(":lib:kafka-key-generator-client")) implementation(project(":lib:kafka")) implementation(project(":lib:kafka-streams")) implementation(project(":lib:hoplite-config")) + api(arrow.core) + implementation(orgApacheKafka.kafkaStreams) implementation(ktorServer.bundles.withNettyAndMicrometer) diff --git a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/Startup.kt b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/Startup.kt index 53cdf3a5..541ee59a 100644 --- a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/Startup.kt +++ b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/Startup.kt @@ -5,6 +5,7 @@ import io.micrometer.core.instrument.binder.kafka.KafkaStreamsMetrics import io.micrometer.prometheusmetrics.PrometheusConfig import io.micrometer.prometheusmetrics.PrometheusMeterRegistry import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentForenkletStatus +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentPerson import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.health.Health import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.health.initKtor import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.kafka.appTopology @@ -51,6 +52,7 @@ fun main() { applicationConfiguration.hendelseloggTopic, applicationConfiguration.hendelseStateStoreName, pdlHentForenkletStatus = PdlHentForenkletStatus.create(), + pdlHentPerson = PdlHentPerson.create(), ) val kafkaStreams = KafkaStreams( topology, @@ -69,4 +71,3 @@ fun main() { ).start(wait = true) logger.info("Avsluttet") } - diff --git a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/clients/pdl/PdlClient.kt b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/clients/pdl/PdlClient.kt index 96189202..fd71f076 100644 --- a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/clients/pdl/PdlClient.kt +++ b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/clients/pdl/PdlClient.kt @@ -10,14 +10,38 @@ import no.nav.paw.kafkakeygenerator.auth.azureAdM2MTokenClient import no.nav.paw.kafkakeygenerator.auth.currentNaisEnv import no.nav.paw.pdl.PdlClient import no.nav.paw.pdl.PdlException -import no.nav.paw.pdl.graphql.generated.hentforenkletstatusbolk.HentPersonBolkResult +import no.nav.paw.pdl.graphql.generated.hentforenkletstatusbolk.HentPersonBolkResult as ForenkletStatusBolkResult +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.HentPersonBolkResult import no.nav.paw.pdl.hentForenkletStatusBolk +import no.nav.paw.pdl.hentPersonBolk import org.slf4j.LoggerFactory const val BEHANDLINGSNUMMER = "B452" +fun interface PdlHentPerson { + fun hentPerson(ident: List, callId: String, navConsumerId: String): List? + + companion object { + val logger = LoggerFactory.getLogger("pdlClient") + + fun create(): PdlHentPerson { + val pdlClient = createPdlClient() + return PdlHentPerson { ident, callId, navConsumerId -> + runBlocking { + try { + pdlClient.hentPersonBolk(ident = ident, callId = callId, navConsumerId = navConsumerId, behandlingsnummer = BEHANDLINGSNUMMER) + } catch (e: PdlException) { + logger.error("PDL hentPerson feiler med: $e", e) + null + } + } + } + } + } +} + fun interface PdlHentForenkletStatus { - fun hentForenkletStatus(ident: List, callId: String, navConsumerId: String): List? + fun hentForenkletStatus(ident: List, callId: String, navConsumerId: String): List? companion object { val logger = LoggerFactory.getLogger("pdlClient") diff --git a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/ScheduleAvsluttPerioder.kt b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/ScheduleAvsluttPerioder.kt index 13a2d3ff..d51c8e11 100644 --- a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/ScheduleAvsluttPerioder.kt +++ b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/ScheduleAvsluttPerioder.kt @@ -1,11 +1,24 @@ package no.nav.paw.arbeidssoekerregisteret.utgang.pdl.kafka +import arrow.core.Either import io.micrometer.prometheusmetrics.PrometheusMeterRegistry import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.ApplicationInfo import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentForenkletStatus +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentForenkletStatus.Companion.logger +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentPerson import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.kafka.serdes.HendelseState import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.metrics.tellPdlAvsluttetHendelser import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.metrics.tellStatusFraPdlHentPersonBolk +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.utils.genererPersonFakta +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.utils.negativeOpplysninger +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.utils.statusToOpplysningMap +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.utils.toAarsak +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.utils.toPerson +import no.nav.paw.arbeidssokerregisteret.application.OK +import no.nav.paw.arbeidssokerregisteret.application.Problem +import no.nav.paw.arbeidssokerregisteret.application.evaluer +import no.nav.paw.arbeidssokerregisteret.application.hendelseOpplysningTilDomeneOpplysninger +import no.nav.paw.arbeidssokerregisteret.application.reglerForInngangIPrioritertRekkefolge import no.nav.paw.arbeidssokerregisteret.intern.v1.Avsluttet import no.nav.paw.arbeidssokerregisteret.intern.v1.Hendelse import no.nav.paw.arbeidssokerregisteret.intern.v1.vo.Bruker @@ -13,7 +26,8 @@ import no.nav.paw.arbeidssokerregisteret.intern.v1.vo.BrukerType import no.nav.paw.arbeidssokerregisteret.intern.v1.vo.Metadata import no.nav.paw.arbeidssokerregisteret.intern.v1.vo.Opplysning import no.nav.paw.pdl.graphql.generated.hentforenkletstatusbolk.Folkeregisterpersonstatus -import no.nav.paw.pdl.graphql.generated.hentforenkletstatusbolk.HentPersonBolkResult +import no.nav.paw.pdl.graphql.generated.hentforenkletstatusbolk.HentPersonBolkResult as ForenkletStatusBolkResult +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.HentPersonBolkResult import org.apache.kafka.streams.processor.Cancellable import org.apache.kafka.streams.processor.PunctuationType import org.apache.kafka.streams.processor.api.ProcessorContext @@ -31,6 +45,7 @@ fun scheduleAvsluttPerioder( hendelseStateStore: KeyValueStore, interval: Duration = Duration.ofDays(1), pdlHentForenkletStatus: PdlHentForenkletStatus, + pdlHentPersonBolk: PdlHentPerson, prometheusMeterRegistry: PrometheusMeterRegistry, ): Cancellable = ctx.schedule(interval, PunctuationType.WALL_CLOCK_TIME) { @@ -44,6 +59,18 @@ fun scheduleAvsluttPerioder( .chunked(1000) { chunk -> val identitetsnummere = chunk.map { it.value.identitetsnummer } + // Versjon 2 + val pdlHentPersonResults = hentPersonBolk(identitetsnummere, pdlHentPersonBolk) + if (pdlHentPersonResults == null) { + logger.warn("PDL hentPersonBolk returnerte null") + } else { + pdlHentPersonResults.processResultsV2( + chunk, + logger + ) + } + + // Versjon 1 val pdlResults = hentForenkletStatus(identitetsnummere, pdlHentForenkletStatus) if (pdlResults == null) { logger.error("PDL hentForenkletStatus returnerte null") @@ -61,7 +88,8 @@ fun scheduleAvsluttPerioder( } } -private fun List.processResults( + +private fun List.processResults( chunk: List>, hendelseStateStore: KeyValueStore, ctx: ProcessorContext, @@ -87,9 +115,14 @@ private fun List.processResults( val aarsak = folkeregisterpersonstatus .filterAvsluttPeriodeGrunnlag(hendelseState.opplysninger) - .ifEmpty { return@forEachIndexed } + .ifEmpty { + logger.info("Versjon 1: OK, matchende opplysning fra startet hendelse og forhåndsgodkjent av ansatt") + return@forEachIndexed + } .toAarsak() + logger.info("Versjon 2: PROBLEM, negative opplysninger fra pdl: ${folkeregisterpersonstatus.filterAvsluttPeriodeGrunnlag(hendelseState.opplysninger)}, generert aarsak: $aarsak") + val avsluttetHendelse = genererAvsluttetHendelseRecord(hendelseState, aarsak) logger.info("Sender avsluttet hendelse med aarsak: $aarsak") @@ -101,8 +134,73 @@ private fun List.processResults( } } +private fun List.processResultsV2( + chunk: List>, + logger: Logger +) = this.forEach { result -> + if (result.code in pdlErrorResponses) { + logger.error("Versjon 2: Feil ved henting av Person fra PDL: ${result.code}") + return@forEach + } + + val person = result.person ?: throw IllegalStateException("Versjon 2: Person mangler") + val hendelseOpplysninger = chunk.find { it.value.identitetsnummer == result.ident } + ?.value?.opplysninger ?: throw IllegalStateException("Versjon 2: HendelseState mangler") + + val domeneOpplysninger = hendelseOpplysninger + .filterNot { it == Opplysning.FORHAANDSGODKJENT_AV_ANSATT } + .map { hendelseOpplysningTilDomeneOpplysninger(it) as no.nav.paw.arbeidssokerregisteret.application.opplysninger.Opplysning } + .toSet() + + val opplysningerEvaluering = reglerForInngangIPrioritertRekkefolge.evaluer(domeneOpplysninger) + val pdlEvaluering = reglerForInngangIPrioritertRekkefolge.evaluer(genererPersonFakta(person.toPerson())) + + val erForhaandsgodkjent = hendelseOpplysninger.contains(Opplysning.FORHAANDSGODKJENT_AV_ANSATT) + + when { + pdlEvaluering.isLeft() -> handleLeftEvaluation( + pdlEvaluering, opplysningerEvaluering, erForhaandsgodkjent, logger + ) + pdlEvaluering.isRight() -> handleRightEvaluation( + opplysningerEvaluering, erForhaandsgodkjent, logger + ) + } +} + +private fun handleLeftEvaluation( + pdlEvaluering: Either, + opplysningerEvaluering: Either, + erForhaandsgodkjent: Boolean, + logger: Logger +) { + val pdlEvalueringResultat = pdlEvaluering.leftOrNull()?.opplysning?.toSet() + ?: throw IllegalStateException("Versjon 2: PDL evaluering mangler opplysning") + val opplysningerEvalueringResultat = opplysningerEvaluering.leftOrNull()?.opplysning?.toSet() + ?: throw IllegalStateException("Versjon 2: Opplysninger evaluering mangler opplysning") + + if (pdlEvalueringResultat == opplysningerEvalueringResultat && erForhaandsgodkjent) { + logger.info("Versjon 2: OK, matchende opplysning fra startet hendelse og forhåndsgodkjent av ansatt: $pdlEvalueringResultat") + } else { + val aarsak = pdlEvalueringResultat.filterNot { it in opplysningerEvalueringResultat }.toAarsak() + logger.info("Versjon 2: PROBLEM, negative opplysninger fra pdl: $pdlEvalueringResultat, generert aarsak: $aarsak") + } +} + +private fun handleRightEvaluation( + opplysningerEvaluering: Either, + erForhaandsgodkjent: Boolean, + logger: Logger +) { + if (opplysningerEvaluering.isLeft() && erForhaandsgodkjent) { + logger.info("Versjon 2: OK, ingen negative opplysninger fra pdl, negative opplysninger fra startet hendelse og forhåndsgodkjent av ansatt funnet") + } else { + logger.info("Versjon 2: OK, ingen negative opplysninger fra pdl") + } +} + + private fun hentPersonStatusOgHendelseState( - result: HentPersonBolkResult, + result: ForenkletStatusBolkResult, chunk: List> ): Pair, HendelseState>? { val person = result.person ?: return null @@ -123,13 +221,16 @@ private fun oppdaterHendelseStateOpplysninger( .toSet() ) hendelseStateStore.put(hendelseState.periodeId, oppdatertHendelseState) + logger.info("Versjon 1: OK, ingen negative opplysninger fra pdl, negative opplysninger fra startet hendelse og forhåndsgodkjent av ansatt funnet") + } else { + logger.info("Versjon 1: OK, ingen negative opplysninger fra pdl") } } private fun hentForenkletStatus( identitetsnummere: List, pdlHentForenkletStatus: PdlHentForenkletStatus, -): List? { +): List? { return pdlHentForenkletStatus.hentForenkletStatus( identitetsnummere, UUID.randomUUID().toString(), @@ -137,6 +238,17 @@ private fun hentForenkletStatus( ) } +private fun hentPersonBolk( + identitetsnummere: List, + pdlHentPersonBolk: PdlHentPerson, +): List? { + return pdlHentPersonBolk.hentPerson( + identitetsnummere, + UUID.randomUUID().toString(), + "paw-arbeidssoekerregisteret-utgang-pdl", + ) +} + private fun List>.filterValidHendelseStates(): List> = this.filter { entry -> val hendelseState = entry.value @@ -156,31 +268,7 @@ fun List.filterAvsluttPeriodeGrunnlag( .toSet() } -private fun Set.toAarsak(): String = - this.joinToString(separator = ", ") { - when (it) { - Opplysning.DOED -> "Personen er doed" - Opplysning.SAVNET -> "Personen er savnet" - Opplysning.IKKE_BOSATT -> "Personen er ikke bosatt etter folkeregisterloven" - Opplysning.OPPHOERT_IDENTITET -> "Personen har opphoert identitet" - else -> it.name - } - } -private val negativeOpplysninger = setOf( - Opplysning.IKKE_BOSATT, - Opplysning.SAVNET, - Opplysning.DOED, - Opplysning.OPPHOERT_IDENTITET, -) - -private val statusToOpplysningMap = mapOf( - "ikkeBosatt" to Opplysning.IKKE_BOSATT, - "forsvunnet" to Opplysning.SAVNET, - "doedIFolkeregisteret" to Opplysning.DOED, - "opphoert" to Opplysning.OPPHOERT_IDENTITET, - "dNummer" to Opplysning.DNUMMER -) private val List.erBosattEtterFolkeregisterloven get(): Boolean = diff --git a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/Topology.kt b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/Topology.kt index d53b0a2a..56dd3b33 100644 --- a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/Topology.kt +++ b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/Topology.kt @@ -2,6 +2,7 @@ package no.nav.paw.arbeidssoekerregisteret.utgang.pdl.kafka import io.micrometer.prometheusmetrics.PrometheusMeterRegistry import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentForenkletStatus +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentPerson import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.kafka.processors.oppdaterHendelseState import no.nav.paw.arbeidssokerregisteret.api.v1.Periode import no.nav.paw.arbeidssokerregisteret.intern.v1.HendelseSerde @@ -18,6 +19,7 @@ fun StreamsBuilder.appTopology( hendelseLoggTopic: String, hendelseStateStoreName: String, pdlHentForenkletStatus: PdlHentForenkletStatus, + pdlHentPerson: PdlHentPerson ): Topology { stream(hendelseLoggTopic, Consumed.with(Serdes.Long(), HendelseSerde())) .filter { _, value -> value is Startet } @@ -28,7 +30,8 @@ fun StreamsBuilder.appTopology( .oppdaterHendelseState( hendelseStateStoreName = hendelseStateStoreName, prometheusMeterRegistry = prometheusRegistry, - pdlHentForenkletStatus = pdlHentForenkletStatus + pdlHentForenkletStatus = pdlHentForenkletStatus, + pdlHentPerson = pdlHentPerson ) .to(hendelseLoggTopic, Produced.with(Serdes.Long(), HendelseSerde())) diff --git a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/processors/PeriodeProcessor.kt b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/processors/PeriodeProcessor.kt index 40634374..71d5369a 100644 --- a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/processors/PeriodeProcessor.kt +++ b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/kafka/processors/PeriodeProcessor.kt @@ -2,6 +2,7 @@ package no.nav.paw.arbeidssoekerregisteret.utgang.pdl.kafka.processors import io.micrometer.prometheusmetrics.PrometheusMeterRegistry import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentForenkletStatus +import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.clients.pdl.PdlHentPerson import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.kafka.scheduleAvsluttPerioder import no.nav.paw.arbeidssoekerregisteret.utgang.pdl.kafka.serdes.HendelseState import no.nav.paw.arbeidssokerregisteret.api.v1.Periode @@ -18,13 +19,15 @@ import java.util.UUID fun KStream.oppdaterHendelseState( hendelseStateStoreName: String, prometheusMeterRegistry: PrometheusMeterRegistry, - pdlHentForenkletStatus: PdlHentForenkletStatus + pdlHentForenkletStatus: PdlHentForenkletStatus, + pdlHentPerson: PdlHentPerson ): KStream { val processor = { PeriodeProcessor( hendelseStateStoreName, prometheusMeterRegistry, - pdlHentForenkletStatus + pdlHentForenkletStatus, + pdlHentPerson ) } return process(processor, Named.`as`("periodeProsessor"), hendelseStateStoreName) @@ -33,7 +36,8 @@ fun KStream.oppdaterHendelseState( class PeriodeProcessor( private val hendelseStateStoreName: String, private val prometheusMeterRegistry: PrometheusMeterRegistry, - private val pdlHentForenkletStatus: PdlHentForenkletStatus + private val pdlHentForenkletStatus: PdlHentForenkletStatus, + private val pdlHentPersonBolk: PdlHentPerson, ) : Processor { private var hendelseStateStore: KeyValueStore? = null private var context: ProcessorContext? = null @@ -47,6 +51,7 @@ class PeriodeProcessor( requireNotNull(hendelseStateStore), Duration.ofDays(1), pdlHentForenkletStatus, + pdlHentPersonBolk, prometheusMeterRegistry ) } diff --git a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/utils/OpplysningMappers.kt b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/utils/OpplysningMappers.kt new file mode 100644 index 00000000..dd44eb52 --- /dev/null +++ b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/utils/OpplysningMappers.kt @@ -0,0 +1,91 @@ +package no.nav.paw.arbeidssoekerregisteret.utgang.pdl.utils + +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.DomeneOpplysning +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.adreseOpplysning +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.alderOpplysning +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.euEoesStatsborgerOpplysning +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.forenkletFregOpplysning +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.gbrStatsborgerOpplysning +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.norskStatsborgerOpplysning +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.oppholdstillatelseOpplysning +import no.nav.paw.arbeidssokerregisteret.application.opplysninger.utflyttingOpplysning +import no.nav.paw.arbeidssokerregisteret.intern.v1.vo.Opplysning +import no.nav.paw.pdl.graphql.generated.hentperson.Person + +fun Set.toAarsak(): String = + this.joinToString(separator = ", ") { + when (it) { + Opplysning.DOED -> "Personen er doed" + Opplysning.SAVNET -> "Personen er savnet" + Opplysning.IKKE_BOSATT -> "Personen er ikke bosatt etter folkeregisterloven" + Opplysning.OPPHOERT_IDENTITET -> "Personen har opphoert identitet" + else -> it.name + } + } + +fun List.toAarsak(): String = + this.joinToString(separator = ", ") { + when (it) { + DomeneOpplysning.ErDoed -> "Personen er død" + DomeneOpplysning.ErSavnet -> "Personen er savnet" + DomeneOpplysning.IkkeBosatt -> "Personen er ikke bosatt etter folkeregisterloven" + DomeneOpplysning.OpphoertIdentitet -> "Personen har opphørt identitet" + DomeneOpplysning.ErForhaandsgodkjent -> "Registrering er forhåndsgodkjent av NAV-ansatt" + DomeneOpplysning.ErOver18Aar -> "Personen er over 18 år" + DomeneOpplysning.ErUnder18Aar -> "Personen er under 18 år" + DomeneOpplysning.ErEuEoesStatsborger -> "Personen er EØS/EU statsborger" + DomeneOpplysning.ErGbrStatsborger -> "Personen er britisk statsborger" + DomeneOpplysning.ErNorskStatsborger -> "Personen er norsk statsborger" + DomeneOpplysning.UkjentFoedselsdato -> "Personen har ukjent fødselsdato" + DomeneOpplysning.UkjentFoedselsaar -> "Personen har ukjent fødselsår" + DomeneOpplysning.TokenxPidIkkeFunnet -> "Innlogget bruker er ikke en logget inn via TOKENX med PID" + DomeneOpplysning.HarNorskAdresse -> "Personen har norsk adresse" + DomeneOpplysning.HarUtenlandskAdresse -> "Personen har utenlandsk adresse" + DomeneOpplysning.HarRegistrertAdresseIEuEoes -> "Personen har en registrert adresse i EØS/EU" + DomeneOpplysning.IngenAdresseFunnet -> "Personen har ingen adresse i våre systemer" + DomeneOpplysning.BosattEtterFregLoven -> "Personen er bosatt i Norge i henhold til Folkeregisterloven" + DomeneOpplysning.Dnummer -> "Personen har D-nummer" + DomeneOpplysning.UkjentForenkletFregStatus -> "Personen har ukjent forenklet folkeregisterstatus" + DomeneOpplysning.HarGyldigOppholdstillatelse -> "Personen har gyldig oppholdstillatelse" + DomeneOpplysning.OppholdstillatelseUtgaaatt -> "Personen har oppholdstillatelse som er utgått" + DomeneOpplysning.BarnFoedtINorgeUtenOppholdstillatelse -> "Personen er født i Norge uten oppholdstillatelse" + DomeneOpplysning.IngenInformasjonOmOppholdstillatelse -> "Personen har ingen informasjon om oppholdstillatelse" + DomeneOpplysning.UkjentStatusForOppholdstillatelse -> "Personen har ukjent status for oppholdstillatelse" + DomeneOpplysning.PersonIkkeFunnet -> "Personen er ikke funnet i våre systemer" + DomeneOpplysning.SisteFlyttingVarUtAvNorge -> "Personens siste flytting var ut av Norge" + DomeneOpplysning.SisteFlyttingVarInnTilNorge -> "Personens siste flytting var inn til Norge" + DomeneOpplysning.IkkeMuligAAIdentifisereSisteFlytting -> "Personens siste flytting er ikke mulig å identifisere" + DomeneOpplysning.IngenFlytteInformasjon -> "Personen har ingen flytte informasjon" + else -> it.id + } + } + +val negativeOpplysninger = setOf( + Opplysning.IKKE_BOSATT, + Opplysning.SAVNET, + Opplysning.DOED, + Opplysning.OPPHOERT_IDENTITET, +) + +val statusToOpplysningMap = mapOf( + "ikkeBosatt" to Opplysning.IKKE_BOSATT, + "forsvunnet" to Opplysning.SAVNET, + "doedIFolkeregisteret" to Opplysning.DOED, + "opphoert" to Opplysning.OPPHOERT_IDENTITET, + "dNummer" to Opplysning.DNUMMER +) + +fun genererPersonFakta(person: Person): Set { + require(person.foedsel.size <= 1) { "Personen har flere fødselsdatoer enn forventet" } + require(person.bostedsadresse.size <= 1) { "Personen har flere bostedsadresser enn forventet" } + require(person.opphold.size <= 1) { "Personen har flere opphold enn forventet" } + + return alderOpplysning(person.foedsel.firstOrNull()) + + adreseOpplysning(person.bostedsadresse.firstOrNull()) + + euEoesStatsborgerOpplysning(person.statsborgerskap) + + gbrStatsborgerOpplysning(person.statsborgerskap) + + norskStatsborgerOpplysning(person.statsborgerskap) + + forenkletFregOpplysning(person.folkeregisterpersonstatus) + + oppholdstillatelseOpplysning(person.opphold.firstOrNull()) + + utflyttingOpplysning(person.innflyttingTilNorge, person.utflyttingFraNorge) +} \ No newline at end of file diff --git a/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/utils/PDLMappers.kt b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/utils/PDLMappers.kt new file mode 100644 index 00000000..8559513f --- /dev/null +++ b/apps/utgang-pdl/src/main/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/utils/PDLMappers.kt @@ -0,0 +1,114 @@ +package no.nav.paw.arbeidssoekerregisteret.utgang.pdl.utils + +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Bostedsadresse +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Endring +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Foedsel +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Folkeregistermetadata +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Folkeregisterpersonstatus +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.InnflyttingTilNorge +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Matrikkeladresse +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Metadata +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Opphold +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Person +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Statsborgerskap +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.UtenlandskAdresse +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.UtflyttingFraNorge +import no.nav.paw.pdl.graphql.generated.hentpersonbolk.Vegadresse + +fun Person.toPerson(): no.nav.paw.pdl.graphql.generated.hentperson.Person = + no.nav.paw.pdl.graphql.generated.hentperson.Person( + foedsel = this.foedsel.toFoedsel(), + bostedsadresse = this.bostedsadresse.toBostedsadresseBolk(), + opphold = this.opphold.toOpphold(), + statsborgerskap = this.statsborgerskap.toStatsborgerskap(), + folkeregisterpersonstatus = this.folkeregisterpersonstatus.toFolkeregisterpersonstatus(), + innflyttingTilNorge = this.innflyttingTilNorge.toInnflyttingTilNorge(), + utflyttingFraNorge = this.utflyttingFraNorge.toUtflyttingFraNorge(), + ) + +fun List.toUtflyttingFraNorge(): List = this.map { + no.nav.paw.pdl.graphql.generated.hentperson.UtflyttingFraNorge( + utflyttingsdato = it.utflyttingsdato, + folkeregistermetadata = it.folkeregistermetadata?.toFolkeregistermetadata(), + ) +} + +fun Folkeregistermetadata.toFolkeregistermetadata(): no.nav.paw.pdl.graphql.generated.hentperson.Folkeregistermetadata = + no.nav.paw.pdl.graphql.generated.hentperson.Folkeregistermetadata( + gyldighetstidspunkt = this.gyldighetstidspunkt, + ajourholdstidspunkt = this.ajourholdstidspunkt, + ) + +fun List.toInnflyttingTilNorge(): List = this.map { + no.nav.paw.pdl.graphql.generated.hentperson.InnflyttingTilNorge( + folkeregistermetadata = it.folkeregistermetadata?.toFolkeregistermetadata() + ) +} + +fun List.toFolkeregisterpersonstatus(): List = this.map { + no.nav.paw.pdl.graphql.generated.hentperson.Folkeregisterpersonstatus( + forenkletStatus = it.forenkletStatus, + metadata = it.metadata.toMetadata(), + ) +} + +fun List.toStatsborgerskap(): List = this.map { + no.nav.paw.pdl.graphql.generated.hentperson.Statsborgerskap( + land = it.land, + metadata = it.metadata.toMetadata(), + ) +} + +fun List.toOpphold(): List = this.map { + no.nav.paw.pdl.graphql.generated.hentperson.Opphold( + oppholdFra = it.oppholdFra, + oppholdTil = it.oppholdTil, + type = it.type, + metadata = it.metadata.toMetadata(), + ) +} + +fun Metadata.toMetadata(): no.nav.paw.pdl.graphql.generated.hentperson.Metadata = no.nav.paw.pdl.graphql.generated.hentperson.Metadata( + endringer = this.endringer.map { it.toEndring() }, +) + +fun Endring.toEndring(): no.nav.paw.pdl.graphql.generated.hentperson.Endring = + no.nav.paw.pdl.graphql.generated.hentperson.Endring( + type = this.type, + registrert = this.registrert, + kilde = this.kilde, + ) + + +fun List.toFoedsel(): List = this.map { + no.nav.paw.pdl.graphql.generated.hentperson.Foedsel( + foedselsdato = it.foedselsdato, + foedselsaar = it.foedselsaar, + ) +} + +fun List.toBostedsadresseBolk(): List = this.map { + no.nav.paw.pdl.graphql.generated.hentperson.Bostedsadresse( + angittFlyttedato = it.angittFlyttedato, + gyldigFraOgMed = it.gyldigFraOgMed, + gyldigTilOgMed = it.gyldigTilOgMed, + vegadresse = it.vegadresse?.toVegadresse(), + matrikkeladresse = it.matrikkeladresse?.toMatikkeladresse(), + utenlandskAdresse = it.utenlandskAdresse?.toUtenlandskAdresse(), + ) +} + +fun Vegadresse.toVegadresse(): no.nav.paw.pdl.graphql.generated.hentperson.Vegadresse = + no.nav.paw.pdl.graphql.generated.hentperson.Vegadresse( + kommunenummer = this.kommunenummer, + ) + +fun Matrikkeladresse.toMatikkeladresse(): no.nav.paw.pdl.graphql.generated.hentperson.Matrikkeladresse = + no.nav.paw.pdl.graphql.generated.hentperson.Matrikkeladresse( + kommunenummer = this.kommunenummer, + ) + +fun UtenlandskAdresse.toUtenlandskAdresse(): no.nav.paw.pdl.graphql.generated.hentperson.UtenlandskAdresse = + no.nav.paw.pdl.graphql.generated.hentperson.UtenlandskAdresse( + landkode = this.landkode, + ) \ No newline at end of file diff --git a/apps/utgang-pdl/src/main/resources/local/kafka_configuration_schemareg.toml b/apps/utgang-pdl/src/main/resources/local/kafka_streams_configuration_schemareg.toml similarity index 100% rename from apps/utgang-pdl/src/main/resources/local/kafka_configuration_schemareg.toml rename to apps/utgang-pdl/src/main/resources/local/kafka_streams_configuration_schemareg.toml diff --git a/apps/utgang-pdl/src/test/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/ApplicationTest.kt b/apps/utgang-pdl/src/test/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/ApplicationTest.kt index 7e51e736..6bf3b545 100644 --- a/apps/utgang-pdl/src/test/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/ApplicationTest.kt +++ b/apps/utgang-pdl/src/test/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/ApplicationTest.kt @@ -464,4 +464,54 @@ fun generatePdlMockResponse(ident: String, forenkletStatus: List, status ), code = status, ) -) \ No newline at end of file +) + +/* +fun generatePdlHentPersonMockResponse(ident: String, forenkletStatus: List): List = + listOf( + PersonBolkResult( + ident, + PersonBolk( + foedsel = listOf( + FoedselBolk( + foedselsdato = "1990-01-01", + foedselsaar = 1990 + ) + ), + statsborgerskap = listOf( + StatsborgerskapBolk( + land = "NOR", + metadata = MetadataBolk( + endringer = emptyList() + ) + ) + ), + opphold = listOf( + OppholdBolk( + oppholdFra = "2020-01-01", + oppholdTil = "2021-01-01", + type = Oppholdstillatelse.PERMANENT, + metadata = MetadataBolk( + endringer = emptyList() + ) + ) + ), + folkeregisterpersonstatus = forenkletStatus.map { + FolkeregisterpersonstatusBolk( + forenkletStatus = it, + metadata = MetadataBolk( + endringer = emptyList() + ) + ) + }, + bostedsadresse = listOf( + BostedsadresseBolk( + angittFlyttedato = null, + ) + ), + innflyttingTilNorge = emptyList(), + utflyttingFraNorge = emptyList(), + ), + "ok" + ) + )*/ diff --git a/apps/utgang-pdl/src/test/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/TestScope.kt b/apps/utgang-pdl/src/test/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/TestScope.kt index a56519ac..7ce0972e 100644 --- a/apps/utgang-pdl/src/test/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/TestScope.kt +++ b/apps/utgang-pdl/src/test/kotlin/no/nav/paw/arbeidssoekerregisteret/utgang/pdl/TestScope.kt @@ -12,7 +12,7 @@ import no.nav.paw.arbeidssokerregisteret.api.v1.Periode import no.nav.paw.arbeidssokerregisteret.intern.v1.Hendelse import no.nav.paw.arbeidssokerregisteret.intern.v1.HendelseSerde import no.nav.paw.config.hoplite.loadNaisOrLocalConfiguration -import no.nav.paw.pdl.graphql.generated.hentforenkletstatusbolk.HentPersonBolkResult +import no.nav.paw.pdl.graphql.generated.hentforenkletstatusbolk.HentPersonBolkResult as HentForenkletStatusBolkResult import org.apache.avro.specific.SpecificRecord import org.apache.kafka.common.serialization.Serde import org.apache.kafka.common.serialization.Serdes @@ -35,7 +35,7 @@ data class TestScope( val topologyTestDriver: TopologyTestDriver ) -fun testScope(pdlMockResponse: List): TestScope { +fun testScope(pdlMockResponse: List): TestScope { val applicationConfig = loadNaisOrLocalConfiguration( APPLICATION_CONFIG_FILE ) @@ -62,6 +62,9 @@ fun testScope(pdlMockResponse: List): TestScope { pdlHentForenkletStatus = { _, _, _ -> pdlMockResponse }, + pdlHentPerson = { _, _, _ -> + null + }, prometheusRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) ), kafkaStreamProperties diff --git a/domain/arbeidssoeker-regler/src/main/kotlin/no/nav/paw/arbeidssokerregisteret/application/RegelExtensions.kt b/domain/arbeidssoeker-regler/src/main/kotlin/no/nav/paw/arbeidssokerregisteret/application/RegelExtensions.kt index 0109b64a..46d1713d 100644 --- a/domain/arbeidssoeker-regler/src/main/kotlin/no/nav/paw/arbeidssokerregisteret/application/RegelExtensions.kt +++ b/domain/arbeidssoeker-regler/src/main/kotlin/no/nav/paw/arbeidssokerregisteret/application/RegelExtensions.kt @@ -57,3 +57,43 @@ fun domeneOpplysningTilHendelseOpplysning(opplysning: DomeneOpplysning): Hendels DomeneOpplysning.ErNorskStatsborger -> HendelseOpplysning.ER_NORSK_STATSBORGER DomeneOpplysning.HarRegistrertAdresseIEuEoes -> HendelseOpplysning.HAR_REGISTRERT_ADRESSE_I_EU_EOES } + +fun hendelseOpplysningTilDomeneOpplysninger(opplysning: HendelseOpplysning): DomeneOpplysning? = + when (opplysning) { + HendelseOpplysning.BARN_FOEDT_I_NORGE_UTEN_OPPHOLDSTILLATELSE -> DomeneOpplysning.BarnFoedtINorgeUtenOppholdstillatelse + HendelseOpplysning.BOSATT_ETTER_FREG_LOVEN -> DomeneOpplysning.BosattEtterFregLoven + HendelseOpplysning.DNUMMER -> DomeneOpplysning.Dnummer + HendelseOpplysning.DOED -> DomeneOpplysning.ErDoed + HendelseOpplysning.ER_EU_EOES_STATSBORGER -> DomeneOpplysning.ErEuEoesStatsborger + HendelseOpplysning.FORHAANDSGODKJENT_AV_ANSATT -> DomeneOpplysning.ErForhaandsgodkjent + HendelseOpplysning.ER_GBR_STATSBORGER -> DomeneOpplysning.ErGbrStatsborger + HendelseOpplysning.ER_OVER_18_AAR -> DomeneOpplysning.ErOver18Aar + HendelseOpplysning.SAVNET -> DomeneOpplysning.ErSavnet + HendelseOpplysning.ER_UNDER_18_AAR -> DomeneOpplysning.ErUnder18Aar + HendelseOpplysning.HAR_GYLDIG_OPPHOLDSTILLATELSE -> DomeneOpplysning.HarGyldigOppholdstillatelse + HendelseOpplysning.HAR_NORSK_ADRESSE -> DomeneOpplysning.HarNorskAdresse + HendelseOpplysning.HAR_UTENLANDSK_ADRESSE -> DomeneOpplysning.HarUtenlandskAdresse + HendelseOpplysning.IKKE_BOSATT -> DomeneOpplysning.IkkeBosatt + HendelseOpplysning.IKKE_MULIG_AA_IDENTIFISERE_SISTE_FLYTTING -> DomeneOpplysning.IkkeMuligAAIdentifisereSisteFlytting + HendelseOpplysning.INGEN_ADRESSE_FUNNET -> DomeneOpplysning.IngenAdresseFunnet + HendelseOpplysning.INGEN_FLYTTE_INFORMASJON -> DomeneOpplysning.IngenFlytteInformasjon + HendelseOpplysning.INGEN_INFORMASJON_OM_OPPHOLDSTILLATELSE -> DomeneOpplysning.IngenInformasjonOmOppholdstillatelse + HendelseOpplysning.OPPHOERT_IDENTITET -> DomeneOpplysning.OpphoertIdentitet + HendelseOpplysning.OPPHOLDSTILATELSE_UTGAATT -> DomeneOpplysning.OppholdstillatelseUtgaaatt + HendelseOpplysning.PERSON_IKKE_FUNNET -> DomeneOpplysning.PersonIkkeFunnet + HendelseOpplysning.SISTE_FLYTTING_VAR_INN_TIL_NORGE -> DomeneOpplysning.SisteFlyttingVarInnTilNorge + HendelseOpplysning.SISTE_FLYTTING_VAR_UT_AV_NORGE -> DomeneOpplysning.SisteFlyttingVarUtAvNorge + HendelseOpplysning.TOKENX_PID_IKKE_FUNNET -> DomeneOpplysning.TokenxPidIkkeFunnet + HendelseOpplysning.UKJENT_FOEDSELSAAR -> DomeneOpplysning.UkjentFoedselsaar + HendelseOpplysning.UKJENT_FOEDSELSDATO -> DomeneOpplysning.UkjentFoedselsdato + HendelseOpplysning.UKJENT_FORENKLET_FREG_STATUS -> DomeneOpplysning.UkjentForenkletFregStatus + HendelseOpplysning.UKJENT_STATUS_FOR_OPPHOLDSTILLATELSE -> DomeneOpplysning.UkjentStatusForOppholdstillatelse + HendelseOpplysning.ER_NORSK_STATSBORGER -> DomeneOpplysning.ErNorskStatsborger + HendelseOpplysning.HAR_REGISTRERT_ADRESSE_I_EU_EOES -> DomeneOpplysning.HarRegistrertAdresseIEuEoes + HendelseOpplysning.SAMME_SOM_INNLOGGET_BRUKER -> null + HendelseOpplysning.IKKE_SAMME_SOM_INNLOGGER_BRUKER -> null + HendelseOpplysning.ANSATT_IKKE_TILGANG -> null + HendelseOpplysning.ANSATT_TILGANG -> null + HendelseOpplysning.IKKE_ANSATT -> null + HendelseOpplysning.UKJENT_OPPLYSNING -> null + } diff --git a/settings.gradle.kts b/settings.gradle.kts index 79946932..8c0a6b31 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -60,7 +60,7 @@ dependencyResolutionManagement { } versionCatalogs { // PAW greier - val pawPdlClientVersion = "24.07.04.39-1" + val pawPdlClientVersion = "24.08.08.40-1" val pawAaregClientVersion = "24.07.04.18-1" val arbeidssokerregisteretVersion = "1.9348086045.48-1"