Skip to content

Hent inntekt med inntektId #318

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
deploy-dev:
name: Deploy to dev
needs: [build]
if: github.ref == 'refs/heads/main'
if: github.ref == 'refs/heads/hent-inntekt-med-inntektId'
runs-on: ubuntu-latest
permissions:
contents: "read"
Expand All @@ -64,21 +64,21 @@ jobs:
VARS: nais/vars.yaml
VAR: image=${{ needs.build.outputs.image }}
PRINT_PAYLOAD: true
deploy-prod:
name: Deploy to Production
needs: [build, deploy-dev]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: "read"
id-token: "write"
environment: prod-gcp
steps:
- uses: actions/checkout@v4
- uses: nais/deploy/actions/deploy@v2
env:
CLUSTER: prod-gcp
RESOURCE: nais/prod/nais.yaml
VARS: nais/vars.yaml
VAR: image=${{ needs.build.outputs.image }}
PRINT_PAYLOAD: true
# deploy-prod:
# name: Deploy to Production
# needs: [build, deploy-dev]
# if: github.ref == 'refs/heads/main'
# runs-on: ubuntu-latest
# permissions:
# contents: "read"
# id-token: "write"
# environment: prod-gcp
# steps:
# - uses: actions/checkout@v4
# - uses: nais/deploy/actions/deploy@v2
# env:
# CLUSTER: prod-gcp
# RESOURCE: nais/prod/nais.yaml
# VARS: nais/vars.yaml
# VAR: image=${{ needs.build.outputs.image }}
# PRINT_PAYLOAD: true
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/common.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,16 @@ fun main() {
val cachedInntektsGetter = BehandlingsInntektsGetter(inntektskomponentHttpClient, postgresInntektStore)
// Marks inntekt as used
val subsumsjonBruktDataConsumer =
KafkaSubsumsjonBruktDataConsumer(config, postgresInntektStore).apply {
listen()
}.also {
Runtime.getRuntime().addShutdownHook(
Thread {
it.stop()
},
)
}
KafkaSubsumsjonBruktDataConsumer(config, postgresInntektStore)
.apply {
listen()
}.also {
Runtime.getRuntime().addShutdownHook(
Thread {
it.stop()
},
)
}

// Provides a HTTP API for getting inntekt
embeddedServer(Netty, port = config.application.httpPort) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,28 @@ class BehandlingsInntektsGetter(
suspend fun getKlassifisertInntekt(
inntektparametre: Inntektparametre,
callId: String? = null,
): Inntekt {
return klassifiserOgMapInntekt(getSpesifisertInntekt(inntektparametre, callId))
}
): Inntekt = klassifiserOgMapInntekt(getSpesifisertInntekt(inntektparametre, callId))

fun getKlassifisertInntekt(inntektId: InntektId): Inntekt {
return klassifiserOgMapInntekt(inntektStore.getSpesifisertInntekt(inntektId))
}
fun getKlassifisertInntekt(inntektId: InntektId): Inntekt = klassifiserOgMapInntekt(inntektStore.getSpesifisertInntekt(inntektId))

suspend fun getSpesifisertInntekt(
inntektparametre: Inntektparametre,
callId: String? = null,
): SpesifisertInntekt {
return mapToSpesifisertInntekt(
): SpesifisertInntekt =
mapToSpesifisertInntekt(
getBehandlingsInntekt(inntektparametre, callId),
inntektparametre.opptjeningsperiode.sisteAvsluttendeKalenderMåned,
)
}

internal suspend fun getBehandlingsInntekt(
inntektparametre: Inntektparametre,
callId: String? = null,
): StoredInntekt {
return isInntektStored(inntektparametre)?.let {
): StoredInntekt =
isInntektStored(inntektparametre)?.let {
LOGGER.info { "Henter stored inntekt: ${inntektparametre.toDebugString()}" }
inntektStore.getInntekt(it)
}
?: fetchAndStoreInntekt(inntektparametre, callId)
}

private suspend fun fetchAndStoreInntekt(
inntektparametre: Inntektparametre,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ internal fun Application.inntektApi(
}
exception<InntektskomponentenHttpClientException> { call, cause ->
val statusCode =
if (HttpStatusCode.fromValue(cause.status)
if (HttpStatusCode
.fromValue(cause.status)
.isSuccess()
) {
HttpStatusCode.InternalServerError
Expand Down Expand Up @@ -218,7 +219,7 @@ internal fun Application.inntektApi(
routing {
route("/v1") {
route("/inntekt") {
uklassifisertInntekt(inntektskomponentHttpClient, inntektStore, personOppslag)
uklassifisertInntekt(inntektskomponentHttpClient, inntektStore, personOppslag, enhetsregisterClient)
}
opptjeningsperiodeApi(inntektStore)
enhetsregisteret(enhetsregisterClient)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ interface InntektStore {

fun getBeregningsdato(inntektId: InntektId): LocalDate

fun getInntektPersonMapping(inntektId: String): InntektPersonMapping

fun storeInntekt(
command: StoreInntektCommand,
created: ZonedDateTime = ZonedDateTime.now(ZoneOffset.UTC),
Expand All @@ -26,6 +28,8 @@ interface InntektStore {
fun getManueltRedigert(inntektId: InntektId): ManueltRedigert?

fun markerInntektBrukt(inntektId: InntektId): Int

fun getInntektMedPersonFnr(inntektId: InntektId): StoredInntektMedFnr
}

data class Inntektparametre(
Expand All @@ -36,20 +40,33 @@ data class Inntektparametre(
) {
val opptjeningsperiode: Opptjeningsperiode = Opptjeningsperiode(beregningsdato)

fun toDebugString(): String {
return "Inntektparametre(aktørId='$aktørId', beregningsdato=$beregningsdato, regelkontekst=$regelkontekst)"
}
fun toDebugString(): String = "Inntektparametre(aktørId='$aktørId', beregningsdato=$beregningsdato, regelkontekst=$regelkontekst)"
}

data class RegelKontekst(val id: String, val type: String)
data class RegelKontekst(
val id: String,
val type: String,
)

data class StoreInntektCommand(
val inntektparametre: Inntektparametre,
val inntekt: InntektkomponentResponse,
val manueltRedigert: ManueltRedigert? = null,
)

data class ManueltRedigert(val redigertAv: String) {
data class InntektPersonMapping(
val inntektId: InntektId,
val aktørId: String,
val fnr: String? = null,
val kontekstId: String,
val beregningsdato: LocalDate,
val timestamp: LocalDateTime,
val kontekstType: String,
)

data class ManueltRedigert(
val redigertAv: String,
) {
companion object {
fun from(
bool: Boolean,
Expand All @@ -68,9 +85,14 @@ data class StoredInntekt(
val timestamp: LocalDateTime? = null,
)

data class DetachedInntekt(val inntekt: InntektkomponentResponse, val manueltRedigert: Boolean)
data class DetachedInntekt(
val inntekt: InntektkomponentResponse,
val manueltRedigert: Boolean,
)

data class InntektId(val id: String) {
data class InntektId(
val id: String,
) {
init {
try {
ULID.parseULID(id)
Expand All @@ -80,9 +102,23 @@ data class InntektId(val id: String) {
}
}

class InntektNotFoundException(override val message: String) : RuntimeException(message)
data class StoredInntektMedFnr(
val inntektId: InntektId,
val inntekt: InntektkomponentResponse,
val manueltRedigert: Boolean,
val timestamp: LocalDateTime? = null,
val fødselsnummer: String,
)

class InntektNotFoundException(
override val message: String,
) : RuntimeException(message)

class StoreException(override val message: String) : RuntimeException(message)
class StoreException(
override val message: String,
) : RuntimeException(message)

class IllegalInntektIdException(override val message: String, override val cause: Throwable?) :
java.lang.RuntimeException(message, cause)
class IllegalInntektIdException(
override val message: String,
override val cause: Throwable?,
) : java.lang.RuntimeException(message, cause)
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@ import java.time.ZonedDateTime
import javax.sql.DataSource

@Suppress("ktlint:standard:max-line-length")
internal class PostgresInntektStore(private val dataSource: DataSource) : InntektStore, HealthCheck {
internal class PostgresInntektStore(
private val dataSource: DataSource,
) : InntektStore,
HealthCheck {
companion object {
private val ulidGenerator = ULID()
private val LOGGER = KotlinLogging.logger {}
private val markerInntektTimer =
Summary.builder()
Summary
.builder()
.name("marker_inntekt_brukt")
.help("Hvor lang tid det tar å markere en inntekt brukt (i sekunder")
.register()
Expand Down Expand Up @@ -89,6 +93,30 @@ internal class PostgresInntektStore(private val dataSource: DataSource) : Inntek
}
}

override fun getInntektPersonMapping(inntektId: String): InntektPersonMapping {
@Language("sql")
val statement = "SELECT * FROM inntekt_V1_person_mapping WHERE inntektId = :inntektId)".trimMargin()

return using(sessionOf(dataSource)) { session ->
session.run(
queryOf(
statement,
mapOf("inntektId" to inntektId),
).map { row ->
InntektPersonMapping(
inntektId = InntektId(row.string("inntektid")),
aktørId = row.string("aktorid"),
fnr = row.string("fnr"),
kontekstId = row.string("kontekstid"),
beregningsdato = row.zonedDateTime("beregningsdato").toLocalDate(),
timestamp = row.zonedDateTime("timestamp").toLocalDateTime(),
kontekstType = row.string("konteksttype"),
)
}.asSingle,
) ?: throw InntektNotFoundException("Inntekt with id $inntektId not found.")
}
}

override fun getBeregningsdato(inntektId: InntektId): LocalDate {
@Language("sql")
val statement =
Expand All @@ -110,8 +138,8 @@ internal class PostgresInntektStore(private val dataSource: DataSource) : Inntek
}
}

override fun getInntekt(inntektId: InntektId): StoredInntekt {
return using(sessionOf(dataSource)) { session ->
override fun getInntekt(inntektId: InntektId): StoredInntekt =
using(sessionOf(dataSource)) { session ->
session.run(
queryOf(
""" SELECT id, inntekt, manuelt_redigert, timestamp from inntekt_V1 where id = ?""",
Expand All @@ -123,12 +151,10 @@ internal class PostgresInntektStore(private val dataSource: DataSource) : Inntek
manueltRedigert = row.boolean("manuelt_redigert"),
timestamp = row.zonedDateTime("timestamp").toLocalDateTime(),
)
}
.asSingle,
}.asSingle,
)
?: throw InntektNotFoundException("Inntekt with id $inntektId not found.")
}
}

override fun getSpesifisertInntekt(inntektId: InntektId): SpesifisertInntekt {
@Language("sql")
Expand All @@ -137,8 +163,9 @@ internal class PostgresInntektStore(private val dataSource: DataSource) : Inntek
SELECT inntekt.id, inntekt.inntekt, inntekt.manuelt_redigert, inntekt.timestamp, mapping.beregningsdato
from inntekt_V1 inntekt
inner join inntekt_V1_person_mapping mapping on inntekt.id = mapping.inntektid
where inntekt.id = ?"""
.trimIndent()
where inntekt.id = ?

""".trimIndent()

val stored =
using(sessionOf(dataSource)) { session ->
Expand All @@ -153,14 +180,40 @@ internal class PostgresInntektStore(private val dataSource: DataSource) : Inntek
manueltRedigert = row.boolean("manuelt_redigert"),
timestamp = row.zonedDateTime("timestamp").toLocalDateTime(),
) to row.localDate("beregningsdato")
}
.asSingle,
}.asSingle,
)
?: throw InntektNotFoundException("Inntekt with id $inntektId not found.")
}
return mapToSpesifisertInntekt(stored.first, Opptjeningsperiode(stored.second).sisteAvsluttendeKalenderMåned)
}

override fun getInntektMedPersonFnr(inntektId: InntektId): StoredInntektMedFnr {
@Language("sql")
val statement =
"""
SELECT inntekt.id, inntekt.inntekt, inntekt.manuelt_redigert, inntekt.timestamp, mapping.fnr
from inntekt_V1 inntekt
inner join inntekt_V1_person_mapping mapping on inntekt.id = mapping.inntektid
where inntekt.id = ?

""".trimIndent()

return using(sessionOf(dataSource)) { session ->
session.run(
queryOf(statement, inntektId.id)
.map {
StoredInntektMedFnr(
inntektId = InntektId(it.string("id")),
inntekt = it.binaryStream("inntekt").use { jacksonObjectMapper.readValue<InntektkomponentResponse>(it) },
manueltRedigert = it.boolean("manuelt_redigert"),
timestamp = it.zonedDateTime("timestamp").toLocalDateTime(),
fødselsnummer = it.string("fnr"),
)
}.asSingle,
) ?: throw InntektNotFoundException("Inntekt with id $inntektId not found.")
}
}

override fun storeInntekt(
command: StoreInntektCommand,
created: ZonedDateTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ data class GUIInntekt(
val inntektsmottaker: Inntektsmottaker? = null,
)

data class Inntektsmottaker(val pnr: String?, val navn: String?)
data class Inntektsmottaker(
val pnr: String?,
val navn: String?,
)

data class GUIInntektsKomponentResponse(
val fraDato: YearMonth?,
Expand Down Expand Up @@ -62,3 +65,8 @@ data class InntektMedVerdikode(
val tilleggsinformasjon: TilleggInformasjon? = null,
val verdikode: String,
)

data class OrganisasjonNavnOgIdMapping(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename

val organisasjonsnummer: String,
val organisasjonNavn: String,
)
Loading
Loading