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

Hybridbrev: Opnar for å redigere (delar av) brev frå Brevbakeren #1840

Merged
merged 12 commits into from
Jul 25, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import no.nav.etterlatte.brev.behandling.SakOgBehandlingService
import no.nav.etterlatte.brev.behandlingklient.BehandlingKlient
import no.nav.etterlatte.brev.beregning.BeregningKlient
import no.nav.etterlatte.brev.brevRoute
import no.nav.etterlatte.brev.brevbaker.BrevbakerJSONBlockMixIn
import no.nav.etterlatte.brev.brevbaker.BrevbakerJSONParagraphMixIn
import no.nav.etterlatte.brev.brevbaker.BrevbakerKlient
import no.nav.etterlatte.brev.db.BrevRepository
import no.nav.etterlatte.brev.distribusjon.DistribusjonKlient
Expand All @@ -46,6 +48,7 @@ import no.nav.etterlatte.rivers.VedtaksbrevUnderkjent
import no.nav.etterlatte.security.ktor.clientCredential
import no.nav.helse.rapids_rivers.RapidApplication
import no.nav.helse.rapids_rivers.RapidsConnection
import no.nav.pensjon.brevbaker.api.model.RenderedJsonLetter
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import rapidsandrivers.getRapidEnv
Expand Down Expand Up @@ -154,7 +157,10 @@ class ApplicationBuilder {
private fun httpClient(scope: String? = null, forventStatusSuccess: Boolean = true) = HttpClient(OkHttp) {
expectSuccess = forventStatusSuccess
install(ContentNegotiation) {
jackson()
jackson() {
addMixIn(RenderedJsonLetter.Block::class.java, BrevbakerJSONBlockMixIn::class.java)
addMixIn(RenderedJsonLetter.ParagraphContent::class.java, BrevbakerJSONParagraphMixIn::class.java)
}
}
if (scope != null) {
install(Auth) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package no.nav.etterlatte.brev

import no.nav.etterlatte.brev.model.Slate
import no.nav.pensjon.brevbaker.api.model.RenderedJsonLetter

object BlockTilSlateKonverterer {
fun konverter(it: RenderedJsonLetter) = Slate(
it
.blocks
.map { block -> tilSlateElement(block) }
.toList()
)

private fun tilSlateElement(block: RenderedJsonLetter.Block) = when (block.type) {
RenderedJsonLetter.Block.Type.TITLE1 -> Slate.Element(
type = Slate.ElementType.HEADING_TWO,
children = children(block)
)
RenderedJsonLetter.Block.Type.TITLE2 -> Slate.Element(
type = Slate.ElementType.HEADING_THREE,
children = children(block)
)

RenderedJsonLetter.Block.Type.PARAGRAPH -> Slate.Element(
type = Slate.ElementType.PARAGRAPH,
children = children(block)
)
}

private fun children(block: RenderedJsonLetter.Block): List<Slate.InnerElement> = when (block.type) {
RenderedJsonLetter.Block.Type.TITLE1 -> (block as RenderedJsonLetter.Block.Title1).content.map { konverter(it) }
RenderedJsonLetter.Block.Type.TITLE2 -> (block as RenderedJsonLetter.Block.Title2).content.map { konverter(it) }
RenderedJsonLetter.Block.Type.PARAGRAPH -> (block as RenderedJsonLetter.Block.Paragraph).content.map {
konverter(
it
)
}
}

private fun konverter(it: RenderedJsonLetter.ParagraphContent): Slate.InnerElement = when (it.type) {
RenderedJsonLetter.ParagraphContent.Type.ITEM_LIST -> Slate.InnerElement(
type = Slate.ElementType.BULLETED_LIST,
children =
(it as RenderedJsonLetter.ParagraphContent.ItemList).items
.map { item ->
Slate.InnerElement(
type = Slate.ElementType.LIST_ITEM,
text = item.content.joinToString()
)
}
)

RenderedJsonLetter.ParagraphContent.Type.LITERAL, RenderedJsonLetter.ParagraphContent.Type.VARIABLE ->
Slate.InnerElement(
type = Slate.ElementType.PARAGRAPH,
text = (it as RenderedJsonLetter.ParagraphContent.Text).text
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import no.nav.etterlatte.brev.behandling.Behandling
import no.nav.etterlatte.brev.behandling.SakOgBehandlingService
import no.nav.etterlatte.brev.brevbaker.BrevbakerKlient
import no.nav.etterlatte.brev.brevbaker.BrevbakerRequest
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode
import no.nav.etterlatte.brev.db.BrevRepository
import no.nav.etterlatte.brev.dokarkiv.DokarkivServiceImpl
import no.nav.etterlatte.brev.journalpost.JournalpostResponse
Expand All @@ -20,8 +19,10 @@ import no.nav.etterlatte.brev.model.BrevProsessType.MANUELL
import no.nav.etterlatte.brev.model.ManueltBrevData
import no.nav.etterlatte.brev.model.OpprettNyttBrev
import no.nav.etterlatte.brev.model.Pdf
import no.nav.etterlatte.brev.model.Slate
import no.nav.etterlatte.brev.model.SlateHelper
import no.nav.etterlatte.brev.model.Status
import no.nav.etterlatte.libs.common.behandling.RevurderingAarsak
import no.nav.etterlatte.libs.common.vedtak.VedtakStatus
import no.nav.etterlatte.rivers.VedtakTilJournalfoering
import no.nav.etterlatte.token.BrukerTokenInfo
Expand Down Expand Up @@ -90,29 +91,42 @@ class VedtaksbrevService(
val behandling = sakOgBehandlingService.hentBehandling(brev.sakId, brev.behandlingId!!, brukerTokenInfo)
val avsender = adresseService.hentAvsender(behandling.vedtak)

val (brevKode, brevData) = opprettBrevData(brev, behandling)
val brevRequest = BrevbakerRequest.fra(brevKode, brevData, behandling, avsender)
val kode = BrevDataMapper.brevKode(behandling, brev.prosessType)
val brevData = opprettBrevData(brev, behandling)
val brevRequest = BrevbakerRequest.fra(kode.ferdigstilling, brevData, behandling, avsender)

return genererPdf(brev.id, brevRequest)
.also { pdf -> ferdigstillHvisVedtakFattet(brev, behandling, pdf, brukerTokenInfo) }
}

private fun opprettBrevData(brev: Brev, behandling: Behandling): Pair<EtterlatteBrevKode, BrevData> =
private fun opprettBrevData(brev: Brev, behandling: Behandling): BrevData =
when (brev.prosessType) {
AUTOMATISK -> BrevDataMapper.fra(behandling)
MANUELL -> {
val payload = requireNotNull(db.hentBrevPayload(brev.id))

// TODO: Map brevkode
Pair(EtterlatteBrevKode.OMS_OPPHOER_MANUELL, ManueltBrevData(payload.elements))
AUTOMATISK -> {
when (behandling.revurderingsaarsak) {
RevurderingAarsak.OMGJOERING_AV_FARSKAP -> manueltBrevData(brev)
RevurderingAarsak.ADOPSJON -> manueltBrevData(brev)
else -> BrevDataMapper.brevData(behandling)
}
}
MANUELL -> manueltBrevData(brev)
}

private fun opprettInnhold(behandling: Behandling, prosessType: BrevProsessType): BrevInnhold {
private fun manueltBrevData(brev: Brev) = ManueltBrevData(requireNotNull(db.hentBrevPayload(brev.id)).elements)

private suspend fun opprettInnhold(behandling: Behandling, prosessType: BrevProsessType): BrevInnhold {
val tittel = "Vedtak om ${behandling.vedtak.type.name.lowercase()}"

val payload = when (prosessType) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hadde det gitt mening med en tredje prosesstype for brev? I denne og forrige when er det basically en sjekk på om du er en spesiell versjon av automatisk i kraft av revurderingsårsak, men det kunne vært basert på f.eks. prosessType REDIGERBAR_AUTOMATISK e.l.

Har ikke oversikt over de andre stedene det evt. må håndteres da :p

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, det er ein fristande ide. Samtidig trur eg at vi etter kvart skal over på redigerbar automatisk for alle brev, så usikker på om det vil trengs på sikt 🤔

AUTOMATISK -> null
AUTOMATISK -> {
when (behandling.revurderingsaarsak) {
RevurderingAarsak.OMGJOERING_AV_FARSKAP, RevurderingAarsak.ADOPSJON -> {
hentRedigerbarTekstFraBrevbakeren(behandling)
}

else -> null
}
}

MANUELL -> SlateHelper.hentInitiellPayload(behandling).flettInn(behandling)
}

Expand Down Expand Up @@ -167,4 +181,15 @@ class VedtaksbrevService(
.let { Pdf(it) }
.also { logger.info("Generert brev (id=$brevID) med størrelse: ${it.bytes.size}") }
}

private suspend fun hentRedigerbarTekstFraBrevbakeren(behandling: Behandling): Slate {
val request = BrevbakerRequest.fra(
BrevDataMapper.brevKode(behandling, AUTOMATISK).redigering,
BrevDataMapper.brevData(behandling),
behandling,
adresseService.hentAvsender(behandling.vedtak)
)
val brevbakerResponse = brevbaker.genererJSON(request)
return BlockTilSlateKonverterer.konverter(brevbakerResponse)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import no.nav.etterlatte.libs.common.logging.getXCorrelationId
import no.nav.etterlatte.libs.common.objectMapper
import no.nav.etterlatte.libs.common.toJson
import no.nav.pensjon.brevbaker.api.model.LetterMetadata
import no.nav.pensjon.brevbaker.api.model.RenderedJsonLetter
import org.slf4j.LoggerFactory
import kotlin.time.DurationUnit
import kotlin.time.ExperimentalTime
Expand Down Expand Up @@ -51,6 +52,22 @@ class BrevbakerKlient(private val client: HttpClient, private val apiUrl: String
} catch (ex: Exception) {
throw BrevbakerException("Feil ved kall til brevbaker", ex)
}

@OptIn(ExperimentalTime::class)
suspend fun genererJSON(brevRequest: BrevbakerRequest): RenderedJsonLetter = try {
measureTimedValue {
client.post("$apiUrl/etterlatte/json") {
contentType(ContentType.Application.Json)
header("Nav_Call_Id", getXCorrelationId())
sebassonav marked this conversation as resolved.
Show resolved Hide resolved
setBody(brevRequest.toJsonNode())
}.body<RenderedJsonLetter>()
}.let { (result, duration) ->
logger.info("Fullført brevbaker JSON OK (${duration.toString(DurationUnit.SECONDS, 2)})")
result
}
} catch (ex: Exception) {
throw BrevbakerException("Feil ved kall til brevbaker", ex)
}
}

class BrevbakerException(msg: String, cause: Throwable) : Exception(msg, cause)
Expand All @@ -59,4 +76,6 @@ class BrevbakerPdfResponse(val base64pdf: String, val letterMetadata: LetterMeta

class BrevbakerHTMLResponse(val html: Map<String, String>, val letterMetadata: LetterMetadata)

class BrevbakerJSONResponse(val json: RenderedJsonLetter, val letterMetadata: LetterMetadata)

private fun BrevbakerRequest.toJsonNode(): JsonNode = objectMapper.readTree(toJson())
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ enum class EtterlatteBrevKode {
OMS_INNVILGELSE_AUTO,
OMS_INNVILGELSE_MANUELL,
OMS_OPPHOER_MANUELL,
BARNEPENSJON_REVURDERING_SOESKENJUSTERING,
BARNEPENSJON_REVURDERING_ADOPSJON,
BARNEPENSJON_REVURDERING_OMGJOERING_AV_FARSKAP,
BARNEPENSJON_REVURDERING_ADOPSJON
BARNEPENSJON_REVURDERING_OPPHOER,
BARNEPENSJON_REVURDERING_SOESKENJUSTERING
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package no.nav.etterlatte.brev.brevbaker

import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import no.nav.pensjon.brevbaker.api.model.RenderedJsonLetter

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "type",
defaultImpl = Void::class
)
@JsonSubTypes(
JsonSubTypes.Type(value = RenderedJsonLetter.Block.Title1::class, name = "TITLE1"),
JsonSubTypes.Type(value = RenderedJsonLetter.Block.Title2::class, name = "TITLE2"),
JsonSubTypes.Type(value = RenderedJsonLetter.Block.Paragraph::class, name = "PARAGRAPH")
)
interface BrevbakerJSONBlockMixIn

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "type",
defaultImpl = Void::class
)
@JsonSubTypes(
JsonSubTypes.Type(value = RenderedJsonLetter.ParagraphContent.ItemList::class, name = "ITEM_LIST"),
JsonSubTypes.Type(value = RenderedJsonLetter.ParagraphContent.Text.Literal::class, name = "LITERAL"),
JsonSubTypes.Type(value = RenderedJsonLetter.ParagraphContent.Text.Variable::class, name = "VARIABLE")
)
interface BrevbakerJSONParagraphMixIn
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,84 @@ package no.nav.etterlatte.brev.model

import no.nav.etterlatte.brev.behandling.Behandling
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode.BARNEPENSJON_AVSLAG
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode.BARNEPENSJON_INNVILGELSE
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode.BARNEPENSJON_REVURDERING_ADOPSJON
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode.BARNEPENSJON_REVURDERING_OMGJOERING_AV_FARSKAP
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode.BARNEPENSJON_REVURDERING_OPPHOER
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode.BARNEPENSJON_REVURDERING_SOESKENJUSTERING
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode.OMS_INNVILGELSE_AUTO
import no.nav.etterlatte.brev.brevbaker.EtterlatteBrevKode.OMS_OPPHOER_MANUELL
import no.nav.etterlatte.libs.common.behandling.RevurderingAarsak
import no.nav.etterlatte.libs.common.behandling.SakType
import no.nav.etterlatte.libs.common.vedtak.VedtakType

object BrevDataMapper {
fun fra(
behandling: Behandling
): Pair<EtterlatteBrevKode, BrevData> = when (behandling.sakType) {

fun brevKode(behandling: Behandling, brevProsessType: BrevProsessType) = when (brevProsessType) {
BrevProsessType.AUTOMATISK -> brevKodeAutomatisk(behandling)
BrevProsessType.MANUELL -> BrevkodePar(OMS_OPPHOER_MANUELL)
}

private fun brevKodeAutomatisk(behandling: Behandling): BrevkodePar = when (behandling.sakType) {
SakType.BARNEPENSJON -> {
when (val vedtakType = behandling.vedtak.type) {
VedtakType.INNVILGELSE -> Pair(
EtterlatteBrevKode.BARNEPENSJON_INNVILGELSE,
InnvilgetBrevData.fra(
behandling
)
)
VedtakType.AVSLAG -> Pair(
EtterlatteBrevKode.BARNEPENSJON_AVSLAG,
AvslagBrevData.fra(behandling)
)
VedtakType.INNVILGELSE -> BrevkodePar(BARNEPENSJON_INNVILGELSE)
VedtakType.AVSLAG -> BrevkodePar(BARNEPENSJON_AVSLAG)
VedtakType.ENDRING -> when (behandling.revurderingsaarsak) {
RevurderingAarsak.SOESKENJUSTERING -> Pair(
EtterlatteBrevKode.BARNEPENSJON_REVURDERING_SOESKENJUSTERING,
SoeskenjusteringRevurderingBrevdata.fra(behandling)
)
RevurderingAarsak.SOESKENJUSTERING -> BrevkodePar(BARNEPENSJON_REVURDERING_SOESKENJUSTERING)
else -> TODO("Revurderingsbrev for ${behandling.revurderingsaarsak} er ikke støttet")
}

VedtakType.OPPHOER -> when (behandling.revurderingsaarsak) {
RevurderingAarsak.ADOPSJON -> Pair(
EtterlatteBrevKode.BARNEPENSJON_REVURDERING_ADOPSJON,
AdopsjonRevurderingBrevdata.fra(behandling)
)
RevurderingAarsak.OMGJOERING_AV_FARSKAP -> Pair(
EtterlatteBrevKode.BARNEPENSJON_REVURDERING_OMGJOERING_AV_FARSKAP,
OmgjoeringAvFarskapRevurderingBrevdata.fra(behandling)
)
RevurderingAarsak.ADOPSJON ->
BrevkodePar(BARNEPENSJON_REVURDERING_ADOPSJON, BARNEPENSJON_REVURDERING_OPPHOER)

RevurderingAarsak.OMGJOERING_AV_FARSKAP ->
BrevkodePar(BARNEPENSJON_REVURDERING_OMGJOERING_AV_FARSKAP, BARNEPENSJON_REVURDERING_OPPHOER)

else -> TODO("Vedtakstype er ikke støttet: $vedtakType")
}
}
}

SakType.OMSTILLINGSSTOENAD -> {
when (val vedtakType = behandling.vedtak.type) {
VedtakType.INNVILGELSE -> Pair(
EtterlatteBrevKode.OMS_INNVILGELSE_AUTO,
InnvilgetBrevData.fra(
behandling
)
)
VedtakType.INNVILGELSE -> BrevkodePar(OMS_INNVILGELSE_AUTO)
VedtakType.AVSLAG -> TODO("Vedtakstype er ikke støttet: $vedtakType")
VedtakType.ENDRING -> TODO("Vedtakstype er ikke støttet: $vedtakType")
VedtakType.OPPHOER -> TODO("Vedtakstype er ikke støttet: $vedtakType")
}
}
}

fun brevData(behandling: Behandling): BrevData = when (behandling.sakType) {
SakType.BARNEPENSJON -> {
when (val vedtakType = behandling.vedtak.type) {
VedtakType.INNVILGELSE -> InnvilgetBrevData.fra(behandling)
VedtakType.AVSLAG -> AvslagBrevData.fra(behandling)
VedtakType.ENDRING -> when (behandling.revurderingsaarsak) {
RevurderingAarsak.SOESKENJUSTERING -> SoeskenjusteringRevurderingBrevdata.fra(behandling)
else -> TODO("Revurderingsbrev for ${behandling.revurderingsaarsak} er ikke støttet")
}

VedtakType.OPPHOER -> when (behandling.revurderingsaarsak) {
RevurderingAarsak.ADOPSJON -> AdopsjonRevurderingBrevdata.fra(behandling)
RevurderingAarsak.OMGJOERING_AV_FARSKAP -> OmgjoeringAvFarskapRevurderingBrevdata.fra(behandling)
else -> TODO("Vedtakstype er ikke støttet: $vedtakType")
}
}
}

SakType.OMSTILLINGSSTOENAD -> {
when (val vedtakType = behandling.vedtak.type) {
VedtakType.INNVILGELSE -> InnvilgetBrevData.fra(behandling)
VedtakType.AVSLAG -> TODO("Vedtakstype er ikke støttet: $vedtakType")
VedtakType.ENDRING -> TODO("Vedtakstype er ikke støttet: $vedtakType")
VedtakType.OPPHOER -> TODO("Vedtakstype er ikke støttet: $vedtakType")
}
}
}

data class BrevkodePar(val redigering: EtterlatteBrevKode, val ferdigstilling: EtterlatteBrevKode = redigering)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ data class Slate(
@JsonValue val elements: List<Element> = emptyList()
) {
fun flettInn(behandling: Behandling): Slate = when (behandling.revurderingsaarsak) {
RevurderingAarsak.ADOPSJON -> erstatt(this, BrevDataMapper.fra(behandling).second)
RevurderingAarsak.ADOPSJON -> erstatt(this, BrevDataMapper.brevData(behandling))
Copy link
Contributor

Choose a reason for hiding this comment

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

Ser at omgjøring av farskap er litt med og litt ikke med i denne PR'en -- hadde vært lettere å følge med hvis det var alt eller ingenting for den revurderingsårsaken

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Godt poeng! Noterer det bak øyret til neste gong.

else -> this
}

Expand Down
Loading