Skip to content

Commit b9e53b9

Browse files
committed
feat/add dinesykmeldte api
1 parent 2a34204 commit b9e53b9

21 files changed

+1583
-1278
lines changed

gradle.properties

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
kotlin.code.style=official
2-
org.gradle.caching=true
2+
org.gradle.caching=true
3+
kotlin.daemon.jvmargs=-Xmx1g
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package no.nav.syfo.dinesykmeldte.api
2+
3+
import io.ktor.http.HttpStatusCode
4+
import io.ktor.server.auth.authentication
5+
import io.ktor.server.response.respond
6+
import io.ktor.server.routing.Route
7+
import io.ktor.server.routing.get
8+
import no.nav.syfo.dinesykmeldte.service.DineSykmeldteService
9+
import no.nav.syfo.plugins.BrukerPrincipal
10+
import no.nav.syfo.util.logger
11+
import no.nav.syfo.util.securelog
12+
13+
private val log = logger("no.nav.syfo.dinesykmeldte")
14+
15+
fun Route.registerDineSykmeldteApi(dineSykmeldteService: DineSykmeldteService) {
16+
get("api/dinesykmeldte") {
17+
val principal: BrukerPrincipal = call.authentication.principal()!!
18+
val fnr = principal.fnr
19+
securelog.info("Mottak kall mot /api/dinesykmeldte for fnr: $fnr")
20+
val sykmeldte = dineSykmeldteService.getDineSykmeldte(fnr)
21+
log.info("Hentet ${sykmeldte.size} fra db")
22+
call.respond(sykmeldte)
23+
}
24+
25+
get("api/dinesykmeldte/{narmestelederId}") {
26+
val narmestelederId = call.parameters["narmestelederId"]!!
27+
val principal: BrukerPrincipal = call.authentication.principal()!!
28+
val fnr = principal.fnr
29+
securelog.info(
30+
"Mottak kall mot /api/dinesykmeldte/{narmestelederId} for fnr: $fnr " +
31+
"og narmestelederId: $narmestelederId"
32+
)
33+
when (val sykmeldt = dineSykmeldteService.getSykmeldt(narmestelederId, fnr)) {
34+
null -> call.respond(HttpStatusCode.NotFound)
35+
else -> {
36+
call.respond(sykmeldt)
37+
}
38+
}
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
data class Ansatt(
4+
val fnr: String,
5+
val navn: String,
6+
val orgnummer: String,
7+
val narmestelederId: String,
8+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
data class Arbeidsevne(
4+
val tilretteleggingArbeidsplass: String?,
5+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
import java.time.LocalDate
4+
5+
data class Bekreftelse(
6+
val sykmelder: String,
7+
val utstedelsesdato: LocalDate,
8+
val sykmelderTlf: String?,
9+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
data class DineSykmeldteSykmelding(
4+
val sykmeldingId: String,
5+
val pasient: Pasient,
6+
val mulighetForArbeid: MulighetForArbeid,
7+
val skalViseSkravertFelt: Boolean = true,
8+
val friskmelding: Friskmelding,
9+
val arbeidsgiver: String?,
10+
val bekreftelse: Bekreftelse,
11+
val arbeidsevne: Arbeidsevne,
12+
val innspillTilArbeidsgiver: String?,
13+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
data class Friskmelding(
4+
val arbeidsfoerEtterPerioden: Boolean?,
5+
val hensynPaaArbeidsplassen: String?,
6+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
data class MulighetForArbeid(
4+
val aktivitetIkkeMulig434: List<String>,
5+
val aarsakAktivitetIkkeMulig434: String,
6+
val perioder: List<Periode>,
7+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
data class Pasient(
4+
val fnr: String,
5+
val navn: String?,
6+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
import java.time.LocalDate
4+
5+
data class Periode(
6+
val fom: LocalDate,
7+
val tom: LocalDate,
8+
val grad: Int?,
9+
val behandlingsdager: Int?,
10+
val reisetilskudd: Boolean,
11+
val avventende: String?,
12+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package no.nav.syfo.dinesykmeldte.model
2+
3+
data class Sykmeldt(
4+
val narmestelederId: String,
5+
val orgnummer: String,
6+
val fnr: String,
7+
val navn: String?,
8+
val sykmeldinger: List<DineSykmeldteSykmelding>?,
9+
val aktivSykmelding: Boolean?,
10+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package no.nav.syfo.dinesykmeldte.service
2+
3+
import no.nav.syfo.dinesykmeldte.model.Ansatt
4+
import no.nav.syfo.dinesykmeldte.model.Sykmeldt
5+
import no.nav.syfo.dinesykmeldte.util.isActive
6+
import no.nav.syfo.dinesykmeldte.util.toDineSykmeldteSykmelding
7+
import no.nav.syfo.minesykmeldte.db.MinSykmeldtDbModel
8+
import no.nav.syfo.minesykmeldte.db.MineSykmeldteDb
9+
10+
class DineSykmeldteService(
11+
private val sykmeldingDb: MineSykmeldteDb,
12+
) {
13+
suspend fun getSykmeldt(narmestelederId: String, fnr: String): Sykmeldt? {
14+
val dineSykmeldte =
15+
toDineSykmeldte(
16+
sykmeldingDb.getMineSykmeldteWithoutSoknad(
17+
lederFnr = fnr,
18+
narmestelederId = narmestelederId
19+
)
20+
)
21+
if (dineSykmeldte.size > 1) {
22+
throw RuntimeException("Fant flere sykmeldte med samme narmestelederId")
23+
}
24+
return dineSykmeldte.singleOrNull()
25+
}
26+
27+
suspend fun getDineSykmeldte(fnr: String): List<Sykmeldt> {
28+
return toDineSykmeldte(
29+
sykmeldingDb.getMineSykmeldteWithoutSoknad(lederFnr = fnr, narmestelederId = null)
30+
)
31+
}
32+
33+
private fun toDineSykmeldte(sykmeldinger: List<MinSykmeldtDbModel>) =
34+
sykmeldinger
35+
.groupBy {
36+
Ansatt(
37+
fnr = it.sykmeldtFnr,
38+
navn = it.sykmeldtNavn,
39+
orgnummer = it.orgnummer,
40+
narmestelederId = it.narmestelederId,
41+
)
42+
}
43+
.map { ansatt ->
44+
Sykmeldt(
45+
narmestelederId = ansatt.key.narmestelederId,
46+
orgnummer = ansatt.key.orgnummer,
47+
fnr = ansatt.key.fnr,
48+
ansatt.key.navn,
49+
sykmeldinger = ansatt.value.map { it.toDineSykmeldteSykmelding(ansatt.key) },
50+
aktivSykmelding =
51+
ansatt.value.any { it.sykmelding.sykmeldingsperioder.isActive() },
52+
)
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package no.nav.syfo.dinesykmeldte.util
2+
3+
import java.time.LocalDate
4+
import no.nav.syfo.dinesykmeldte.model.Ansatt
5+
import no.nav.syfo.dinesykmeldte.model.Arbeidsevne
6+
import no.nav.syfo.dinesykmeldte.model.Bekreftelse
7+
import no.nav.syfo.dinesykmeldte.model.DineSykmeldteSykmelding
8+
import no.nav.syfo.dinesykmeldte.model.Friskmelding
9+
import no.nav.syfo.dinesykmeldte.model.MulighetForArbeid
10+
import no.nav.syfo.dinesykmeldte.model.Pasient
11+
import no.nav.syfo.dinesykmeldte.model.Periode
12+
import no.nav.syfo.minesykmeldte.db.MinSykmeldtDbModel
13+
import no.nav.syfo.sykmelding.model.sykmelding.arbeidsgiver.BehandlerAGDTO
14+
import no.nav.syfo.sykmelding.model.sykmelding.arbeidsgiver.SykmeldingsperiodeAGDTO
15+
16+
fun MinSykmeldtDbModel.toDineSykmeldteSykmelding(ansatt: Ansatt): DineSykmeldteSykmelding {
17+
return DineSykmeldteSykmelding(
18+
pasient =
19+
Pasient(
20+
fnr = sykmeldtFnr,
21+
navn = ansatt.navn,
22+
),
23+
sykmeldingId = sykmelding.id,
24+
mulighetForArbeid =
25+
MulighetForArbeid(
26+
perioder = getPerioder(),
27+
aktivitetIkkeMulig434 = getAktivitetIkkeMulig(this.sykmelding.sykmeldingsperioder),
28+
aarsakAktivitetIkkeMulig434 =
29+
getAktivitetIkkeMuligBeskrivelse(this.sykmelding.sykmeldingsperioder),
30+
),
31+
skalViseSkravertFelt = true,
32+
arbeidsgiver = this.orgNavn,
33+
innspillTilArbeidsgiver = this.sykmelding.meldingTilArbeidsgiver,
34+
arbeidsevne =
35+
Arbeidsevne(
36+
tilretteleggingArbeidsplass = this.sykmelding.tiltakArbeidsplassen,
37+
),
38+
bekreftelse =
39+
Bekreftelse(
40+
sykmelder = this.sykmelding.behandler?.let { getSykmelderNavn(it) } ?: "",
41+
utstedelsesdato = this.sykmelding.behandletTidspunkt.toLocalDate(),
42+
sykmelderTlf = this.sykmelding.behandler?.tlf,
43+
),
44+
friskmelding =
45+
Friskmelding(
46+
arbeidsfoerEtterPerioden = this.sykmelding.prognose?.arbeidsforEtterPeriode,
47+
hensynPaaArbeidsplassen = this.sykmelding.prognose?.hensynArbeidsplassen,
48+
),
49+
)
50+
}
51+
52+
fun getSykmelderNavn(behandlerDTO: BehandlerAGDTO): String {
53+
return if (behandlerDTO.mellomnavn.isNullOrEmpty()) {
54+
capitalizeFirstLetter("${behandlerDTO.fornavn} ${behandlerDTO.etternavn}")
55+
} else {
56+
capitalizeFirstLetter(
57+
"${behandlerDTO.fornavn} ${behandlerDTO.mellomnavn} ${behandlerDTO.etternavn}"
58+
)
59+
}
60+
}
61+
62+
fun capitalizeFirstLetter(string: String): String {
63+
return string
64+
.lowercase()
65+
.split(" ")
66+
.joinToString(" ") { it.replaceFirstChar { char -> char.titlecaseChar() } }
67+
.split("-")
68+
.joinToString("-") { it.replaceFirstChar { char -> char.titlecaseChar() } }
69+
.trimEnd()
70+
}
71+
72+
fun getAktivitetIkkeMuligBeskrivelse(sykmeldingsperioder: List<SykmeldingsperiodeAGDTO>): String {
73+
return sykmeldingsperioder
74+
.mapNotNull { it.aktivitetIkkeMulig?.arbeidsrelatertArsak?.beskrivelse }
75+
.distinct()
76+
.joinToString(separator = ", ")
77+
}
78+
79+
fun getAktivitetIkkeMulig(sykmeldingsperioder: List<SykmeldingsperiodeAGDTO>): List<String> {
80+
return sykmeldingsperioder
81+
.mapNotNull { it.aktivitetIkkeMulig?.arbeidsrelatertArsak }
82+
.flatMap { it.arsak }
83+
.map { it.name }
84+
.distinct()
85+
}
86+
87+
private fun MinSykmeldtDbModel.getPerioder(): List<Periode> {
88+
return sykmelding.sykmeldingsperioder.map { it.toPerioder() }
89+
}
90+
91+
private fun SykmeldingsperiodeAGDTO.toPerioder(): Periode {
92+
return Periode(
93+
fom = this.fom,
94+
tom = this.tom,
95+
grad = this.gradert?.grad ?: 100,
96+
behandlingsdager = this.behandlingsdager,
97+
reisetilskudd = this.reisetilskudd,
98+
avventende = this.innspillTilArbeidsgiver,
99+
)
100+
}
101+
102+
fun List<SykmeldingsperiodeAGDTO>.isActive(date: LocalDate = LocalDate.now()): Boolean {
103+
return any { !it.fom.isAfter(date) && !date.isAfter(it.tom) }
104+
}

src/main/kotlin/no/nav/syfo/minesykmeldte/MineSykmeldteService.kt

+2-6
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class MineSykmeldteService(
124124
Dialogmote(
125125
hendelseId = it.hendelseId,
126126
tekst = it.tekst
127-
?: throw IllegalStateException("Dialogmøte uten tekst: ${it.id}"),
127+
?: throw IllegalStateException("Dialogmøte uten tekst: ${it.id}"),
128128
mottatt = it.mottatt,
129129
)
130130
}
@@ -264,7 +264,7 @@ private fun Pair<SykmeldtDbModel, SoknadDbModel>.toSoknad(): Soknad {
264264
tom = soknadDb.tom,
265265
lest = soknadDb.lest,
266266
sendtDato = soknadDb.sykepengesoknad.sendtArbeidsgiver
267-
?: throw IllegalStateException("Søknad uten sendt dato: ${soknadDb.soknadId}"),
267+
?: throw IllegalStateException("Søknad uten sendt dato: ${soknadDb.soknadId}"),
268268
sendtTilNavDato = soknadDb.sykepengesoknad.sendtNav,
269269
korrigererSoknadId = soknadDb.sykepengesoknad.korrigerer,
270270
korrigertBySoknadId = soknadDb.sykepengesoknad.korrigertAv,
@@ -371,22 +371,19 @@ private fun SykmeldingsperiodeAGDTO.toSykmeldingPeriode(): Periode =
371371
)
372372
},
373373
)
374-
375374
PeriodetypeDTO.AVVENTENDE ->
376375
Avventende(
377376
this.fom,
378377
this.tom,
379378
tilrettelegging = this.innspillTilArbeidsgiver,
380379
)
381-
382380
PeriodetypeDTO.BEHANDLINGSDAGER ->
383381
Behandlingsdager(
384382
this.fom,
385383
this.tom,
386384
this.behandlingsdager
387385
?: throw IllegalStateException("Behandlingsdager without behandlingsdager"),
388386
)
389-
390387
PeriodetypeDTO.GRADERT -> {
391388
val gradering = this.gradert
392389
requireNotNull(gradering) { "Gradert periode uten gradert-data burde ikke eksistere" }
@@ -398,7 +395,6 @@ private fun SykmeldingsperiodeAGDTO.toSykmeldingPeriode(): Periode =
398395
gradering.reisetilskudd,
399396
)
400397
}
401-
402398
PeriodetypeDTO.REISETILSKUDD ->
403399
Reisetilskudd(
404400
this.fom,

0 commit comments

Comments
 (0)