Skip to content

Commit

Permalink
Legg til bedre logging ved mapping-feil for simulering
Browse files Browse the repository at this point in the history
  • Loading branch information
hestad committed Oct 23, 2023
1 parent c402df2 commit cd9b892
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 151 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package no.nav.su.se.bakover.client.oppdrag.simulering

import arrow.core.Either
import arrow.core.getOrElse
import no.nav.su.se.bakover.common.domain.Saksnummer
import no.nav.su.se.bakover.common.infrastructure.xml.xmlMapper
import no.nav.su.se.bakover.common.person.Fnr
import no.nav.su.se.bakover.common.sikkerLogg
import no.nav.su.se.bakover.common.tid.periode.Måned
import no.nav.su.se.bakover.common.tid.periode.Periode
import no.nav.su.se.bakover.domain.oppdrag.Fagområde
import no.nav.su.se.bakover.domain.oppdrag.Utbetaling
import no.nav.su.se.bakover.domain.oppdrag.simulering.SimulerUtbetalingRequest
import no.nav.su.se.bakover.domain.oppdrag.simulering.SimuleringFeilet
import no.nav.system.os.entiteter.beregningskjema.BeregningStoppnivaa
import no.nav.system.os.entiteter.beregningskjema.BeregningStoppnivaaDetaljer
import no.nav.system.os.entiteter.beregningskjema.BeregningsPeriode
import no.nav.system.os.tjenester.simulerfpservice.simulerfpserviceservicetypes.SimulerBeregningRequest
import no.nav.system.os.tjenester.simulerfpservice.simulerfpservicegrensesnitt.SimulerBeregningRequest
import no.nav.system.os.tjenester.simulerfpservice.simulerfpserviceservicetypes.SimulerBeregningResponse
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import økonomi.domain.KlasseKode
import økonomi.domain.KlasseType
Expand All @@ -22,57 +28,92 @@ import økonomi.domain.simulering.SimulertUtbetaling
import java.time.Clock
import java.time.LocalDate

private val log = LoggerFactory.getLogger("SimuleringResponseMapper")
private val defaultLog = LoggerFactory.getLogger("SimuleringResponseMapper")

/**
* https://confluence.adeo.no/display/OKSY/Returdata+fra+Oppdragssystemet+til+fagrutinen
*
* @param log For testing.
* @param sikkerLogg For testing.
*/
internal class SimuleringResponseMapper private constructor(
val simulering: Simulering,
val clock: Clock,
) {

constructor(
rawResponse: String,
oppdragResponse: SimulerBeregningResponse,
clock: Clock,
saksnummer: Saksnummer,
) : this(oppdragResponse.toSimulering(saksnummer, rawResponse), clock)

constructor(
utbetaling: Utbetaling,
simuleringsperiode: SimulerBeregningRequest.SimuleringsPeriode,
clock: Clock,
) : this(
utbetaling.mapTomResponsFraOppdrag(
simuleringsperiode = simuleringsperiode.toPeriode(),
clock = clock,
),
clock,
)
}

private fun SimulerBeregningRequest.SimuleringsPeriode.toPeriode(): Periode {
return Periode.create(LocalDate.parse(datoSimulerFom), LocalDate.parse(datoSimulerTom))
fun SimulerBeregningResponse?.toSimulering(
request: SimulerUtbetalingRequest,
clock: Clock,
soapRequest: SimulerBeregningRequest,
log: Logger = defaultLog,
sikkerLogg: Logger = no.nav.su.se.bakover.common.sikkerLogg,
): Either<SimuleringFeilet.TekniskFeil, Simulering> {
val saksnummer = request.utbetaling.saksnummer
// TODO jah: Ideelt sett burde vi fått tak i den rå XMLen, men CXF gjør det ikke så lett for oss (OutInterceptor).
// Siden dette er javaklasser uten toString() så serialiserer vi de før vi lagrer/logger.
val rawResponse: String? = this?.let {
serializeSoapMessage(log = log, sikkerLogg = sikkerLogg, message = this, request = request)
}
val rawRequest: String = serializeSoapMessage(log = log, sikkerLogg = sikkerLogg, message = soapRequest, request = request)
return Either.catch {
if (this == null) {
request.utbetaling.mapTomResponsFraOppdrag(
simuleringsperiode = request.simuleringsperiode,
clock = clock,
)
} else {
Simulering(
gjelderId = Fnr(simulering.gjelderId),
gjelderNavn = simulering.gjelderNavn.trim(),
datoBeregnet = LocalDate.parse(simulering.datoBeregnet),
nettoBeløp = simulering.belop.toInt(),
måneder = simulering.beregningsPeriode.map {
it.toSimulertPeriode(
saksnummer = saksnummer,
request = request,
rawRequest = rawRequest,
rawResponse = rawResponse!!,
log = log,
)
},
rawResponse = rawResponse!!,
)
}
}.mapLeft { throwable ->
log.error("Kunne ikke mappe SimulerBeregningResponse til Simulering for saksnummer $saksnummer. Se sikkerlogg for stacktrace og context.")
sikkerLogg.error(
"Kunne ikke mappe SimulerBeregningResponse til Simulering for saksnummer $saksnummer. Response: $rawResponse, SoapRequest: $rawRequest, Request: $request",
throwable,
)
SimuleringFeilet.TekniskFeil
}
}

private fun SimulerBeregningResponse.toSimulering(
saksnummer: Saksnummer,
rawResponse: String,
): Simulering {
return Simulering(
gjelderId = Fnr(simulering.gjelderId),
gjelderNavn = simulering.gjelderNavn.trim(),
datoBeregnet = LocalDate.parse(simulering.datoBeregnet),
nettoBeløp = simulering.belop.toInt(),
måneder = simulering.beregningsPeriode.map { it.toSimulertPeriode(saksnummer, rawResponse) },
rawResponse = rawResponse,
)
private fun serializeSoapMessage(
log: Logger,
sikkerLogg: Logger,
message: Any,
request: SimulerUtbetalingRequest,
): String {
return Either.catch {
xmlMapper.writeValueAsString(message)
}.getOrElse { throwable ->
"Kunne ikke serialisere ${message.javaClass.simpleName} til XML, se sikkerlogg for stacktrace og context. Lagrer denne strengen istedenfor.".also { errorMessage ->
log.error(errorMessage)
sikkerLogg.error(
"Kunne ikke serialisere ${message.javaClass.simpleName} til XML. Request: $request",
throwable,
)
}
}
}

/**
* @param rawResponse Brukes kun for logging.
* @param request Brukes kun for logging.
* @param rawRequest Brukes kun for logging.
*/
private fun BeregningsPeriode.toSimulertPeriode(
saksnummer: Saksnummer,
rawResponse: String,
request: SimulerUtbetalingRequest,
rawRequest: String,
log: Logger,
): SimulertMåned {
return SimulertMåned(
måned = Måned.fra(LocalDate.parse(periodeFom), LocalDate.parse(periodeTom)),
Expand All @@ -87,10 +128,12 @@ private fun BeregningsPeriode.toSimulertPeriode(
fagsystemId,
)
sikkerLogg.debug(
"Simuleringen filtrerte vekk uønsket fagsystemid for saksnummer {}. fagsystemId={}. rawResponse: {}",
"Simuleringen filtrerte vekk uønsket fagsystemid for saksnummer {}. fagsystemId={}. soapResponse: {}, soapRequest: {}, request: {}",
saksnummer,
fagsystemId,
rawResponse,
rawRequest,
request,
)
}
}
Expand All @@ -104,30 +147,32 @@ private fun BeregningsPeriode.toSimulertPeriode(
kodeFagomraade,
)
sikkerLogg.debug(
"Simuleringen filtrerte vekk uønsket kodeFagomraade for saksnummer {}. kodeFagomraade={}. rawResponse: {}",
"Simuleringen filtrerte vekk uønsket kodeFagomraade for saksnummer {}. kodeFagomraade={}. soapResponse: {}, soapRequest: {}, request: {}",
saksnummer,
kodeFagomraade,
rawResponse,
rawRequest,
request,
)
}
}
}.map {
it.toSimulertUtbetaling()
it.toSimulertUtbetaling(log = log)
}.let {
when {
it.isEmpty() -> null
it.size > 1 -> throw IllegalStateException("Simulering inneholder flere utbetalinger for samme sak $saksnummer. Se sikkerlogg for flere detaljer og feilmelding.").also {
sikkerLogg.error("Simulering inneholder flere utbetalinger for samme sak $saksnummer. rawResponse: $rawResponse")
}

// Vi fanger og logger exceptions ytterst.
it.size > 1 -> throw IllegalStateException("Simulering inneholder flere utbetalinger for samme sak $saksnummer.")
else -> it.first()
}
},
)
}

private fun BeregningStoppnivaa.toSimulertUtbetaling() =
SimulertUtbetaling(
private fun BeregningStoppnivaa.toSimulertUtbetaling(
log: Logger,
): SimulertUtbetaling {
return SimulertUtbetaling(
fagSystemId = fagsystemId.trim(),
utbetalesTilNavn = utbetalesTilNavn.trim(),
utbetalesTilId = Fnr(utbetalesTilId),
Expand All @@ -152,6 +197,7 @@ private fun BeregningStoppnivaa.toSimulertUtbetaling() =
}
.map { it.toSimulertDetalj() },
)
}

private fun BeregningStoppnivaaDetaljer.toSimulertDetalj() =
SimulertDetaljer(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package no.nav.su.se.bakover.client.oppdrag.simulering

import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.left
import arrow.core.right
import com.ctc.wstx.exc.WstxEOFException
import no.nav.su.se.bakover.common.infrastructure.xml.xmlMapper
import no.nav.su.se.bakover.common.serialize
import no.nav.su.se.bakover.common.sikkerLogg
import no.nav.su.se.bakover.domain.oppdrag.simulering.SimulerUtbetalingRequest
Expand All @@ -14,6 +11,7 @@ import no.nav.su.se.bakover.domain.oppdrag.simulering.SimuleringFeilet
import no.nav.system.os.eksponering.simulerfpservicewsbinding.SimulerBeregningFeilUnderBehandling
import no.nav.system.os.eksponering.simulerfpservicewsbinding.SimulerFpService
import no.nav.system.os.tjenester.simulerfpservice.simulerfpservicegrensesnitt.SimulerBeregningRequest
import no.nav.system.os.tjenester.simulerfpservice.simulerfpserviceservicetypes.SimulerBeregningResponse
import org.slf4j.LoggerFactory
import økonomi.domain.simulering.Simulering
import java.net.SocketException
Expand All @@ -34,26 +32,13 @@ internal class SimuleringSoapClient(
): Either<SimuleringFeilet, Simulering> {
val simulerRequest = SimuleringRequestBuilder(request).build()
return try {
simulerFpService.simulerBeregning(simulerRequest)?.response?.let {
// TODO jah: Ideelt sett burde vi fått tak i den rå XMLen, men CXF gjør det ikke så lett for oss (OutInterceptor).
val rawResponse: String = Either.catch {
xmlMapper.writeValueAsString(it)
}.getOrElse {
log.error("Kunne ikke simulere SimulerBeregningResponse til xml, se sikkerlogg for stacktrace.")
sikkerLogg.error("Kunne ikke simulere SimulerBeregningResponse til xml.", it)
"Kunne ikke simulere SimulerBeregningResponse til xml, se sikkerlogg for stacktrace."
}
SimuleringResponseMapper(
rawResponse = rawResponse,
oppdragResponse = it,
simulerFpService.simulerBeregning(simulerRequest)?.response.let { response: SimulerBeregningResponse? ->
response.toSimulering(
request = request,
soapRequest = simulerRequest,
clock = clock,
saksnummer = request.utbetaling.saksnummer,
).simulering.right()
} ?: SimuleringResponseMapper(
utbetaling = request.utbetaling,
simuleringsperiode = simulerRequest.request.simuleringsPeriode,
clock = clock,
).simulering.right()
)
}
} catch (e: SimulerBeregningFeilUnderBehandling) {
log.warn("Funksjonell feil ved simulering, se sikkerlogg for detaljer", e)
sikkerLogg.warn(
Expand Down
Loading

0 comments on commit cd9b892

Please sign in to comment.