Skip to content
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

Fjern gammel kvittering #822

Merged
merged 8 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.UseSerializers
import kotlinx.serialization.builtins.serializer
import no.nav.helsearbeidsgiver.domene.inntektsmelding.deprecated.Inntekt
import no.nav.helsearbeidsgiver.domene.inntektsmelding.deprecated.Inntektsmelding
import no.nav.helsearbeidsgiver.domene.inntektsmelding.deprecated.KvitteringEkstern
import no.nav.helsearbeidsgiver.domene.inntektsmelding.deprecated.KvitteringSimba
import no.nav.helsearbeidsgiver.domene.inntektsmelding.v1.Avsender
import no.nav.helsearbeidsgiver.domene.inntektsmelding.v1.Periode
import no.nav.helsearbeidsgiver.domene.inntektsmelding.v1.Sykmeldt
import no.nav.helsearbeidsgiver.domene.inntektsmelding.v1.skjema.SkjemaInntektsmelding
import no.nav.helsearbeidsgiver.felles.Tekst
import no.nav.helsearbeidsgiver.felles.domene.EksternInntektsmelding
import no.nav.helsearbeidsgiver.felles.domene.Forespoersel
import no.nav.helsearbeidsgiver.felles.domene.KvitteringResultat
import no.nav.helsearbeidsgiver.felles.domene.LagretInntektsmelding
import no.nav.helsearbeidsgiver.felles.metrics.Metrics
import no.nav.helsearbeidsgiver.felles.rapidsrivers.redis.RedisConnection
import no.nav.helsearbeidsgiver.felles.rapidsrivers.redis.RedisPrefix
import no.nav.helsearbeidsgiver.felles.rapidsrivers.redis.RedisStore
import no.nav.helsearbeidsgiver.felles.utils.toOffsettDateTimeOslo
import no.nav.helsearbeidsgiver.inntektsmelding.api.RedisPoller
import no.nav.helsearbeidsgiver.inntektsmelding.api.RedisPollerTimeoutException
import no.nav.helsearbeidsgiver.inntektsmelding.api.Routes
Expand All @@ -43,9 +41,7 @@ import no.nav.helsearbeidsgiver.inntektsmelding.api.utils.respondOk
import no.nav.helsearbeidsgiver.utils.json.fromJson
import no.nav.helsearbeidsgiver.utils.json.serializer.OffsetDateTimeSerializer
import no.nav.helsearbeidsgiver.utils.json.toPretty
import no.nav.helsearbeidsgiver.utils.pipe.orDefault
import java.time.OffsetDateTime
import java.time.ZoneId
import java.util.UUID

fun Route.kvittering(
Expand Down Expand Up @@ -82,10 +78,18 @@ fun Route.kvittering(
val resultat = resultatJson.success?.fromJson(KvitteringResultat.serializer())
if (resultat != null) {
sikkerLogger.info("Hentet kvittering for '$forespoerselId'.\n${resultatJson.success?.toPretty()}")
if (resultat.skjema == null && resultat.inntektsmelding == null && resultat.eksternInntektsmelding == null) {
respondNotFound("Kvittering ikke funnet for forespørselId: $forespoerselId", String.serializer())
} else {
respondOk(resultat.tilResponse(), KvitteringResponse.serializer())

when (val lagret = resultat.lagret) {
is LagretInntektsmelding.Skjema -> {
val skjemaResponse = lagResponse(resultat.forespoersel, resultat.sykmeldtNavn, resultat.orgNavn, lagret)
respondOk(skjemaResponse, KvitteringResponse.serializer())
}
is LagretInntektsmelding.Ekstern -> {
val eksternResponse = lagResponse(lagret)
respondOk(eksternResponse, KvitteringResponse.serializer())
}
null ->
respondNotFound("Kvittering ikke funnet for forespørselId: $forespoerselId", String.serializer())
}
} else {
val feilmelding = resultatJson.failure?.fromJson(String.serializer()) ?: Tekst.TEKNISK_FEIL_FORBIGAAENDE
Expand All @@ -110,88 +114,61 @@ fun Route.kvittering(

@Serializable
private data class KvitteringResponse(
val kvitteringNavNo: KvitteringNavNo?,
val kvitteringDokument: KvitteringSimba?,
val kvitteringEkstern: KvitteringEkstern?,
)

@Serializable
private data class KvitteringNavNo(
val sykmeldt: Sykmeldt,
val avsender: Avsender,
val sykmeldingsperioder: List<Periode>,
val skjema: SkjemaInntektsmelding,
val mottatt: OffsetDateTime,
)

private fun KvitteringResultat.tilResponse(): KvitteringResponse =
KvitteringResponse(
kvitteringNavNo = tilKvitteringNavNo(),
kvitteringDokument = inntektsmelding?.tilKvitteringSimba(),
kvitteringEkstern = eksternInntektsmelding?.tilKvitteringEkstern(),
val kvitteringNavNo: NavNo?,
val kvitteringEkstern: Ekstern?,
) {
@Serializable
data class NavNo(
val sykmeldt: Sykmeldt,
val avsender: Avsender,
val sykmeldingsperioder: List<Periode>,
val skjema: SkjemaInntektsmelding,
val mottatt: OffsetDateTime,
)

private fun KvitteringResultat.tilKvitteringNavNo(): KvitteringNavNo? {
val skjemaKvittering = skjema
return if (skjemaKvittering != null) {
KvitteringNavNo(
sykmeldt =
Sykmeldt(
fnr = forespoersel.fnr,
navn = sykmeldtNavn,
),
avsender =
Avsender(
orgnr = forespoersel.orgnr,
orgNavn = orgNavn,
navn = avsenderNavn,
tlf = skjemaKvittering.avsenderTlf,
),
sykmeldingsperioder = forespoersel.sykmeldingsperioder,
skjema = skjemaKvittering,
// midlertidig, erstattes med non-null alternativ
mottatt = inntektsmelding?.tidspunkt ?: OffsetDateTime.now(),
)
} else {
null
}
@Serializable
data class Ekstern(
val avsenderSystem: String,
val referanse: String,
val mottatt: OffsetDateTime,
)
}

private fun Inntektsmelding.tilKvitteringSimba(): KvitteringSimba =
KvitteringSimba(
orgnrUnderenhet = orgnrUnderenhet,
identitetsnummer = identitetsnummer,
fulltNavn = fulltNavn,
virksomhetNavn = virksomhetNavn,
behandlingsdager = behandlingsdager,
egenmeldingsperioder = egenmeldingsperioder,
arbeidsgiverperioder = arbeidsgiverperioder,
// Frontend tolker feltet bestemmendeFraværsdag som om det var inntektsdato.
// Vi vil slippe denne hacken ved overgang til v1.Inntektsmelding, som kun inneholder inntektsdato (ikke bestemmende fraværsdag).
bestemmendeFraværsdag = inntektsdato ?: bestemmendeFraværsdag,
fraværsperioder = fraværsperioder,
inntekt =
Inntekt(
bekreftet = true,
// Kan slette nullable inntekt og fallback når IM med gammelt format slettes fra database
beregnetInntekt = inntekt?.beregnetInntekt ?: beregnetInntekt,
endringÅrsak = inntekt?.endringÅrsak,
manueltKorrigert = inntekt?.manueltKorrigert.orDefault(false),
private fun lagResponse(
forespoersel: Forespoersel,
sykmeldtNavn: String,
orgNavn: String,
lagret: LagretInntektsmelding.Skjema,
): KvitteringResponse =
KvitteringResponse(
kvitteringNavNo =
KvitteringResponse.NavNo(
sykmeldt =
Sykmeldt(
fnr = forespoersel.fnr,
navn = sykmeldtNavn,
),
avsender =
Avsender(
orgnr = forespoersel.orgnr,
orgNavn = orgNavn,
navn = lagret.avsenderNavn ?: "Ukjent navn",
tlf = lagret.skjema.avsenderTlf,
),
sykmeldingsperioder = forespoersel.sykmeldingsperioder,
skjema = lagret.skjema,
mottatt = lagret.mottatt.toOffsettDateTimeOslo(),
),
fullLønnIArbeidsgiverPerioden = fullLønnIArbeidsgiverPerioden,
refusjon = refusjon,
naturalytelser = naturalytelser,
årsakInnsending = årsakInnsending,
bekreftOpplysninger = true,
tidspunkt = tidspunkt,
forespurtData = forespurtData,
telefonnummer = telefonnummer,
innsenderNavn = innsenderNavn,
kvitteringEkstern = null,
)

private fun EksternInntektsmelding.tilKvitteringEkstern(): KvitteringEkstern =
KvitteringEkstern(
avsenderSystemNavn,
arkivreferanse,
tidspunkt.atZone(ZoneId.systemDefault()).toOffsetDateTime(),
private fun lagResponse(lagret: LagretInntektsmelding.Ekstern): KvitteringResponse =
KvitteringResponse(
kvitteringNavNo = null,
kvitteringEkstern =
KvitteringResponse.Ekstern(
avsenderSystem = lagret.ekstern.avsenderSystemNavn,
referanse = lagret.ekstern.arkivreferanse,
mottatt = lagret.ekstern.tidspunkt.toOffsettDateTimeOslo(),
),
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@file:Suppress("NonAsciiCharacters")

package no.nav.helsearbeidsgiver.inntektsmelding.api.aktiveorgnr

import io.kotest.matchers.shouldBe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ package no.nav.helsearbeidsgiver.inntektsmelding.api.kvittering
import io.ktor.http.HttpStatusCode
import io.mockk.coEvery
import no.nav.helsearbeidsgiver.felles.domene.KvitteringResultat
import no.nav.helsearbeidsgiver.felles.domene.LagretInntektsmelding
import no.nav.helsearbeidsgiver.felles.domene.ResultJson
import no.nav.helsearbeidsgiver.felles.json.toJson
import no.nav.helsearbeidsgiver.felles.test.mock.mockEksternInntektsmelding
import no.nav.helsearbeidsgiver.felles.test.mock.mockForespoersel
import no.nav.helsearbeidsgiver.felles.test.mock.mockInntektsmelding
import no.nav.helsearbeidsgiver.felles.test.mock.mockSkjemaInntektsmelding
import no.nav.helsearbeidsgiver.inntektsmelding.api.Routes
import no.nav.helsearbeidsgiver.inntektsmelding.api.utils.ApiTest
import no.nav.helsearbeidsgiver.inntektsmelding.api.utils.harTilgangResultat
import no.nav.helsearbeidsgiver.utils.json.toJson
import no.nav.helsearbeidsgiver.utils.test.date.mars
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.util.UUID
Expand Down Expand Up @@ -56,9 +56,11 @@ private val resultat =
KvitteringResultat(
forespoersel = mockForespoersel(),
sykmeldtNavn = "Syk Meldt",
avsenderNavn = "Avs Ender",
orgNavn = "Orga Nisasjon",
skjema = mockSkjemaInntektsmelding(),
inntektsmelding = mockInntektsmelding(),
eksternInntektsmelding = mockEksternInntektsmelding(),
lagret =
LagretInntektsmelding.Skjema(
avsenderNavn = "Avs Ender",
skjema = mockSkjemaInntektsmelding(),
mottatt = 4.mars.atStartOfDay(),
),
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import no.nav.helsearbeidsgiver.domene.inntektsmelding.v1.Sykmeldt
import no.nav.helsearbeidsgiver.domene.inntektsmelding.v1.skjema.SkjemaInntektsmelding
import no.nav.helsearbeidsgiver.felles.domene.Forespoersel
import no.nav.helsearbeidsgiver.felles.domene.ForslagInntekt
import no.nav.helsearbeidsgiver.felles.utils.zoneIdOslo
import no.nav.helsearbeidsgiver.felles.utils.toOffsettDateTimeOslo
import java.time.LocalDateTime
import java.util.UUID

Expand Down Expand Up @@ -76,7 +76,7 @@ fun mapInntektsmelding(
inntekt = inntekt,
refusjon = refusjon,
aarsakInnsending = aarsakInnsending,
mottatt = mottatt.atZone(zoneIdOslo).toOffsetDateTime(),
mottatt = mottatt.toOffsettDateTimeOslo(),
vedtaksperiodeId = forespoersel.vedtaksperiodeId,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import no.nav.helsearbeidsgiver.felles.test.mock.mockSkjemaInntektsmelding
import no.nav.helsearbeidsgiver.felles.test.mock.utenPaakrevdAGP
import no.nav.helsearbeidsgiver.felles.test.mock.utenPaakrevdInntekt
import no.nav.helsearbeidsgiver.felles.test.mock.utenPaakrevdRefusjon
import no.nav.helsearbeidsgiver.felles.utils.zoneIdOslo
import no.nav.helsearbeidsgiver.felles.utils.toOffsettDateTimeOslo
import no.nav.helsearbeidsgiver.utils.test.date.august
import no.nav.helsearbeidsgiver.utils.test.date.desember
import no.nav.helsearbeidsgiver.utils.test.date.juli
Expand Down Expand Up @@ -83,7 +83,7 @@ class MapInntektsmeldingKtTest :

vedtaksperiodeId shouldBe forespoersel.vedtaksperiodeId

mottatt shouldBe imMottatt.atZone(zoneIdOslo).toOffsetDateTime()
mottatt shouldBe imMottatt.toOffsettDateTimeOslo()
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package no.nav.helsearbeidsgiver.inntektsmelding.db

import no.nav.helsearbeidsgiver.domene.inntektsmelding.Utils.convert
import no.nav.helsearbeidsgiver.domene.inntektsmelding.Utils.convertAgp
import no.nav.helsearbeidsgiver.domene.inntektsmelding.Utils.convertInntekt
import no.nav.helsearbeidsgiver.domene.inntektsmelding.deprecated.Inntektsmelding
import no.nav.helsearbeidsgiver.domene.inntektsmelding.v1.skjema.SkjemaInntektsmelding
import no.nav.helsearbeidsgiver.felles.domene.EksternInntektsmelding
import no.nav.helsearbeidsgiver.felles.domene.LagretInntektsmelding
import no.nav.helsearbeidsgiver.felles.metrics.Metrics
import no.nav.helsearbeidsgiver.inntektsmelding.db.tabell.InntektsmeldingEntitet
import no.nav.helsearbeidsgiver.utils.log.logger
import no.nav.helsearbeidsgiver.utils.log.sikkerLogger
import no.nav.helsearbeidsgiver.utils.pipe.orDefault
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Query
import org.jetbrains.exposed.sql.SortOrder
Expand All @@ -25,25 +28,51 @@ class InntektsmeldingRepository(
private val logger = logger()
private val sikkerLogger = sikkerLogger()

fun hentNyesteEksternEllerInternInntektsmelding(forespoerselId: UUID): Triple<SkjemaInntektsmelding?, Inntektsmelding?, EksternInntektsmelding?> =
fun hentNyesteEksternEllerInternInntektsmelding(forespoerselId: UUID): LagretInntektsmelding? =
Metrics.dbInntektsmelding.recordTime(InntektsmeldingRepository::hentNyesteEksternEllerInternInntektsmelding) {
transaction(db) {
InntektsmeldingEntitet
.select(
InntektsmeldingEntitet.skjema,
InntektsmeldingEntitet.dokument,
InntektsmeldingEntitet.skjema,
InntektsmeldingEntitet.eksternInntektsmelding,
InntektsmeldingEntitet.innsendt,
).where { InntektsmeldingEntitet.forespoerselId eq forespoerselId.toString() }
.orderBy(InntektsmeldingEntitet.innsendt, SortOrder.DESC)
.limit(1)
.map {
Triple(
it[InntektsmeldingEntitet.skjema],
Quadruple(
Copy link
Contributor

Choose a reason for hiding this comment

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

Kan man ikke droppe map og bare gjøre

val inntektsmelding = result[InntektsmeldingEntitet.dokument]
val skjema = result[InntektsmeldingEntitet.skjema]
val eksternInntektsmelding = result[InntektsmeldingEntitet.eksternInntektsmelding]
val mottatt = result[InntektsmeldingEntitet.innsendt]

Synes ikke at Quadruple-objektet hjelper noe særlig på lesbarhet i hvert fall

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Jeg brukte Quadruple for å holde transaksjonen mot databasen kortest mulig, siden det som kommer etter ikke er en del av spørringen, men det er kanskje ikke så farlig 🤔

it[InntektsmeldingEntitet.dokument],
it[InntektsmeldingEntitet.skjema],
it[InntektsmeldingEntitet.eksternInntektsmelding],
it[InntektsmeldingEntitet.innsendt],
)
}.firstOrNull()
}.orDefault(Triple(null, null, null))
}
}.firstOrNull()
?.let { result ->
val inntektsmelding = result.first
val skjema = result.second
val eksternInntektsmelding = result.third
val mottatt = result.fourth

when {
skjema != null -> LagretInntektsmelding.Skjema(inntektsmelding?.innsenderNavn, skjema, mottatt)
inntektsmelding != null -> {
val bakoverkompatibeltSkjema =
SkjemaInntektsmelding(
forespoerselId = forespoerselId,
avsenderTlf = inntektsmelding.telefonnummer.orEmpty(),
agp = inntektsmelding.convertAgp(),
inntekt = inntektsmelding.convertInntekt(),
refusjon = inntektsmelding.refusjon.convert(),
)

LagretInntektsmelding.Skjema(inntektsmelding.innsenderNavn, bakoverkompatibeltSkjema, mottatt)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Navn på avsender lagres nå kun i inntektsmelding.innsenderNavn. Dette bør nok lagres i egen kolonne i databasen på sikt.

}
eksternInntektsmelding != null -> LagretInntektsmelding.Ekstern(eksternInntektsmelding)
else -> null
}
}
}

fun oppdaterJournalpostId(
Expand Down Expand Up @@ -82,7 +111,7 @@ class InntektsmeldingRepository(
InntektsmeldingEntitet.insert {
it[this.forespoerselId] = forespoerselId.toString()
it[eksternInntektsmelding] = eksternIm
it[innsendt] = LocalDateTime.now()
it[innsendt] = eksternIm.tidspunkt
}
}
}
Expand Down Expand Up @@ -149,18 +178,25 @@ class InntektsmeldingRepository(
}
}
}

private fun hentNyesteImQuery(forespoerselId: UUID): Query =
InntektsmeldingEntitet
.selectAll()
.where { (InntektsmeldingEntitet.forespoerselId eq forespoerselId.toString()) and InntektsmeldingEntitet.dokument.isNotNull() }
.orderBy(InntektsmeldingEntitet.innsendt, SortOrder.DESC)
.limit(1)

private fun hentNyesteImSkjemaQuery(forespoerselId: UUID): Query =
InntektsmeldingEntitet
.selectAll()
.where { InntektsmeldingEntitet.forespoerselId eq forespoerselId.toString() }
.orderBy(InntektsmeldingEntitet.innsendt, SortOrder.DESC)
.limit(1)
}

private class Quadruple<A, B, C, D>(
val first: A,
val second: B,
val third: C,
val fourth: D,
)

private fun hentNyesteImQuery(forespoerselId: UUID): Query =
InntektsmeldingEntitet
.selectAll()
.where { (InntektsmeldingEntitet.forespoerselId eq forespoerselId.toString()) and InntektsmeldingEntitet.dokument.isNotNull() }
.orderBy(InntektsmeldingEntitet.innsendt, SortOrder.DESC)
.limit(1)

private fun hentNyesteImSkjemaQuery(forespoerselId: UUID): Query =
InntektsmeldingEntitet
.selectAll()
.where { InntektsmeldingEntitet.forespoerselId eq forespoerselId.toString() }
.orderBy(InntektsmeldingEntitet.innsendt, SortOrder.DESC)
.limit(1)
Loading
Loading