From a96c532949a25d32a44332636845c1b487d3c75d Mon Sep 17 00:00:00 2001 From: Stian Gustavsson Date: Mon, 25 Nov 2024 11:06:19 +0100 Subject: [PATCH 01/12] Bugfix/auth header log fix (#3674) * Fjerner bearer token som persisteres til logg gjennom instrumentering --- .../logging/TestnavLogbackEncoder.java | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/logging/TestnavLogbackEncoder.java b/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/logging/TestnavLogbackEncoder.java index 67acbbe5fe..3f43eac0b0 100644 --- a/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/logging/TestnavLogbackEncoder.java +++ b/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/logging/TestnavLogbackEncoder.java @@ -33,8 +33,8 @@ public class TestnavLogbackEncoder extends LogstashEncoder { // matches exactly 11 digits (\\d{11}) that are not immediately preceded ((? { + if (match.group().charAt(2) == '0' || match.group().charAt(2) == '1') { + return match.group().substring(0, 6) + "xxxxx"; } - } - matcher.appendTail(result); + return match.group(); + }); + + message = bearer.matcher(message).replaceAll("REDACTED_BEARER"); - return result.toString(); + return message; } } \ No newline at end of file From fb484212f33f04e544833b297d8f84af3962b502 Mon Sep 17 00:00:00 2001 From: Stian Gustavsson Date: Mon, 25 Nov 2024 11:22:02 +0100 Subject: [PATCH 02/12] Update TestnavLogbackEncoder.java Fix for ident formatMessage --- .../libs/reactivecore/logging/TestnavLogbackEncoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/logging/TestnavLogbackEncoder.java b/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/logging/TestnavLogbackEncoder.java index 3f43eac0b0..ebaf3ca809 100644 --- a/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/logging/TestnavLogbackEncoder.java +++ b/libs/reactive-core/src/main/java/no/nav/testnav/libs/reactivecore/logging/TestnavLogbackEncoder.java @@ -114,7 +114,7 @@ private void appendStackTraceCauses(ThrowableProxy exception, StringWriter write private String formatMessage(String message) { message = identNummer.matcher(message).replaceAll(match -> { - if (match.group().charAt(2) == '0' || match.group().charAt(2) == '1') { + if (match.group().charAt(2) < '4') { return match.group().substring(0, 6) + "xxxxx"; } return match.group(); @@ -124,4 +124,4 @@ private String formatMessage(String message) { return message; } -} \ No newline at end of file +} 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 03/12] =?UTF-8?q?Feilh=C3=A5ndtering=20n=C3=A5r=20bestllin?= =?UTF-8?q?ger=20henger=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 c01e025da1..116483bcbf 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 c3323e5fa2..44041c8fbf 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 e3fa29f5e6..7df12b55b4 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 c02029cb36..db73b7fd72 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 659e55c914..fce6dbb03d 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 38959d37e9..0c1025f437 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 45fe3beee7..081ec64154 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 024390f63a..81a6d2790d 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 44a268944c..209f503eab 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 0000000000..a582c6f384 --- /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 0000000000..c161a3701d --- /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 0000000000..7ab766c850 --- /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 0000000000..cda53ff1e6 --- /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 0000000000..f2d9fcdc23 --- /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 0000000000..63425e08f3 --- /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 8585dd2916..22ce9ec37a 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 d81437c616..c7714481e7 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 550e2ef520..f4dd7d8c3e 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 836083f658..e8e287829b 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 a59a812337..7bba84342e 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 2d6f4a2d8c..ca19852f03 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 e156d178db..8e5af8858e 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 c04d76911f..c2852a337b 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 35fae04882..b1e1401ce9 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 d2b8c9bae1..0c315e0d2b 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 72e258ad4f..5d3ea19ac0 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 0000000000..57f7bbe188 --- /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 83eac6dc0e..17d1a07836 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); } } From 8d70cf9a9825e6927ea3c2b7038d0b78e66234b8 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Mon, 25 Nov 2024 14:23:03 +0100 Subject: [PATCH 04/12] Add VURDI to ArenaKvalifiseringsgruppe enum Extended the ArenaKvalifiseringsgruppe enum to include the new value VURDI. This change allows the system to recognize and process the new qualification group within the domain model. --- .../resultset/arenaforvalter/ArenaKvalifiseringsgruppe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/arenaforvalter/ArenaKvalifiseringsgruppe.java b/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/arenaforvalter/ArenaKvalifiseringsgruppe.java index 7d50d42882..8883fbe652 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/arenaforvalter/ArenaKvalifiseringsgruppe.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/domain/resultset/arenaforvalter/ArenaKvalifiseringsgruppe.java @@ -2,5 +2,5 @@ public enum ArenaKvalifiseringsgruppe { - IKVAL, BFORM, BATT, VARIG, IVURD, BKART + IKVAL, BFORM, BATT, VARIG, IVURD, BKART, VURDI } From ab5ce9a116d0035189a506eca1f1be29f58838a8 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Mon, 25 Nov 2024 15:42:16 +0100 Subject: [PATCH 05/12] Refactor ErrorStatusDecoder to use @RequiredArgsConstructor Replaced @NoArgsConstructor with @RequiredArgsConstructor to enforce dependency injection for ObjectMapper. This change ensures that ObjectMapper is always properly initialized and final, enhancing code clarity and reliability. --- .../no/nav/dolly/errorhandling/ErrorStatusDecoder.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) 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 8e5af8858e..893a8f55d1 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.NoArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; @@ -20,7 +20,7 @@ @Slf4j @Service -@NoArgsConstructor +@RequiredArgsConstructor public class ErrorStatusDecoder { private static final String TEKNISK_FEIL = "Teknisk feil {} mottatt fra system"; @@ -31,11 +31,7 @@ public class ErrorStatusDecoder { private static final String DETAILS = "details"; private static final String FEIL = "Feil= "; - private ObjectMapper objectMapper; - - public ErrorStatusDecoder(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - } + private final ObjectMapper objectMapper; public static String getInfoVenter(String system) { From 6c48b04a14000b0f300a3635b662a2a1ed4ecfed Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Mon, 25 Nov 2024 15:48:03 +0100 Subject: [PATCH 06/12] Disable PensjonforvalterHelperTest class Added @Disabled annotation to the entire PensjonforvalterHelperTest class to temporarily prevent its execution. This change is likely intended for debugging or ongoing refactoring purposes. --- .../pensjonforvalter/utils/PensjonforvalterHelperTest.java | 2 ++ 1 file changed, 2 insertions(+) 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 index 57f7bbe188..7f932dfce8 100644 --- 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 @@ -2,6 +2,7 @@ import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; import no.nav.dolly.errorhandling.ErrorStatusDecoder; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -12,6 +13,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +@Disabled @ExtendWith(MockitoExtension.class) class PensjonforvalterHelperTest { From 34de03165c8387dc524c7fdb8e89930d2c3f7422 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 26 Nov 2024 07:53:04 +0100 Subject: [PATCH 07/12] Update PensjonforvalterHelperTest to include missing imports Added necessary Mockito imports and initialized `errorStatusDecoder` with `ObjectMapper` to enable proper testing. The disabled annotation has been removed for the test class. --- .../pensjonforvalter/utils/PensjonforvalterHelperTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 index 7f932dfce8..e867502efc 100644 --- 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 @@ -1,8 +1,8 @@ package no.nav.dolly.bestilling.pensjonforvalter.utils; +import com.fasterxml.jackson.databind.ObjectMapper; import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; import no.nav.dolly.errorhandling.ErrorStatusDecoder; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -13,12 +13,11 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -@Disabled @ExtendWith(MockitoExtension.class) class PensjonforvalterHelperTest { @Spy - private ErrorStatusDecoder errorStatusDecoder; + private ErrorStatusDecoder errorStatusDecoder = new ErrorStatusDecoder(new ObjectMapper()); @InjectMocks private PensjonforvalterHelper pensjonforvalterHelper; From 7d3e9efca84a43ed7bea9e493193e6179fd37296 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 26 Nov 2024 08:28:23 +0100 Subject: [PATCH 08/12] Add deserializer for Instant in JsonMapperConfig Introduce a new deserializer for the Instant class to support parsing timestamps in JSON. This enhances date parsing capabilities, particularly for formats with or without the 'Z' suffix. --- .../no/nav/dolly/config/JsonMapperConfig.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/dolly-backend/src/main/java/no/nav/dolly/config/JsonMapperConfig.java b/apps/dolly-backend/src/main/java/no/nav/dolly/config/JsonMapperConfig.java index a8eb426cdd..efd4797e34 100644 --- a/apps/dolly-backend/src/main/java/no/nav/dolly/config/JsonMapperConfig.java +++ b/apps/dolly-backend/src/main/java/no/nav/dolly/config/JsonMapperConfig.java @@ -19,6 +19,7 @@ import org.springframework.context.annotation.Configuration; import java.io.IOException; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.YearMonth; @@ -43,7 +44,8 @@ public ObjectMapper objectMapper() { .addDeserializer(YearMonth.class, new DollyYearMonthDeserializer()) .addSerializer(YearMonth.class, new YearMonthSerializer(DateTimeFormatter.ofPattern(YEAR_MONTH))) .addDeserializer(ZonedDateTime.class, new DollyZonedDateTimeDeserializer()) - .addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(DateTimeFormatter.ISO_DATE_TIME)); + .addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(DateTimeFormatter.ISO_DATE_TIME)) + .addDeserializer(Instant.class, new DollyInstantDeserializer()); return JsonMapper .builder() .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) @@ -107,4 +109,17 @@ public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext d return dateTime.length() > 10 ? LocalDateTime.parse(dateTime) : LocalDate.parse(dateTime).atStartOfDay(); } } + + private static class DollyInstantDeserializer extends JsonDeserializer { + + @Override + public Instant deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + if (isBlank(node.asText())) { + return null; + } + var timestamp = node.asText(); + return Instant.parse(timestamp.contains("Z") ? timestamp : timestamp + "Z"); + } + } } From 8f116cb93fa20f325f1c3989de46921de70ecbb4 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 26 Nov 2024 10:05:41 +0100 Subject: [PATCH 09/12] Refactor PensjonforvalterHelper to use final fields Replace the no-args constructor with Lombok's @RequiredArgsConstructor to ensure mandatory dependencies are final and not nullable. This change simplifies initialization and enhances code stability. --- .../utils/PensjonforvalterHelper.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) 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 index f2d9fcdc23..210fee4566 100644 --- 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 @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.dolly.bestilling.pensjonforvalter.domain.PensjonforvalterResponse; import no.nav.dolly.domain.jpa.TransaksjonMapping; @@ -21,18 +21,12 @@ @Slf4j @Service -@NoArgsConstructor +@RequiredArgsConstructor 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; - } + private final TransaksjonMappingService transaksjonMappingService; + private final ObjectMapper objectMapper; + private final ErrorStatusDecoder errorStatusDecoder; @SuppressWarnings("java:S3740") public void saveAPTransaksjonId(String ident, String miljoe, Long bestillingId, From 68de33a34a01b9537e27c39adc6712d1888deb1e Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 26 Nov 2024 10:19:54 +0100 Subject: [PATCH 10/12] Disable PensjonPensjonsdataServiceTest Annotate PensjonPensjonsdataServiceTest with @Disabled to temporarily prevent these tests from running. This change helps focus on fixing or investigating specific issues without being distracted by these tests. --- .../service/PensjonPensjonsdataServiceTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java index 5d3ea19ac0..221fcad10b 100644 --- a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java +++ b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java @@ -14,6 +14,7 @@ import no.nav.dolly.domain.resultset.RsDollyUtvidetBestilling; import no.nav.dolly.domain.resultset.pensjon.PensjonData; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -45,6 +46,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +@Disabled @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) class PensjonPensjonsdataServiceTest { From 92338faceee0205dc91c846077870476d02c2f6b Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 26 Nov 2024 10:26:16 +0100 Subject: [PATCH 11/12] Add object and service dependencies in test setup This commit adds `ObjectMapper`, `TransaksjonMappingRepository`, `TransaksjonMappingService`, and `ErrorStatusDecoder` to `PensjonPensjonsdataServiceTest.java`. This ensures that the required dependencies are fully initialized and available for testing. It also removes the `@Disabled` annotation to enable the test suite. --- .../service/PensjonPensjonsdataServiceTest.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java index 221fcad10b..51baa643da 100644 --- a/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java +++ b/apps/dolly-backend/src/test/java/no/nav/dolly/bestilling/pensjonforvalter/service/PensjonPensjonsdataServiceTest.java @@ -1,5 +1,6 @@ package no.nav.dolly.bestilling.pensjonforvalter.service; +import com.fasterxml.jackson.databind.ObjectMapper; import ma.glasnost.orika.MapperFacade; import ma.glasnost.orika.MappingContext; import no.nav.dolly.bestilling.pensjonforvalter.PensjonforvalterConsumer; @@ -13,8 +14,10 @@ import no.nav.dolly.domain.jpa.BestillingProgress; import no.nav.dolly.domain.resultset.RsDollyUtvidetBestilling; import no.nav.dolly.domain.resultset.pensjon.PensjonData; +import no.nav.dolly.errorhandling.ErrorStatusDecoder; +import no.nav.dolly.repository.TransaksjonMappingRepository; +import no.nav.dolly.service.TransaksjonMappingService; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -46,15 +49,19 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; -@Disabled @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) class PensjonPensjonsdataServiceTest { private static final String IDENT = "11111111111"; + @Mock + private TransaksjonMappingRepository transaksjonMappingRepository; + @Spy - private PensjonforvalterHelper pensjonforvalterHelper; + private PensjonforvalterHelper pensjonforvalterHelper = + new PensjonforvalterHelper(new TransaksjonMappingService(transaksjonMappingRepository, new ObjectMapper()), + new ObjectMapper(), new ErrorStatusDecoder(new ObjectMapper())); @Mock private PensjonforvalterConsumer pensjonforvalterConsumer; From ea6439f583fc55636b69009f444f2f6f091dbdfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristen=20H=C3=A6rum?= Date: Tue, 26 Nov 2024 11:32:16 +0100 Subject: [PATCH 12/12] Remove 'fullmakt' from GraphQL queries (#3677) Removed 'fullmakt' field from pdlbolkquery.graphql, pdlPerson2Query.graphql, and pdlPersonQuery.graphql. This exclusion simplifies the query structure and eliminates redundant data retrieval related to fullmakt details. --- .../src/main/resources/pdl/pdlPerson2Query.graphql | 10 ---------- .../src/main/resources/pdl/pdlPersonQuery.graphql | 5 ----- .../src/main/resources/pdl/pdlbolkquery.graphql | 10 ---------- 3 files changed, 25 deletions(-) diff --git a/apps/person-service/src/main/resources/pdl/pdlPerson2Query.graphql b/apps/person-service/src/main/resources/pdl/pdlPerson2Query.graphql index 0d82bbdf21..af41a1ceee 100644 --- a/apps/person-service/src/main/resources/pdl/pdlPerson2Query.graphql +++ b/apps/person-service/src/main/resources/pdl/pdlPerson2Query.graphql @@ -442,16 +442,6 @@ query($ident: ID!, $historikk: Boolean!) { ...metadataDetails } }, - fullmakt(historikk: $historikk) { - motpartsPersonident, - motpartsRolle, - omraader, - gyldigFraOgMed, - gyldigTilOgMed, - metadata { - ...metadataDetails - } - }, folkeregisteridentifikator(historikk: $historikk) { identifikasjonsnummer, status, diff --git a/apps/person-service/src/main/resources/pdl/pdlPersonQuery.graphql b/apps/person-service/src/main/resources/pdl/pdlPersonQuery.graphql index ec6ab1fd0b..36e3187433 100644 --- a/apps/person-service/src/main/resources/pdl/pdlPersonQuery.graphql +++ b/apps/person-service/src/main/resources/pdl/pdlPersonQuery.graphql @@ -141,11 +141,6 @@ query($ident1: ID!) { opplysningsId } } - fullmakt { - metadata { - opplysningsId - } - } }, hentIdenter(ident: $ident1, historikk: true, grupper: [AKTORID, FOLKEREGISTERIDENT, NPID]) { identer { diff --git a/apps/person-service/src/main/resources/pdl/pdlbolkquery.graphql b/apps/person-service/src/main/resources/pdl/pdlbolkquery.graphql index e3036e802a..4cb19544e2 100644 --- a/apps/person-service/src/main/resources/pdl/pdlbolkquery.graphql +++ b/apps/person-service/src/main/resources/pdl/pdlbolkquery.graphql @@ -449,16 +449,6 @@ query($identer: [ID!]!) { ...metadataDetails } }, - fullmakt(historikk: true) { - motpartsPersonident, - motpartsRolle, - omraader, - gyldigFraOgMed, - gyldigTilOgMed, - metadata { - ...metadataDetails - } - }, folkeregisteridentifikator(historikk: true) { identifikasjonsnummer, status,