From cb769ddea38c61b3a7a04bf003a026ce22986ac5 Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Thu, 21 Nov 2024 06:48:28 +0100 Subject: [PATCH] =?UTF-8?q?Sl=C3=A5r=20sammen=20over=20helg=20dersom=20til?= =?UTF-8?q?kommet=20inntekt=20er=20lik=20p=C3=A5=20begge=20sider=20(#573)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Slår sammen over helg dersom tilkommet inntekt er lik på begge sider * Legger til test --- .../TilkommetInntektsforholdTjeneste.java | 11 +- ...ringsbehovUtlederTilkommetInntektTest.java | 18 +- .../TilkommetInntektsforholdTjenesteTest.java | 168 ++++++++++++++++++ 3 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 kalkulator/src/test/java/no/nav/folketrygdloven/kalkulator/steg/tilkommetInntekt/TilkommetInntektsforholdTjenesteTest.java diff --git a/kalkulator/src/main/java/no/nav/folketrygdloven/kalkulator/steg/tilkommetInntekt/TilkommetInntektsforholdTjeneste.java b/kalkulator/src/main/java/no/nav/folketrygdloven/kalkulator/steg/tilkommetInntekt/TilkommetInntektsforholdTjeneste.java index 2a981552..05ad778a 100644 --- a/kalkulator/src/main/java/no/nav/folketrygdloven/kalkulator/steg/tilkommetInntekt/TilkommetInntektsforholdTjeneste.java +++ b/kalkulator/src/main/java/no/nav/folketrygdloven/kalkulator/steg/tilkommetInntekt/TilkommetInntektsforholdTjeneste.java @@ -27,6 +27,7 @@ import no.nav.folketrygdloven.kalkulator.modell.typer.InternArbeidsforholdRefDto; import no.nav.folketrygdloven.kalkulator.modell.typer.StatusOgArbeidsgiver; import no.nav.folketrygdloven.kalkulator.tid.Intervall; +import no.nav.folketrygdloven.kalkulator.tid.TimelineWeekendCompressor; import no.nav.folketrygdloven.kalkulus.kodeverk.AktivitetStatus; import no.nav.folketrygdloven.kalkulus.kodeverk.AndelKilde; import no.nav.folketrygdloven.kalkulus.kodeverk.UttakArbeidType; @@ -90,7 +91,15 @@ public static LocalDateTimeline> finnTilkommetInntekts var utbetalingTidslinje = finnTidslinjeForUtbetalingsperiode((UtbetalingsgradGrunnlag) utbetalingsgradGrunnlag); aktivitetTidslinje = aktivitetTidslinje.intersection(utbetalingTidslinje, StandardCombinators::leftOnly); } - return aktivitetTidslinje.map(s -> mapTilkommetTidslinje(andelerFraStart, yrkesaktiviteter, utbetalingsgradGrunnlag, s, ikkeFiltrerVedFulltFravær)).compress(); + var tilkommetTidslinje = aktivitetTidslinje.map(s -> mapTilkommetTidslinje(andelerFraStart, yrkesaktiviteter, utbetalingsgradGrunnlag, s, ikkeFiltrerVedFulltFravær)).compress(); + return slåSammenOverHelgDersomLike(tilkommetTidslinje); + } + + private static LocalDateTimeline slåSammenOverHelgDersomLike(LocalDateTimeline tidslinje) { + var factory = new TimelineWeekendCompressor.CompressorFactory(Objects::equals, (i, lhs, rhs) -> new LocalDateSegment<>(i, lhs.getValue())); + TimelineWeekendCompressor compressor = tidslinje.toSegments().stream() + .collect(factory::get, TimelineWeekendCompressor::accept, TimelineWeekendCompressor::combine); + return new LocalDateTimeline<>(compressor.getSegmenter()); } private static LocalDateTimeline> finnDagpengetidslinje(InntektArbeidYtelseGrunnlagDto iayGrunnlag, LocalDate skjæringstidspunkt) { diff --git a/kalkulator/src/test/java/no/nav/folketrygdloven/kalkulator/steg/fordeling/avklaringsbehov/AvklaringsbehovUtlederTilkommetInntektTest.java b/kalkulator/src/test/java/no/nav/folketrygdloven/kalkulator/steg/fordeling/avklaringsbehov/AvklaringsbehovUtlederTilkommetInntektTest.java index dfea020f..d16f715e 100644 --- a/kalkulator/src/test/java/no/nav/folketrygdloven/kalkulator/steg/fordeling/avklaringsbehov/AvklaringsbehovUtlederTilkommetInntektTest.java +++ b/kalkulator/src/test/java/no/nav/folketrygdloven/kalkulator/steg/fordeling/avklaringsbehov/AvklaringsbehovUtlederTilkommetInntektTest.java @@ -21,13 +21,13 @@ import no.nav.folketrygdloven.kalkulator.modell.iay.AktivitetsAvtaleDto; import no.nav.folketrygdloven.kalkulator.modell.iay.AktivitetsAvtaleDtoBuilder; import no.nav.folketrygdloven.kalkulator.modell.iay.InntektArbeidYtelseAggregatBuilder; +import no.nav.folketrygdloven.kalkulator.modell.iay.InntektArbeidYtelseGrunnlagDto; import no.nav.folketrygdloven.kalkulator.modell.iay.InntektArbeidYtelseGrunnlagDtoBuilder; import no.nav.folketrygdloven.kalkulator.modell.iay.InntektDtoBuilder; import no.nav.folketrygdloven.kalkulator.modell.iay.InntektspostDtoBuilder; import no.nav.folketrygdloven.kalkulator.modell.iay.VersjonTypeDto; import no.nav.folketrygdloven.kalkulator.modell.iay.YrkesaktivitetDto; import no.nav.folketrygdloven.kalkulator.modell.iay.YrkesaktivitetDtoBuilder; -import no.nav.folketrygdloven.kalkulator.modell.iay.YtelseAnvistDto; import no.nav.folketrygdloven.kalkulator.modell.iay.YtelseAnvistDtoBuilder; import no.nav.folketrygdloven.kalkulator.modell.iay.YtelseDtoBuilder; import no.nav.folketrygdloven.kalkulator.modell.iay.permisjon.PermisjonDtoBuilder; @@ -594,6 +594,15 @@ private Set finnTilkomneAndeler(Intervall periode, PleiepengerSyktBarnGrunnlag utbetalingsgradGrunnlag, LocalDate skjæringstidspunkt) { + var iay = lagIAY(yrkesaktiviteter, dagpengePerioder, inntekter); + var tidslinje = TilkommetInntektsforholdTjeneste.finnTilkommetInntektsforholdTidslinje(skjæringstidspunkt, + andelerFraStart, utbetalingsgradGrunnlag, iay); + var segmenter = tidslinje.intersection(new LocalDateInterval(periode.getFomDato(), periode.getTomDato())).compress().toSegments(); + return segmenter.isEmpty() ? new LinkedHashSet<>() : segmenter.stream().map(LocalDateSegment::getValue) + .filter(s -> !s.isEmpty()).findFirst().orElse(Set.of()); + } + + private static InntektArbeidYtelseGrunnlagDto lagIAY(List yrkesaktiviteter, List dagpengePerioder, List inntekter) { var oppdatere = InntektArbeidYtelseAggregatBuilder.oppdatere(Optional.empty(), VersjonTypeDto.REGISTER); var aktørArbeid = InntektArbeidYtelseAggregatBuilder.AktørArbeidBuilder.oppdatere(Optional.empty()); yrkesaktiviteter.forEach(aktørArbeid::leggTilYrkesaktivitet); @@ -619,11 +628,8 @@ private Set finnTilkomneAndeler(Intervall periode, oppdatere.leggTilAktørYtelse(aktørYtelse); } - var tidslinje = TilkommetInntektsforholdTjeneste.finnTilkommetInntektsforholdTidslinje(skjæringstidspunkt, - andelerFraStart, utbetalingsgradGrunnlag, InntektArbeidYtelseGrunnlagDtoBuilder.nytt().medData(oppdatere).build()); - var segmenter = tidslinje.intersection(new LocalDateInterval(periode.getFomDato(), periode.getTomDato())).compress().toSegments(); - return segmenter.isEmpty() ? new LinkedHashSet<>() : segmenter.stream().map(LocalDateSegment::getValue) - .filter(s -> !s.isEmpty()).findFirst().orElse(Set.of()); + var iay = InntektArbeidYtelseGrunnlagDtoBuilder.nytt().medData(oppdatere).build(); + return iay; } private List lagInntektForYrkesaktiviteter(List yrkesaktiviteter, PleiepengerSyktBarnGrunnlag utbetalingsgradGrunnlag) { diff --git a/kalkulator/src/test/java/no/nav/folketrygdloven/kalkulator/steg/tilkommetInntekt/TilkommetInntektsforholdTjenesteTest.java b/kalkulator/src/test/java/no/nav/folketrygdloven/kalkulator/steg/tilkommetInntekt/TilkommetInntektsforholdTjenesteTest.java new file mode 100644 index 00000000..5a7bd66c --- /dev/null +++ b/kalkulator/src/test/java/no/nav/folketrygdloven/kalkulator/steg/tilkommetInntekt/TilkommetInntektsforholdTjenesteTest.java @@ -0,0 +1,168 @@ +package no.nav.folketrygdloven.kalkulator.steg.tilkommetInntekt; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; + +import no.nav.folketrygdloven.kalkulator.input.PleiepengerSyktBarnGrunnlag; +import no.nav.folketrygdloven.kalkulator.modell.beregningsgrunnlag.BGAndelArbeidsforholdDto; +import no.nav.folketrygdloven.kalkulator.modell.beregningsgrunnlag.BeregningsgrunnlagPrStatusOgAndelDto; +import no.nav.folketrygdloven.kalkulator.modell.iay.AktivitetsAvtaleDtoBuilder; +import no.nav.folketrygdloven.kalkulator.modell.iay.InntektArbeidYtelseAggregatBuilder; +import no.nav.folketrygdloven.kalkulator.modell.iay.InntektArbeidYtelseGrunnlagDto; +import no.nav.folketrygdloven.kalkulator.modell.iay.InntektArbeidYtelseGrunnlagDtoBuilder; +import no.nav.folketrygdloven.kalkulator.modell.iay.VersjonTypeDto; +import no.nav.folketrygdloven.kalkulator.modell.iay.YrkesaktivitetDto; +import no.nav.folketrygdloven.kalkulator.modell.iay.YrkesaktivitetDtoBuilder; +import no.nav.folketrygdloven.kalkulator.modell.svp.AktivitetDto; +import no.nav.folketrygdloven.kalkulator.modell.svp.PeriodeMedUtbetalingsgradDto; +import no.nav.folketrygdloven.kalkulator.modell.svp.UtbetalingsgradPrAktivitetDto; +import no.nav.folketrygdloven.kalkulator.modell.typer.Aktivitetsgrad; +import no.nav.folketrygdloven.kalkulator.modell.typer.Arbeidsgiver; +import no.nav.folketrygdloven.kalkulator.modell.typer.InternArbeidsforholdRefDto; +import no.nav.folketrygdloven.kalkulator.tid.Intervall; +import no.nav.folketrygdloven.kalkulus.kodeverk.AktivitetStatus; +import no.nav.folketrygdloven.kalkulus.kodeverk.AndelKilde; +import no.nav.folketrygdloven.kalkulus.kodeverk.ArbeidType; +import no.nav.folketrygdloven.kalkulus.kodeverk.UttakArbeidType; +import no.nav.fpsak.tidsserie.LocalDateInterval; +import no.nav.fpsak.tidsserie.LocalDateSegment; +import no.nav.fpsak.tidsserie.LocalDateTimeline; +import no.nav.fpsak.tidsserie.StandardCombinators; + +class TilkommetInntektsforholdTjenesteTest { + + + public static final String ARBEIDSGIVER_ORGNR = "123456789"; + public static final String ARBEIDSGIVER_ORGNR2 = "123456719"; + + public static final LocalDate STP = LocalDate.of(2024, 11, 20); + + @Test + void skal_slå_sammen_perioder_med_tilkommet_over_helg_og_returnere_første_dag_med_tilkommet_som_virkedag() { + + var arbeidsgiver = Arbeidsgiver.virksomhet(ARBEIDSGIVER_ORGNR); + var arbeidstakerandelFraStart = lagArbeidstakerandel(arbeidsgiver, 1L, AndelKilde.PROSESS_START, InternArbeidsforholdRefDto.nullRef()); + var utbetalingsgradFraStart = new UtbetalingsgradPrAktivitetDto(lagAktivitet(arbeidsgiver, InternArbeidsforholdRefDto.nullRef()), + lagUtbetalingsgrader(100, STP, STP.plusDays(20))); + + var arbeidsgiver2 = Arbeidsgiver.virksomhet(ARBEIDSGIVER_ORGNR2); + var tilkommetDato = STP.plusDays(10); + var utbetalingsgradNyAndel = new UtbetalingsgradPrAktivitetDto( + lagAktivitet(arbeidsgiver2, InternArbeidsforholdRefDto.nullRef()), + lagUtbetalingsgrader(50, tilkommetDato, STP.plusDays(20))); + + var yrkesaktivitet = lagYrkesaktivitet(arbeidsgiver, STP.minusMonths(10), STP.plusDays(9), InternArbeidsforholdRefDto.nullRef()); + var nyYrkesaktivitet = lagYrkesaktivitet(arbeidsgiver2, tilkommetDato, STP.plusDays(20), InternArbeidsforholdRefDto.nullRef()); + + + var utbetalingsgradGrunnlag = new PleiepengerSyktBarnGrunnlag(List.of( + utbetalingsgradFraStart, + utbetalingsgradNyAndel)); + + var iay = lagIAY(List.of(yrkesaktivitet, nyYrkesaktivitet)); + var tidslinje = TilkommetInntektsforholdTjeneste.finnTilkommetInntektsforholdTidslinje( + STP, + List.of(arbeidstakerandelFraStart), + utbetalingsgradGrunnlag, iay); + + var segmenter = tidslinje.toSegments(); + + assertThat(segmenter.size()).isEqualTo(2); + var iterator = segmenter.iterator(); + var førsteSegment = iterator.next(); + assertThat(førsteSegment.getValue().isEmpty()).isTrue(); + assertThat(førsteSegment.getFom()).isEqualTo(STP); + assertThat(førsteSegment.getTom()).isEqualTo(tilkommetDato.minusDays(1)); + + var andreSegment = iterator.next(); + var førsteVirkedagMedTilkommet = tilkommetDato.plusDays(2); + assertThat(andreSegment.getValue().size()).isEqualTo(1); + assertThat(andreSegment.getFom()).isEqualTo(førsteVirkedagMedTilkommet); + assertThat(andreSegment.getTom()).isEqualTo(STP.plusDays(20)); + + } + + private static InntektArbeidYtelseGrunnlagDto lagIAY(List yrkesaktiviteter) { + var oppdatere = InntektArbeidYtelseAggregatBuilder.oppdatere(Optional.empty(), VersjonTypeDto.REGISTER); + var aktørArbeid = InntektArbeidYtelseAggregatBuilder.AktørArbeidBuilder.oppdatere(Optional.empty()); + yrkesaktiviteter.forEach(aktørArbeid::leggTilYrkesaktivitet); + oppdatere.leggTilAktørArbeid(aktørArbeid); + var iay = InntektArbeidYtelseGrunnlagDtoBuilder.nytt().medData(oppdatere).build(); + return iay; + } + + private BeregningsgrunnlagPrStatusOgAndelDto lagArbeidstakerandel(Arbeidsgiver arbeidsgiver2, long andelsnr, AndelKilde kilde, InternArbeidsforholdRefDto arbeidsforholdRef) { + return BeregningsgrunnlagPrStatusOgAndelDto.ny() + .medAndelsnr(andelsnr) + .medBGAndelArbeidsforhold(BGAndelArbeidsforholdDto.builder().medArbeidsgiver(arbeidsgiver2).medArbeidsforholdRef(arbeidsforholdRef)) + .medKilde(kilde) + .medAktivitetStatus(AktivitetStatus.ARBEIDSTAKER) + .build(); + } + + private YrkesaktivitetDto lagYrkesaktivitet(Arbeidsgiver arbeidsgiver2, LocalDate fom, LocalDate tom, InternArbeidsforholdRefDto arbeidsforholdId) { + return YrkesaktivitetDtoBuilder.oppdatere(Optional.empty()) + .medArbeidsgiver(arbeidsgiver2) + .medArbeidsforholdId(arbeidsforholdId) + .medArbeidType(ArbeidType.ORDINÆRT_ARBEIDSFORHOLD) + .leggTilAktivitetsAvtale(AktivitetsAvtaleDtoBuilder.ny() + .medPeriode(Intervall.fraOgMedTilOgMed(fom, tom)) + .medErAnsettelsesPeriode(true)) + .build(); + } + + private List lagUtbetalingsgrader(int i, LocalDate fom, LocalDate tom) { + var tidslinje = new LocalDateTimeline<>(fom, tom, true); + var utenhelg = fjernHelg(tidslinje); + var helger = new LocalDateTimeline<>(fom, tom, true).disjoint(utenhelg); + + var utbetalingsgraderForHelger = lagUtbetalingsgraderFraTidslinje(0, utenhelg); + var utbetalingsgraderForUkedager = lagUtbetalingsgraderFraTidslinje(i, utenhelg); + utbetalingsgraderForUkedager.addAll(utbetalingsgraderForHelger); + return utbetalingsgraderForUkedager; + } + + private List lagUtbetalingsgraderFraTidslinje(int i, LocalDateTimeline utenhelg) { + return utenhelg.getLocalDateIntervals().stream() + .map(p -> lagPeriodeMedUtbetalingsgrad(i, p.getFomDato(), p.getTomDato())) + .collect(Collectors.toCollection(ArrayList::new)); + } + + + public static LocalDateTimeline fjernHelg(LocalDateTimeline input) { + List> helger = new ArrayList<>(); + for (LocalDateInterval intervall : input.getLocalDateIntervals()) { + LocalDate d = intervall.getFomDato(); + while (!d.isAfter(intervall.getTomDato())) { + if (d.getDayOfWeek() == DayOfWeek.SUNDAY) { + helger.add(new LocalDateSegment<>(d, d, null)); + d = d.plusDays(6); + } else if (d.getDayOfWeek() == DayOfWeek.SATURDAY) { + helger.add(new LocalDateSegment<>(d, d.plusDays(1), null)); + d = d.plusWeeks(1); + } else { + d = d.plusDays(DayOfWeek.SATURDAY.getValue() - d.getDayOfWeek().getValue()); + } + } + } + LocalDateTimeline helgetidslinje = new LocalDateTimeline<>(helger, StandardCombinators::coalesceLeftHandSide); + return input.disjoint(helgetidslinje); + } + + private PeriodeMedUtbetalingsgradDto lagPeriodeMedUtbetalingsgrad(int i, LocalDate fom, LocalDate tom) { + return new PeriodeMedUtbetalingsgradDto(Intervall.fraOgMedTilOgMed(fom, tom), null, Aktivitetsgrad.fra(100 - i)); + } + + private AktivitetDto lagAktivitet(Arbeidsgiver arbeidsgiver2, InternArbeidsforholdRefDto ref) { + return new AktivitetDto(arbeidsgiver2, ref, UttakArbeidType.ORDINÆRT_ARBEID); + } + +} \ No newline at end of file