From c3d8c86498bb66bd2205aa876b2c7bf6e7f3844c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristen=20H=C3=A6rum?= Date: Mon, 25 Nov 2024 14:12:05 +0100 Subject: [PATCH] =?UTF-8?q?Feilh=C3=A5ndtering=20n=C3=A5r=20bestllinger=20?= =?UTF-8?q?henger=20(#3673)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Handle timeouts in WebClientFilter and ArenaForvalterClient Add TimeoutException handling in WebClientFilter for improved error messaging and status codes. Update ArenaForvalterClient to include timeout on WebClient calls with a 30-second limit, and provide detailed error messages on timeout exceptions. * Add Pensjonforvalter integration and enhance configuration Introduce automated tests for PensjonforvalterHelper. Create PensjonPdlPersonService for fetching extended person data from PDL. Update ApplicationConfig to include a configurable client timeout. Expand RsDollyBestilling to include a check for Pensjon data. Consolidate logic in PensjonforvalterClient by leveraging new services and managing timeouts effectively. Ensure proper handling of related entities and integrate error handling for improved resilience. * Refactor service clients to use ApplicationConfig for timeouts Replaced hardcoded timeout values with dynamic values from ApplicationConfig in PersonServiceClient. Additionally, restructured PensjonforvalterClient to include ApplicationConfig and reordered dependencies for consistency. * Add ApplicationConfig mock to ArenaForvalterClientTest Previously, the ApplicationConfig was not being mocked in tests. This addition ensures that the ApplicationConfig dependencies are properly handled during test runs, improving the accuracy and coverage of the unit tests. * Fix TPS messaging status handling and client timeout Refine logic for filtering TPS messaging status to exclude specific messages. Add application-configured timeout and error handling in TpsMessagingClient for better fault tolerance. * Add error handling and timeout to AaregClient Introduce a timeout mechanism to limit client response time and add error handling to manage potential issues gracefully. Updated dependencies and refactored code for improved readability and maintenance. * Add client timeout mock to `ArenaForvalterClientTest` Included mock setup for `applicationConfig.getClientTimeout()` returning 30L, ensuring consistent behavior in tests. Refactored test `gjenopprett_TekniskFeil` to use `StepVerifier` for reactive stream verification. * Refactor Dokarkiv interface to use Mono instead of Flux This commit refactors the Dokarkiv modules to shift from using Flux to Mono for single response handling. This change simplifies the code, improves performance, and ensures proper error handling with the introduction of a timeout mechanism. The refactor also introduces better logging and error reporting functionalities. * Refactor InntektsmeldingClient to improve error handling Revised the gjenopprett method in InntektsmeldingClient to enhance error handling and timeout management. Introduced filtering and mapping for environments, and added a new isExistInntekstsmelding method in RsDollyBestilling to streamline checks. * Add timeout and error handling in SykemeldingClient Configured a timeout feature based on the presence of synthetic sykemelding and added error handling to provide more informative error responses. This improves client resilience and clarity in case of failures. --- .../dolly/bestilling/aareg/AaregClient.java | 17 +- .../arenaforvalter/ArenaForvalterClient.java | 16 +- .../arenaforvalter/utils/ArenaStatusUtil.java | 13 +- .../bestilling/dokarkiv/DokarkivClient.java | 74 ++- .../bestilling/dokarkiv/DokarkivConsumer.java | 9 +- .../dokarkiv/command/DokarkivPostCommand.java | 7 +- .../InntektsmeldingClient.java | 57 +- .../InntektsmeldingMappingStrategy.java | 1 + .../PensjonforvalterClient.java | 591 +----------------- .../service/PensjonPdlPersonService.java | 124 ++++ .../service/PensjonPensjonsdataService.java | 185 ++++++ .../service/PensjonPersondataService.java | 87 +++ .../service/PensjonVedtakService.java | 150 +++++ .../utils/PensjonforvalterHelper.java | 93 +++ .../utils/PensjonforvalterUtils.java | 72 +++ .../personservice/PersonServiceClient.java | 28 +- .../sykemelding/SykemeldingClient.java | 8 + .../TpsMessagingClient.java | 20 +- .../nav/dolly/config/ApplicationConfig.java | 6 + .../domain/resultset/RsDollyBestilling.java | 10 + .../dolly/domain/resultset/SystemTyper.java | 5 +- .../errorhandling/ErrorStatusDecoder.java | 20 +- ...estillingPensjonforvalterStatusMapper.java | 5 +- .../BestillingTpsMessagingStatusMapper.java | 2 +- .../src/main/resources/application-local.yaml | 5 + .../src/main/resources/application.yaml | 3 + .../bestilling/aareg/AaregClientTest.java | 27 +- .../ArenaForvalterClientTest.java | 20 +- .../PensjonPensjonsdataServiceTest.java} | 553 ++++++---------- .../utils/PensjonforvalterHelperTest.java | 56 ++ .../reactivecore/utils/WebClientFilter.java | 22 +- 31 files changed, 1229 insertions(+), 1057 deletions(-) create mode 100644 apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPdlPersonService.java create mode 100644 apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataService.java create mode 100644 apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPersondataService.java create mode 100644 apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonVedtakService.java create mode 100644 apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterHelper.java create mode 100644 apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterUtils.java rename apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/{PensjonforvalterClientTest.java => service/PensjonPensjonsdataServiceTest.java} (50%) create mode 100644 apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterHelperTest.java diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/aareg/AaregClient.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/aareg/AaregClient.java index c01e025da1d..116483bcbfc 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/aareg/AaregClient.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/aareg/AaregClient.java @@ -8,6 +8,7 @@ import no.nav.dolly.bestilling.ClientRegister; import no.nav.dolly.bestilling.aareg.amelding.AmeldingService; import no.nav.dolly.bestilling.aareg.domain.ArbeidsforholdRespons; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.jpa.BestillingProgress; import no.nav.dolly.domain.jpa.Bruker; import no.nav.dolly.domain.resultset.RsDollyUtvidetBestilling; @@ -16,11 +17,13 @@ import no.nav.dolly.errorhandling.ErrorStatusDecoder; import no.nav.dolly.util.TransactionHelperService; import no.nav.testnav.libs.dto.aareg.v1.Arbeidsforhold; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import no.nav.testnav.libs.securitycore.domain.AccessToken; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; import java.time.YearMonth; import java.util.List; import java.util.Set; @@ -49,9 +52,10 @@ public class AaregClient implements ClientRegister { private static final String SYSTEM = "AAREG"; private final AaregConsumer aaregConsumer; + private final AmeldingService ameldingService; + private final ApplicationConfig applicationConfig; private final ErrorStatusDecoder errorStatusDecoder; private final MapperFacade mapperFacade; - private final AmeldingService ameldingService; private final TransactionHelperService transactionHelperService; @Override @@ -66,7 +70,7 @@ public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, Dolly var miljoerTrygg = new AtomicReference<>(miljoer); var initStatus = miljoer.stream() - .map(miljo -> String.format("%s:%s", miljo, getInfoVenter(SYSTEM))) + .map(miljo -> "%s:%s".formatted(miljo, getInfoVenter(SYSTEM))) .collect(Collectors.joining(",")); transactionHelperService.persister(progress, BestillingProgress::getAaregStatus, @@ -83,11 +87,20 @@ public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, Dolly return ameldingService.sendAmelding(bestilling, dollyPerson, miljoerTrygg.get()); } }) + .timeout(Duration.ofSeconds(applicationConfig.getClientTimeout())) + .onErrorResume(error -> getErrors(error, miljoerTrygg.get())) .map(status -> futurePersist(progress, status)); } return Flux.empty(); } + private Flux getErrors(Throwable error, Set miljoer) { + + return Flux.just(miljoer.stream() + .map(miljoe -> "%s:Feil= %s".formatted(miljoe, ErrorStatusDecoder.encodeStatus(WebClientFilter.getMessage(error)))) + .collect(Collectors.joining(","))); + } + @Override public void release(List identer) { diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/arenaforvalter/ArenaForvalterClient.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/arenaforvalter/ArenaForvalterClient.java index c3323e5fa25..44041c8fbff 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/arenaforvalter/ArenaForvalterClient.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/arenaforvalter/ArenaForvalterClient.java @@ -10,23 +10,27 @@ import no.nav.dolly.bestilling.arenaforvalter.service.ArenaDagpengerService; import no.nav.dolly.bestilling.arenaforvalter.service.ArenaStansYtelseService; import no.nav.dolly.bestilling.arenaforvalter.utils.ArenaEksisterendeVedtakUtil; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.jpa.BestillingProgress; import no.nav.dolly.domain.resultset.RsDollyUtvidetBestilling; import no.nav.dolly.domain.resultset.arenaforvalter.Arenadata; import no.nav.dolly.domain.resultset.dolly.DollyPerson; import no.nav.dolly.util.IdentTypeUtil; import no.nav.dolly.util.TransactionHelperService; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; import java.util.List; import java.util.stream.Collectors; import static java.util.Objects.nonNull; import static no.nav.dolly.bestilling.arenaforvalter.utils.ArenaStatusUtil.AAP; import static no.nav.dolly.bestilling.arenaforvalter.utils.ArenaStatusUtil.AAP115; +import static no.nav.dolly.bestilling.arenaforvalter.utils.ArenaStatusUtil.ANDREFEIL; import static no.nav.dolly.bestilling.arenaforvalter.utils.ArenaStatusUtil.BRUKER; import static no.nav.dolly.bestilling.arenaforvalter.utils.ArenaStatusUtil.DAGPENGER; import static no.nav.dolly.bestilling.arenaforvalter.utils.ArenaStatusUtil.fmtResponse; @@ -41,13 +45,14 @@ public class ArenaForvalterClient implements ClientRegister { private static final String MILJOE_FMT = "%s$BRUKER= %s"; private static final String SYSTEM = "Arena"; - private final ArenaForvalterConsumer arenaForvalterConsumer; - private final TransactionHelperService transactionHelperService; - private final ArenaBrukerService arenaBrukerService; + private final ApplicationConfig applicationConfig; private final ArenaAap115Service arenaAap115Service; private final ArenaAapService arenaAapService; + private final ArenaBrukerService arenaBrukerService; private final ArenaDagpengerService arenaDagpengerService; + private final ArenaForvalterConsumer arenaForvalterConsumer; private final ArenaStansYtelseService arenaStansYtelseService; + private final TransactionHelperService transactionHelperService; @Override public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, DollyPerson dollyPerson, BestillingProgress progress, boolean isOpprettEndre) { @@ -66,6 +71,9 @@ public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, Dolly BestillingProgress::setArenaforvalterStatus, initStatus); }) .flatMap(miljoer -> doArenaOpprett(ordre, dollyPerson.getIdent(), miljoer) + .timeout(Duration.ofSeconds(applicationConfig.getClientTimeout())) + .onErrorResume(error -> + Mono.just(fmtResponse(miljoer, ANDREFEIL, WebClientFilter.getMessage(error)))) .map(status -> futurePersist(progress, status)))); } @@ -94,7 +102,7 @@ private Mono doArenaOpprett(Arenadata arenadata, String ident, List fmtResponse(miljoe, DAGPENGER, dagpengerStatus)) )); - } else { + } else { return Flux.just(fmtResponse(miljoe, BRUKER, NOT_SUPPORTED)); } }) diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/arenaforvalter/utils/ArenaStatusUtil.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/arenaforvalter/utils/ArenaStatusUtil.java index e3fa29f5e61..7df12b55b4c 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/arenaforvalter/utils/ArenaStatusUtil.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/arenaforvalter/utils/ArenaStatusUtil.java @@ -11,6 +11,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.Collection; import java.util.Map; import java.util.stream.Collectors; @@ -29,6 +30,7 @@ public class ArenaStatusUtil { public static final String AAP115 = "AAP115"; public static final String AAP = "AAP"; public static final String DAGPENGER = "DAGP"; + public static final String ANDREFEIL = "ARENA Oppretting Feil="; public static Mono getDagpengerStatus(ArenaNyeDagpengerResponse response, ErrorStatusDecoder errorStatusDecoder) { @@ -37,7 +39,7 @@ public static Mono getDagpengerStatus(ArenaNyeDagpengerResponse response .map(status -> errorStatusDecoder.getErrorText(response.getStatus(), getMessage(response.getFeilmelding()))), Flux.fromIterable(response.getNyeDagp()) .filter(nyDagP -> nonNull(nyDagP.getNyeDagpResponse())) - .map(nyDagP -> "JA".equals(nyDagP.getNyeDagpResponse().getUtfall()) ? + .map(nyDagP -> "JA".equals(nyDagP.getNyeDagpResponse().getUtfall()) ? "OK" : encodeStatus(ArenaUtils.AVSLAG + nyDagP.getNyeDagpResponse().getBegrunnelse())) .collect(Collectors.joining()), @@ -78,9 +80,16 @@ public static Mono getAapStatus(AapResponse response, ErrorStatusDecoder } } + public static String fmtResponse(Collection miljoer, String system, String status) { + + return miljoer.stream() + .map(miljo -> fmtResponse(miljo, system, status)) + .collect(Collectors.joining(",")); + } + public static String fmtResponse(String miljoe, String system, String status) { - return String.format(MILJOE_FMT, miljoe, system, encodeStatus(status)); + return MILJOE_FMT.formatted(miljoe, system, encodeStatus(status)); } public static String getMessage(String jsonFeilmelding) { diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/DokarkivClient.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/DokarkivClient.java index c02029cb361..db73b7fd72e 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/DokarkivClient.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/DokarkivClient.java @@ -12,6 +12,7 @@ import no.nav.dolly.bestilling.dokarkiv.domain.DokarkivResponse; import no.nav.dolly.bestilling.dokarkiv.domain.JoarkTransaksjon; import no.nav.dolly.bestilling.personservice.PersonServiceConsumer; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.PdlPersonBolk; import no.nav.dolly.domain.jpa.BestillingProgress; import no.nav.dolly.domain.jpa.TransaksjonMapping; @@ -21,17 +22,21 @@ import no.nav.dolly.errorhandling.ErrorStatusDecoder; import no.nav.dolly.service.TransaksjonMappingService; import no.nav.dolly.util.TransactionHelperService; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; import java.time.LocalDateTime; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import static no.nav.dolly.domain.resultset.SystemTyper.DOKARKIV; +import static no.nav.dolly.errorhandling.ErrorStatusDecoder.encodeStatus; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -40,13 +45,14 @@ @RequiredArgsConstructor public class DokarkivClient implements ClientRegister { + private final ApplicationConfig applicationConfig; private final DokarkivConsumer dokarkivConsumer; + private final ErrorStatusDecoder errorStatusDecoder; private final MapperFacade mapperFacade; - private final TransaksjonMappingService transaksjonMappingService; private final ObjectMapper objectMapper; - private final TransactionHelperService transactionHelperService; private final PersonServiceConsumer personServiceConsumer; - private final ErrorStatusDecoder errorStatusDecoder; + private final TransactionHelperService transactionHelperService; + private final TransaksjonMappingService transaksjonMappingService; @Override public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, DollyPerson dollyPerson, BestillingProgress progress, boolean isOpprettEndre) { @@ -54,26 +60,32 @@ public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, Dolly return Flux.just(bestilling) .filter(bestilling1 -> nonNull(bestilling1.getDokarkiv())) .map(RsDollyUtvidetBestilling::getDokarkiv) - .flatMap(dokarkiv -> Flux.from(getPersonData(List.of(dollyPerson.getIdent())) - .map(person -> buildRequest(dokarkiv, person)) - .flatMap(request -> dokarkivConsumer.getEnvironments() - .flatMapIterable(env -> env) - .filter(env -> bestilling.getEnvironments().contains(env)) - .flatMap(env -> - !transaksjonMappingService.existAlready(DOKARKIV, - dollyPerson.getIdent(), env, bestilling.getId()) || isOpprettEndre ? - - dokarkivConsumer.postDokarkiv(env, request) - .map(status -> - getStatus(dollyPerson.getIdent(), - bestilling.getId(), status)) : - - Mono.just(env + ":OK") - )) - .collect(Collectors.joining(","))) + .flatMap(dokarkiv -> Flux.from(getPersonData(dollyPerson.getIdent()) + .flatMap(person -> getFilteredMiljoer(bestilling.getEnvironments()) + .flatMapMany(miljoer -> Flux.fromIterable(miljoer) + .flatMap(env -> buildRequest(dokarkiv, person) + .flatMap(request -> + !transaksjonMappingService.existAlready(DOKARKIV, + dollyPerson.getIdent(), env, bestilling.getId()) || isOpprettEndre ? + dokarkivConsumer.postDokarkiv(env, request) + .map(status -> + getStatus(dollyPerson.getIdent(), + bestilling.getId(), status)) : + Mono.just(env + ":OK") + )) + .timeout(Duration.ofSeconds(applicationConfig.getClientTimeout())) + .onErrorResume(error -> getErrors(error, miljoer)) + ))) + .collect(Collectors.joining(",")) .map(status -> futurePersist(progress, status))); } + private Flux getErrors(Throwable error, List miljoer) { + + return Flux.fromIterable(miljoer) + .map(miljoe -> "%s:%s".formatted(miljoe, encodeStatus(WebClientFilter.getMessage(error)))); + } + private ClientFuture futurePersist(BestillingProgress progress, String status) { return () -> { @@ -84,12 +96,20 @@ private ClientFuture futurePersist(BestillingProgress progress, String status) { }; } + private Mono> getFilteredMiljoer(Set miljoer) { + + return dokarkivConsumer.getEnvironments() + .flatMapMany(Flux::fromIterable) + .filter(miljoer::contains) + .collectList(); + } + private String getStatus(String ident, Long bestillingId, DokarkivResponse response) { log.info("Dokarkiv response {} for ident {}", response, ident); if (isNull(response)) { - return null; + return "UKJENT:Intet svar"; } if (isBlank(response.getFeilmelding())) { @@ -101,7 +121,7 @@ private String getStatus(String ident, Long bestillingId, DokarkivResponse respo return String.format("%s:FEIL=Teknisk feil se logg! %s", response.getMiljoe(), isNotBlank(response.getFeilmelding()) ? - ErrorStatusDecoder.encodeStatus(errorStatusDecoder.getStatusMessage(response.getFeilmelding())) : + encodeStatus(errorStatusDecoder.getStatusMessage(response.getFeilmelding())) : "UKJENT"); } } @@ -112,9 +132,9 @@ public void release(List identer) { // Sletting er ikke støttet } - private Flux getPersonData(List identer) { + private Flux getPersonData(String ident) { - return personServiceConsumer.getPdlPersoner(identer) + return personServiceConsumer.getPdlPersoner(List.of(ident)) .filter(pdlPersonBolk -> nonNull(pdlPersonBolk.getData())) .map(PdlPersonBolk::getData) .map(PdlPersonBolk.Data::getHentPersonBolk) @@ -122,12 +142,12 @@ private Flux getPersonData(List identer) { .filter(personBolk -> nonNull(personBolk.getPerson())); } - private DokarkivRequest buildRequest(RsDokarkiv rsDokarkiv, PdlPersonBolk.PersonBolk personBolk) { + private Mono buildRequest(RsDokarkiv rsDokarkiv, PdlPersonBolk.PersonBolk personBolk) { var context = new MappingContext.Factory().getContext(); context.setProperty("personBolk", personBolk); - return mapperFacade.map(rsDokarkiv, DokarkivRequest.class, context); + return Mono.just(mapperFacade.map(rsDokarkiv, DokarkivRequest.class, context)); } private void saveTransaksjonId(DokarkivResponse response, String ident, Long bestillingId, String miljoe) { @@ -140,7 +160,7 @@ private void saveTransaksjonId(DokarkivResponse response, String ident, Long bes .bestillingId(bestillingId) .transaksjonId(toJson(JoarkTransaksjon.builder() .journalpostId(response.getJournalpostId()) - .dokumentInfoId(response.getDokumenter().get(0).getDokumentInfoId()) + .dokumentInfoId(response.getDokumenter().getFirst().getDokumentInfoId()) .build())) .datoEndret(LocalDateTime.now()) .miljoe(miljoe) diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/DokarkivConsumer.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/DokarkivConsumer.java index 659e55c914b..fce6dbb03df 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/DokarkivConsumer.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/DokarkivConsumer.java @@ -13,7 +13,6 @@ import no.nav.testnav.libs.standalone.servletsecurity.exchange.TokenExchange; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.List; @@ -41,18 +40,18 @@ public DokarkivConsumer( .build(); } - @Timed(name = "providers", tags = { "operation", "dokarkiv-opprett" }) - public Flux postDokarkiv(String environment, DokarkivRequest dokarkivRequest) { + @Timed(name = "providers", tags = {"operation", "dokarkiv-opprett"}) + public Mono postDokarkiv(String environment, DokarkivRequest dokarkivRequest) { log.info("Dokarkiv sender melding for ident {} miljoe {} request {}", dokarkivRequest.getBruker().getId(), environment, dokarkivRequest); return tokenService.exchange(serverProperties) - .flatMapMany(token -> new DokarkivPostCommand(webClient, environment, dokarkivRequest, + .flatMap(token -> new DokarkivPostCommand(webClient, environment, dokarkivRequest, token.getTokenValue()).call()); } - @Timed(name = "providers", tags = { "operation", "dokarkiv_getEnvironments" }) + @Timed(name = "providers", tags = {"operation", "dokarkiv_getEnvironments"}) public Mono> getEnvironments() { return tokenService.exchange(serverProperties) diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/command/DokarkivPostCommand.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/command/DokarkivPostCommand.java index 38959d37e97..0c1025f437f 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/command/DokarkivPostCommand.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/dokarkiv/command/DokarkivPostCommand.java @@ -6,7 +6,6 @@ import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import no.nav.testnav.libs.securitycore.config.UserConstant; import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.retry.Retry; @@ -18,7 +17,7 @@ import static org.springframework.http.HttpHeaders.AUTHORIZATION; @RequiredArgsConstructor -public class DokarkivPostCommand implements Callable> { +public class DokarkivPostCommand implements Callable> { private final WebClient webClient; private final String environment; @@ -27,7 +26,7 @@ public class DokarkivPostCommand implements Callable> { @Override - public Flux call() { + public Mono call() { return webClient.post() .uri(builder -> @@ -38,7 +37,7 @@ public Flux call() { .header(UserConstant.USER_HEADER_JWT, getUserJwt()) .bodyValue(dokarkivRequest) .retrieve() - .bodyToFlux(DokarkivResponse.class) + .bodyToMono(DokarkivResponse.class) .map(response -> { response.setMiljoe(environment); return response; diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/inntektsmelding/InntektsmeldingClient.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/inntektsmelding/InntektsmeldingClient.java index 45fe3beee76..081ec641543 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/inntektsmelding/InntektsmeldingClient.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/inntektsmelding/InntektsmeldingClient.java @@ -8,8 +8,10 @@ import no.nav.dolly.bestilling.ClientFuture; import no.nav.dolly.bestilling.ClientRegister; import no.nav.dolly.bestilling.inntektsmelding.domain.TransaksjonMappingDTO; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.jpa.BestillingProgress; import no.nav.dolly.domain.jpa.TransaksjonMapping; +import no.nav.dolly.domain.resultset.RsDollyBestilling; import no.nav.dolly.domain.resultset.RsDollyUtvidetBestilling; import no.nav.dolly.domain.resultset.dolly.DollyPerson; import no.nav.dolly.errorhandling.ErrorStatusDecoder; @@ -17,17 +19,19 @@ import no.nav.dolly.service.TransaksjonMappingService; import no.nav.dolly.util.TransactionHelperService; import no.nav.testnav.libs.dto.inntektsmeldingservice.v1.requests.InntektsmeldingRequest; -import org.apache.commons.lang3.StringUtils; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; +import java.time.Duration; import java.time.LocalDateTime; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import static java.util.Collections.singletonList; -import static java.util.Objects.nonNull; import static no.nav.dolly.domain.resultset.SystemTyper.INNTKMELD; +import static no.nav.dolly.errorhandling.ErrorStatusDecoder.encodeStatus; import static org.apache.commons.lang3.StringUtils.isBlank; @Slf4j @@ -42,31 +46,37 @@ public class InntektsmeldingClient implements ClientRegister { private final TransaksjonMappingService transaksjonMappingService; private final ObjectMapper objectMapper; private final TransactionHelperService transactionHelperService; - private final ErrorStatusDecoder errorStatusDecoder; + private final ApplicationConfig applicationConfig; @Override public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, DollyPerson dollyPerson, BestillingProgress progress, boolean isOpprettEndre) { - if (nonNull(bestilling.getInntektsmelding())) { - - var context = MappingContextUtils.getMappingContext(); - context.setProperty("ident", dollyPerson.getIdent()); - - return Flux.from( - Flux.fromIterable(bestilling.getEnvironments()) - .flatMap(environment -> { - var request = mapperFacade.map(bestilling.getInntektsmelding(), InntektsmeldingRequest.class, context); - request.setMiljoe(environment); - return postInntektsmelding(isOpprettEndre || - !transaksjonMappingService.existAlready(INNTKMELD, dollyPerson.getIdent(), environment, bestilling.getId()), - request, bestilling.getId()); - }) - .filter(StringUtils::isNotBlank) - .collect(Collectors.joining(",")) - .map(status -> futurePersist(progress, status))); - } - return Flux.empty(); + return Flux.just(bestilling) + .filter(RsDollyBestilling::isExistInntekstsmelding) + .map(RsDollyBestilling::getInntektsmelding) + .flatMap(inntektsmelding -> Flux.just(bestilling.getEnvironments()) + .flatMap(miljoer -> Flux.fromIterable(miljoer) + .flatMap(environment -> { + var context = MappingContextUtils.getMappingContext(); + context.setProperty("ident", dollyPerson.getIdent()); + context.setProperty("miljoe", environment); + var request = mapperFacade.map(bestilling.getInntektsmelding(), InntektsmeldingRequest.class, context); + return postInntektsmelding(isOpprettEndre || + !transaksjonMappingService.existAlready(INNTKMELD, dollyPerson.getIdent(), environment, bestilling.getId()), + request, bestilling.getId()); + })) + .timeout(Duration.ofSeconds(applicationConfig.getClientTimeout())) + .onErrorResume(error -> getErrors(error, bestilling.getEnvironments())) + .collect(Collectors.joining(",")) + .map(status -> futurePersist(progress, status))); + } + + private Flux getErrors(Throwable error, Set environments) { + + return Flux.fromIterable(environments) + .map(env -> STATUS_FMT.formatted(env, + encodeStatus(WebClientFilter.getMessage(error)))); } @Override @@ -75,7 +85,8 @@ public void release(List identer) { // Inntektsmelding mangler pt. sletting } - private ClientFuture futurePersist(BestillingProgress progress, String status) { + private ClientFuture futurePersist(BestillingProgress progress, String + status) { return () -> { transactionHelperService.persister(progress, diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/inntektsmelding/mapper/InntektsmeldingMappingStrategy.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/inntektsmelding/mapper/InntektsmeldingMappingStrategy.java index 024390f63a2..81a6d2790dc 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/inntektsmelding/mapper/InntektsmeldingMappingStrategy.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/inntektsmelding/mapper/InntektsmeldingMappingStrategy.java @@ -56,6 +56,7 @@ public void mapAtoB(RsInntektsmelding rsInntektsmelding, Avsendertype.ORGNR : Avsendertype.FNR).name()); inntektsmelding.setArbeidstakerFnr((String) context.getProperty("ident")); + inntektsmelding.setMiljoe((String) context.getProperty("miljoe")); } }) .byDefault() diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/PensjonforvalterClient.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/PensjonforvalterClient.java index 44a268944c0..209f503eabb 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/PensjonforvalterClient.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/PensjonforvalterClient.java @@ -1,105 +1,49 @@ package no.nav.dolly.bestilling.pensjonforvalter; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import ma.glasnost.orika.MapperFacade; -import ma.glasnost.orika.MappingContext; import no.nav.dolly.bestilling.ClientFuture; import no.nav.dolly.bestilling.ClientRegister; -import no.nav.dolly.bestilling.pdldata.PdlDataConsumer; -import no.nav.dolly.bestilling.pensjonforvalter.domain.AfpOffentligRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.AlderspensjonRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.AlderspensjonSoknadRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.AlderspensjonVedtakRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonPersonRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonPoppGenerertInntektRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonPoppInntektRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonSamboerRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonSamboerResponse; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonSivilstandWrapper; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonTpForholdRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonTpYtelseRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonUforetrygdRequest; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonVedtakResponse; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonVedtakResponse.SakType; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonsavtaleRequest; -import no.nav.dolly.bestilling.personservice.PersonServiceConsumer; -import no.nav.dolly.consumer.norg2.Norg2Consumer; -import no.nav.dolly.consumer.norg2.dto.Norg2EnhetResponse; -import no.nav.dolly.domain.PdlPerson; -import no.nav.dolly.domain.PdlPersonBolk; +import no.nav.dolly.bestilling.pensjonforvalter.service.PensjonPdlPersonService; +import no.nav.dolly.bestilling.pensjonforvalter.service.PensjonPensjonsdataService; +import no.nav.dolly.bestilling.pensjonforvalter.service.PensjonPersondataService; +import no.nav.dolly.bestilling.pensjonforvalter.service.PensjonVedtakService; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.jpa.BestillingProgress; -import no.nav.dolly.domain.jpa.TransaksjonMapping; import no.nav.dolly.domain.resultset.IdentType; import no.nav.dolly.domain.resultset.RsDollyUtvidetBestilling; -import no.nav.dolly.domain.resultset.SystemTyper; import no.nav.dolly.domain.resultset.dolly.DollyPerson; -import no.nav.dolly.domain.resultset.pensjon.PensjonData; import no.nav.dolly.errorhandling.ErrorStatusDecoder; -import no.nav.dolly.mapper.MappingContextUtils; -import no.nav.dolly.service.TransaksjonMappingService; import no.nav.dolly.util.IdentTypeUtil; import no.nav.dolly.util.TransactionHelperService; -import no.nav.testnav.libs.data.pdlforvalter.v1.FullPersonDTO; -import no.nav.testnav.libs.data.pdlforvalter.v1.FullmaktDTO; -import no.nav.testnav.libs.data.pdlforvalter.v1.PersonDTO; -import no.nav.testnav.libs.data.pdlforvalter.v1.RelasjonType; -import org.apache.commons.lang3.StringUtils; -import org.springframework.http.HttpStatus; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.util.function.Tuple2; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.HashMap; +import java.time.Duration; import java.util.List; -import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.Stream; -import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; -import static no.nav.dolly.domain.resultset.SystemTyper.PEN_AP; -import static no.nav.dolly.domain.resultset.SystemTyper.PEN_UT; -import static org.apache.poi.util.StringUtil.isNotBlank; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.ANNET; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.PENSJON_FORVALTER; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.SEP; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.SYSTEM; +import static no.nav.dolly.errorhandling.ErrorStatusDecoder.encodeStatus; @Slf4j @Service @RequiredArgsConstructor public class PensjonforvalterClient implements ClientRegister { - private static final String SEP = "$"; - private static final String IDENT = "ident"; - private static final String MILJOER = "miljoer"; - private static final String NAV_ENHET = "navEnhet"; - private static final String SYSTEM = "PESYS"; - private static final String PENSJON_FORVALTER = "PensjonForvalter#"; - private static final String SAMBOER_REGISTER = "Samboer#"; - private static final String POPP_INNTEKTSREGISTER = "PoppInntekt#"; - private static final String TP_FORHOLD = "TpForhold#"; - private static final String PEN_ALDERSPENSJON = "AP#"; - private static final String PEN_UFORETRYGD = "Ufoer#"; - private static final String PEN_PENSJONSAVTALE = "Pensjonsavtale#"; - private static final String PEN_AFP_OFFENTLIG = "AfpOffentlig#"; - private static final String PERIODE = "/periode/"; - + private final ApplicationConfig applicationConfig; + private final PensjonPdlPersonService pensjonPdlPersonService; + private final PensjonPensjonsdataService pensjonPensjonsdataService; + private final PensjonPersondataService pensjonPersondataService; + private final PensjonVedtakService pensjonVedtakService; private final PensjonforvalterConsumer pensjonforvalterConsumer; - private final MapperFacade mapperFacade; - private final ErrorStatusDecoder errorStatusDecoder; private final TransactionHelperService transactionHelperService; - private final PersonServiceConsumer personServiceConsumer; - private final PdlDataConsumer pdlDataConsumer; - private final TransaksjonMappingService transaksjonMappingService; - private final ObjectMapper objectMapper; - private final Norg2Consumer norg2Consumer; @Override public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, DollyPerson dollyPerson, BestillingProgress progress, boolean isOpprettEndre) { @@ -112,15 +56,11 @@ public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, Dolly .map(miljoe -> miljoe.equals("q4") ? "q1" : miljoe) .collect(Collectors.toSet())); - var bestillingId = bestilling.getId(); - var statusResultat = new ArrayList(); - return Flux.from(Flux.from(pensjonforvalterConsumer.getMiljoer()) .flatMap(tilgjengeligeMiljoer -> { bestilteMiljoer.set(bestilteMiljoer.get().stream() .filter(tilgjengeligeMiljoer::contains) .collect(Collectors.toSet())); - return Flux.just(bestilling) .doOnNext(bestilling1 -> { if (!dollyPerson.isOrdre()) { @@ -130,86 +70,29 @@ public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, Dolly prepInitStatus(tilgjengeligeMiljoer), SEP); } }) - .flatMap(bestilling1 -> getIdenterRelasjoner(dollyPerson.getIdent()) - .collectList() - .map(this::getPersonData) - .flatMap(persondata -> Mono.zip( - getPdlPerson(persondata), - getNavEnhetNr(persondata, dollyPerson.getIdent()))) - .doOnNext(utvidetPersondata -> { - if (utvidetPersondata.getT1().isEmpty()) { - log.warn("Persondata for {} gir tom response fra PDL", dollyPerson.getIdent()); - } - }) - .filter(utvidetPersondata -> !utvidetPersondata.getT1().isEmpty()) - .flatMap(utvidetPersondata -> Flux.concat( - opprettPersoner(dollyPerson.getIdent(), tilgjengeligeMiljoer, utvidetPersondata.getT1()) - .map(response -> PENSJON_FORVALTER + decodeStatus(response, dollyPerson.getIdent())), - - lagreSamboer(dollyPerson.getIdent(), tilgjengeligeMiljoer) - .map(response -> SAMBOER_REGISTER + decodeStatus(response, dollyPerson.getIdent())) - ) - .collectList() - .doOnNext(statusResultat::addAll) - .filter(status -> status.stream().allMatch(entry -> entry.contains("OK"))) - .map(status -> Flux.just(bestilling1) - .filter(bestilling2 -> nonNull(bestilling2.getPensjonforvalter())) - .map(RsDollyUtvidetBestilling::getPensjonforvalter) - .flatMap(pensjon -> Flux.merge( - - lagreInntekt(pensjon, - dollyPerson.getIdent(), bestilteMiljoer.get()) - .map(response -> POPP_INNTEKTSREGISTER + decodeStatus(response, dollyPerson.getIdent())), - - lagreGenerertInntekt(pensjon, - dollyPerson.getIdent(), bestilteMiljoer.get()) - .map(response -> POPP_INNTEKTSREGISTER + decodeStatus(response, dollyPerson.getIdent())), - - lagreTpForhold(pensjon, dollyPerson.getIdent(), bestilteMiljoer.get()) - .map(response -> TP_FORHOLD + decodeStatus(response, dollyPerson.getIdent())), + .flatMap(bestilling1 -> pensjonPdlPersonService.getUtvidetPersondata(dollyPerson.getIdent()) + .flatMapMany(utvidetPersondata -> + Flux.concat( + pensjonPersondataService.lagrePersondata(dollyPerson.getIdent(), utvidetPersondata.getT1(), tilgjengeligeMiljoer), + pensjonPensjonsdataService.lagrePensjonsdata(bestilling1, dollyPerson.getIdent(), tilgjengeligeMiljoer), + pensjonVedtakService.lagrePensjonVedtak(bestilling1, dollyPerson.getIdent(), utvidetPersondata, tilgjengeligeMiljoer) + ))) - lagrePensjonsavtale(pensjon, dollyPerson.getIdent(), bestilteMiljoer.get()) - .map(response -> PEN_PENSJONSAVTALE + decodeStatus(response, dollyPerson.getIdent())), + .timeout(Duration.ofSeconds(applicationConfig.getClientTimeout())) + .onErrorResume(error -> getErrors(tilgjengeligeMiljoer, error)); - lagreAfpOffentlig(pensjon, dollyPerson.getIdent(), bestilteMiljoer.get()) - .map(response -> PEN_AFP_OFFENTLIG + decodeStatus(response, dollyPerson.getIdent())) - ) - .collectList() - .doOnNext(statusResultat::addAll) - - .map(status2 -> Flux.just(pensjon) - .flatMap(pensjon2 -> Flux.merge( - - lagreAlderspensjon( - pensjon2, - utvidetPersondata, - dollyPerson.getIdent(), - bestilteMiljoer.get(), - bestillingId) - .map(response -> PEN_ALDERSPENSJON + decodeStatus(response, dollyPerson.getIdent())), - - lagreUforetrygd( - pensjon2, - utvidetPersondata.getT2(), - dollyPerson.getIdent(), - bestilteMiljoer.get(), - bestillingId) - .map(response -> PEN_UFORETRYGD + decodeStatus(response, dollyPerson.getIdent())) - ) - .collectList() - .doOnNext(statusResultat::addAll) - )))))); }) - .flatMap(Flux::from) - .flatMap(Flux::from) - .flatMap(Flux::fromIterable) - .collectList() - .map(status -> statusResultat.stream() - .filter(StringUtils::isNotBlank) - .collect(Collectors.joining("$"))) + .collect(Collectors.joining("$")) .map(status2 -> futurePersist(dollyPerson, progress, status2))); } + private Flux getErrors(Set miljoer, Throwable throwable) { + + return Flux.fromIterable(miljoer) + .map(miljo -> "%s%s:Feil= %s".formatted(ANNET, miljo, + encodeStatus(WebClientFilter.getMessage(throwable)))); + } + @Override public void release(List identer) { @@ -220,85 +103,6 @@ public void release(List identer) { pensjonforvalterConsumer.sletteAfpOffentlig(identer); } - public static PensjonforvalterResponse mergePensjonforvalterResponses(List responser) { - - var status = new HashMap(); - responser.forEach(respons -> respons.getStatus() - .forEach(detalj -> { - if (detalj.getResponse().isResponse2xx()) { - status.putIfAbsent(detalj.getMiljo(), detalj.getResponse()); - } else { - status.put(detalj.getMiljo(), detalj.getResponse()); - } - })); - - return PensjonforvalterResponse.builder() - .status(status.entrySet().stream() - .map(detalj -> PensjonforvalterResponse.ResponseEnvironment.builder() - .miljo(detalj.getKey()) - .response(detalj.getValue()) - .build()) - .toList()) - .build(); - } - - private Mono getNavEnhetNr(Flux persondata, String ident) { - - return persondata - .doOnNext(data -> { - if (isNull(data.getHentGeografiskTilknytningBolk()) || - data.getHentGeografiskTilknytningBolk().stream() - .anyMatch(bolk -> isNull(bolk.getGeografiskTilknytning()))) { - - log.warn("GT for {} gir tom response fra PDL", ident); - } - }) - .filter(data -> nonNull(data.getHentGeografiskTilknytningBolk())) - .map(PdlPersonBolk.Data::getHentGeografiskTilknytningBolk) - .flatMap(Flux::fromIterable) - .filter(data -> nonNull(data.getGeografiskTilknytning())) - .map(PdlPersonBolk.GeografiskTilknytningBolk::getGeografiskTilknytning) - .map(PensjonforvalterClient::getGeografiskTilknytning) - .flatMap(norg2Consumer::getNorgEnhet) - .filter(norgenhet -> nonNull(norgenhet.getEnhetNr())) - .map(Norg2EnhetResponse::getEnhetNr) - .collectList() - .doOnNext(norgdata -> log.info("Mottatt norgdata: {}", norgdata)) - .map(norgdata -> !norgdata.isEmpty() ? norgdata.getFirst() : "0315"); - } - - private Flux lagreSamboer(String ident, Set tilgjengeligeMiljoer) { - - return Flux.concat(annulerAlleSamboere(ident, tilgjengeligeMiljoer), - pdlDataConsumer.getPersoner(List.of(ident)) - .map(hovedperson -> { - var context = new MappingContext.Factory().getContext(); - context.setProperty(IDENT, ident); - return (List) mapperFacade.map(PensjonSivilstandWrapper.builder() - .sivilstander(hovedperson.getPerson().getSivilstand()) - .build(), List.class, context); - }) - .flatMap(Flux::fromIterable) - .flatMap(request -> Flux.fromIterable(tilgjengeligeMiljoer) - .flatMap(miljoe -> pensjonforvalterConsumer.lagreSamboer(request, miljoe)) - .filter(response -> request.getPidBruker().equals(ident)))); - } - - private Flux annulerAlleSamboere(String ident, Set tilgjengeligeMiljoer) { - - return Flux.fromIterable(tilgjengeligeMiljoer) - .flatMap(miljoe -> pensjonforvalterConsumer.hentSamboer(ident, miljoe) - .flatMap(response -> Flux.merge(Flux.just(response), Flux.fromIterable(response.getSamboerforhold()) - .map(PensjonSamboerResponse.Samboerforhold::getPidSamboer) - .flatMap(identSamboer -> pensjonforvalterConsumer.hentSamboer(identSamboer, miljoe))) - .flatMap(samboerResponse -> Flux.fromIterable(samboerResponse.getSamboerforhold()) - .flatMap(samboer -> pensjonforvalterConsumer.annullerSamboer( - getPeriodeId(samboer.get_links().getAnnuller().getHref()), miljoe) - .filter(response1 -> samboer.getPidBruker().equals(ident) && - response1.getStatus().stream() - .noneMatch(status -> status.getResponse().getHttpStatus().getStatus() == 200)))))); - } - private String prepInitStatus(Set miljoer) { return PENSJON_FORVALTER + @@ -317,331 +121,4 @@ private ClientFuture futurePersist(DollyPerson dollyPerson, BestillingProgress p return progress; }; } - - private Flux getIdenterRelasjoner(String ident) { - - return Flux.concat(Flux.just(ident), - getPersonData(List.of(ident)) - .map(PdlPersonBolk.Data::getHentPersonBolk) - .flatMap(Flux::fromIterable) - .filter(personBolk -> nonNull(personBolk.getPerson())) - .flatMap(person -> Flux.fromStream(Stream.of( - person.getPerson().getSivilstand().stream() - .map(PdlPerson.Sivilstand::getRelatertVedSivilstand) - .filter(Objects::nonNull), - person.getPerson().getForelderBarnRelasjon().stream() - .map(PdlPerson.ForelderBarnRelasjon::getRelatertPersonsIdent) - .filter(Objects::nonNull), - person.getPerson().getFullmakt().stream() - .map(FullmaktDTO::getMotpartsPersonident)) - .flatMap(Function.identity()))), - pdlDataConsumer.getPersoner(List.of(ident)) - .flatMap(person -> Flux.fromIterable(person.getRelasjoner()) - .filter(relasjon -> relasjon.getRelasjonType() != RelasjonType.GAMMEL_IDENTITET) - .map(FullPersonDTO.RelasjonDTO::getRelatertPerson) - .map(PersonDTO::getIdent))) - .distinct(); - } - - private Flux getPersonData(List identer) { - - return personServiceConsumer.getPdlPersoner(identer) - .doOnNext(bolk -> { - if (isNull(bolk.getData()) || bolk.getData().getHentPersonBolk().stream() - .anyMatch(personBolk -> isNull(personBolk.getPerson()))) { - log.warn("PDL-data mangler for {}, bolkPersoner: {}, ", String.join(", ", identer), bolk); - } - }) - .filter(pdlPersonBolk -> nonNull(pdlPersonBolk.getData())) - .map(PdlPersonBolk::getData); - } - - private Flux opprettPersoner(String hovedperson, Set miljoer, - List personer) { - - return Flux.fromIterable(personer) - .map(person -> mapperFacade.map(person, PensjonPersonRequest.class)) - .flatMap(request -> pensjonforvalterConsumer.opprettPerson(request, miljoer) - .filter(response -> hovedperson.equals(request.getFnr()))); - } - - private Flux lagreAlderspensjon(PensjonData pensjonData, - Tuple2, String> utvidetPersondata, - String ident, Set miljoer, - Long bestillingId) { - - return Flux.just(pensjonData) - .filter(PensjonData::hasAlderspensjon) - .map(PensjonData::getAlderspensjon) - .flatMap(alderspensjon -> Flux.fromIterable(miljoer) - .flatMap(miljoe -> pensjonforvalterConsumer.hentVedtak(ident, miljoe) - .collectList() - .map(vedtakResponse -> !hasVedtak(vedtakResponse, SakType.AP)) - .map(skalOpprette -> { - if (skalOpprette) { - - AlderspensjonRequest pensjonRequest; - var context = new MappingContext.Factory().getContext(); - context.setProperty(IDENT, ident); - context.setProperty(MILJOER, List.of(miljoe)); - - if (alderspensjon.isSoknad()) { - context.setProperty("relasjoner", utvidetPersondata.getT1()); - pensjonRequest = mapperFacade.map(alderspensjon, AlderspensjonSoknadRequest.class, context); - - } else { - context.setProperty(NAV_ENHET, utvidetPersondata.getT2()); - pensjonRequest = mapperFacade.map(alderspensjon, AlderspensjonVedtakRequest.class, context); - } - - var finalPensjonRequest = new AtomicReference<>(pensjonRequest); - return pensjonforvalterConsumer.lagreAlderspensjon(pensjonRequest) - .map(response -> { - response.getStatus().forEach(status -> - saveAPTransaksjonId(ident, status.getMiljo(), bestillingId, - PEN_AP, finalPensjonRequest)); - return response; - }); - - } else { - return getStatus(miljoe, 200, "OK"); - } - }))) - .flatMap(Flux::from); - } - - private Flux lagreUforetrygd(PensjonData pensjondata, String navEnhetNr, - String ident, Set miljoer, Long bestillingId) { - - return Flux.just(pensjondata) - .filter(PensjonData::hasUforetrygd) - .map(PensjonData::getUforetrygd) - .flatMap(uforetrygd -> Flux.fromIterable(miljoer) - .flatMap(miljoe -> pensjonforvalterConsumer.hentVedtak(ident, miljoe) - .collectList() - .map(vedtak -> { - if (!hasVedtak(vedtak, SakType.UT)) { - - var context = MappingContextUtils.getMappingContext(); - context.setProperty(IDENT, ident); - context.setProperty(MILJOER, List.of(miljoe)); - context.setProperty(NAV_ENHET, navEnhetNr); - return Flux.just(mapperFacade.map(uforetrygd, PensjonUforetrygdRequest.class, context)) - .flatMap(request -> pensjonforvalterConsumer.lagreUforetrygd(request) - .map(response -> { - response.getStatus().stream() - .filter(status -> status.getResponse().isResponse2xx()) - .forEach(status -> - saveAPTransaksjonId(ident, status.getMiljo(), bestillingId, - PEN_UT, new AtomicReference<>(request))); - return response; - })); - } else { - return getStatus(miljoe, 200, "OK"); - } - }))) - .flatMap(Flux::from); - } - - @SuppressWarnings("java:S3740") - private void saveAPTransaksjonId(String ident, String miljoe, Long bestillingId, SystemTyper - type, AtomicReference vedtak) { - - log.info("Lagrer transaksjon for {} i {} ", ident, miljoe); - transaksjonMappingService.delete(ident, miljoe, type.name()); - - transaksjonMappingService.save( - TransaksjonMapping.builder() - .ident(ident) - .bestillingId(bestillingId) - .transaksjonId(toJson(vedtak.get())) - .datoEndret(LocalDateTime.now()) - .miljoe(miljoe) - .system(type.name()) - .build()); - } - - private Flux lagreInntekt(PensjonData pensjonData, String ident, - Set miljoer) { - - return Flux.just(pensjonData) - .filter(PensjonData::hasInntekt) - .map(PensjonData::getInntekt) - .flatMap(inntekt -> Flux.fromIterable(miljoer) - .flatMap(miljoe -> { - - var request = mapperFacade.map(inntekt, PensjonPoppInntektRequest.class); - request.setFnr(ident); - request.setMiljoer(List.of(miljoe)); - return pensjonforvalterConsumer.lagreInntekter(request); - })); - } - - private Flux lagreGenerertInntekt(PensjonData pensjonData, String ident, - Set miljoer) { - - return Flux.just(pensjonData) - .filter(PensjonData::hasGenerertInntekt) - .map(PensjonData::getGenerertInntekt) - .flatMap(generertInntekt -> Flux.fromIterable(miljoer) - .flatMap(miljoe -> { - - var request = mapperFacade.map(generertInntekt, PensjonPoppGenerertInntektRequest.class); - request.setFnr(ident); - request.setMiljoer(List.of(miljoe)); - return pensjonforvalterConsumer.lagreGenererteInntekter(request); - })); - } - - private Mono lagreTpForhold(PensjonData pensjonData, String - ident, Set miljoer) { - - return Flux.just(pensjonData) - .filter(PensjonData::hasTp) - .map(PensjonData::getTp) - .flatMap(Flux::fromIterable) - .map(tp -> { - - var context = new MappingContext.Factory().getContext(); - context.setProperty(IDENT, ident); - context.setProperty(MILJOER, miljoer); - - var tpForholdRequest = mapperFacade.map(tp, PensjonTpForholdRequest.class, context); - return pensjonforvalterConsumer.lagreTpForhold(tpForholdRequest) - .flatMap(forholdSvar -> { - log.info("Lagret TP-forhold {}", forholdSvar); - return Flux.fromIterable(tp.getYtelser()) - .flatMap(ytelse -> { - context.setProperty("ordning", tp.getOrdning()); - PensjonTpYtelseRequest pensjonTpYtelseRequest = mapperFacade.map(ytelse, PensjonTpYtelseRequest.class, context); - return pensjonforvalterConsumer.lagreTpYtelse(pensjonTpYtelseRequest); - }); - } - ); - }) - .flatMap(Flux::from) - .collectList() - .filter(resultat -> !resultat.isEmpty()) - .map(PensjonforvalterClient::mergePensjonforvalterResponses); - } - - private Flux lagrePensjonsavtale(PensjonData pensjon, String ident, Set miljoer) { - - return Flux.just(pensjon) - .filter(PensjonData::hasPensjonsavtale) - .map(PensjonData::getPensjonsavtale) - .flatMap(pensjonsavtaler -> Flux.fromIterable(pensjonsavtaler) - .flatMap(pensjonsavtale -> { - - var context = MappingContextUtils.getMappingContext(); - context.setProperty(IDENT, ident); - context.setProperty(MILJOER, miljoer); - - var pensjonsavtaleRequest = mapperFacade.map(pensjonsavtale, PensjonsavtaleRequest.class, context); - return pensjonforvalterConsumer.lagrePensjonsavtale(pensjonsavtaleRequest); - })); - } - - private Flux lagreAfpOffentlig(PensjonData pensjonData, String ident, Set miljoer) { - - return Flux.just(pensjonData) - .filter(PensjonData::hasAfpOffentlig) - .map(PensjonData::getAfpOffentlig) - .flatMap(pensjon -> Flux.fromIterable(miljoer) - .flatMap(miljoe -> { - - var context = MappingContextUtils.getMappingContext(); - context.setProperty(IDENT, ident); - var request = mapperFacade.map(pensjon, AfpOffentligRequest.class, context); - return pensjonforvalterConsumer.lagreAfpOffentlig(request, ident, miljoe); - })); - } - - private String decodeStatus(PensjonforvalterResponse response, String ident) { - - log.info("Mottatt status på {} fra Pensjon-Testdata-Facade: {}", ident, response); - - return response.getStatus().stream() - .map(entry -> String.format("%s:%s", entry.getMiljo(), - entry.getResponse().isResponse2xx() ? "OK" : - getError(entry))) - .collect(Collectors.joining(",")); - } - - private String toJson(Object object) { - - try { - return objectMapper.writeValueAsString(object); - } catch (JsonProcessingException e) { - log.error("Feilet å konvertere transaksjonsId for pensjonForvalter", e); - } - return null; - } - - private static boolean hasVedtak(List pensjonsvedtak, SakType type) { - - return pensjonsvedtak.stream().anyMatch(entry -> entry.getSakType() == type && - entry.getSisteOppdatering().contains("opprettet")); - } - - private static Mono> getPdlPerson(Flux persondata) { - - return persondata - .map(PdlPersonBolk.Data::getHentPersonBolk) - .flatMap(Flux::fromIterable) - .filter(personBolk -> nonNull(personBolk.getPerson())) - .collectList(); - } - - private static String getPeriodeId(String lenke) { - return lenke.substring(lenke.indexOf(PERIODE) + PERIODE.length()) - .replace("/annuller", ""); - } - - private static Flux getStatus(String miljoe, Integer status, String reasonPhrase) { - - return Flux.just(PensjonforvalterResponse.builder() - .status(List.of(PensjonforvalterResponse.ResponseEnvironment.builder() - .miljo(miljoe) - .response(PensjonforvalterResponse.Response.builder() - .httpStatus(PensjonforvalterResponse.HttpStatus.builder() - .status(status) - .reasonPhrase(reasonPhrase) - .build()) - .message(reasonPhrase) - .build()) - .build())) - .build()); - } - - private static String getGeografiskTilknytning(PdlPersonBolk.GeografiskTilknytning tilknytning) { - - if (isNotBlank(tilknytning.getGtKommune())) { - return tilknytning.getGtKommune(); - - } else if (isNotBlank(tilknytning.getGtBydel())) { - return tilknytning.getGtBydel(); - - } else { - return "030102"; - } - } - - String getError(PensjonforvalterResponse.ResponseEnvironment entry) { - - var response = entry.getResponse(); - var httpStatus = response.getHttpStatus(); - - if (isNotBlank(response.getMessage())) { - if (response.getMessage().contains("{")) { - return ErrorStatusDecoder.encodeStatus( - "Feil: " + response.getMessage().split("\\{")[1].split("}")[0].replace("message\":", "")); - } else { - return ErrorStatusDecoder.encodeStatus("Feil: " + response.getMessage()); - } - - } else { - return errorStatusDecoder.getErrorText(HttpStatus.valueOf(httpStatus.getStatus()), httpStatus.getReasonPhrase()); - } - } } \ No newline at end of file diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPdlPersonService.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPdlPersonService.java new file mode 100644 index 00000000000..a582c6f3845 --- /dev/null +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPdlPersonService.java @@ -0,0 +1,124 @@ +package no.nav.dolly.bestilling.pensjonforvalter.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import no.nav.dolly.bestilling.pdldata.PdlDataConsumer; +import no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils; +import no.nav.dolly.bestilling.personservice.PersonServiceConsumer; +import no.nav.dolly.consumer.norg2.Norg2Consumer; +import no.nav.dolly.consumer.norg2.dto.Norg2EnhetResponse; +import no.nav.dolly.domain.PdlPerson; +import no.nav.dolly.domain.PdlPersonBolk; +import no.nav.testnav.libs.data.pdlforvalter.v1.FullPersonDTO; +import no.nav.testnav.libs.data.pdlforvalter.v1.FullmaktDTO; +import no.nav.testnav.libs.data.pdlforvalter.v1.PersonDTO; +import no.nav.testnav.libs.data.pdlforvalter.v1.RelasjonType; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.function.Tuple2; + +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Stream; + +import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PensjonPdlPersonService { + + private final Norg2Consumer norg2Consumer; + private final PdlDataConsumer pdlDataConsumer; + private final PersonServiceConsumer personServiceConsumer; + + public Mono, String>> getUtvidetPersondata(String ident) { + + return getIdenterRelasjoner(ident) + .collectList() + .map(this::getPersonData) + .flatMap(persondata -> Mono.zip( + getPdlPerson(persondata), + getNavEnhetNr(persondata, ident))) + .doOnNext(utvidetPersondata -> { + if (utvidetPersondata.getT1().isEmpty()) { + log.warn("Persondata for {} gir tom response fra PDL", ident); + } + }); + } + + private Flux getIdenterRelasjoner(String ident) { + + return Flux.concat(Flux.just(ident), + getPersonData(List.of(ident)) + .map(PdlPersonBolk.Data::getHentPersonBolk) + .flatMap(Flux::fromIterable) + .filter(personBolk -> nonNull(personBolk.getPerson())) + .flatMap(person -> Flux.fromStream(Stream.of( + person.getPerson().getSivilstand().stream() + .map(PdlPerson.Sivilstand::getRelatertVedSivilstand) + .filter(Objects::nonNull), + person.getPerson().getForelderBarnRelasjon().stream() + .map(PdlPerson.ForelderBarnRelasjon::getRelatertPersonsIdent) + .filter(Objects::nonNull), + person.getPerson().getFullmakt().stream() + .map(FullmaktDTO::getMotpartsPersonident)) + .flatMap(Function.identity()))), + pdlDataConsumer.getPersoner(List.of(ident)) + .flatMap(person -> Flux.fromIterable(person.getRelasjoner()) + .filter(relasjon -> relasjon.getRelasjonType() != RelasjonType.GAMMEL_IDENTITET) + .map(FullPersonDTO.RelasjonDTO::getRelatertPerson) + .map(PersonDTO::getIdent))) + .distinct(); + } + + private Flux getPersonData(List identer) { + + return personServiceConsumer.getPdlPersoner(identer) + .doOnNext(bolk -> { + if (isNull(bolk.getData()) || bolk.getData().getHentPersonBolk().stream() + .anyMatch(personBolk -> isNull(personBolk.getPerson()))) { + log.warn("PDL-data mangler for {}, bolkPersoner: {}, ", String.join(", ", identer), bolk); + } + }) + .filter(pdlPersonBolk -> nonNull(pdlPersonBolk.getData())) + .map(PdlPersonBolk::getData); + } + + private static Mono> getPdlPerson(Flux persondata) { + + return persondata + .map(PdlPersonBolk.Data::getHentPersonBolk) + .flatMap(Flux::fromIterable) + .filter(personBolk -> nonNull(personBolk.getPerson())) + .collectList(); + } + + private Mono getNavEnhetNr(Flux persondata, String ident) { + + return persondata + .doOnNext(data -> { + if (isNull(data.getHentGeografiskTilknytningBolk()) || + data.getHentGeografiskTilknytningBolk().stream() + .anyMatch(bolk -> isNull(bolk.getGeografiskTilknytning()))) { + + log.warn("GT for {} gir tom response fra PDL", ident); + } + }) + .filter(data -> nonNull(data.getHentGeografiskTilknytningBolk())) + .map(PdlPersonBolk.Data::getHentGeografiskTilknytningBolk) + .flatMap(Flux::fromIterable) + .filter(data -> nonNull(data.getGeografiskTilknytning())) + .map(PdlPersonBolk.GeografiskTilknytningBolk::getGeografiskTilknytning) + .map(PensjonforvalterUtils::getGeografiskTilknytning) + .flatMap(norg2Consumer::getNorgEnhet) + .filter(norgenhet -> nonNull(norgenhet.getEnhetNr())) + .map(Norg2EnhetResponse::getEnhetNr) + .collectList() + .doOnNext(norgdata -> log.info("Mottatt norgdata: {}", norgdata)) + .map(norgdata -> !norgdata.isEmpty() ? norgdata.getFirst() : "0315"); + } +} diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataService.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataService.java new file mode 100644 index 00000000000..c161a3701d3 --- /dev/null +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataService.java @@ -0,0 +1,185 @@ +package no.nav.dolly.bestilling.pensjonforvalter.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import ma.glasnost.orika.MapperFacade; +import ma.glasnost.orika.MappingContext; +import no.nav.dolly.bestilling.pensjonforvalter.PensjonforvalterConsumer; +import no.nav.dolly.bestilling.pensjonforvalter.domain.AfpOffentligRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonPoppGenerertInntektRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonPoppInntektRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonTpForholdRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonTpYtelseRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonsavtaleRequest; +import no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterHelper; +import no.nav.dolly.domain.resultset.RsDollyBestilling; +import no.nav.dolly.domain.resultset.pensjon.PensjonData; +import no.nav.dolly.mapper.MappingContextUtils; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.IDENT; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.MILJOER; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.PEN_AFP_OFFENTLIG; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.PEN_PENSJONSAVTALE; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.POPP_INNTEKTSREGISTER; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.TP_FORHOLD; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PensjonPensjonsdataService { + + private final PensjonforvalterConsumer pensjonforvalterConsumer; + private final PensjonforvalterHelper pensjonforvalterHelper; + private final MapperFacade mapperFacade; + + public Flux lagrePensjonsdata(RsDollyBestilling bestilling, String ident, Set miljoer) { + + return Flux.just(bestilling) + .filter(RsDollyBestilling::isPensjon) + .map(RsDollyBestilling::getPensjonforvalter) + .flatMap(pensjon -> Flux.merge( + lagreInntekt(pensjon, + ident, miljoer) + .map(response -> POPP_INNTEKTSREGISTER + pensjonforvalterHelper.decodeStatus(response, ident)), + + lagreGenerertInntekt(pensjon, + ident, miljoer) + .map(response -> POPP_INNTEKTSREGISTER + pensjonforvalterHelper.decodeStatus(response, ident)), + + lagreTpForhold(pensjon, ident, miljoer) + .map(response -> TP_FORHOLD + pensjonforvalterHelper.decodeStatus(response, ident)), + + lagrePensjonsavtale(pensjon, ident, miljoer) + .map(response -> PEN_PENSJONSAVTALE + pensjonforvalterHelper.decodeStatus(response, ident)), + + lagreAfpOffentlig(pensjon, ident, miljoer) + .map(response -> PEN_AFP_OFFENTLIG + pensjonforvalterHelper.decodeStatus(response, ident)) + )); + } + + + private Flux lagreInntekt(PensjonData pensjonData, String ident, + Set miljoer) { + + return Flux.just(pensjonData) + .filter(PensjonData::hasInntekt) + .map(PensjonData::getInntekt) + .flatMap(inntekt -> Flux.fromIterable(miljoer) + .flatMap(miljoe -> { + + var request = mapperFacade.map(inntekt, PensjonPoppInntektRequest.class); + request.setFnr(ident); + request.setMiljoer(List.of(miljoe)); + return pensjonforvalterConsumer.lagreInntekter(request); + })); + } + + private Flux lagreGenerertInntekt(PensjonData pensjonData, String ident, + Set miljoer) { + + return Flux.just(pensjonData) + .filter(PensjonData::hasGenerertInntekt) + .map(PensjonData::getGenerertInntekt) + .flatMap(generertInntekt -> Flux.fromIterable(miljoer) + .flatMap(miljoe -> { + + var request = mapperFacade.map(generertInntekt, PensjonPoppGenerertInntektRequest.class); + request.setFnr(ident); + request.setMiljoer(List.of(miljoe)); + return pensjonforvalterConsumer.lagreGenererteInntekter(request); + })); + } + + public Mono lagreTpForhold(PensjonData pensjonData, String + ident, Set miljoer) { + + return Flux.just(pensjonData) + .filter(PensjonData::hasTp) + .map(PensjonData::getTp) + .flatMap(Flux::fromIterable) + .flatMap(tp -> { + + var context = new MappingContext.Factory().getContext(); + context.setProperty(IDENT, ident); + context.setProperty(MILJOER, miljoer); + + var tpForholdRequest = mapperFacade.map(tp, PensjonTpForholdRequest.class, context); + return pensjonforvalterConsumer.lagreTpForhold(tpForholdRequest) + .flatMap(forholdSvar -> { + log.info("Lagret TP-forhold {}", forholdSvar); + return Flux.fromIterable(tp.getYtelser()) + .flatMap(ytelse -> { + context.setProperty("ordning", tp.getOrdning()); + PensjonTpYtelseRequest pensjonTpYtelseRequest = mapperFacade.map(ytelse, PensjonTpYtelseRequest.class, context); + return pensjonforvalterConsumer.lagreTpYtelse(pensjonTpYtelseRequest); + }); + } + ); + }) + .collectList() + .filter(resultat -> !resultat.isEmpty()) + .map(PensjonPensjonsdataService::mergePensjonforvalterResponses); + } + + private Flux lagrePensjonsavtale(PensjonData pensjon, String ident, Set miljoer) { + + return Flux.just(pensjon) + .filter(PensjonData::hasPensjonsavtale) + .map(PensjonData::getPensjonsavtale) + .flatMap(pensjonsavtaler -> Flux.fromIterable(pensjonsavtaler) + .flatMap(pensjonsavtale -> { + + var context = MappingContextUtils.getMappingContext(); + context.setProperty(IDENT, ident); + context.setProperty(MILJOER, miljoer); + + var pensjonsavtaleRequest = mapperFacade.map(pensjonsavtale, PensjonsavtaleRequest.class, context); + return pensjonforvalterConsumer.lagrePensjonsavtale(pensjonsavtaleRequest); + })); + } + + private Flux lagreAfpOffentlig(PensjonData pensjonData, String ident, Set miljoer) { + + return Flux.just(pensjonData) + .filter(PensjonData::hasAfpOffentlig) + .map(PensjonData::getAfpOffentlig) + .flatMap(pensjon -> Flux.fromIterable(miljoer) + .flatMap(miljoe -> { + + var context = MappingContextUtils.getMappingContext(); + context.setProperty(IDENT, ident); + var request = mapperFacade.map(pensjon, AfpOffentligRequest.class, context); + return pensjonforvalterConsumer.lagreAfpOffentlig(request, ident, miljoe); + })); + } + + public static PensjonforvalterResponse mergePensjonforvalterResponses(List responser) { + + var status = new HashMap(); + responser.forEach(respons -> respons.getStatus() + .forEach(detalj -> { + if (detalj.getResponse().isResponse2xx()) { + status.putIfAbsent(detalj.getMiljo(), detalj.getResponse()); + } else { + status.put(detalj.getMiljo(), detalj.getResponse()); + } + })); + + return PensjonforvalterResponse.builder() + .status(status.entrySet().stream() + .map(detalj -> PensjonforvalterResponse.ResponseEnvironment.builder() + .miljo(detalj.getKey()) + .response(detalj.getValue()) + .build()) + .toList()) + .build(); + } +} diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPersondataService.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPersondataService.java new file mode 100644 index 00000000000..7ab766c850e --- /dev/null +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPersondataService.java @@ -0,0 +1,87 @@ +package no.nav.dolly.bestilling.pensjonforvalter.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import ma.glasnost.orika.MapperFacade; +import ma.glasnost.orika.MappingContext; +import no.nav.dolly.bestilling.pdldata.PdlDataConsumer; +import no.nav.dolly.bestilling.pensjonforvalter.PensjonforvalterConsumer; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonPersonRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonSamboerRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonSamboerResponse; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonSivilstandWrapper; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; +import no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterHelper; +import no.nav.dolly.domain.PdlPersonBolk; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; + +import java.util.List; +import java.util.Set; + +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.IDENT; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.PENSJON_FORVALTER; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.SAMBOER_REGISTER; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.getPeriodeId; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PensjonPersondataService { + + private final PensjonforvalterConsumer pensjonforvalterConsumer; + private final PdlDataConsumer pdlDataConsumer; + private final PensjonforvalterHelper pensjonforvalterHelper; + private final MapperFacade mapperFacade; + + public Flux lagrePersondata(String ident, List persondata, Set miljoer) { + + return Flux.merge( + opprettPersoner(ident, miljoer, persondata) + .map(response -> PENSJON_FORVALTER + pensjonforvalterHelper.decodeStatus(response, ident)), + lagreSamboer(ident, miljoer) + .map(response -> SAMBOER_REGISTER + pensjonforvalterHelper.decodeStatus(response, ident)) + ); + } + + private Flux opprettPersoner(String hovedperson, Set miljoer, + List personer) { + + return Flux.fromIterable(personer) + .map(person -> mapperFacade.map(person, PensjonPersonRequest.class)) + .flatMap(request -> pensjonforvalterConsumer.opprettPerson(request, miljoer) + .filter(response -> hovedperson.equals(request.getFnr()))); + } + + private Flux lagreSamboer(String ident, Set tilgjengeligeMiljoer) { + + return Flux.concat(annulerAlleSamboere(ident, tilgjengeligeMiljoer), + pdlDataConsumer.getPersoner(List.of(ident)) + .map(hovedperson -> { + var context = new MappingContext.Factory().getContext(); + context.setProperty(IDENT, ident); + return (List) mapperFacade.map(PensjonSivilstandWrapper.builder() + .sivilstander(hovedperson.getPerson().getSivilstand()) + .build(), List.class, context); + }) + .flatMap(Flux::fromIterable) + .flatMap(request -> Flux.fromIterable(tilgjengeligeMiljoer) + .flatMap(miljoe -> pensjonforvalterConsumer.lagreSamboer(request, miljoe)) + .filter(response -> request.getPidBruker().equals(ident)))); + } + + private Flux annulerAlleSamboere(String ident, Set tilgjengeligeMiljoer) { + + return Flux.fromIterable(tilgjengeligeMiljoer) + .flatMap(miljoe -> pensjonforvalterConsumer.hentSamboer(ident, miljoe) + .flatMap(response -> Flux.merge(Flux.just(response), Flux.fromIterable(response.getSamboerforhold()) + .map(PensjonSamboerResponse.Samboerforhold::getPidSamboer) + .flatMap(identSamboer -> pensjonforvalterConsumer.hentSamboer(identSamboer, miljoe))) + .flatMap(samboerResponse -> Flux.fromIterable(samboerResponse.getSamboerforhold()) + .flatMap(samboer -> pensjonforvalterConsumer.annullerSamboer( + getPeriodeId(samboer.get_links().getAnnuller().getHref()), miljoe) + .filter(response1 -> samboer.getPidBruker().equals(ident) && + response1.getStatus().stream() + .noneMatch(status -> status.getResponse().getHttpStatus().getStatus() == 200)))))); + } +} diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonVedtakService.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonVedtakService.java new file mode 100644 index 00000000000..cda53ff1e67 --- /dev/null +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonVedtakService.java @@ -0,0 +1,150 @@ +package no.nav.dolly.bestilling.pensjonforvalter.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import ma.glasnost.orika.MapperFacade; +import ma.glasnost.orika.MappingContext; +import no.nav.dolly.bestilling.pensjonforvalter.PensjonforvalterConsumer; +import no.nav.dolly.bestilling.pensjonforvalter.domain.AlderspensjonRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.AlderspensjonSoknadRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.AlderspensjonVedtakRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonUforetrygdRequest; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonVedtakResponse; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; +import no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterHelper; +import no.nav.dolly.domain.PdlPersonBolk; +import no.nav.dolly.domain.resultset.RsDollyBestilling; +import no.nav.dolly.domain.resultset.pensjon.PensjonData; +import no.nav.dolly.mapper.MappingContextUtils; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.util.function.Tuple2; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.IDENT; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.MILJOER; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.NAV_ENHET; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.PEN_ALDERSPENSJON; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.PEN_UFORETRYGD; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.getStatus; +import static no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterUtils.hasVedtak; +import static no.nav.dolly.domain.resultset.SystemTyper.PEN_AP; +import static no.nav.dolly.domain.resultset.SystemTyper.PEN_UT; +import static org.apache.commons.lang3.BooleanUtils.isTrue; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PensjonVedtakService { + + private final PensjonforvalterHelper pensjonforvalterHelper; + private final PensjonforvalterConsumer pensjonforvalterConsumer; + private final MapperFacade mapperFacade; + + public Flux lagrePensjonVedtak(RsDollyBestilling bestilling, String ident, + Tuple2, String> utvidetPersondata, + Set miljoer) { + + return Flux.just(bestilling) + .filter(RsDollyBestilling::isPensjon) + .map(RsDollyBestilling::getPensjonforvalter) + .flatMap(pensjon -> Flux.merge( + lagreAlderspensjon( + pensjon, + utvidetPersondata, + ident, + miljoer, + bestilling.getId()) + .map(response -> PEN_ALDERSPENSJON + pensjonforvalterHelper.decodeStatus(response, ident)), + + lagreUforetrygd( + pensjon, + utvidetPersondata.getT2(), + ident, + miljoer, + bestilling.getId()) + .map(response -> PEN_UFORETRYGD + pensjonforvalterHelper.decodeStatus(response, ident)) + )); + } + + private Flux lagreAlderspensjon(PensjonData pensjonData, + Tuple2, String> utvidetPersondata, + String ident, Set miljoer, + Long bestillingId) { + + return Flux.just(pensjonData) + .filter(PensjonData::hasAlderspensjon) + .map(PensjonData::getAlderspensjon) + .flatMap(alderspensjon -> Flux.fromIterable(miljoer) + .flatMap(miljoe -> pensjonforvalterConsumer.hentVedtak(ident, miljoe) + .collectList() + .map(vedtakResponse -> !hasVedtak(vedtakResponse, PensjonVedtakResponse.SakType.AP)) + .map(skalOpprette -> { + if (isTrue(skalOpprette)) { + + AlderspensjonRequest pensjonRequest; + var context = new MappingContext.Factory().getContext(); + context.setProperty(IDENT, ident); + context.setProperty(MILJOER, List.of(miljoe)); + + if (alderspensjon.isSoknad()) { + context.setProperty("relasjoner", utvidetPersondata.getT1()); + pensjonRequest = mapperFacade.map(alderspensjon, AlderspensjonSoknadRequest.class, context); + + } else { + context.setProperty(NAV_ENHET, utvidetPersondata.getT2()); + pensjonRequest = mapperFacade.map(alderspensjon, AlderspensjonVedtakRequest.class, context); + } + + var finalPensjonRequest = new AtomicReference<>(pensjonRequest); + return pensjonforvalterConsumer.lagreAlderspensjon(pensjonRequest) + .map(response -> { + response.getStatus().forEach(status -> + pensjonforvalterHelper.saveAPTransaksjonId(ident, status.getMiljo(), bestillingId, + PEN_AP, finalPensjonRequest)); + return response; + }); + + } else { + return getStatus(miljoe, 200, "OK"); + } + }))) + .flatMap(Flux::from); + } + + private Flux lagreUforetrygd(PensjonData pensjondata, String navEnhetNr, + String ident, Set miljoer, Long bestillingId) { + + return Flux.just(pensjondata) + .filter(PensjonData::hasUforetrygd) + .map(PensjonData::getUforetrygd) + .flatMap(uforetrygd -> Flux.fromIterable(miljoer) + .flatMap(miljoe -> pensjonforvalterConsumer.hentVedtak(ident, miljoe) + .collectList() + .map(vedtak -> { + if (!hasVedtak(vedtak, PensjonVedtakResponse.SakType.UT)) { + + var context = MappingContextUtils.getMappingContext(); + context.setProperty(IDENT, ident); + context.setProperty(MILJOER, List.of(miljoe)); + context.setProperty(NAV_ENHET, navEnhetNr); + return Flux.just(mapperFacade.map(uforetrygd, PensjonUforetrygdRequest.class, context)) + .flatMap(request -> pensjonforvalterConsumer.lagreUforetrygd(request) + .map(response -> { + response.getStatus().stream() + .filter(status -> status.getResponse().isResponse2xx()) + .forEach(status -> + pensjonforvalterHelper.saveAPTransaksjonId(ident, status.getMiljo(), bestillingId, + PEN_UT, new AtomicReference<>(request))); + return response; + })); + } else { + return getStatus(miljoe, 200, "OK"); + } + }))) + .flatMap(Flux::from); + } +} diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterHelper.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterHelper.java new file mode 100644 index 00000000000..f2d9fcdc23f --- /dev/null +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterHelper.java @@ -0,0 +1,93 @@ +package no.nav.dolly.bestilling.pensjonforvalter.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; +import no.nav.dolly.domain.jpa.TransaksjonMapping; +import no.nav.dolly.domain.resultset.SystemTyper; +import no.nav.dolly.errorhandling.ErrorStatusDecoder; +import no.nav.dolly.service.TransaksjonMappingService; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import static no.nav.dolly.errorhandling.ErrorStatusDecoder.encodeStatus; +import static org.apache.poi.util.StringUtil.isNotBlank; + +@Slf4j +@Service +@NoArgsConstructor +public class PensjonforvalterHelper { + + private TransaksjonMappingService transaksjonMappingService; + private ObjectMapper objectMapper; + private ErrorStatusDecoder errorStatusDecoder; + + public PensjonforvalterHelper(TransaksjonMappingService transaksjonMappingService, ObjectMapper objectMapper, ErrorStatusDecoder errorStatusDecoder) { + this.transaksjonMappingService = transaksjonMappingService; + this.objectMapper = objectMapper; + this.errorStatusDecoder = errorStatusDecoder; + } + + @SuppressWarnings("java:S3740") + public void saveAPTransaksjonId(String ident, String miljoe, Long bestillingId, + SystemTyper type, AtomicReference vedtak) { + + log.info("Lagrer transaksjon for {} i {} ", ident, miljoe); + transaksjonMappingService.delete(ident, miljoe, type.name()); + + transaksjonMappingService.save( + TransaksjonMapping.builder() + .ident(ident) + .bestillingId(bestillingId) + .transaksjonId(toJson(vedtak.get())) + .datoEndret(LocalDateTime.now()) + .miljoe(miljoe) + .system(type.name()) + .build()); + } + + private String toJson(Object object) { + + try { + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + log.error("Feilet å konvertere transaksjonsId for pensjonForvalter", e); + } + return null; + } + + public String decodeStatus(PensjonforvalterResponse response, String ident) { + + log.info("Mottatt status på {} fra Pensjon-Testdata-Facade: {}", ident, response); + + return response.getStatus().stream() + .map(entry -> String.format("%s:%s", entry.getMiljo(), + entry.getResponse().isResponse2xx() ? "OK" : + getError(entry))) + .collect(Collectors.joining(",")); + } + + public String getError(PensjonforvalterResponse.ResponseEnvironment entry) { + + var response = entry.getResponse(); + var httpStatus = response.getHttpStatus(); + + if (isNotBlank(response.getMessage())) { + if (response.getMessage().contains("{")) { + return encodeStatus( + "Feil: " + response.getMessage().split("\\{")[1].split("}")[0].replace("message\":", "")); + } else { + return encodeStatus("Feil: " + response.getMessage()); + } + + } else { + return errorStatusDecoder.getErrorText(HttpStatus.valueOf(httpStatus.getStatus()), httpStatus.getReasonPhrase()); + } + } +} diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterUtils.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterUtils.java new file mode 100644 index 00000000000..63425e08f32 --- /dev/null +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterUtils.java @@ -0,0 +1,72 @@ +package no.nav.dolly.bestilling.pensjonforvalter.utils; + +import lombok.experimental.UtilityClass; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonVedtakResponse; +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; +import no.nav.dolly.domain.PdlPersonBolk; +import reactor.core.publisher.Flux; + +import java.util.List; + +import static org.apache.poi.util.StringUtil.isNotBlank; + +@UtilityClass +public class PensjonforvalterUtils { + + public static final String SEP = "$"; + public static final String IDENT = "ident"; + public static final String MILJOER = "miljoer"; + public static final String NAV_ENHET = "navEnhet"; + public static final String SYSTEM = "PESYS"; + public static final String PENSJON_FORVALTER = "PensjonForvalter#"; + public static final String SAMBOER_REGISTER = "Samboer#"; + public static final String POPP_INNTEKTSREGISTER = "PoppInntekt#"; + public static final String TP_FORHOLD = "TpForhold#"; + public static final String PEN_ALDERSPENSJON = "AP#"; + public static final String PEN_UFORETRYGD = "Ufoer#"; + public static final String PEN_PENSJONSAVTALE = "Pensjonsavtale#"; + public static final String PEN_AFP_OFFENTLIG = "AfpOffentlig#"; + public static final String ANNET = "Annet#"; + public static final String PERIODE = "/periode/"; + + public static boolean hasVedtak(List pensjonsvedtak, PensjonVedtakResponse.SakType type) { + + return pensjonsvedtak.stream().anyMatch(entry -> entry.getSakType() == type && + entry.getSisteOppdatering().contains("opprettet")); + } + + public static String getPeriodeId(String lenke) { + return lenke.substring(lenke.indexOf(PERIODE) + PERIODE.length()) + .replace("/annuller", ""); + } + + public static Flux getStatus(String miljoe, Integer status, String reasonPhrase) { + + return Flux.just(PensjonforvalterResponse.builder() + .status(List.of(PensjonforvalterResponse.ResponseEnvironment.builder() + .miljo(miljoe) + .response(PensjonforvalterResponse.Response.builder() + .httpStatus(PensjonforvalterResponse.HttpStatus.builder() + .status(status) + .reasonPhrase(reasonPhrase) + .build()) + .message(reasonPhrase) + .build()) + .build())) + .build()); + } + + public static String getGeografiskTilknytning(PdlPersonBolk.GeografiskTilknytning tilknytning) { + + if (isNotBlank(tilknytning.getGtKommune())) { + return tilknytning.getGtKommune(); + + } else if (isNotBlank(tilknytning.getGtBydel())) { + return tilknytning.getGtBydel(); + + } else { + return "030102"; + } + } + +} diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/personservice/PersonServiceClient.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/personservice/PersonServiceClient.java index 8585dd2916f..22ce9ec37a3 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/personservice/PersonServiceClient.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/personservice/PersonServiceClient.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import no.nav.dolly.bestilling.ClientFuture; import no.nav.dolly.bestilling.personservice.dto.PersonServiceResponse; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.PdlPerson; import no.nav.dolly.domain.PdlPersonBolk; import no.nav.dolly.domain.jpa.BestillingProgress; @@ -16,6 +17,7 @@ import no.nav.dolly.exceptions.DollyFunctionalException; import no.nav.dolly.util.TransactionHelperService; import no.nav.testnav.libs.data.pdlforvalter.v1.FullmaktDTO; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.apache.commons.lang3.StringUtils; import org.apache.poi.util.StringUtil; import org.springframework.stereotype.Service; @@ -46,11 +48,11 @@ public class PersonServiceClient { private static final String PDL_SYNC_START = "Info: Synkronisering mot PDL startet ..."; private static final int TIMEOUT = 500; - private static final int MAX_SEKUNDER = 30; private final PersonServiceConsumer personServiceConsumer; private final ErrorStatusDecoder errorStatusDecoder; private final TransactionHelperService transactionHelperService; private final ObjectMapper objectMapper; + private final ApplicationConfig applicationConfig; public Flux syncPerson(DollyPerson dollyPerson, BestillingProgress progress) { @@ -60,11 +62,24 @@ public Flux syncPerson(DollyPerson dollyPerson, BestillingProgress var startTime = System.currentTimeMillis(); return Flux.from(getIdentWithRelasjoner(dollyPerson, progress) - .flatMap(status -> getPersonService(LocalTime.now().plusSeconds(MAX_SEKUNDER), LocalTime.now(), + .flatMap(status -> getPersonService(LocalTime.now().plusSeconds(applicationConfig.getClientTimeout()), LocalTime.now(), new PersonServiceResponse(), status)) + .timeout(Duration.ofSeconds(applicationConfig.getClientTimeout())) + .onErrorResume(error -> getError(error, dollyPerson)) .doOnNext(status -> logStatus(status, startTime)) .collectList() - .map(status -> futurePersist(dollyPerson, progress, status))); + .map(status -> futurePersist(dollyPerson, progress, status)) + ); + } + + private Flux getError(Throwable error, DollyPerson person) { + + return Flux.just(PersonServiceResponse.builder() + .ident(person.getIdent()) + .formattertMelding("Feil= %s".formatted(ErrorStatusDecoder.encodeStatus(WebClientFilter.getMessage(error)))) + .status(WebClientFilter.getStatus(error)) + .exists(false) + .build()); } private Map> getHendelseIder(boolean isOrdre, BestillingProgress progress) { @@ -177,13 +192,14 @@ private void logStatus(PersonServiceResponse status, long startTime) { log.error("Synkronisering mot PersonService (isPerson) for {} gitt opp etter {} ms.", status.getIdent(), System.currentTimeMillis() - startTime); status.setFormattertMelding(String.format("Feil: Synkronisering mot PDL gitt opp etter %d sekunder.", - MAX_SEKUNDER)); + applicationConfig.getClientTimeout())); } else { - log.error("Feilet å sjekke om person finnes for ident {}, medgått tid {} ms, feil {}.", + log.error("Feilet å sjekke om person finnes for ident {}, medgått tid {} ms, {}.", status.getIdent(), System.currentTimeMillis() - startTime, errorStatusDecoder.getErrorText(status.getStatus(), status.getFeilmelding())); - status.setFormattertMelding("Feilet å skjekke status, se logg!"); + status.setFormattertMelding("Feil: Synkronisering mot PDL gitt opp etter %d sekunder." + .formatted(applicationConfig.getClientTimeout())); } } diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/sykemelding/SykemeldingClient.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/sykemelding/SykemeldingClient.java index d81437c6162..c7714481e7c 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/sykemelding/SykemeldingClient.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/sykemelding/SykemeldingClient.java @@ -12,6 +12,7 @@ import no.nav.dolly.bestilling.sykemelding.domain.DetaljertSykemeldingRequest; import no.nav.dolly.bestilling.sykemelding.domain.SyntSykemeldingRequest; import no.nav.dolly.bestilling.sykemelding.dto.SykemeldingResponse; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.consumer.kodeverk.KodeverkConsumer; import no.nav.dolly.consumer.norg2.Norg2Consumer; import no.nav.dolly.consumer.norg2.dto.Norg2EnhetResponse; @@ -24,10 +25,12 @@ import no.nav.dolly.errorhandling.ErrorStatusDecoder; import no.nav.dolly.service.TransaksjonMappingService; import no.nav.dolly.util.TransactionHelperService; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; import java.time.LocalDateTime; import java.util.List; import java.util.Objects; @@ -35,6 +38,7 @@ import static java.util.Objects.nonNull; import static no.nav.dolly.domain.resultset.SystemTyper.SYKEMELDING; +import static no.nav.dolly.errorhandling.ErrorStatusDecoder.encodeStatus; import static no.nav.dolly.util.DollyTextUtil.getGenereringStartet; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -53,6 +57,7 @@ public class SykemeldingClient implements ClientRegister { private final PersonServiceConsumer personServiceConsumer; private final KodeverkConsumer kodeverkConsumer; private final Norg2Consumer norg2Consumer; + private final ApplicationConfig applicationConfig; @Override public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, DollyPerson dollyPerson, BestillingProgress progress, boolean isOpprettEndre) { @@ -76,6 +81,9 @@ public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, Dolly .doOnNext(status -> saveTransaksjonId(status, bestilling.getId())) .map(this::getStatus) .collect(Collectors.joining())) + .timeout(Duration.ofSeconds(applicationConfig.getClientTimeout() * + (sykemelding.hasSyntSykemelding() ? 3 : 1))) + .onErrorResume(error -> Mono.just(encodeStatus(WebClientFilter.getMessage(error)))) .collect(Collectors.joining()) .map(status -> futurePersist(progress, status)); } diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/tpsmessagingservice/TpsMessagingClient.java b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/tpsmessagingservice/TpsMessagingClient.java index 550e2ef5200..f4dd7d8c3e1 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/tpsmessagingservice/TpsMessagingClient.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/bestilling/tpsmessagingservice/TpsMessagingClient.java @@ -7,6 +7,7 @@ import no.nav.dolly.bestilling.ClientRegister; import no.nav.dolly.bestilling.personservice.PersonServiceConsumer; import no.nav.dolly.bestilling.skjermingsregister.SkjermingUtil; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.PdlPerson; import no.nav.dolly.domain.PdlPersonBolk; import no.nav.dolly.domain.jpa.BestillingProgress; @@ -16,11 +17,13 @@ import no.nav.dolly.util.TransactionHelperService; import no.nav.testnav.libs.data.tpsmessagingservice.v1.SpraakDTO; import no.nav.testnav.libs.data.tpsmessagingservice.v1.TpsMeldingResponseDTO; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; import java.util.Collection; import java.util.List; import java.util.Map; @@ -50,6 +53,7 @@ public class TpsMessagingClient implements ClientRegister { private final PersonServiceConsumer personServiceConsumer; private final TransactionHelperService transactionHelperService; private final MiljoerConsumer miljoerConsumer; + private final ApplicationConfig applicationConfig; private static String getResultat(TpsMeldingResponseDTO respons) { @@ -61,9 +65,9 @@ private static String getStatus(String melding, List stat return !statuser.isEmpty() ? - String.format("%s#%s", melding, + "%s#%s".formatted(melding, statuser.stream() - .map(respons -> String.format(STATUS_FMT, + .map(respons -> STATUS_FMT.formatted( respons.getMiljoe(), getResultat(respons))) .collect(Collectors.joining(","))) : @@ -103,11 +107,23 @@ public Flux gjenopprett(RsDollyUtvidetBestilling bestilling, Dolly .toList()) .flatMap(Flux::fromIterable) .filter(StringUtils::isNotBlank) + .timeout(Duration.ofSeconds(applicationConfig.getClientTimeout())) + .onErrorResume(error -> getError(error, miljoer)) .collect(Collectors.joining(SEP)); })) .map(status -> futurePersist(dollyPerson, progress, status)); } + private Flux getError(Throwable error, List miljoer) { + + return Flux.just("Meldinger til TPS#%s".formatted( + miljoer.stream() + .map(miljoe -> STATUS_FMT.formatted( + miljoe, + "FEIL= " + ErrorStatusDecoder.encodeStatus(WebClientFilter.getMessage(error)))) + .collect(Collectors.joining(",")))); + } + private boolean isTpsMessage(RsDollyUtvidetBestilling bestilling) { return (nonNull(bestilling.getTpsMessaging()) && diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/config/ApplicationConfig.java b/apps/dolly-backend/src/main/java/no/nav/dolly/config/ApplicationConfig.java index 836083f6583..e8e287829bf 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/config/ApplicationConfig.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/config/ApplicationConfig.java @@ -1,15 +1,18 @@ package no.nav.dolly.config; import jakarta.annotation.PostConstruct; +import lombok.Getter; import no.nav.testnav.libs.reactivecore.config.CoreConfig; import no.nav.testnav.libs.servletcore.config.ApplicationCoreConfig; import no.nav.testnav.libs.servletsecurity.config.SecureOAuth2ServerToServerConfiguration; import no.nav.testnav.libs.standalone.servletsecurity.config.InsecureJwtServerToServerConfiguration; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.retry.annotation.EnableRetry; import org.springframework.security.core.context.SecurityContextHolder; +@Getter @Configuration @EnableRetry @Import({ @@ -20,6 +23,9 @@ }) public class ApplicationConfig { + @Value("${dolly.client.general.timeout}") + private Long clientTimeout; + @PostConstruct public void enableAuthCtxOnSpawnedThreads() { SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/RsDollyBestilling.java b/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/RsDollyBestilling.java index a59a8123373..7bba84342ef 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/RsDollyBestilling.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/RsDollyBestilling.java @@ -131,6 +131,16 @@ public List getYrkesskader() { return yrkesskader; } + @JsonIgnore + public boolean isPensjon() { + return nonNull(pensjonforvalter); + } + + @JsonIgnore + public boolean isExistInntekstsmelding() { + return nonNull(inntektsmelding); + } + @JsonIgnore public boolean isNonEmpty() { diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/SystemTyper.java b/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/SystemTyper.java index 2d6f4a2d8c4..ca19852f037 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/SystemTyper.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/SystemTyper.java @@ -17,21 +17,22 @@ public enum SystemTyper { ARENA_DAGP("Arena dagpenger"), BRREGSTUB("Brønnøysundregistrene (BRREGSTUB)"), DOKARKIV("Dokumentarkiv (JOARK)"), + FULLMAKT("Fullmakt (Representasjon)"), HISTARK("Saksmappearkiv (HISTARK)"), INNTK("Inntektskomponenten (INNTK)"), INNTKMELD("Inntektsmelding (ALTINN/JOARK)"), INST2("Institusjonsopphold (INST2)"), KONTOREGISTER("Bankkontoregister"), KRRSTUB("Digital kontaktinformasjon (DKIF)"), - FULLMAKT("Fullmakt (Representasjon)"), MEDL("Medlemskap (MEDL)"), ORGANISASJON_FORVALTER("Enhetsregisteret (EREG)"), PDLIMPORT("Import av personer (TESTNORGE)"), PDL_FORVALTER("Opprett persondetaljer"), PDL_ORDRE("Ordre til PDL"), PDL_PERSONSTATUS("Person finnes i PDL"), - PEN_AP("Alderspensjon (AP)"), PEN_AFP_OFFENTLIG("AFP offentlig (PEN)"), + PEN_ANNET("Pensjon (PEN)"), + PEN_AP("Alderspensjon (AP)"), PEN_FORVALTER("Pensjon persondata (PEN)"), PEN_INNTEKT("Pensjonsopptjening (POPP)"), PEN_PENSJONSAVTALE("Pensjonsavtale (PEN)"), diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/errorhandling/ErrorStatusDecoder.java b/apps/dolly-backend/src/main/java/no/nav/dolly/errorhandling/ErrorStatusDecoder.java index e156d178db2..8e5af8858ee 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/errorhandling/ErrorStatusDecoder.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/errorhandling/ErrorStatusDecoder.java @@ -1,7 +1,7 @@ package no.nav.dolly.errorhandling; import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; @@ -20,7 +20,7 @@ @Slf4j @Service -@RequiredArgsConstructor +@NoArgsConstructor public class ErrorStatusDecoder { private static final String TEKNISK_FEIL = "Teknisk feil {} mottatt fra system"; @@ -31,7 +31,11 @@ public class ErrorStatusDecoder { private static final String DETAILS = "details"; private static final String FEIL = "Feil= "; - private final ObjectMapper objectMapper; + private ObjectMapper objectMapper; + + public ErrorStatusDecoder(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } public static String getInfoVenter(String system) { @@ -67,16 +71,6 @@ public String getErrorText(HttpStatus errorStatus, String errorMsg) { return builder.toString(); } - public String decodeException(Exception e) { - - log.error(TEKNISK_FEIL, e.getMessage(), e); - return new StringBuilder() - .append(FEIL) - .append(TEKNISK_FEIL_SE_LOGG) - .append(encodeStatus(e.getMessage())) - .toString(); - } - public String decodeThrowable(Throwable error) { StringBuilder builder = new StringBuilder() diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/mapper/BestillingPensjonforvalterStatusMapper.java b/apps/dolly-backend/src/main/java/no/nav/dolly/mapper/BestillingPensjonforvalterStatusMapper.java index c04d76911f4..c2852a337b1 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/mapper/BestillingPensjonforvalterStatusMapper.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/mapper/BestillingPensjonforvalterStatusMapper.java @@ -16,6 +16,7 @@ import static java.util.Objects.nonNull; import static no.nav.dolly.domain.resultset.SystemTyper.PEN_AFP_OFFENTLIG; +import static no.nav.dolly.domain.resultset.SystemTyper.PEN_ANNET; import static no.nav.dolly.domain.resultset.SystemTyper.PEN_AP; import static no.nav.dolly.domain.resultset.SystemTyper.PEN_FORVALTER; import static no.nav.dolly.domain.resultset.SystemTyper.PEN_INNTEKT; @@ -37,6 +38,7 @@ public final class BestillingPensjonforvalterStatusMapper { private static final String SAMBOER = "Samboer"; private static final String PENSJONSAVTALE = "Pensjonsavtale"; private static final String PEN_AFPOFFENTLIG = "AfpOffentlig"; + private static final String ANNET = "Annet"; public static List buildPensjonforvalterStatusMap(List progressList) { @@ -53,7 +55,7 @@ public static List buildPensjonforvalterStatusMap(List 1 ? miljoStatuser[0] : null; if (nonNull(miljoe)) { - String status = miljoStatuser.length > 1 ? miljoStatuser[1] : miljoStatuser[0]; + String status = miljoStatuser[1]; insertArtifact(meldStatusMiljoeIdents, melding, status, miljoe, progress.getIdent()); } }); @@ -71,6 +73,7 @@ public static List buildPensjonforvalterStatusMap(List Opprett fiktive testpersoner med arbeidsforhold, inntekter, sykemelding og annet i hht testbehov. version: Versjon 1 + client: + general: + timeout: 30 server: port: 8080 diff --git a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/aareg/AaregClientTest.java b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/aareg/AaregClientTest.java index 35fae048824..b1e1401ce99 100644 --- a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/aareg/AaregClientTest.java +++ b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/aareg/AaregClientTest.java @@ -4,6 +4,7 @@ import ma.glasnost.orika.MappingContext; import no.nav.dolly.bestilling.ClientFuture; import no.nav.dolly.bestilling.aareg.domain.ArbeidsforholdRespons; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.jpa.BestillingProgress; import no.nav.dolly.domain.jpa.Bruker; import no.nav.dolly.domain.resultset.RsDollyBestillingRequest; @@ -48,6 +49,9 @@ class AaregClientTest { private static final String ENV = "u2"; private static final String ORGNUMMER = "222222222"; + @Mock + private ApplicationConfig applicationConfig; + @Mock private AaregConsumer aaregConsumer; @@ -74,6 +78,7 @@ class AaregClientTest { @BeforeEach void setup() { + when(applicationConfig.getClientTimeout()).thenReturn(30L); when(aaregConsumer.getAccessToken()) .thenReturn(Mono.just(accessToken)); statusCaptor = ArgumentCaptor.forClass(String.class); @@ -127,28 +132,6 @@ void gjenopprettArbeidsforhold_intetTidligereArbeidsforholdFinnes_OK() { verify(aaregConsumer).opprettArbeidsforhold(any(Arbeidsforhold.class), eq(ENV), eq(accessToken))); } - @Test - void gjenopprettArbeidsforhold_intetTidligereArbeidsforholdFinnes_lesKasterException() { - when(mapperFacade.mapAsList(anyList(), eq(Arbeidsforhold.class), any())) - .thenReturn(singletonList(new Arbeidsforhold())); - when(aaregConsumer.hentArbeidsforhold(IDENT, ENV, accessToken)) - .thenReturn(Mono.just(new ArbeidsforholdRespons())); - when(aaregConsumer.opprettArbeidsforhold(any(Arbeidsforhold.class), eq(ENV), eq(accessToken))) - .thenReturn(Flux.just(new ArbeidsforholdRespons())); - when(mapperFacade.mapAsList(anyList(), eq(Arbeidsforhold.class))) - .thenReturn(buildArbeidsforhold(true).getEksisterendeArbeidsforhold()); - - var request = new RsDollyBestillingRequest(); - request.setAareg(singletonList(RsAareg.builder().build())); - request.setEnvironments(singleton(ENV)); - aaregClient.gjenopprett(request, - DollyPerson.builder().ident(IDENT) - .bruker(bruker) - .build(), bestillingProgress, false) - .subscribe(resultat -> - verify(aaregConsumer).opprettArbeidsforhold(any(Arbeidsforhold.class), eq(ENV), eq(accessToken))); - } - @Test void gjenopprettArbeidsforhold_tidligereArbeidsforholdFinnesAktoerPerson_returnsOK() { var request = new RsDollyBestillingRequest(); diff --git a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/arenaforvalter/ArenaForvalterClientTest.java b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/arenaforvalter/ArenaForvalterClientTest.java index d2b8c9bae15..0c315e0d2b4 100644 --- a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/arenaforvalter/ArenaForvalterClientTest.java +++ b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/arenaforvalter/ArenaForvalterClientTest.java @@ -7,13 +7,13 @@ import no.nav.dolly.bestilling.arenaforvalter.service.ArenaBrukerService; import no.nav.dolly.bestilling.arenaforvalter.service.ArenaDagpengerService; import no.nav.dolly.bestilling.arenaforvalter.service.ArenaStansYtelseService; +import no.nav.dolly.config.ApplicationConfig; import no.nav.dolly.domain.jpa.BestillingProgress; import no.nav.dolly.domain.resultset.RsDollyBestillingRequest; import no.nav.dolly.domain.resultset.arenaforvalter.Arenadata; import no.nav.dolly.domain.resultset.dolly.DollyPerson; import no.nav.dolly.util.TransactionHelperService; import org.hamcrest.Matchers; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -45,6 +45,9 @@ class ArenaForvalterClientTest { private static final String IDENT = "12423353112"; private static final String ENV = "q2"; + @Mock + private ApplicationConfig applicationConfig; + @Mock private ArenaForvalterConsumer arenaForvalterConsumer; @@ -80,6 +83,8 @@ void setup() { @Test void gjenopprett_Ok() { + when(applicationConfig.getClientTimeout()).thenReturn(30L); + BestillingProgress progress = new BestillingProgress(); when(arenaForvalterConsumer.getEnvironments()).thenReturn(Flux.just(ENV)); when(arenaForvalterConsumer.getArenaBruker(anyString(), anyString())) @@ -111,6 +116,8 @@ void gjenopprett_Ok() { @Test void gjenopprett_FunksjonellFeil() { + when(applicationConfig.getClientTimeout()).thenReturn(30L); + var progress = new BestillingProgress(); when(arenaForvalterConsumer.getEnvironments()).thenReturn(Flux.just(ENV)); @@ -144,6 +151,8 @@ void gjenopprett_FunksjonellFeil() { @Test void gjenopprett_TekniskFeil() { + when(applicationConfig.getClientTimeout()).thenReturn(30L); + var progress = new BestillingProgress(); var request = new RsDollyBestillingRequest(); @@ -151,10 +160,11 @@ void gjenopprett_TekniskFeil() { request.setEnvironments(singleton(ENV)); when(arenaForvalterConsumer.getEnvironments()).thenReturn(Flux.just(ENV)); - var gjenopprett = arenaForvalterClient.gjenopprett(request, DollyPerson.builder().ident(IDENT) - .build(), progress, false); - - Assertions.assertThrows(NullPointerException.class, () -> gjenopprett .blockFirst()); + StepVerifier.create(arenaForvalterClient.gjenopprett(request, DollyPerson.builder().ident(IDENT) + .build(), progress, false) + .map(ClientFuture::get)) + .assertNext(status -> assertThat(status.getArenaforvalterStatus(), is(nullValue()))) + .verifyComplete(); } @Test diff --git a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/PensjonforvalterClientTest.java b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java similarity index 50% rename from apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/PensjonforvalterClientTest.java rename to apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java index 72e258ad4f5..5d3ea19ac06 100644 --- a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/PensjonforvalterClientTest.java +++ b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java @@ -1,43 +1,30 @@ -package no.nav.dolly.bestilling.pensjonforvalter; +package no.nav.dolly.bestilling.pensjonforvalter.service; import ma.glasnost.orika.MapperFacade; import ma.glasnost.orika.MappingContext; -import no.nav.dolly.bestilling.ClientFuture; -import no.nav.dolly.bestilling.pdldata.PdlDataConsumer; +import no.nav.dolly.bestilling.pensjonforvalter.PensjonforvalterConsumer; import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonPersonRequest; import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonTpForholdRequest; import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonTpYtelseRequest; import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; -import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse.ResponseEnvironment; -import no.nav.dolly.bestilling.personservice.PersonServiceConsumer; -import no.nav.dolly.consumer.norg2.Norg2Consumer; -import no.nav.dolly.consumer.norg2.dto.Norg2EnhetResponse; -import no.nav.dolly.domain.PdlPerson; +import no.nav.dolly.bestilling.pensjonforvalter.utils.PensjonforvalterHelper; import no.nav.dolly.domain.PdlPersonBolk; import no.nav.dolly.domain.jpa.Bestilling; import no.nav.dolly.domain.jpa.BestillingProgress; import no.nav.dolly.domain.resultset.RsDollyUtvidetBestilling; -import no.nav.dolly.domain.resultset.dolly.DollyPerson; import no.nav.dolly.domain.resultset.pensjon.PensjonData; -import no.nav.dolly.errorhandling.ErrorStatusDecoder; -import no.nav.dolly.util.TransactionHelperService; -import no.nav.testnav.libs.securitycore.domain.AccessToken; -import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; -import org.springframework.http.HttpStatus; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.util.ArrayList; @@ -45,86 +32,198 @@ import java.util.List; import java.util.Set; -import static no.nav.dolly.bestilling.pensjonforvalter.PensjonforvalterClient.mergePensjonforvalterResponses; +import static no.nav.dolly.bestilling.pensjonforvalter.service.PensjonPensjonsdataService.mergePensjonforvalterResponses; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anySet; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) -class PensjonforvalterClientTest { +class PensjonPensjonsdataServiceTest { private static final String IDENT = "11111111111"; + @Spy + private PensjonforvalterHelper pensjonforvalterHelper; + @Mock private PensjonforvalterConsumer pensjonforvalterConsumer; @Mock private MapperFacade mapperFacade; - @Mock - private AccessToken accessToken; + @InjectMocks + private PensjonPensjonsdataService pensjonPensjonsdataService; - @Mock - private TransactionHelperService transactionHelperService; + @BeforeEach + void setup() { + when(mapperFacade.map(any(PdlPersonBolk.PersonBolk.class), eq(PensjonPersonRequest.class))).thenReturn(new PensjonPersonRequest()); + when(pensjonforvalterConsumer.opprettPerson(any(PensjonPersonRequest.class), anySet())) + .thenReturn(Flux.just(new PensjonforvalterResponse())); + } - @Mock - private PersonServiceConsumer personServiceConsumer; + @Test + void testLagreTpForhold_withOkResult() { - @Mock - private PdlDataConsumer pdlDataConsumer; + var tp1 = getTpOrdningWithYtelser("1111", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())); + var tp2 = getTpOrdningWithYtelser("2222", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())); - @Mock - private Norg2Consumer norg2Consumer; + PensjonData pensjonData = new PensjonData(); + pensjonData.setTp(Arrays.asList(tp1, tp2)); - @Mock - private ErrorStatusDecoder errorStatusDecoder; + var bestilling = new RsDollyUtvidetBestilling(); + bestilling.setEnvironments(Set.of("TEST1", "TEST2")); + bestilling.setPensjonforvalter(pensjonData); - @Captor - ArgumentCaptor statusCaptor; + var progress = new BestillingProgress(); + var dbBestilling = Bestilling.builder().id(1L).build(); + progress.setBestilling(dbBestilling); - @InjectMocks - private PensjonforvalterClient pensjonforvalterClient; + when(pensjonforvalterConsumer.lagreTpForhold(any(PensjonTpForholdRequest.class))) + .thenReturn(Flux.just(PensjonforvalterResponse.builder() + .status(List.of( + new PensjonforvalterResponse.ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()), + new PensjonforvalterResponse.ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()))) + .build())); - @BeforeEach - void setup() { - statusCaptor = ArgumentCaptor.forClass(String.class); - when(mapperFacade.map(any(PdlPersonBolk.PersonBolk.class), eq(PensjonPersonRequest.class))).thenReturn(new PensjonPersonRequest()); - when(accessToken.getTokenValue()).thenReturn("123"); - when(pensjonforvalterConsumer.opprettPerson(any(PensjonPersonRequest.class), anySet())) - .thenReturn(Flux.just(new PensjonforvalterResponse())); + when(pensjonforvalterConsumer.lagreTpYtelse(any(PensjonTpYtelseRequest.class))) + .thenReturn(Flux.just(PensjonforvalterResponse.builder() + .status(List.of( + new PensjonforvalterResponse.ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()), + new PensjonforvalterResponse.ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()))) + .build())); - var pdlPersonBolk = PdlPersonBolk.builder() - .data(PdlPersonBolk.Data.builder() - .hentGeografiskTilknytningBolk(List.of(PdlPersonBolk.GeografiskTilknytningBolk.builder() - .geografiskTilknytning(PdlPersonBolk.GeografiskTilknytning.builder() - .gtKommune("1200") - .build()) - .build())) - .hentPersonBolk(List.of(PdlPersonBolk.PersonBolk.builder() - .ident(IDENT) - .person(new PdlPerson.Person()) - .build())) - .build()) - .build(); - when(personServiceConsumer.getPdlPersoner(anyList())).thenReturn(Flux.just(pdlPersonBolk)); - when(norg2Consumer.getNorgEnhet(anyString())).thenReturn(Mono.just(Norg2EnhetResponse.builder().enhetNr("0315").build())); + when(mapperFacade.map(any(PensjonData.TpOrdning.class), eq(PensjonTpForholdRequest.class), any(MappingContext.class))) + .thenReturn(new PensjonTpForholdRequest()); + when(mapperFacade.map(any(PensjonData.TpYtelse.class), eq(PensjonTpYtelseRequest.class), any(MappingContext.class))) + .thenReturn(new PensjonTpYtelseRequest()); + + StepVerifier.create(pensjonPensjonsdataService.lagrePensjonsdata(bestilling, IDENT, bestilling.getEnvironments())) + .assertNext(status -> { + assertThat(status, containsString("TpForhold#")); + assertThat(Arrays.asList(status.split("#")[1].split(",")), containsInAnyOrder("TEST1:OK", "TEST2:OK")); + }) + .verifyComplete(); + } + + @Test + void testLagreTpForhold_withOneFailedResult() { + + var tp1 = getTpOrdningWithYtelser("1111", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())); + var tp2 = getTpOrdningWithYtelser("2222", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())); + + var pensjonData = new PensjonData(); + pensjonData.setTp(Arrays.asList(tp1, tp2)); + + var bestilling = new RsDollyUtvidetBestilling(); + bestilling.setEnvironments(Set.of("TEST1", "TEST2")); + bestilling.setPensjonforvalter(pensjonData); + + var progress = new BestillingProgress(); + var dbBestilling = Bestilling.builder().id(1L).build(); + progress.setBestilling(dbBestilling); + + when(pensjonforvalterConsumer.lagreTpForhold(any(PensjonTpForholdRequest.class))) + .thenReturn(Flux.just(PensjonforvalterResponse.builder() + .status(List.of( + new PensjonforvalterResponse.ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()), + new PensjonforvalterResponse.ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()))) + .build())); + + when(pensjonforvalterConsumer.lagreTpYtelse(any(PensjonTpYtelseRequest.class))) + .thenReturn(Flux.just(PensjonforvalterResponse.builder() + .status(List.of( + new PensjonforvalterResponse.ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()), + new PensjonforvalterResponse.ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("Intern feil", 500)) + .message("{ytelse2 feil on TEST2}") + .build()))) + .build())); + + when(mapperFacade.map(any(PensjonData.TpOrdning.class), eq(PensjonTpForholdRequest.class), any(MappingContext.class))) + .thenReturn(new PensjonTpForholdRequest()); + when(mapperFacade.map(any(PensjonData.TpYtelse.class), eq(PensjonTpYtelseRequest.class), any(MappingContext.class))) + .thenReturn(new PensjonTpYtelseRequest()); + + StepVerifier.create(pensjonPensjonsdataService.lagrePensjonsdata(bestilling, IDENT, bestilling.getEnvironments())) + .assertNext(status -> { + assertThat(status, containsString("TpForhold#")); + assertThat(Arrays.asList(status.split("#")[1].split(",")), containsInAnyOrder("TEST1:OK", "TEST2:Feil= ytelse2 feil on TEST2")); + }) + .verifyComplete(); + } + + @Test + void testLagreTpForhold_withException() { + + var bestilling = new RsDollyUtvidetBestilling(); + bestilling.setEnvironments(Set.of("TEST1", "TEST2")); + bestilling.setPensjonforvalter(PensjonData.builder() + .tp(List.of(getTpOrdningWithYtelser("1111", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())), + getTpOrdningWithYtelser("2222", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())))) + .build()); + + when(pensjonforvalterConsumer.lagreTpForhold(any(PensjonTpForholdRequest.class))) + .thenReturn(Flux.just(PensjonforvalterResponse.builder() + .status(List.of( + new PensjonforvalterResponse.ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()), + new PensjonforvalterResponse.ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("", 200)) + .build()) + )) + .build())); + + when(pensjonforvalterConsumer.lagreTpYtelse(any(PensjonTpYtelseRequest.class))) + .thenReturn(Flux.just(PensjonforvalterResponse.builder() + .status(List.of( + new PensjonforvalterResponse.ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) + .build()), + new PensjonforvalterResponse.ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() + .httpStatus(new PensjonforvalterResponse.HttpStatus("Internal Server Error", 500)) + .message(String.format("Klarte ikke å få TP-ytelse respons for %s i PESYS (pensjon)", "12345")) + .build()))) + .build())); + + + when(mapperFacade.map(any(PensjonData.TpOrdning.class), eq(PensjonTpForholdRequest.class), any(MappingContext.class))) + .thenReturn(new PensjonTpForholdRequest()); + when(mapperFacade.map(any(PensjonData.TpYtelse.class), eq(PensjonTpYtelseRequest.class), any(MappingContext.class))) + .thenReturn(new PensjonTpYtelseRequest()); + + StepVerifier.create(pensjonPensjonsdataService.lagrePensjonsdata(bestilling, IDENT, bestilling.getEnvironments())) + .assertNext(status -> { + assertThat(status, containsString("TpForhold#")); + assertThat(Arrays.asList(status.split("#")[1].split(",")), containsInAnyOrder("TEST1:OK", + "TEST2:Feil= Klarte ikke å få TP-ytelse respons for 12345 i PESYS (pensjon)")); + }) + .verifyComplete(); } - // empty new response list to empty previous list - // none empty new response list to empty previous list - // empty new response list to none empty previous list @Test void testMergePensjonforvalterResponses_withEmptyList() { var response1 = new PensjonforvalterResponse(); @@ -171,8 +270,8 @@ void testMergePensjonforvalterResponses_withSameEnvironments_200_til_200(String var result = mergePensjonforvalterResponses(List.of(response1, response2)); assertThat(result.getStatus(), hasSize(1)); - assertThat(result.getStatus().get(0).getMiljo(), is(equalTo(resultatMiljo))); - assertThat(result.getStatus().get(0).getResponse().getHttpStatus().getStatus(), is(equalTo(resultatStatus))); + assertThat(result.getStatus().getFirst().getMiljo(), is(equalTo(resultatMiljo))); + assertThat(result.getStatus().getFirst().getResponse().getHttpStatus().getStatus(), is(equalTo(resultatStatus))); } // none empty new response list to none empty previous list with different env name @@ -184,10 +283,10 @@ void testMergePensjonforvalterResponses_withDifferentEnvironments() { var result = mergePensjonforvalterResponses(List.of(response1, response2)); assertThat(result.getStatus(), hasSize(2)); - assertThat(result.getStatus().get(0).getMiljo(), is(equalTo("T1"))); - assertThat(result.getStatus().get(0).getResponse().getHttpStatus().getStatus(), is(equalTo(200))); - assertThat(result.getStatus().get(1).getMiljo(), is(equalTo("T2"))); - assertThat(result.getStatus().get(1).getResponse().getHttpStatus().getStatus(), is(equalTo(200))); + assertThat(result.getStatus().getFirst().getMiljo(), is(equalTo("T1"))); + assertThat(result.getStatus().getFirst().getResponse().getHttpStatus().getStatus(), is(equalTo(200))); + assertThat(result.getStatus().getLast().getMiljo(), is(equalTo("T2"))); + assertThat(result.getStatus().getLast().getResponse().getHttpStatus().getStatus(), is(equalTo(200))); } // none empty new reponse list with 2 env (status 200), previous list with 2 env but 1 is same, 1 is different (status 200) @@ -255,272 +354,6 @@ void testMergePensjonforvalterResponses_withMixedEnvironments_500_til_500() { assertThat(resultat.getStatus().get(2).getResponse().getHttpStatus().getStatus(), is(equalTo(500))); } - @Test - void testLagreTpForhold_withOkResult() { - - var tp1 = PensjonforvalterClientTestUtil.getTpOrdningWithYtelser("1111", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())); - var tp2 = PensjonforvalterClientTestUtil.getTpOrdningWithYtelser("2222", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())); - - PensjonData pensjonData = new PensjonData(); - pensjonData.setTp(Arrays.asList(tp1, tp2)); - - var bestilling = new RsDollyUtvidetBestilling(); - bestilling.setEnvironments(Set.of("TEST1", "TEST2")); - bestilling.setPensjonforvalter(pensjonData); - - var dollyPerson = DollyPerson.builder() - .ident(IDENT) - .build(); - - var progress = new BestillingProgress(); - var dbBestilling = Bestilling.builder().id(1L).build(); - progress.setBestilling(dbBestilling); - - when(pensjonforvalterConsumer.getMiljoer()).thenReturn(Mono.just(Set.of("TEST1", "TEST2"))); - - when(pensjonforvalterConsumer.opprettPerson(any(PensjonPersonRequest.class), anySet())) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of(ResponseEnvironment.builder() - .miljo("TEST1") - .response(PensjonforvalterResponse.Response.builder() - .httpStatus(PensjonforvalterResponse.HttpStatus.builder() - .status(200) - .build()) - .build()) - .build())) - .build())); - - when(pensjonforvalterConsumer.lagreTpForhold(any(PensjonTpForholdRequest.class))) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of( - new ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()), - new ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()))) - .build())); - - when(pensjonforvalterConsumer.lagreTpYtelse(any(PensjonTpYtelseRequest.class))) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of( - new ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()), - new ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()))) - .build())); - - when(mapperFacade.map(any(PdlPersonBolk.PersonBolk.class), eq(PensjonPersonRequest.class))) - .thenReturn(PensjonPersonRequest.builder() - .fnr(IDENT) - .build()); - when(mapperFacade.map(any(PensjonData.TpOrdning.class), eq(PensjonTpForholdRequest.class), any(MappingContext.class))) - .thenReturn(new PensjonTpForholdRequest()); - when(mapperFacade.map(any(PensjonData.TpYtelse.class), eq(PensjonTpYtelseRequest.class), any(MappingContext.class))) - .thenReturn(new PensjonTpYtelseRequest()); - when(pdlDataConsumer.getPersoner(anyList())).thenReturn(Flux.empty()); - when(pensjonforvalterConsumer.hentSamboer(anyString(), anyString())).thenReturn(Flux.empty()); - - StepVerifier.create(pensjonforvalterClient.gjenopprett(bestilling, dollyPerson, progress, false) - .map(ClientFuture::get)) - .assertNext(status -> { - verify(transactionHelperService, times(2)) - .persister(any(BestillingProgress.class), any(), any(), statusCaptor.capture(), anyString()); - assertThat(statusCaptor.getAllValues().get(0).split("#")[0], is(equalTo("PensjonForvalter"))); - assertThat(Arrays.asList(statusCaptor.getAllValues().get(0).split("#")[1].split(",")), - containsInAnyOrder("TEST1:Info= Oppretting startet mot PESYS ...", "TEST2:Info= Oppretting startet mot PESYS ...")); - assertThat(statusCaptor.getAllValues().get(1), is(CoreMatchers.equalTo("PensjonForvalter#TEST1:OK$TpForhold#TEST2:OK,TEST1:OK"))); - }) - .verifyComplete(); - } - - @Test - void testLagreTpForhold_withOneFailedResult() { - - var tp1 = PensjonforvalterClientTestUtil.getTpOrdningWithYtelser("1111", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())); - var tp2 = PensjonforvalterClientTestUtil.getTpOrdningWithYtelser("2222", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())); - - var pensjonData = new PensjonData(); - pensjonData.setTp(Arrays.asList(tp1, tp2)); - - var bestilling = new RsDollyUtvidetBestilling(); - bestilling.setEnvironments(Set.of("TEST1", "TEST2")); - bestilling.setPensjonforvalter(pensjonData); - - var dollyPerson = DollyPerson.builder() - .ident(IDENT) - .build(); - - var progress = new BestillingProgress(); - var dbBestilling = Bestilling.builder().id(1L).build(); - progress.setBestilling(dbBestilling); - - when(pensjonforvalterConsumer.getMiljoer()).thenReturn(Mono.just(Set.of("TEST1", "TEST2"))); - - when(pensjonforvalterConsumer.opprettPerson(any(PensjonPersonRequest.class), anySet())) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of(ResponseEnvironment.builder() - .miljo("TEST1") - .response(PensjonforvalterResponse.Response.builder() - .httpStatus(PensjonforvalterResponse.HttpStatus.builder() - .status(200) - .build()) - .build()) - .build(), - ResponseEnvironment.builder() - .miljo("TEST2") - .response(PensjonforvalterResponse.Response.builder() - .httpStatus(PensjonforvalterResponse.HttpStatus.builder() - .status(200) - .build()) - .build()) - .build())) - .build())); - - when(pensjonforvalterConsumer.lagreTpForhold(any(PensjonTpForholdRequest.class))) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of( - new ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()), - new ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()))) - .build())); - - when(pensjonforvalterConsumer.lagreTpYtelse(any(PensjonTpYtelseRequest.class))) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of( - new ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()), - new ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("Intern feil", 500)) - .message("{ytelse2 feil on TEST2}") - .build()))) - .build())); - - when(mapperFacade.map(any(PdlPersonBolk.PersonBolk.class), eq(PensjonPersonRequest.class))) - .thenReturn(PensjonPersonRequest.builder() - .fnr(IDENT) - .build()); - when(mapperFacade.map(any(PensjonData.TpOrdning.class), eq(PensjonTpForholdRequest.class), any(MappingContext.class))) - .thenReturn(new PensjonTpForholdRequest()); - when(mapperFacade.map(any(PensjonData.TpYtelse.class), eq(PensjonTpYtelseRequest.class), any(MappingContext.class))) - .thenReturn(new PensjonTpYtelseRequest()); - when(errorStatusDecoder.getErrorText(any(), any())) - .thenCallRealMethod(); - when(pdlDataConsumer.getPersoner(anyList())).thenReturn(Flux.empty()); - when(pensjonforvalterConsumer.hentSamboer(anyString(), anyString())).thenReturn(Flux.empty()); - - StepVerifier.create(pensjonforvalterClient.gjenopprett(bestilling, dollyPerson, progress, false) - .map(ClientFuture::get)) - .assertNext(status -> { - verify(transactionHelperService, times(2)) - .persister(any(BestillingProgress.class), any(), any(), statusCaptor.capture(), anyString()); - assertThat(statusCaptor.getAllValues().get(0).split("#")[0], is(equalTo("PensjonForvalter"))); - assertThat(Arrays.asList(statusCaptor.getAllValues().get(0).split("#")[1].split(",")), - containsInAnyOrder("TEST1:Info= Oppretting startet mot PESYS ...", "TEST2:Info= Oppretting startet mot PESYS ...")); - assertThat(statusCaptor.getAllValues().get(1), is(CoreMatchers.equalTo("PensjonForvalter#TEST1:OK,TEST2:OK$TpForhold#TEST2:Feil= ytelse2 feil on TEST2,TEST1:OK"))); - }) - .verifyComplete(); - } - - @Test - void testLagreTpForhold_withException() { - - var bestilling = new RsDollyUtvidetBestilling(); - bestilling.setEnvironments(Set.of("TEST1", "TEST2")); - bestilling.setPensjonforvalter(PensjonData.builder() - .tp(List.of(PensjonforvalterClientTestUtil.getTpOrdningWithYtelser("1111", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())), - PensjonforvalterClientTestUtil.getTpOrdningWithYtelser("2222", List.of(new PensjonData.TpYtelse(), new PensjonData.TpYtelse())))) - .build()); - - var dollyPerson = DollyPerson.builder() - .ident(IDENT) - .build(); - - var dbBestilling = Bestilling.builder().id(1L).build(); - var progress = BestillingProgress.builder() - .bestilling(dbBestilling) - .build(); - - when(pensjonforvalterConsumer.getMiljoer()).thenReturn(Mono.just(Set.of("TEST1", "TEST2"))); - - when(pensjonforvalterConsumer.opprettPerson(any(PensjonPersonRequest.class), anySet())) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of(ResponseEnvironment.builder() - .miljo("TEST1") - .response(PensjonforvalterResponse.Response.builder() - .httpStatus(PensjonforvalterResponse.HttpStatus.builder() - .status(200) - .build()) - .build()) - .build(), - ResponseEnvironment.builder() - .miljo("TEST2") - .response(PensjonforvalterResponse.Response.builder() - .httpStatus(PensjonforvalterResponse.HttpStatus.builder() - .status(200) - .build()) - .build()) - .build())) - .build())); - - when(pensjonforvalterConsumer.lagreTpForhold(any(PensjonTpForholdRequest.class))) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of( - new ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()), - new ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("", 200)) - .build()) - )) - .build())); - - when(pensjonforvalterConsumer.lagreTpYtelse(any(PensjonTpYtelseRequest.class))) - .thenReturn(Flux.just(PensjonforvalterResponse.builder() - .status(List.of( - new ResponseEnvironment("TEST1", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("OK", 200)) - .build()), - new ResponseEnvironment("TEST2", PensjonforvalterResponse.Response.builder() - .httpStatus(new PensjonforvalterResponse.HttpStatus("Internal Server Error", 500)) - .message(String.format("Klarte ikke å få TP-ytelse respons for %s i PESYS (pensjon)", "12345")) - .build()))) - .build())); - - when(mapperFacade.map(any(PdlPersonBolk.PersonBolk.class), eq(PensjonPersonRequest.class))) - .thenReturn(PensjonPersonRequest.builder() - .fnr(IDENT) - .build()); - when(mapperFacade.map(any(PensjonData.TpOrdning.class), eq(PensjonTpForholdRequest.class), any(MappingContext.class))) - .thenReturn(new PensjonTpForholdRequest()); - when(mapperFacade.map(any(PensjonData.TpYtelse.class), eq(PensjonTpYtelseRequest.class), any(MappingContext.class))) - .thenReturn(new PensjonTpYtelseRequest()); - when(errorStatusDecoder.getErrorText(eq(HttpStatus.INTERNAL_SERVER_ERROR), anyString())) - .thenReturn("Feil= Klarte ikke å få TP-ytelse respons for 12345 i PESYS (pensjon)"); - when(pdlDataConsumer.getPersoner(anyList())).thenReturn(Flux.empty()); - when(pensjonforvalterConsumer.hentSamboer(anyString(), anyString())).thenReturn(Flux.empty()); - - StepVerifier.create(pensjonforvalterClient.gjenopprett(bestilling, dollyPerson, progress, false) - .map(ClientFuture::get)) - .assertNext(status -> { - verify(transactionHelperService, times(2)) - .persister(any(BestillingProgress.class), any(), any(), statusCaptor.capture(), anyString()); - assertThat(statusCaptor.getAllValues().get(0).split("#")[0], is(equalTo("PensjonForvalter"))); - assertThat(Arrays.asList(statusCaptor.getAllValues().get(0).split("#")[1].split(",")), - containsInAnyOrder("TEST1:Info= Oppretting startet mot PESYS ...", "TEST2:Info= Oppretting startet mot PESYS ...")); - assertThat(statusCaptor.getAllValues().get(1), - is(CoreMatchers.equalTo("PensjonForvalter#TEST1:OK,TEST2:OK$" + - "TpForhold#TEST2:Feil= Klarte ikke å få TP-ytelse respons for 12345 i PESYS (pensjon),TEST1:OK"))); - }) - .verifyComplete(); - } - static class PensjonforvalterClientTestUtil { static PensjonData.TpOrdning getTpOrdning(String ordning) { @@ -529,22 +362,15 @@ static PensjonData.TpOrdning getTpOrdning(String ordning) { return tp; } - static PensjonData.TpOrdning getTpOrdningWithYtelser(String ordning, List ytelser) { - PensjonData.TpOrdning tp = new PensjonData.TpOrdning(); - tp.setOrdning(ordning); - tp.setYtelser(ytelser); - return tp; - } - static PensjonforvalterResponse getPensjonforvalterResponse(int httpStatusCode, String... miljoe) { var response = new PensjonforvalterResponse(); - var status = new ArrayList(); + var status = new ArrayList(); var statusResponse = new PensjonforvalterResponse.Response(); statusResponse.setHttpStatus(new PensjonforvalterResponse.HttpStatus(httpStatusCode == 200 ? "OK" : "FEIL", httpStatusCode)); - Arrays.stream(miljoe).forEach(m -> status.add(new ResponseEnvironment(m, statusResponse))); + Arrays.stream(miljoe).forEach(m -> status.add(new PensjonforvalterResponse.ResponseEnvironment(m, statusResponse))); response.setStatus(status); @@ -552,38 +378,11 @@ static PensjonforvalterResponse getPensjonforvalterResponse(int httpStatusCode, } } - @ParameterizedTest - @CsvSource( - value = { - "{MESSAGE},REASON,Feil= MESSAGE", - "null,REASON,Feil= REASON", - "null,null,Feil= 500 INTERNAL_SERVER_ERROR" - }, - nullValues = { - "null" - } - ) - void testGetError(String message, String reason, String expected) { - - when(errorStatusDecoder.getErrorText(any(), any())) - .thenCallRealMethod(); - var entry = ResponseEnvironment - .builder() - .miljo("ENV") - .response( - PensjonforvalterResponse.Response - .builder() - .path("/test") - .message(message) - .httpStatus( - PensjonforvalterResponse.HttpStatus - .builder() - .status(500) - .reasonPhrase(reason) - .build()) - .build()) + private static PensjonData.TpOrdning getTpOrdningWithYtelser(String ordning, List ytelser) { + + return PensjonData.TpOrdning.builder() + .ordning(ordning) + .ytelser(ytelser) .build(); - var error = pensjonforvalterClient.getError(entry); - assertThat(error, is(expected)); } } \ No newline at end of file diff --git a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterHelperTest.java b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterHelperTest.java new file mode 100644 index 00000000000..57f7bbe1888 --- /dev/null +++ b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/utils/PensjonforvalterHelperTest.java @@ -0,0 +1,56 @@ +package no.nav.dolly.bestilling.pensjonforvalter.utils; + +import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; +import no.nav.dolly.errorhandling.ErrorStatusDecoder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.InjectMocks; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +@ExtendWith(MockitoExtension.class) +class PensjonforvalterHelperTest { + + @Spy + private ErrorStatusDecoder errorStatusDecoder; + + @InjectMocks + private PensjonforvalterHelper pensjonforvalterHelper; + + @ParameterizedTest + @CsvSource( + value = { + "{MESSAGE},REASON,Feil= MESSAGE", + "null,REASON,Feil= REASON", + "null,null,Feil= 500 INTERNAL_SERVER_ERROR" + }, + nullValues = { + "null" + } + ) + void testGetError(String message, String reason, String expected) { + + var entry = PensjonforvalterResponse.ResponseEnvironment + .builder() + .miljo("ENV") + .response( + PensjonforvalterResponse.Response + .builder() + .path("/test") + .message(message) + .httpStatus( + PensjonforvalterResponse.HttpStatus + .builder() + .status(500) + .reasonPhrase(reason) + .build()) + .build()) + .build(); + var error = pensjonforvalterHelper.getError(entry); + assertThat(error, is(expected)); + } +} \ No newline at end of file diff --git a/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/utils/WebClientFilter.java b/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/utils/WebClientFilter.java index 83eac6dc0ec..17d1a078364 100644 --- a/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/utils/WebClientFilter.java +++ b/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/utils/WebClientFilter.java @@ -11,6 +11,7 @@ import java.net.SocketException; import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeoutException; @Slf4j @UtilityClass @@ -46,6 +47,10 @@ public static String getMessage(Throwable throwable) { return requestException.getCause().toString(); } + } else if (throwable instanceof TimeoutException) { + + return "Mottaker svarer ikke, eller har for lang svartid."; + } else { return throwable.getMessage(); } @@ -53,14 +58,23 @@ public static String getMessage(Throwable throwable) { public static HttpStatus getStatus(Throwable throwable) { - return throwable instanceof WebClientResponseException webClientResponseException ? - HttpStatus.valueOf(webClientResponseException.getStatusCode().value()) : - HttpStatus.INTERNAL_SERVER_ERROR; + if (throwable instanceof WebClientResponseException webClientResponseException) { + return HttpStatus.valueOf(webClientResponseException.getStatusCode().value()); + + } else if (throwable instanceof TimeoutException) { + return HttpStatus.REQUEST_TIMEOUT; + + } else { + return HttpStatus.INTERNAL_SERVER_ERROR; + } } public static void logErrorMessage(Throwable throwable) { - if (!(throwable instanceof WebClientResponseException)) { + if ((throwable instanceof WebClientResponseException webClientResponseException)) { + log.error("%s, %s".formatted(throwable.getMessage(), + webClientResponseException.getResponseBodyAsString()), throwable); + } else { log.error(throwable.getMessage(), throwable); } }