Skip to content

Commit 7fd4b63

Browse files
committed
Kronetilleggutrekk - '/v2/inntekt/<id>/harDagpenger' som svarer true/false om dagpenger er med inntektsgrunnlaget.
- FLyttet logikk fra task/arena-6881 greina - Route som svarer på '/v2/inntekt/<id>/harDagpenger' med azure ad auth, svarer med json '{"id" : "<id>", "svar" : true|false }' DAG-148
1 parent 7069afc commit 7fd4b63

File tree

7 files changed

+267
-1
lines changed

7 files changed

+267
-1
lines changed

dp-inntekt-api/src/main/kotlin/no/nav/dagpenger/inntekt/Application.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import kotlinx.coroutines.launch
99
import kotlinx.coroutines.runBlocking
1010
import mu.KotlinLogging
1111
import no.nav.dagpenger.inntekt.Config.inntektApiConfig
12+
import no.nav.dagpenger.inntekt.db.KronetilleggUttrekk
1213
import no.nav.dagpenger.inntekt.db.PostgresInntektStore
1314
import no.nav.dagpenger.inntekt.db.dataSourceFrom
1415
import no.nav.dagpenger.inntekt.db.migrate
@@ -93,6 +94,7 @@ fun main() {
9394
}
9495
}
9596

97+
val kronetilleggUttrekk = KronetilleggUttrekk(dataSource)
9698
// Provides a HTTP API for getting inntekt
9799
embeddedServer(Netty, port = config.application.httpPort) {
98100
inntektApi(
@@ -104,6 +106,7 @@ fun main() {
104106
authApiKeyVerifier,
105107
jwkProvider,
106108
enhetsregisterClient,
109+
kronetilleggUttrekk,
107110
listOf(
108111
postgresInntektStore as HealthCheck,
109112
subsumsjonBruktDataConsumer as HealthCheck

dp-inntekt-api/src/main/kotlin/no/nav/dagpenger/inntekt/InntektApi.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import no.nav.dagpenger.inntekt.Config.application
3636
import no.nav.dagpenger.inntekt.db.IllegalInntektIdException
3737
import no.nav.dagpenger.inntekt.db.InntektNotFoundException
3838
import no.nav.dagpenger.inntekt.db.InntektStore
39+
import no.nav.dagpenger.inntekt.db.KronetilleggUttrekk
3940
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.InntektskomponentClient
4041
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.InntektskomponentenHttpClientException
4142
import no.nav.dagpenger.inntekt.oppslag.PersonOppslag
@@ -44,6 +45,7 @@ import no.nav.dagpenger.inntekt.v1.enhetsregisteret
4445
import no.nav.dagpenger.inntekt.v1.inntekt
4546
import no.nav.dagpenger.inntekt.v1.opptjeningsperiodeApi
4647
import no.nav.dagpenger.inntekt.v1.uklassifisertInntekt
48+
import no.nav.dagpenger.inntekt.v1.uttrekk
4749
import no.nav.dagpenger.ktor.auth.ApiKeyCredential
4850
import no.nav.dagpenger.ktor.auth.ApiKeyVerifier
4951
import no.nav.dagpenger.ktor.auth.ApiPrincipal
@@ -55,7 +57,7 @@ import java.util.concurrent.atomic.AtomicLong
5557
private val LOGGER = KotlinLogging.logger {}
5658
private val sikkerLogg = KotlinLogging.logger("tjenestekall")
5759

58-
fun Application.inntektApi(
60+
internal fun Application.inntektApi(
5961
config: Configuration = Config.config,
6062
inntektskomponentHttpClient: InntektskomponentClient,
6163
inntektStore: InntektStore,
@@ -64,6 +66,7 @@ fun Application.inntektApi(
6466
apiAuthApiKeyVerifier: AuthApiKeyVerifier,
6567
jwkProvider: JwkProvider,
6668
enhetsregisterClient: EnhetsregisterClient,
69+
kronetilleggUttrekk: KronetilleggUttrekk,
6770
healthChecks: List<HealthCheck>,
6871
collectorRegistry: CollectorRegistry = CollectorRegistry.defaultRegistry
6972
) {
@@ -228,6 +231,7 @@ fun Application.inntektApi(
228231
route("/inntekt") {
229232
authenticate("azure") {
230233
inntekt(behandlingsInntektsGetter)
234+
uttrekk(kronetilleggUttrekk)
231235
}
232236
}
233237
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package no.nav.dagpenger.inntekt.db
2+
3+
import kotliquery.queryOf
4+
import kotliquery.sessionOf
5+
import kotliquery.using
6+
import no.nav.dagpenger.events.inntekt.v1.InntektKlasse
7+
import no.nav.dagpenger.inntekt.klassifiserer.klassifiserOgMapInntekt
8+
import no.nav.dagpenger.inntekt.mapping.mapToSpesifisertInntekt
9+
import no.nav.dagpenger.inntekt.opptjeningsperiode.Opptjeningsperiode
10+
import java.time.LocalDate
11+
import javax.sql.DataSource
12+
13+
internal class KronetilleggUttrekk(private val dataSource: DataSource) {
14+
15+
fun utrekkFra(inntektId: InntektId): Uttrekk = hentInntekt(inntektId).let { kronetilleggInntekt ->
16+
val opptjeningsperiode = Opptjeningsperiode(kronetilleggInntekt.beregningsdato)
17+
val klassifisertDbInntekt = klassifiserOgMapInntekt(
18+
mapToSpesifisertInntekt(
19+
kronetilleggInntekt.inntekt,
20+
opptjeningsperiode.sisteAvsluttendeKalenderMåned
21+
)
22+
)
23+
return if (klassifisertDbInntekt.inntektsListe.any { inntekt ->
24+
inntekt.klassifiserteInntekter.any {
25+
it.inntektKlasse == InntektKlasse.DAGPENGER ||
26+
it.inntektKlasse == InntektKlasse.DAGPENGER_FANGST_FISKE
27+
}
28+
}
29+
) {
30+
Uttrekk(inntektId.id, true)
31+
} else {
32+
Uttrekk(inntektId.id, false)
33+
}
34+
}
35+
36+
private fun hentInntekt(
37+
inntektId: InntektId
38+
) = using(sessionOf(dataSource)) { session ->
39+
session.run(
40+
// language=PostgreSQL
41+
queryOf(
42+
"""
43+
SELECT id, inntekt.inntekt, manuelt_redigert, beregningsdato, kontekstid
44+
FROM inntekt_v1_person_mapping
45+
JOIN inntekt_v1 inntekt on inntekt.id = inntekt_v1_person_mapping.inntektid
46+
WHERE inntektid = :inntektId;
47+
""".trimIndent(),
48+
mapOf(
49+
"inntektId" to inntektId.id,
50+
)
51+
).map {
52+
KronetilleggInntekt(
53+
beregningsdato = it.localDate("beregningsdato"),
54+
inntekt = StoredInntekt(
55+
inntektId = InntektId(inntektId.id),
56+
inntekt = PostgresInntektStore.adapter.fromJson(it.string("inntekt"))!!,
57+
manueltRedigert = it.boolean("manuelt_redigert")
58+
),
59+
vedtakId = it.int("kontekstid"),
60+
)
61+
}.asSingle
62+
) ?: throw InntektNotFoundException("Inntekt with id ${inntektId.id} not found.")
63+
}
64+
}
65+
66+
private data class KronetilleggInntekt(
67+
val beregningsdato: LocalDate,
68+
val inntekt: StoredInntekt,
69+
val vedtakId: Int,
70+
)
71+
72+
data class Uttrekk(val id: String, val svar: Boolean)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package no.nav.dagpenger.inntekt.v1
2+
3+
import io.ktor.application.call
4+
import io.ktor.response.respond
5+
import io.ktor.routing.Route
6+
import io.ktor.routing.get
7+
import io.ktor.routing.route
8+
import no.nav.dagpenger.inntekt.db.InntektId
9+
import no.nav.dagpenger.inntekt.db.KronetilleggUttrekk
10+
11+
internal fun Route.uttrekk(kronetilleggUttrekk: KronetilleggUttrekk) {
12+
13+
route("{inntektID}") {
14+
get("harDagpenger") {
15+
val inntektId = InntektId(this.call.parameters["inntektID"] ?: throw IllegalArgumentException("inntektID mangler i parameter"))
16+
val uttrekk = kronetilleggUttrekk.utrekkFra(inntektId)
17+
call.respond(uttrekk)
18+
}
19+
}
20+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package no.nav.dagpenger.inntekt.db
2+
3+
import no.nav.dagpenger.inntekt.DataSource
4+
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.Aktoer
5+
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.AktoerType
6+
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.ArbeidsInntektInformasjon
7+
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.ArbeidsInntektMaaned
8+
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.Inntekt
9+
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.InntektBeskrivelse
10+
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.InntektType
11+
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.InntektkomponentResponse
12+
import no.nav.dagpenger.inntekt.withMigratedDb
13+
import org.junit.jupiter.api.Assertions.assertFalse
14+
import org.junit.jupiter.api.Assertions.assertTrue
15+
import org.junit.jupiter.api.Test
16+
import java.math.BigDecimal
17+
import java.time.LocalDate
18+
import java.time.YearMonth
19+
20+
internal class KronetilleggUttrekkTest {
21+
22+
@Test
23+
fun `skal finne inntekter med dagpenger som grunnlag`() {
24+
val inntektMedOrdinæreDagpenger = storeInntektCommand(inntektMedOrdinæreDagpenger)
25+
val inntektMedOrdinæreDagpengerMedFiskHyre = storeInntektCommand(inntektMedOrdinæreDagpengerMedFiskeHyre)
26+
val inntektMedFangOgFiskDagpenger = storeInntektCommand(inntektMedFangstOgFiskDagpenger)
27+
val inntektUten = storeInntektCommand(inntektUtenDagpenger)
28+
withMigratedDb {
29+
val uttrekk = KronetilleggUttrekk(DataSource.instance)
30+
val store = PostgresInntektStore(DataSource.instance)
31+
store.storeInntekt(inntektMedOrdinæreDagpenger).also {
32+
assertTrue(uttrekk.utrekkFra(it.inntektId).svar)
33+
}
34+
store.storeInntekt(inntektMedOrdinæreDagpengerMedFiskHyre).also {
35+
assertTrue(uttrekk.utrekkFra(it.inntektId).svar)
36+
}
37+
store.storeInntekt(inntektMedFangOgFiskDagpenger).also {
38+
assertTrue(uttrekk.utrekkFra(it.inntektId).svar)
39+
}
40+
store.storeInntekt(inntektUten).also {
41+
assertFalse(uttrekk.utrekkFra(it.inntektId).svar)
42+
}
43+
}
44+
}
45+
46+
private val inntektMedOrdinæreDagpenger = Inntekt(
47+
beloep = BigDecimal(2000),
48+
fordel = "?",
49+
beskrivelse = InntektBeskrivelse.DAGPENGER_VED_ARBEIDSLOESHET,
50+
inntektskilde = "skatt",
51+
inntektsstatus = "?",
52+
inntektsperiodetype = "?",
53+
inntektType = InntektType.YTELSE_FRA_OFFENTLIGE,
54+
utbetaltIMaaned = YearMonth.now()
55+
)
56+
private val inntektMedOrdinæreDagpengerMedFiskeHyre = Inntekt(
57+
beloep = BigDecimal(2000),
58+
fordel = "?",
59+
beskrivelse = InntektBeskrivelse.DAGPENGER_TIL_FISKER_SOM_BARE_HAR_HYRE,
60+
inntektskilde = "skatt",
61+
inntektsstatus = "?",
62+
inntektsperiodetype = "?",
63+
inntektType = InntektType.YTELSE_FRA_OFFENTLIGE,
64+
utbetaltIMaaned = YearMonth.now()
65+
)
66+
67+
private val inntektMedFangstOgFiskDagpenger = Inntekt(
68+
beloep = BigDecimal(2000),
69+
fordel = "?",
70+
beskrivelse = InntektBeskrivelse.DAGPENGER_TIL_FISKER,
71+
inntektskilde = "skatt",
72+
inntektsstatus = "?",
73+
inntektsperiodetype = "?",
74+
inntektType = InntektType.NAERINGSINNTEKT,
75+
utbetaltIMaaned = YearMonth.now()
76+
)
77+
78+
private val inntektUtenDagpenger = Inntekt(
79+
beloep = BigDecimal(2000),
80+
fordel = "?",
81+
beskrivelse = InntektBeskrivelse.FASTLOENN,
82+
inntektskilde = "skatt",
83+
inntektsstatus = "?",
84+
inntektsperiodetype = "?",
85+
inntektType = InntektType.LOENNSINNTEKT,
86+
utbetaltIMaaned = YearMonth.now()
87+
)
88+
89+
private fun storeInntektCommand(inntekt: Inntekt) = StoreInntektCommand(
90+
inntektparametre = Inntektparametre("1234", LocalDate.now(), RegelKontekst("1234", "vedtak")),
91+
inntekt = InntektkomponentResponse(
92+
ident = Aktoer(AktoerType.AKTOER_ID, "1235"),
93+
arbeidsInntektMaaned = listOf(
94+
ArbeidsInntektMaaned(
95+
aarMaaned = YearMonth.now(), emptyList(),
96+
arbeidsInntektInformasjon = ArbeidsInntektInformasjon(
97+
inntektListe = listOf(
98+
inntekt
99+
)
100+
)
101+
)
102+
)
103+
)
104+
)
105+
}

dp-inntekt-api/src/test/kotlin/no/nav/dagpenger/inntekt/v1/TestApplication.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import no.nav.dagpenger.inntekt.BehandlingsInntektsGetter
1818
import no.nav.dagpenger.inntekt.Config
1919
import no.nav.dagpenger.inntekt.HealthCheck
2020
import no.nav.dagpenger.inntekt.db.InntektStore
21+
import no.nav.dagpenger.inntekt.db.KronetilleggUttrekk
2122
import no.nav.dagpenger.inntekt.inntektApi
2223
import no.nav.dagpenger.inntekt.inntektskomponenten.v1.InntektskomponentClient
2324
import no.nav.dagpenger.inntekt.oppslag.PersonOppslag
@@ -58,6 +59,7 @@ internal object TestApplication {
5859
apiAuthApiKeyVerifier: AuthApiKeyVerifier = mockk(relaxed = true),
5960
jwkProvider: JwkProvider = mockk(relaxed = true),
6061
enhetsregisterClient: EnhetsregisterClient = mockk(relaxed = true),
62+
kronetilleggUttrekk: KronetilleggUttrekk = mockk(relaxed = true),
6163
healthChecks: List<HealthCheck> = emptyList()
6264
): Application.() -> Unit {
6365
return fun Application.() {
@@ -71,6 +73,7 @@ internal object TestApplication {
7173
jwkProvider = jwkProvider,
7274
enhetsregisterClient = enhetsregisterClient,
7375
healthChecks = healthChecks,
76+
kronetilleggUttrekk = kronetilleggUttrekk,
7477
collectorRegistry = CollectorRegistry(true)
7578
)
7679
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package no.nav.dagpenger.inntekt.v1
2+
3+
import de.huxhorn.sulky.ulid.ULID
4+
import io.ktor.http.HttpMethod
5+
import io.ktor.http.HttpStatusCode
6+
import io.ktor.server.testing.TestApplicationEngine
7+
import io.ktor.server.testing.withTestApplication
8+
import io.mockk.every
9+
import io.mockk.mockk
10+
import no.nav.dagpenger.inntekt.db.InntektId
11+
import no.nav.dagpenger.inntekt.db.InntektNotFoundException
12+
import no.nav.dagpenger.inntekt.db.KronetilleggUttrekk
13+
import no.nav.dagpenger.inntekt.db.Uttrekk
14+
import no.nav.dagpenger.inntekt.v1.TestApplication.handleAuthenticatedAzureAdRequest
15+
import no.nav.dagpenger.inntekt.v1.TestApplication.mockInntektApi
16+
import org.junit.jupiter.api.Test
17+
import kotlin.test.assertEquals
18+
19+
internal class UttrekkRouteTest {
20+
21+
@Test
22+
fun `skal svare om dagpenger er med i inntektsgrunnlaget()`() {
23+
24+
val uttrekk = mockk<KronetilleggUttrekk>()
25+
val id = ULID().nextULID()
26+
every {
27+
uttrekk.utrekkFra(InntektId(id))
28+
} returns Uttrekk(id.toString(), true)
29+
30+
testApp(uttrekk) {
31+
handleAuthenticatedAzureAdRequest(HttpMethod.Get, "/v2/inntekt/$id/harDagpenger").apply {
32+
assertEquals(HttpStatusCode.OK, response.status())
33+
assertEquals("""{"id":"$id","svar":true}""", response.content)
34+
}
35+
}
36+
}
37+
38+
@Test
39+
fun `ikke eksisterende inntekt id gir 404`() {
40+
val id = ULID().nextULID()
41+
val uttrekk = mockk<KronetilleggUttrekk>()
42+
every {
43+
uttrekk.utrekkFra(InntektId(id))
44+
} throws InntektNotFoundException("fant ikke")
45+
testApp(uttrekk) {
46+
handleAuthenticatedAzureAdRequest(HttpMethod.Get, "/v2/inntekt/$id/harDagpenger").apply {
47+
assertEquals(HttpStatusCode.NotFound, response.status())
48+
}
49+
}
50+
}
51+
52+
private fun testApp(uttrekk: KronetilleggUttrekk, callback: TestApplicationEngine.() -> Unit) {
53+
withTestApplication(
54+
mockInntektApi(
55+
kronetilleggUttrekk = uttrekk
56+
)
57+
) { callback() }
58+
}
59+
}

0 commit comments

Comments
 (0)