Skip to content

Commit 8cab505

Browse files
authored
TSFF-1095: Reduksjon inntekt (#152)
* FIX: Refaktorering av uttak, deler opp i meir tydelige steg * Lager egne vurderere per regel * Legger til regel for reduksjon ved innrapportert inntekt * Legger på javadoc * Bytter rekkefølge på avslag ved død og innvilgelse * Test for reduksjon * Mapper rapporterte inntekter * Bruker statiske datoer i test * Legger til behandlingsårsak i perioder til vurdering utleder * Endringer etter QA: Gjer regelvurderere uavhengig av kvarandre * Legger nokDagerTidslinje inn i Avslagsvurderer * Legger til kommentarer
1 parent 25e54e8 commit 8cab505

21 files changed

+1035
-153
lines changed

behandlingslager/domene/src/main/java/no/nav/ung/sak/behandlingslager/ytelse/uttak/UngdomsytelseUttakPeriode.java

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.math.BigDecimal;
44
import java.time.LocalDate;
55

6+
import no.nav.fpsak.tidsserie.LocalDateInterval;
67
import org.hibernate.annotations.Type;
78

89
import jakarta.persistence.Column;
@@ -53,6 +54,12 @@ public UngdomsytelseUttakPeriode(BigDecimal utbetalingsgrad,
5354
this.periode = periode.toRange();
5455
}
5556

57+
public UngdomsytelseUttakPeriode(LocalDate fom, LocalDate tom, BigDecimal utbetalingsgrad, UngdomsytelseUttakAvslagsårsak avslagsårsak) {
58+
this.periode = Range.closed(fom, tom);
59+
this.utbetalingsgrad = utbetalingsgrad;
60+
this.avslagsårsak = avslagsårsak;
61+
}
62+
5663
public UngdomsytelseUttakPeriode(UngdomsytelseUttakAvslagsårsak avslagsårsak,
5764
DatoIntervallEntitet periode) {
5865
this.utbetalingsgrad = BigDecimal.ZERO;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package no.nav.ung.sak.domene.behandling.steg.uttak;
2+
3+
import jakarta.enterprise.context.Dependent;
4+
import jakarta.inject.Inject;
5+
import no.nav.fpsak.tidsserie.LocalDateSegment;
6+
import no.nav.fpsak.tidsserie.LocalDateTimeline;
7+
import no.nav.fpsak.tidsserie.StandardCombinators;
8+
import no.nav.ung.sak.domene.arbeidsforhold.InntektArbeidYtelseTjeneste;
9+
import no.nav.ung.sak.domene.behandling.steg.uttak.regler.InntektType;
10+
import no.nav.ung.sak.domene.behandling.steg.uttak.regler.RapportertInntekt;
11+
import no.nav.ung.sak.domene.iay.modell.InntektArbeidYtelseGrunnlag;
12+
import no.nav.ung.sak.domene.iay.modell.OppgittOpptjening;
13+
import org.jetbrains.annotations.NotNull;
14+
15+
import java.time.LocalDateTime;
16+
import java.util.ArrayList;
17+
import java.util.Comparator;
18+
import java.util.List;
19+
import java.util.Set;
20+
21+
@Dependent
22+
public class RapportertInntektMapper {
23+
24+
private InntektArbeidYtelseTjeneste inntektArbeidYtelseTjeneste;
25+
26+
@Inject
27+
public RapportertInntektMapper(InntektArbeidYtelseTjeneste inntektArbeidYtelseTjeneste) {
28+
this.inntektArbeidYtelseTjeneste = inntektArbeidYtelseTjeneste;
29+
}
30+
31+
public LocalDateTimeline<Set<RapportertInntekt>> map(Long behandlingId) {
32+
// Henter iay-grunnlag (kall til abakus)
33+
final var iayGrunnlag = inntektArbeidYtelseTjeneste.hentGrunnlag(behandlingId);
34+
// Finner rapporterte inntekter pr journalpost sortert på mottattdato med siste mottatt journalpost først
35+
final var sorterteInntekttidslinjerPåMottattdato = finnSorterteInntektstidslinjer(iayGrunnlag);
36+
37+
var resultatTidslinje = new LocalDateTimeline<Set<RapportertInntekt>>(List.of());
38+
for (InntektForMottattidspunkt journalpostMedInntekttidslinje : sorterteInntekttidslinjerPåMottattdato) {
39+
// Dersom vi ikke allerede har lagt til en rapportert inntekt for perioden legger vi den til i resultattidslinjen
40+
if (!resultatTidslinje.intersects(journalpostMedInntekttidslinje.tidslinje())) {
41+
// Trenger ikkje å håndtere overlapp sidan vi aldri går inn her med overlapp
42+
resultatTidslinje = resultatTidslinje.crossJoin(journalpostMedInntekttidslinje.tidslinje());
43+
}
44+
}
45+
46+
return resultatTidslinje;
47+
}
48+
49+
private List<InntektForMottattidspunkt> finnSorterteInntektstidslinjer(InntektArbeidYtelseGrunnlag iayGrunnlag) {
50+
return iayGrunnlag.getOppgittOpptjeningAggregat()
51+
.stream()
52+
.flatMap(o -> o.getOppgitteOpptjeninger().stream().map(RapportertInntektMapper::finnInntekterPrMottattidspunkt))
53+
.sorted(Comparator.reverseOrder())
54+
.toList();
55+
}
56+
57+
private static InntektForMottattidspunkt finnInntekterPrMottattidspunkt(OppgittOpptjening o) {
58+
final var res = new ArrayList<LocalDateSegment<Set<RapportertInntekt>>>();
59+
res.addAll(finnArbeidOgFrilansSegmenter(o));
60+
res.addAll(finnNæringssegmenter(o));
61+
return new InntektForMottattidspunkt(o.getInnsendingstidspunkt(), new LocalDateTimeline<>(res, StandardCombinators::union));
62+
}
63+
64+
private static List<LocalDateSegment<Set<RapportertInntekt>>> finnNæringssegmenter(OppgittOpptjening o) {
65+
return o.getEgenNæring().stream()
66+
.map(it -> new LocalDateSegment<>(
67+
it.getPeriode().toLocalDateInterval(),
68+
Set.of(new RapportertInntekt(
69+
InntektType.SELVSTENDIG_NÆRINGSDRIVENDE,
70+
it.getBruttoInntekt())
71+
))).toList();
72+
}
73+
74+
private static List<LocalDateSegment<Set<RapportertInntekt>>> finnArbeidOgFrilansSegmenter(OppgittOpptjening o) {
75+
return o.getOppgittArbeidsforhold().stream()
76+
.map(it -> new LocalDateSegment<>(
77+
it.getPeriode().toLocalDateInterval(),
78+
Set.of(new RapportertInntekt(
79+
InntektType.ARBEIDSTAKER_ELLER_FRILANSER,
80+
it.getInntekt())
81+
))).toList();
82+
}
83+
84+
private record InntektForMottattidspunkt(LocalDateTime mottattTidspunkt,
85+
LocalDateTimeline<Set<RapportertInntekt>> tidslinje
86+
) implements Comparable<InntektForMottattidspunkt> {
87+
88+
@Override
89+
public int compareTo(@NotNull InntektForMottattidspunkt o) {
90+
return this.mottattTidspunkt.compareTo(o.mottattTidspunkt);
91+
}
92+
}
93+
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package no.nav.ung.sak.domene.behandling.steg.uttak;
2+
3+
import no.nav.fpsak.tidsserie.LocalDateInterval;
4+
import no.nav.fpsak.tidsserie.LocalDateSegment;
5+
import no.nav.fpsak.tidsserie.LocalDateSegmentCombinator;
6+
import no.nav.fpsak.tidsserie.LocalDateTimeline;
7+
import no.nav.ung.kodeverk.ungdomsytelse.uttak.UngdomsytelseUttakAvslagsårsak;
8+
import no.nav.ung.sak.behandlingslager.ytelse.uttak.UngdomsytelseUttakPeriode;
9+
import no.nav.ung.sak.domene.behandling.steg.uttak.regler.UttakResultat;
10+
11+
import java.util.List;
12+
13+
public class UttaksperiodeMapper {
14+
15+
static List<UngdomsytelseUttakPeriode> mapTilUttaksperioder(List<LocalDateTimeline<UttakResultat>> uttakstidslinjer) {
16+
return uttakstidslinjer.stream()
17+
.reduce(UttaksperiodeMapper::kombinerTidslinjer)
18+
.orElse(LocalDateTimeline.empty())
19+
.compress()
20+
.stream()
21+
.map(s -> new UngdomsytelseUttakPeriode(s.getFom(), s.getTom(), s.getValue().utbetalingsgrad(), s.getValue().avslagsårsak()))
22+
.toList();
23+
}
24+
25+
private static LocalDateTimeline<UttakResultat> kombinerTidslinjer(LocalDateTimeline<UttakResultat> t1, LocalDateTimeline<UttakResultat> t2) {
26+
return t1.combine(t2, kombinerUttaksresultater(), LocalDateTimeline.JoinStyle.CROSS_JOIN);
27+
}
28+
29+
private static LocalDateSegmentCombinator<UttakResultat, UttakResultat, UttakResultat> kombinerUttaksresultater() {
30+
return (di, lhs, rhs) -> {
31+
// Hvis en av segmentene er null, bruk det andre
32+
if (lhs == null) {
33+
return new LocalDateSegment<>(di, rhs.getValue());
34+
} else if (rhs == null) {
35+
return new LocalDateSegment<>(di, lhs.getValue());
36+
}
37+
38+
// Hvis begge segmentene er avslått, velg den høyest prioriterte avslagsårsaken
39+
if (lhs.getValue().avslagsårsak() != null && rhs.getValue().avslagsårsak() != null) {
40+
return velgPrioritertAvslagsårsak(di, lhs, rhs);
41+
}
42+
43+
// Hvis ett av segmentene er avslått, bruk dette
44+
if (lhs.getValue().avslagsårsak() != null) {
45+
return new LocalDateSegment<>(di, lhs.getValue());
46+
} else if (rhs.getValue().avslagsårsak() != null) {
47+
return new LocalDateSegment<>(di, rhs.getValue());
48+
}
49+
50+
// Forventer ikke å ha to regler som begge gir innvilget i samme periode
51+
throw new IllegalStateException("Fant to overlappende segmenter for innvilgelse");
52+
};
53+
}
54+
55+
private static LocalDateSegment<UttakResultat> velgPrioritertAvslagsårsak(LocalDateInterval di, LocalDateSegment<UttakResultat> lhs, LocalDateSegment<UttakResultat> rhs) {
56+
if (lhs.getValue().avslagsårsak().equals(UngdomsytelseUttakAvslagsårsak.SØKERS_DØDSFALL) || rhs.getValue().avslagsårsak().equals(UngdomsytelseUttakAvslagsårsak.SØKERS_DØDSFALL)) {
57+
return new LocalDateSegment<>(di, UttakResultat.forAvslag(UngdomsytelseUttakAvslagsårsak.SØKERS_DØDSFALL));
58+
} else {
59+
return new LocalDateSegment<>(di, UttakResultat.forAvslag(lhs.getValue().avslagsårsak()));
60+
}
61+
}
62+
}

behandlingsprosess/src/main/java/no/nav/ung/sak/domene/behandling/steg/uttak/VurderAntallDagerTjeneste.java

-120
This file was deleted.

0 commit comments

Comments
 (0)