Skip to content

Commit

Permalink
Add YrkesskadeClient to handle yrkesskade bestilling
Browse files Browse the repository at this point in the history
Introduces YrkesskadeClient and related classes to handle the creation and status tracking of yrkesskade (work injury) requests. This includes mappings, DTOs, and configurations necessary for the integration with the yrkesskade-proxy.
  • Loading branch information
krharum committed Oct 1, 2024
1 parent 3a3c4a1 commit ea295ee
Show file tree
Hide file tree
Showing 25 changed files with 504 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@ private Flux<Map.Entry<String, Set<String>>> getIdentWithRelasjoner(DollyPerson
.map(PdlPerson.ForelderBarnRelasjon::getRelatertPersonsIdent)
.filter(Objects::nonNull),
person.getPerson().getFullmakt().stream()
.map(FullmaktDTO::getMotpartsPersonident))
.map(FullmaktDTO::getMotpartsPersonident),
person.getPerson().getVergemaalEllerFremtidsfullmakt().stream()
.map(PdlPerson.Vergemaal::getVergeEllerFullmektig)
.map(PdlPerson.VergeEllerFullmektig::getMotpartsPersonident)
.filter(Objects::nonNull))
.flatMap(Function.identity())))
.map(ident -> Map.entry(ident, new HashSet<>())));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package no.nav.dolly.bestilling.yrkesskade;

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 no.nav.dolly.bestilling.ClientFuture;
import no.nav.dolly.bestilling.ClientRegister;
import no.nav.dolly.bestilling.personservice.PersonServiceConsumer;
import no.nav.dolly.bestilling.yrkesskade.dto.ResponseDTO;
import no.nav.dolly.bestilling.yrkesskade.dto.ResponseDTO.Status;
import no.nav.dolly.domain.jpa.BestillingProgress;
import no.nav.dolly.domain.jpa.TransaksjonMapping;
import no.nav.dolly.domain.resultset.RsDollyUtvidetBestilling;
import no.nav.dolly.domain.resultset.dolly.DollyPerson;
import no.nav.dolly.errorhandling.ErrorStatusDecoder;
import no.nav.dolly.mapper.MappingContextUtils;
import no.nav.dolly.service.TransaksjonMappingService;
import no.nav.dolly.util.TransactionHelperService;
import no.nav.testnav.libs.dto.yrkesskade.v1.YrkesskadeRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static no.nav.dolly.domain.resultset.SystemTyper.YRKESSKADE;

@Slf4j
@Service
@RequiredArgsConstructor
public class YrkesskadeClient implements ClientRegister {

private final MapperFacade mapper;
private final ObjectMapper objectMapper;
private final YrkesskadeConsumer yrkesskadeConsumer;
private final TransactionHelperService transactionHelperService;
private final TransaksjonMappingService transaksjonMappingService;
private final PersonServiceConsumer personServiceConsumer;

@Override
public Flux<ClientFuture> gjenopprett(RsDollyUtvidetBestilling bestilling, DollyPerson dollyPerson, BestillingProgress progress, boolean isOpprettEndre) {

var index = new AtomicInteger(0);

return Flux.from(
personServiceConsumer.getPdlPersoner(List.of(dollyPerson.getIdent()))
.filter(yrkesskadeRequest -> isOpprettEndre)
.flatMap(personbolk -> Flux.fromIterable(bestilling.getYrkesskader())
.map(yrkesskade -> {
var context = MappingContextUtils.getMappingContext();
context.setProperty("ident", dollyPerson.getIdent());
context.setProperty("personBolk", personbolk);
return mapper.map(yrkesskade, YrkesskadeRequest.class, context);
})
.flatMap(yrkesskade -> yrkesskadeConsumer.lagreYrkesskade(yrkesskade)
.map(status -> lagreTransaksjon(status, yrkesskade, progress.getBestilling().getId())))
.map(status -> encodeStatus(status, index.incrementAndGet()))
.collectList()
.map(resultat -> futurePersist(progress, resultat))));
}

@Override
public void release(List<String> identer) {
// Er ikke støttet
}

private ResponseDTO encodeStatus(ResponseEntity<String> status, int index) {

return ResponseDTO.builder()
.id(index)
.status(status.getStatusCode().is2xxSuccessful() ? Status.OK : Status.FEIL)
.melding(status.getBody())
.build();
}

private ClientFuture futurePersist(BestillingProgress progress, List<ResponseDTO> response) {

var status = response.stream()
.map(entry -> "Yrkesskade#%d:%s".formatted(entry.getId(),
entry.getStatus() == Status.OK ? "OK" :
"Feil: %s".formatted(ErrorStatusDecoder.encodeStatus(entry.getMelding()))))
.collect(Collectors.joining(","));

return () -> {
transactionHelperService.persister(progress, BestillingProgress::setYrkesskadeStatus, status);
return progress;
};
}

private ResponseEntity<String> lagreTransaksjon(ResponseEntity<String> status, YrkesskadeRequest request,
Long bestillingId) {

if (status.getStatusCode().is2xxSuccessful()) {
transaksjonMappingService.save(TransaksjonMapping.builder()
.bestillingId(bestillingId)
.transaksjonId(toJson(request))
.ident(request.getSkadelidtIdentifikator())
.datoEndret(LocalDateTime.now())
.system(YRKESSKADE.name())
.build());
}
return status;
}

private String toJson(Object object) {

try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
log.error("Feilet å konvertere transaksjonsId for dokarkiv", e);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package no.nav.dolly.bestilling.yrkesskade;

import no.nav.dolly.bestilling.yrkesskade.command.YrkesskadePostCommand;
import no.nav.dolly.config.Consumers;
import no.nav.testnav.libs.dto.yrkesskade.v1.YrkesskadeRequest;
import no.nav.testnav.libs.securitycore.domain.ServerProperties;
import no.nav.testnav.libs.standalone.servletsecurity.exchange.TokenExchange;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;

@Service
public class YrkesskadeConsumer {

private final WebClient webClient;
private final TokenExchange tokenExchange;
private final ServerProperties serverProperties;

public YrkesskadeConsumer(
TokenExchange tokenExchange,
Consumers consumers,
WebClient.Builder webClientBuilder) {

this.tokenExchange = tokenExchange;
serverProperties = consumers.getYrkesskadeProxy();
webClient = webClientBuilder
.baseUrl(serverProperties.getUrl())
.build();
}

public Flux<ResponseEntity<String>> lagreYrkesskade(YrkesskadeRequest request) {

return tokenExchange.exchange(serverProperties)
.flatMapMany(token -> new YrkesskadePostCommand(webClient, request, token.getTokenValue()).call());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package no.nav.dolly.bestilling.yrkesskade.command;

import lombok.RequiredArgsConstructor;
import no.nav.testnav.libs.dto.yrkesskade.v1.YrkesskadeRequest;
import no.nav.testnav.libs.reactivecore.utils.WebClientFilter;
import no.nav.testnav.libs.securitycore.config.UserConstant;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;

import java.time.Duration;
import java.util.concurrent.Callable;

import static no.nav.dolly.util.TokenXUtil.getUserJwt;

@RequiredArgsConstructor
public class YrkesskadePostCommand implements Callable<Flux<ResponseEntity<String>>> {

private static final String YRKESSKADE_URL = "/api/v1/yrkesskader";

private final WebClient webClient;
private final YrkesskadeRequest yrkesskadeRequest;
private final String token;

@Override
public Flux<ResponseEntity<String>> call() {

return webClient
.post()
.uri(uriBuilder -> uriBuilder.path(YRKESSKADE_URL).build())
.accept(MediaType.APPLICATION_JSON)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
.header(UserConstant.USER_HEADER_JWT, getUserJwt())
.bodyValue(yrkesskadeRequest)
.retrieve()
.bodyToFlux(ResponseEntity.class)
.map(response -> (new ResponseEntity<>(response.toString(), response.getStatusCode())))
.doOnError(WebClientFilter::logErrorMessage)
.onErrorResume(throwable -> Mono.just(new ResponseEntity<>(
WebClientFilter.getMessage(throwable),
WebClientFilter.getStatus(throwable))))
.retryWhen(Retry.backoff(3, Duration.ofSeconds(5))
.filter(WebClientFilter::is5xxException));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package no.nav.dolly.bestilling.yrkesskade.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResponseDTO {

public enum Status {OK, FEIL}

private Integer id;
private Status status;
private String melding;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package no.nav.dolly.bestilling.yrkesskade.mapper;

import ma.glasnost.orika.CustomMapper;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import no.nav.dolly.domain.PdlPerson;
import no.nav.dolly.domain.PdlPersonBolk;
import no.nav.dolly.mapper.MappingStrategy;
import no.nav.testnav.libs.dto.yrkesskade.v1.YrkesskadeRequest;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Objects;

@Component
public class YrkesskadeMappingStrategy implements MappingStrategy {

@Override
public void register(MapperFactory factory) {

factory.classMap(YrkesskadeRequest.class, YrkesskadeRequest.class)
.customize(new CustomMapper<>() {
@Override
public void mapAtoB(YrkesskadeRequest kilde, YrkesskadeRequest destinasjon, MappingContext context) {

var ident = (String) context.getProperty("ident");
var personBolk = (PdlPersonBolk) context.getProperty("personBolks");

destinasjon.setSkadelidtIdentifikator(ident);
destinasjon.setInnmelderIdentifikator(
switch (destinasjon.getInnmelderrolle()) {
case denSkadelidte -> ident;
case vergeOgForesatt -> personBolk.getData().getHentPersonBolk().stream()
.map(PdlPersonBolk.PersonBolk::getPerson)
.map(PdlPerson.Person::getVergemaalEllerFremtidsfullmakt)
.flatMap(Collection::stream)
.map(PdlPerson.Vergemaal::getVergeEllerFullmektig)
.map(PdlPerson.VergeEllerFullmektig::getMotpartsPersonident)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
case virksomhetsrepresentant -> destinasjon.getSkadelidtIdentifikator();
});
}
})
.byDefault()
.register();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ public class Consumers {
private ServerProperties testnavTpsMessagingService;
private ServerProperties testnavUdistubProxy;
private ServerProperties testnavSkattekortService;
private ServerProperties yrkesskadeProxy;
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ public class BestillingProgress implements Serializable {
@Column(name = "SKATTEKORT_STATUS")
private String skattekortStatus;

@Column(name = "YRKESSKADE_STATUS")
private String yrkesskadeStatus;

@Column(name = "master")
@Enumerated(EnumType.STRING)
private Master master;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import no.nav.dolly.domain.resultset.tpsmessagingservice.RsTpsMessaging;
import no.nav.dolly.domain.resultset.udistub.model.RsUdiPerson;
import no.nav.testnav.libs.data.arbeidsplassencv.v1.ArbeidsplassenCVDTO;
import no.nav.testnav.libs.dto.yrkesskade.v1.YrkesskadeRequest;

import java.util.List;

Expand Down Expand Up @@ -61,4 +62,5 @@ public class BestilteKriterier {
private RsSykemelding sykemelding;
private ArbeidsplassenCVDTO arbeidsplassenCV;
private SkattekortRequestDTO skattekort;
private List<YrkesskadeRequest> yrkesskader;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import no.nav.dolly.domain.resultset.tpsmessagingservice.RsTpsMessaging;
import no.nav.dolly.domain.resultset.udistub.model.RsUdiPerson;
import no.nav.testnav.libs.data.arbeidsplassencv.v1.ArbeidsplassenCVDTO;
import no.nav.testnav.libs.dto.yrkesskade.v1.YrkesskadeRequest;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
Expand Down Expand Up @@ -77,6 +78,7 @@ public class RsDollyBestilling {
private RsSkjerming skjerming;
private ArbeidsplassenCVDTO arbeidsplassenCV;
private SkattekortRequestDTO skattekort;
private List<YrkesskadeRequest> yrkesskader;

public List<RsAareg> getAareg() {
if (isNull(aareg)) {
Expand Down Expand Up @@ -113,6 +115,13 @@ public List<RsInstdata> getInstdata() {
return instdata;
}

public List<YrkesskadeRequest> getYrkesskader() {
if (isNull(yrkesskader)) {
yrkesskader = new ArrayList<>();
}
return yrkesskader;
}

@JsonIgnore
public boolean isNonEmpty() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public enum SystemTyper {
SYKEMELDING("NAV sykemelding"),
TPS_MESSAGING("Meldinger til TPS"),
TP_FORVALTER("Tjenestepensjon (TP)"),
UDISTUB("Utlendingsdirektoratet (UDI)");
UDISTUB("Utlendingsdirektoratet (UDI)"),
YRKESSKADE("Yrkesskade (YRKESSKADE)");

private String beskrivelse;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import no.nav.dolly.domain.resultset.udistub.model.RsUdiPerson;
import no.nav.testnav.libs.data.arbeidsplassencv.v1.ArbeidsplassenCVDTO;
import no.nav.testnav.libs.dto.skattekortservice.v1.SkattekortRequestDTO;
import no.nav.testnav.libs.dto.yrkesskade.v1.YrkesskadeRequest;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.domain.Persistable;
Expand Down Expand Up @@ -97,6 +98,8 @@ public boolean isNew() {
@Field
private SkattekortRequestDTO skattekort;
@Field
private List<YrkesskadeRequest> yrkesskader;
@Field
private List<String> identer;

@Transient
Expand Down
Loading

0 comments on commit ea295ee

Please sign in to comment.