diff --git a/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/AdresseService.java b/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/AdresseService.java index 44120e286d..58390cbcfe 100644 --- a/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/AdresseService.java +++ b/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/AdresseService.java @@ -4,20 +4,16 @@ import no.nav.pdl.forvalter.exception.InvalidRequestException; import no.nav.pdl.forvalter.utils.FoedselsdatoUtility; import no.nav.testnav.libs.data.pdlforvalter.v1.AdresseDTO; -import no.nav.testnav.libs.data.pdlforvalter.v1.BostedadresseDTO; import no.nav.testnav.libs.data.pdlforvalter.v1.PersonDTO; import no.nav.testnav.libs.dto.generernavnservice.v1.NavnDTO; import org.apache.commons.lang3.StringUtils; +import java.time.Duration; import java.time.LocalDateTime; -import java.util.Comparator; import java.util.List; -import java.util.Objects; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; -import static no.nav.pdl.forvalter.utils.ArtifactUtils.getKilde; -import static no.nav.pdl.forvalter.utils.ArtifactUtils.getMaster; import static no.nav.pdl.forvalter.utils.IdenttypeUtility.isNotNpidIdent; import static no.nav.pdl.forvalter.utils.TestnorgeIdentUtility.isTestnorgeIdent; import static org.apache.commons.lang3.BooleanUtils.isFalse; @@ -33,6 +29,7 @@ public abstract class AdresseService implements BiValid protected static final String VALIDATION_ADRESSE_OVELAP_ERROR = "Adresse: Overlappende adressedatoer er ikke lov"; private static final String NAVN_INVALID_ERROR = "CoAdresseNavn er ikke i liste over gyldige verdier"; + private static final int OUT_OF_BOUND = -1; private final GenererNavnServiceConsumer genererNavnServiceConsumer; @@ -50,11 +47,6 @@ protected static void validateBruksenhet(String bruksenhet) { } } - private static LocalDateTime getDateOrFuture(LocalDateTime dateTime) { - - return nonNull(dateTime) ? dateTime : LocalDateTime.now().plusYears(100); - } - protected void validateCoAdresseNavn(AdresseDTO.CoNavnDTO navn) { if ((isNotBlank(navn.getFornavn()) || @@ -100,133 +92,75 @@ private String buildNavn(AdresseDTO.CoNavnDTO coNavn) { .toString(); } - protected void populateMiscFields(AdresseDTO adresse, PersonDTO person) { - if (isNull(adresse.getGyldigFraOgMed())) { - adresse.setGyldigFraOgMed(person.getBostedsadresse().stream() - .reduce((a1, a2) -> a2) - .map(BostedadresseDTO::getGyldigFraOgMed) - .filter(Objects::nonNull) - .orElse(FoedselsdatoUtility.getFoedselsdato(person))); - } + protected void oppdaterAdressedatoer(List adresser, PersonDTO person) { - adresse.setKilde(getKilde(adresse)); - adresse.setMaster(getMaster(adresse, person)); - } + if (!adresser.isEmpty()) { - protected void enforceIntegrity(List adresser) { + if (isNull(adresser.getLast().getGyldigFraOgMed())) { + adresser.getLast().setGyldigFraOgMed(FoedselsdatoUtility.getFoedselsdato(person)); + } - sortAdresser(adresser); - setPendingTilOgMedDato(adresser); - checkOverlappendeDatoer(adresser); + setPendingFromDato(adresser); + var startIndex = adresser.size() - 1; + setGyldigFromDato(adresser, startIndex); + setGyldigTomDato(adresser); + } } - private void setPendingTilOgMedDato(List adresser) { - - for (var i = 0; i < adresser.size(); i++) { + private static void setGyldigTomDato(List adresser) { - if (i + 1 < adresser.size() && - (isNull(adresser.get(i + 1).getGyldigTilOgMed()) && - nonNull(adresser.get(i).getGyldigFraOgMed()) || - adresser.get(i + 1).getGyldigTilOgMed() - .isAfter(adresser.get(i).getGyldigFraOgMed()))) { - - if (adresser.get(i + 1).getGyldigFraOgMed().toLocalDate().isEqual( - adresser.get(i).getGyldigFraOgMed().toLocalDate())) { - - var time = LocalDateTime.now(); - adresser.get(i).setGyldigFraOgMed(adresser.get(i).getGyldigFraOgMed().toLocalDate() - .atTime(time.getHour(), time.getMinute(), time.getSecond())); - } - - adresser.get(i + 1).setGyldigTilOgMed(getGyldigTilDato(adresser.get(i + 1), adresser.get(i))); + for (int i = adresser.size() - 1; i > 0; i--) { + if (isNull(adresser.get(i).getGyldigTilOgMed())) { + adresser.get(i).setGyldigTilOgMed(adresser.get(i - 1).getGyldigFraOgMed().minusDays(1)); } } } - private LocalDateTime getGyldigTilDato(AdresseDTO adresse1, AdresseDTO adresse2) { - - if (adresse1.getGyldigFraOgMed().toLocalDate() - .isEqual(adresse2.getGyldigFraOgMed().toLocalDate()) || - adresse1.getGyldigFraOgMed().toLocalDate() - .isEqual(adresse2.getGyldigFraOgMed().toLocalDate().minusDays(1))) { - - var time = adresse2.getGyldigFraOgMed().minusSeconds(1); - return adresse2.getGyldigFraOgMed().toLocalDate() - .atTime(time.getHour(), time.getMinute(), time.getSecond()); - - } else if (adresse1.getGyldigFraOgMed().toLocalDate() - .isBefore(adresse2.getGyldigFraOgMed().toLocalDate())) { - - return adresse2.getGyldigFraOgMed().minusDays(1).toLocalDate().atStartOfDay(); + private static void setPendingFromDato(List adresser) { - } else { - - throw new InvalidRequestException(VALIDATION_ADRESSE_OVELAP_ERROR); - } - } - - private void checkOverlappendeDatoer(List adresser) { - - // https://stackoverflow.com/questions/13513932/algorithm-to-detect-overlapping-periods - for (var i = 0; i < adresser.size(); i++) { - for (var j = 0; j < adresser.size(); j++) { - if (i != j && - (adresser.get(i).getGyldigFraOgMed() - .isEqual(adresser.get(j).getGyldigFraOgMed()) || - getDateOrFuture(adresser.get(i).getGyldigTilOgMed()) - .isEqual(getDateOrFuture(adresser.get(j).getGyldigTilOgMed())) || - isAdresseOverlapp(adresser.get(i), adresser.get(j)))) { - throw new InvalidRequestException(VALIDATION_ADRESSE_OVELAP_ERROR); - } + for (int i = adresser.size() - 1; i > 0; i--) { + if (isNull(adresser.get(i - 1).getGyldigFraOgMed()) && nonNull(adresser.get(i).getGyldigTilOgMed())) { + adresser.get(i - 1).setGyldigFraOgMed(adresser.get(i).getGyldigTilOgMed().plusDays(1)); } } } - private boolean isAdresseOverlapp(T adresse1, T adresse2) { - - return isOverlappTilfelle1(adresse1, adresse2) || - isOverlappTilfelle2(adresse1, adresse2) || - isOverlappTilfelle3(adresse1, adresse2); - } - - private boolean isOverlappTilfelle1(T adresse1, T adresse2) { + private static void setGyldigFromDato(List adresser, int startIndex) { - // |<---- Intervall A ----->| - // |<---- Intervall B ----->| - return getDateOrFuture(adresse1.getGyldigFraOgMed()).isBefore(adresse2.getGyldigFraOgMed()) && - adresse2.getGyldigFraOgMed().isBefore(getDateOrFuture(adresse1.getGyldigTilOgMed())); + if (startIndex == OUT_OF_BOUND) { + return; + } + var lowWaterMark = getIndexOfNextFromDate(adresser, startIndex); + var daysInterval = getWeightedDaysInterval(adresser, startIndex, lowWaterMark); + for (int i = startIndex - 1; i > lowWaterMark; i--) { + adresser.get(i).setGyldigFraOgMed(adresser.get(i + 1).getGyldigFraOgMed().plusDays(daysInterval)); + } + setGyldigFromDato(adresser, lowWaterMark); } - private boolean isOverlappTilfelle2(T adresse1, T adresse2) { - // |<---- Intervall A ----->| - // |<---- Intervall B ----->| - return adresse1.getGyldigFraOgMed().isBefore(getDateOrFuture(adresse2.getGyldigTilOgMed())) && - getDateOrFuture(adresse2.getGyldigTilOgMed()).isBefore(getDateOrFuture(adresse1.getGyldigTilOgMed())); - } + private static long getWeightedDaysInterval(List adresser, int index1, int index2) { - private boolean isOverlappTilfelle3(T adresse1, T adresse2) { + var interval = Duration.between(adresser.get(index1).getGyldigFraOgMed(), + index2 == OUT_OF_BOUND ? LocalDateTime.now() : + adresser.get(index2).getGyldigFraOgMed()).toDays(); - // |<--- Intervall A --->| - // |<-------- Intervall B ------->| - return adresse2.getGyldigFraOgMed().isBefore(adresse1.getGyldigFraOgMed()) && - getDateOrFuture(adresse2.getGyldigTilOgMed()).isAfter(getDateOrFuture(adresse1.getGyldigTilOgMed())); + return (interval - interval / (index1 - index2)) / (index1 - index2); } - private void sortAdresser(List adresser) { + private static int getIndexOfNextFromDate(List adresser, int index) { - if (adresser.isEmpty()) { - return; - } - adresser.stream() - .filter(adresse -> isNull(adresse.getGyldigFraOgMed())) - .forEach(adresse -> adresse.setGyldigFraOgMed(LocalDateTime.now())); - adresser.sort(Comparator.comparing(AdresseDTO::getGyldigFraOgMed, Comparator.reverseOrder())); - for (var i = adresser.size(); i > 0; i--) { - adresser.get(i - 1).setId(adresser.size() - i + 1); + for (var i = index - 1; i >= 0; i--) { + if (nonNull(adresser.get(i).getGyldigFraOgMed())) { + return i; + } } + return OUT_OF_BOUND; } + protected boolean isIdSupported(AdresseDTO adresse, String ident) { return isNotNpidIdent(ident) && !isTestnorgeIdent(ident) && !adresse.isPdlMaster(); diff --git a/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/BostedAdresseService.java b/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/BostedAdresseService.java index 4f3b7410a3..8976bf470b 100644 --- a/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/BostedAdresseService.java +++ b/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/BostedAdresseService.java @@ -23,6 +23,8 @@ import static java.util.Objects.isNull; import static java.util.Objects.nonNull; +import static no.nav.pdl.forvalter.utils.ArtifactUtils.getKilde; +import static no.nav.pdl.forvalter.utils.ArtifactUtils.getMaster; import static no.nav.pdl.forvalter.utils.IdenttypeUtility.getIdenttype; import static no.nav.pdl.forvalter.utils.TestnorgeIdentUtility.isTestnorgeIdent; import static no.nav.testnav.libs.data.pdlforvalter.v1.AdressebeskyttelseDTO.AdresseBeskyttelse.STRENGT_FORTROLIG; @@ -51,15 +53,17 @@ public BostedAdresseService(GenererNavnServiceConsumer genererNavnServiceConsume public List convert(PersonDTO person, Boolean relaxed) { - for (var adresse : person.getBostedsadresse()) { + person.getBostedsadresse().stream() + .filter(adresse -> isTrue(adresse.getIsNew()) && (isNotTrue(relaxed))) + .forEach(adresse -> { + handle(adresse, person); + adresse.setKilde(getKilde(adresse)); + adresse.setMaster(getMaster(adresse, person)); + }); - if (isTrue(adresse.getIsNew()) && (isNotTrue(relaxed))) { - handle(adresse, person); - populateMiscFields(adresse, person); + oppdaterAdressedatoer(person.getBostedsadresse(), person); + setAngittFlyttedato(person.getBostedsadresse()); - } - } - enforceIntegrity(person.getBostedsadresse()); return person.getBostedsadresse(); } @@ -192,4 +196,10 @@ private String getLandkode(PersonDTO person) { .map(Optional::get) .findFirst().orElse(null); } + + private static void setAngittFlyttedato(List bostedsadresse) { + + bostedsadresse.forEach(adresse -> + adresse.setAngittFlyttedato(adresse.getGyldigFraOgMed())); + } } diff --git a/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/KontaktAdresseService.java b/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/KontaktAdresseService.java index 9ae0e8f07f..31f63efb03 100644 --- a/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/KontaktAdresseService.java +++ b/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/KontaktAdresseService.java @@ -63,18 +63,16 @@ private static void validatePostBoksAdresse(KontaktadresseDTO.PostboksadresseDTO public List convert(PersonDTO person, Boolean relaxed) { - for (var adresse : person.getKontaktadresse()) { - - if (isTrue(adresse.getIsNew())) { + person.getKontaktadresse().stream() + .filter(adresse -> isTrue(adresse.getIsNew()) && (isNotTrue(relaxed))) + .forEach(adresse -> { + handle(adresse, person); + adresse.setKilde(getKilde(adresse)); + adresse.setMaster(getMaster(adresse, person)); + }); - adresse.setKilde(getKilde(adresse)); - adresse.setMaster(getMaster(adresse, person)); + oppdaterAdressedatoer(person.getBostedsadresse(), person); - if (isNotTrue(relaxed)) { - handle(adresse, person); - } - } - } return person.getKontaktadresse(); } diff --git a/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/OppholdsadresseService.java b/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/OppholdsadresseService.java index 49ee8f10ea..d8b4851642 100644 --- a/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/OppholdsadresseService.java +++ b/apps/pdl-forvalter/src/main/java/no/nav/pdl/forvalter/service/OppholdsadresseService.java @@ -51,16 +51,15 @@ public OppholdsadresseService(GenererNavnServiceConsumer genererNavnServiceConsu public List convert(PersonDTO person) { - for (var adresse : person.getOppholdsadresse()) { - - if (isTrue(adresse.getIsNew())) { - - adresse.setKilde(getKilde(adresse)); - adresse.setMaster(getMaster(adresse, person)); - handle(adresse, person); - } - } - + person.getOppholdsadresse().stream() + .filter(adresse -> isTrue(adresse.getIsNew())) + .forEach(adresse -> { + handle(adresse, person); + adresse.setKilde(getKilde(adresse)); + adresse.setMaster(getMaster(adresse, person)); + }); + + oppdaterAdressedatoer(person.getBostedsadresse(), person); return person.getOppholdsadresse(); } diff --git a/apps/pdl-forvalter/src/test/java/no/nav/pdl/forvalter/service/BostedAdresseServiceTest.java b/apps/pdl-forvalter/src/test/java/no/nav/pdl/forvalter/service/BostedAdresseServiceTest.java index e8c2a01ba7..19fd06bf2a 100644 --- a/apps/pdl-forvalter/src/test/java/no/nav/pdl/forvalter/service/BostedAdresseServiceTest.java +++ b/apps/pdl-forvalter/src/test/java/no/nav/pdl/forvalter/service/BostedAdresseServiceTest.java @@ -149,21 +149,20 @@ void whenOverlappingGyldigTil_thenFixInterval() { .ident(FNR_IDENT) .bostedsadresse(new ArrayList<>(List.of( BostedadresseDTO.builder() - .gyldigFraOgMed(LocalDate.of(2020, 1, 1).atStartOfDay()) - .gyldigTilOgMed(LocalDate.of(2021, 2, 3).atStartOfDay()) - .utenlandskAdresse(new UtenlandskAdresseDTO()) + .gyldigFraOgMed(LocalDate.of(2021, 2, 2).atStartOfDay()) + .matrikkeladresse(new MatrikkeladresseDTO()) .isNew(true) .build(), BostedadresseDTO.builder() - .gyldigFraOgMed(LocalDate.of(2020, 2, 2).atStartOfDay()) - .matrikkeladresse(new MatrikkeladresseDTO()) + .gyldigFraOgMed(LocalDate.of(2020, 1, 1).atStartOfDay()) + .utenlandskAdresse(new UtenlandskAdresseDTO()) .isNew(true) .build()))) .build(); var response = bostedAdresseService.convert(request, null); - assertThat(response.get(1).getGyldigTilOgMed(), is(equalTo(LocalDateTime.of(2020, 2, 1, 0, 0)))); + assertThat(response.get(1).getGyldigTilOgMed(), is(equalTo(LocalDateTime.of(2021, 2, 1, 0, 0)))); } @Test