Skip to content

Commit c689fd8

Browse files
TSFF-1208: Nytt steg for kontroll av inntekt (#239)
* TSFF-1208: Nytt steg for kontroll av inntekt * TSFF-1208: Fjerne modul * TSFF-1208: Håndterer at det ikkje finnes registerinntekter * TSFF-1208: Lager dummy-implementasjon av interface * TSFF-1208: Fikser test * ung-sak.openapi.json updated by build pipeline skip-checks:true * TSFF-1208: Fjerne test --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 6b9ddb1 commit c689fd8

File tree

24 files changed

+709
-60
lines changed

24 files changed

+709
-60
lines changed

behandlingsprosess/src/main/java/no/nav/ung/sak/domene/behandling/steg/beregnytelse/BeregnYtelseSteg.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public BeregnYtelseSteg(UngdomsytelseGrunnlagRepository ungdomsytelseGrunnlagRep
6666
if (ungdomsytelseGrunnlag.isEmpty()) {
6767
return BehandleStegResultat.utførtUtenAksjonspunkter();
6868
}
69-
final var rapportertInntektTidslinje = rapportertInntektMapper.map(kontekst.getBehandlingId());
69+
final var rapportertInntektTidslinje = rapportertInntektMapper.mapAlleGjeldendeRegisterOgBrukersInntekter(kontekst.getBehandlingId());
7070
final var ytelseTidslinje = ytelseperiodeUtleder.utledYtelsestidslinje(kontekst.getBehandlingId());
7171

7272
// Validerer at periodene for rapporterte inntekter er konsistent med ytelsetidslinje

behandlingsprosess/src/main/java/no/nav/ung/sak/domene/behandling/steg/beregnytelse/LagTilkjentYtelse.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class LagTilkjentYtelse {
1919
static LocalDateTimeline<TilkjentYtelsePeriodeResultat> lagTidslinje(LocalDateTimeline<Boolean> godkjentTidslinje, LocalDateTimeline<BeregnetSats> totalsatsTidslinje, LocalDateTimeline<RapporterteInntekter> rapportertInntektTidslinje) {
2020
return totalsatsTidslinje.combine(rapportertInntektTidslinje, (di, sats, rapportertInntekt) -> {
2121
// Dersom det ikke er rapportert inntekt settes denne til 0, ellers summeres alle inntektene
22-
final var rapporertinntekt = rapportertInntekt == null ? BigDecimal.ZERO : rapportertInntekt.getValue().getRapporterteInntekter().stream().map(RapportertInntekt::beløp).reduce(BigDecimal.ZERO, BigDecimal::add);
22+
final var rapporertinntekt = rapportertInntekt == null ? BigDecimal.ZERO : rapportertInntekt.getValue().getBrukerRapporterteInntekter().stream().map(RapportertInntekt::beløp).reduce(BigDecimal.ZERO, BigDecimal::add);
2323
// Mapper verdier til TilkjentYtelsePeriodeResultat
2424
final var periodeResultat = TikjentYtelseBeregner.beregn(di, sats.getValue(), rapporertinntekt);
2525
return new LocalDateSegment<>(di.getFomDato(), di.getTomDato(), periodeResultat);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;
2+
3+
import no.nav.fpsak.tidsserie.LocalDateSegment;
4+
import no.nav.fpsak.tidsserie.LocalDateTimeline;
5+
import no.nav.ung.kodeverk.behandling.BehandlingÅrsakType;
6+
import no.nav.ung.sak.ytelse.RapportertInntekt;
7+
import no.nav.ung.sak.ytelse.RapporterteInntekter;
8+
import no.nav.ung.sak.ytelse.uttalelse.BrukersUttalelseForRegisterinntekt;
9+
10+
import java.math.BigDecimal;
11+
import java.util.Optional;
12+
import java.util.Set;
13+
14+
import static no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll.FinnKontrollresultatForIkkeGodkjentUttalelse.harDiff;
15+
16+
public class Avviksvurdering {
17+
18+
public static final BigDecimal AKSEPTERT_DIFFERANSE = BigDecimal.valueOf(1000);
19+
20+
21+
static Optional<KontrollResultat> gjørAvviksvurderingMotRegisterinntekt(LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter, LocalDateTimeline<BrukersUttalelseForRegisterinntekt> uttalelseTidslinje, LocalDateTimeline<Set<BehandlingÅrsakType>> tidslinjeRelevanteÅrsaker) {
22+
final var inntektDiffKontrollResultat = finnKontrollresultatTidslinje(gjeldendeRapporterteInntekter, tidslinjeRelevanteÅrsaker);
23+
24+
final var tidslinjeForOppgaveTilBruker = inntektDiffKontrollResultat.filterValue(it -> it.equals(KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER));
25+
if (!tidslinjeForOppgaveTilBruker.isEmpty()) {
26+
27+
// Må finne ut om vi skal sette ny frist
28+
final var oppgaverTilBrukerTidslinje = finnNyOppgaveKontrollresultatTidslinje(gjeldendeRapporterteInntekter, uttalelseTidslinje, tidslinjeForOppgaveTilBruker);
29+
30+
if (!oppgaverTilBrukerTidslinje.filterValue(it -> it.equals(KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST)).isEmpty()) {
31+
return Optional.of(KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST);
32+
} else {
33+
return Optional.of(KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER);
34+
}
35+
36+
}
37+
38+
if (!inntektDiffKontrollResultat.filterValue(it -> it.equals(KontrollResultat.BRUK_INNTEKT_FRA_BRUKER)).isEmpty()) {
39+
return Optional.of(KontrollResultat.BRUK_INNTEKT_FRA_BRUKER);
40+
}
41+
return Optional.empty();
42+
}
43+
44+
private static LocalDateTimeline<KontrollResultat> finnNyOppgaveKontrollresultatTidslinje(LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter, LocalDateTimeline<BrukersUttalelseForRegisterinntekt> uttalelseTidslinje, LocalDateTimeline<KontrollResultat> tidslinjeForOppgaveTilBruker) {
45+
final var oppgaverTilBrukerTidslinje = gjeldendeRapporterteInntekter.mapValue(RapporterteInntekter::getRegisterRapporterteInntekter).intersection(tidslinjeForOppgaveTilBruker)
46+
.combine(uttalelseTidslinje.mapValue(BrukersUttalelseForRegisterinntekt::registerInntekt), (di, register, uttalelse) -> {
47+
if (uttalelse == null) {
48+
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER);
49+
}
50+
if (!harDiff(uttalelse.getValue(), register.getValue())) {
51+
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER);
52+
} else {
53+
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST);
54+
}
55+
}, LocalDateTimeline.JoinStyle.LEFT_JOIN);
56+
return oppgaverTilBrukerTidslinje;
57+
}
58+
59+
private static LocalDateTimeline<KontrollResultat> finnKontrollresultatTidslinje(LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter, LocalDateTimeline<Set<BehandlingÅrsakType>> tidslinjeRelevanteÅrsaker) {
60+
final var inntektDiffKontrollResultat = gjeldendeRapporterteInntekter.intersection(tidslinjeRelevanteÅrsaker)
61+
.mapValue(it ->
62+
{
63+
final var register = it.getRegisterRapporterteInntekter().stream()
64+
.map(RapportertInntekt::beløp).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
65+
final var bruker = it.getBrukerRapporterteInntekter().stream()
66+
.map(RapportertInntekt::beløp).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
67+
68+
final var differanse = register.subtract(bruker).abs();
69+
70+
if (differanse.compareTo(AKSEPTERT_DIFFERANSE) > 0) {
71+
return KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER;
72+
} else {
73+
return KontrollResultat.BRUK_INNTEKT_FRA_BRUKER;
74+
}
75+
});
76+
return inntektDiffKontrollResultat;
77+
}
78+
79+
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;
2+
3+
import no.nav.fpsak.tidsserie.LocalDateSegment;
4+
import no.nav.fpsak.tidsserie.LocalDateTimeline;
5+
import no.nav.ung.sak.ytelse.RapportertInntekt;
6+
import no.nav.ung.sak.ytelse.RapporterteInntekter;
7+
import no.nav.ung.sak.ytelse.uttalelse.BrukersUttalelseForRegisterinntekt;
8+
9+
import java.math.BigDecimal;
10+
import java.util.Set;
11+
12+
public class FinnKontrollresultatForIkkeGodkjentUttalelse {
13+
14+
static KontrollResultat finnKontrollresultatForIkkeGodkjentUttalelse(LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter, LocalDateTimeline<BrukersUttalelseForRegisterinntekt> relevantIkkeGodkjentUttalelse) {
15+
final var registerInntektTidslinje = gjeldendeRapporterteInntekter.mapValue(RapporterteInntekter::getRegisterRapporterteInntekter);
16+
final var ikkeGodkjentUttalelseResultater = relevantIkkeGodkjentUttalelse.combine(registerInntektTidslinje, (di, uttalelse, register) -> {
17+
if (!harDiff(uttalelse.getValue().registerInntekt(), register != null ? register.getValue() : Set.of())) {
18+
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_AKSJONSPUNKT);
19+
} else {
20+
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST);
21+
}
22+
}, LocalDateTimeline.JoinStyle.LEFT_JOIN);
23+
24+
if (!ikkeGodkjentUttalelseResultater.filterValue(it -> it == KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST).isEmpty()) {
25+
return KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST;
26+
} else if (!ikkeGodkjentUttalelseResultater.filterValue(it -> it == KontrollResultat.OPPRETT_AKSJONSPUNKT).isEmpty()) {
27+
return KontrollResultat.OPPRETT_AKSJONSPUNKT;
28+
}
29+
30+
return KontrollResultat.OPPRETT_AKSJONSPUNKT;
31+
}
32+
33+
static boolean harDiff(Set<RapportertInntekt> registerInntekFraUttalelse, Set<RapportertInntekt> gjeldendeRegisterinntekt) {
34+
final var totalInntektFraUttalelse = summerInntekter(registerInntekFraUttalelse);
35+
final var totalGjeldendeRegisterInntekt = summerInntekter(gjeldendeRegisterinntekt);
36+
return totalInntektFraUttalelse.compareTo(totalGjeldendeRegisterInntekt) != 0;
37+
}
38+
39+
private static BigDecimal summerInntekter(Set<RapportertInntekt> registerinntektFraUttalelse) {
40+
return registerinntektFraUttalelse.stream()
41+
.map(RapportertInntekt::beløp)
42+
.reduce(BigDecimal::add)
43+
.orElse(BigDecimal.ZERO);
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;
2+
3+
public enum KontrollResultat {
4+
BRUK_INNTEKT_FRA_BRUKER,
5+
OPPRETT_AKSJONSPUNKT,
6+
OPPRETT_OPPGAVE_TIL_BRUKER,
7+
OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST,
8+
SETT_PÅ_VENT_TIL_RAPPORTERINGSFRIST
9+
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;
2+
3+
import jakarta.enterprise.context.ApplicationScoped;
4+
import jakarta.inject.Inject;
5+
import no.nav.ung.sak.behandlingskontroll.*;
6+
import no.nav.ung.sak.perioder.ProsessTriggerPeriodeUtleder;
7+
import no.nav.ung.sak.ytelse.RapportertInntektMapper;
8+
import no.nav.ung.sak.ytelse.uttalelse.RegisterinntektUttalelseTjeneste;
9+
10+
import static no.nav.ung.kodeverk.behandling.BehandlingStegType.KONTROLLER_REGISTER_INNTEKT;
11+
import static no.nav.ung.kodeverk.behandling.FagsakYtelseType.UNGDOMSYTELSE;
12+
13+
@ApplicationScoped
14+
@BehandlingStegRef(value = KONTROLLER_REGISTER_INNTEKT)
15+
@BehandlingTypeRef
16+
@FagsakYtelseTypeRef(UNGDOMSYTELSE)
17+
public class KontrollerInntektSteg implements BehandlingSteg {
18+
19+
private ProsessTriggerPeriodeUtleder prosessTriggerPeriodeUtleder;
20+
private RapportertInntektMapper rapportertInntektMapper;
21+
private RegisterinntektUttalelseTjeneste registerinntektUttalelseTjeneste;
22+
23+
24+
@Inject
25+
public KontrollerInntektSteg(ProsessTriggerPeriodeUtleder prosessTriggerPeriodeUtleder,
26+
RapportertInntektMapper rapportertInntektMapper,
27+
RegisterinntektUttalelseTjeneste registerinntektUttalelseTjeneste) {
28+
this.prosessTriggerPeriodeUtleder = prosessTriggerPeriodeUtleder;
29+
this.rapportertInntektMapper = rapportertInntektMapper;
30+
this.registerinntektUttalelseTjeneste = registerinntektUttalelseTjeneste;
31+
}
32+
33+
public KontrollerInntektSteg() {
34+
}
35+
36+
@Override
37+
public BehandleStegResultat utførSteg(BehandlingskontrollKontekst kontekst) {
38+
39+
final var rapporterteInntekterTidslinje = rapportertInntektMapper.mapAlleGjeldendeRegisterOgBrukersInntekter(kontekst.getBehandlingId());
40+
final var prosessTriggerTidslinje = prosessTriggerPeriodeUtleder.utledTidslinje(kontekst.getBehandlingId());
41+
final var uttalelser = registerinntektUttalelseTjeneste.hentUttalelser(kontekst.getBehandlingId());
42+
final var registerinntekterForIkkeGodkjentUttalelse = rapportertInntektMapper.finnRegisterinntekterForUttalelse(kontekst.getBehandlingId(), uttalelser);
43+
44+
45+
final var kontrollResultat = KontrollerInntektTjeneste.utførKontroll(prosessTriggerTidslinje, rapporterteInntekterTidslinje, registerinntekterForIkkeGodkjentUttalelse);
46+
47+
return BehandleStegResultat.utførtUtenAksjonspunkter(
48+
);
49+
}
50+
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;
2+
3+
import no.nav.fpsak.tidsserie.LocalDateTimeline;
4+
import no.nav.ung.kodeverk.behandling.BehandlingÅrsakType;
5+
import no.nav.ung.sak.ytelse.RapporterteInntekter;
6+
import no.nav.ung.sak.ytelse.uttalelse.BrukersUttalelseForRegisterinntekt;
7+
import no.nav.ung.sak.ytelse.uttalelse.Status;
8+
9+
import java.util.Set;
10+
11+
import static no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll.FinnKontrollresultatForIkkeGodkjentUttalelse.finnKontrollresultatForIkkeGodkjentUttalelse;
12+
13+
public class KontrollerInntektTjeneste {
14+
15+
16+
17+
public static KontrollResultat utførKontroll(LocalDateTimeline<Set<BehandlingÅrsakType>> prosessTriggerTidslinje,
18+
LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter,
19+
LocalDateTimeline<BrukersUttalelseForRegisterinntekt> uttalelseTidslinje) {
20+
21+
// Sjekker først om vi har relevante årsaker
22+
final var tidslinjeRelevanteÅrsaker = prosessTriggerTidslinje.filterValue(it -> it.contains(BehandlingÅrsakType.RE_RAPPORTERING_INNTEKT) || it.contains(BehandlingÅrsakType.RE_KONTROLL_REGISTER_INNTEKT));
23+
final var harIkkePassertRapporteringsfrist = tidslinjeRelevanteÅrsaker.filterValue(it -> !it.contains(BehandlingÅrsakType.RE_KONTROLL_REGISTER_INNTEKT));
24+
// Dersom vi ikkje har passert rapporteringsfrist (ikkje har kontroll-årsak) så skal vi vente til rapporteringsfrist
25+
if (!harIkkePassertRapporteringsfrist.isEmpty()) {
26+
return KontrollResultat.SETT_PÅ_VENT_TIL_RAPPORTERINGSFRIST;
27+
}
28+
29+
final var relevantIkkeGodkjentUttalelse = uttalelseTidslinje.filterValue(it -> it.status().equals(Status.BEKREFTET) && !it.uttalelse().erEndringenGodkjent()).intersection(tidslinjeRelevanteÅrsaker);
30+
if (!relevantIkkeGodkjentUttalelse.isEmpty()) {
31+
return finnKontrollresultatForIkkeGodkjentUttalelse(gjeldendeRapporterteInntekter, relevantIkkeGodkjentUttalelse);
32+
}
33+
34+
final var opprettOppgaveTilBrukerMedNyFrist = Avviksvurdering.gjørAvviksvurderingMotRegisterinntekt(gjeldendeRapporterteInntekter, uttalelseTidslinje, tidslinjeRelevanteÅrsaker);
35+
return opprettOppgaveTilBrukerMedNyFrist.orElse(KontrollResultat.BRUK_INNTEKT_FRA_BRUKER);
36+
37+
}
38+
39+
}

behandlingsprosess/src/test/java/no/nav/ung/sak/domene/behandling/steg/beregnytelse/BeregnYtelseStegTest.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,13 @@ void setUp() {
6161
inntektArbeidYtelseTjeneste = new AbakusInMemoryInntektArbeidYtelseTjeneste();
6262
ungdomsprogramPeriodeRepository = new UngdomsprogramPeriodeRepository(entityManager);
6363
behandlingRepository = new BehandlingRepository(entityManager);
64+
final var ytelseperiodeUtleder = new YtelseperiodeUtleder(
65+
new UngdomsprogramPeriodeTjeneste(ungdomsprogramPeriodeRepository),
66+
behandlingRepository);
6467
beregnYtelseSteg = new BeregnYtelseSteg(ungdomsytelseGrunnlagRepository,
6568
tilkjentYtelseRepository,
66-
new RapportertInntektMapper(inntektArbeidYtelseTjeneste),
67-
new YtelseperiodeUtleder(
68-
new UngdomsprogramPeriodeTjeneste(ungdomsprogramPeriodeRepository),
69-
behandlingRepository));
69+
new RapportertInntektMapper(inntektArbeidYtelseTjeneste, ytelseperiodeUtleder),
70+
ytelseperiodeUtleder);
7071

7172
fagsakRepository = new FagsakRepository(entityManager);
7273

behandlingsprosess/src/test/java/no/nav/ung/sak/domene/behandling/steg/beregnytelse/LagTilkjentYtelseTest.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ void testLagTidslinjeMedTomGodkjentTidslinje() {
3737

3838
LocalDateTimeline<RapporterteInntekter> rapportertInntektTidslinje = new LocalDateTimeline<>(List.of(
3939
new LocalDateSegment<>(LocalDate.of(2023, 1, 15), LocalDate.of(2023, 2, 15),
40-
new RapporterteInntekter(Set.of(new RapportertInntekt(InntektType.ARBEIDSTAKER_ELLER_FRILANSER, BigDecimal.valueOf(50000)))))
40+
new RapporterteInntekter(
41+
Set.of(new RapportertInntekt(InntektType.ARBEIDSTAKER_ELLER_FRILANSER, BigDecimal.valueOf(50000))),
42+
Set.of()))
4143
));
4244

4345
// Call the method under test
@@ -114,7 +116,9 @@ void testLagTidslinjeUtenRapportertInntekt() {
114116

115117
final var rapportertInntekt = BigDecimal.valueOf(150);
116118
LocalDateTimeline<RapporterteInntekter> rapportertInntektTidslinje = new LocalDateTimeline<>(List.of(
117-
new LocalDateSegment<>(fom, tom, new RapporterteInntekter(Set.of(new RapportertInntekt(InntektType.ARBEIDSTAKER_ELLER_FRILANSER, rapportertInntekt))))
119+
new LocalDateSegment<>(fom, tom, new RapporterteInntekter(
120+
Set.of(new RapportertInntekt(InntektType.ARBEIDSTAKER_ELLER_FRILANSER, rapportertInntekt)),
121+
Set.of()))
118122
));
119123

120124
// Act

0 commit comments

Comments
 (0)