Skip to content

TSFF-1208: Nytt steg for kontroll av inntekt #239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public BeregnYtelseSteg(UngdomsytelseGrunnlagRepository ungdomsytelseGrunnlagRep
if (ungdomsytelseGrunnlag.isEmpty()) {
return BehandleStegResultat.utførtUtenAksjonspunkter();
}
final var rapportertInntektTidslinje = rapportertInntektMapper.map(kontekst.getBehandlingId());
final var rapportertInntektTidslinje = rapportertInntektMapper.mapAlleGjeldendeRegisterOgBrukersInntekter(kontekst.getBehandlingId());
final var ytelseTidslinje = ytelseperiodeUtleder.utledYtelsestidslinje(kontekst.getBehandlingId());

// Validerer at periodene for rapporterte inntekter er konsistent med ytelsetidslinje
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class LagTilkjentYtelse {
static LocalDateTimeline<TilkjentYtelsePeriodeResultat> lagTidslinje(LocalDateTimeline<Boolean> godkjentTidslinje, LocalDateTimeline<BeregnetSats> totalsatsTidslinje, LocalDateTimeline<RapporterteInntekter> rapportertInntektTidslinje) {
return totalsatsTidslinje.combine(rapportertInntektTidslinje, (di, sats, rapportertInntekt) -> {
// Dersom det ikke er rapportert inntekt settes denne til 0, ellers summeres alle inntektene
final var rapporertinntekt = rapportertInntekt == null ? BigDecimal.ZERO : rapportertInntekt.getValue().getRapporterteInntekter().stream().map(RapportertInntekt::beløp).reduce(BigDecimal.ZERO, BigDecimal::add);
final var rapporertinntekt = rapportertInntekt == null ? BigDecimal.ZERO : rapportertInntekt.getValue().getBrukerRapporterteInntekter().stream().map(RapportertInntekt::beløp).reduce(BigDecimal.ZERO, BigDecimal::add);
// Mapper verdier til TilkjentYtelsePeriodeResultat
final var periodeResultat = TikjentYtelseBeregner.beregn(di, sats.getValue(), rapporertinntekt);
return new LocalDateSegment<>(di.getFomDato(), di.getTomDato(), periodeResultat);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;

import no.nav.fpsak.tidsserie.LocalDateSegment;
import no.nav.fpsak.tidsserie.LocalDateTimeline;
import no.nav.ung.kodeverk.behandling.BehandlingÅrsakType;
import no.nav.ung.sak.ytelse.RapportertInntekt;
import no.nav.ung.sak.ytelse.RapporterteInntekter;
import no.nav.ung.sak.ytelse.uttalelse.BrukersUttalelseForRegisterinntekt;

import java.math.BigDecimal;
import java.util.Optional;
import java.util.Set;

import static no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll.FinnKontrollresultatForIkkeGodkjentUttalelse.harDiff;

public class Avviksvurdering {

public static final BigDecimal AKSEPTERT_DIFFERANSE = BigDecimal.valueOf(1000);


static Optional<KontrollResultat> gjørAvviksvurderingMotRegisterinntekt(LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter, LocalDateTimeline<BrukersUttalelseForRegisterinntekt> uttalelseTidslinje, LocalDateTimeline<Set<BehandlingÅrsakType>> tidslinjeRelevanteÅrsaker) {
final var inntektDiffKontrollResultat = finnKontrollresultatTidslinje(gjeldendeRapporterteInntekter, tidslinjeRelevanteÅrsaker);

final var tidslinjeForOppgaveTilBruker = inntektDiffKontrollResultat.filterValue(it -> it.equals(KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER));
if (!tidslinjeForOppgaveTilBruker.isEmpty()) {

// Må finne ut om vi skal sette ny frist
final var oppgaverTilBrukerTidslinje = finnNyOppgaveKontrollresultatTidslinje(gjeldendeRapporterteInntekter, uttalelseTidslinje, tidslinjeForOppgaveTilBruker);

if (!oppgaverTilBrukerTidslinje.filterValue(it -> it.equals(KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST)).isEmpty()) {
return Optional.of(KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST);
} else {
return Optional.of(KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER);
}

}

if (!inntektDiffKontrollResultat.filterValue(it -> it.equals(KontrollResultat.BRUK_INNTEKT_FRA_BRUKER)).isEmpty()) {
return Optional.of(KontrollResultat.BRUK_INNTEKT_FRA_BRUKER);
}
return Optional.empty();
}

private static LocalDateTimeline<KontrollResultat> finnNyOppgaveKontrollresultatTidslinje(LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter, LocalDateTimeline<BrukersUttalelseForRegisterinntekt> uttalelseTidslinje, LocalDateTimeline<KontrollResultat> tidslinjeForOppgaveTilBruker) {
final var oppgaverTilBrukerTidslinje = gjeldendeRapporterteInntekter.mapValue(RapporterteInntekter::getRegisterRapporterteInntekter).intersection(tidslinjeForOppgaveTilBruker)
.combine(uttalelseTidslinje.mapValue(BrukersUttalelseForRegisterinntekt::registerInntekt), (di, register, uttalelse) -> {
if (uttalelse == null) {
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER);
}
if (!harDiff(uttalelse.getValue(), register.getValue())) {
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER);
} else {
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST);
}
}, LocalDateTimeline.JoinStyle.LEFT_JOIN);
return oppgaverTilBrukerTidslinje;
}

private static LocalDateTimeline<KontrollResultat> finnKontrollresultatTidslinje(LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter, LocalDateTimeline<Set<BehandlingÅrsakType>> tidslinjeRelevanteÅrsaker) {
final var inntektDiffKontrollResultat = gjeldendeRapporterteInntekter.intersection(tidslinjeRelevanteÅrsaker)
.mapValue(it ->
{
final var register = it.getRegisterRapporterteInntekter().stream()
.map(RapportertInntekt::beløp).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
final var bruker = it.getBrukerRapporterteInntekter().stream()
.map(RapportertInntekt::beløp).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

final var differanse = register.subtract(bruker).abs();

if (differanse.compareTo(AKSEPTERT_DIFFERANSE) > 0) {
return KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER;
} else {
return KontrollResultat.BRUK_INNTEKT_FRA_BRUKER;
}
});
return inntektDiffKontrollResultat;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;

import no.nav.fpsak.tidsserie.LocalDateSegment;
import no.nav.fpsak.tidsserie.LocalDateTimeline;
import no.nav.ung.sak.ytelse.RapportertInntekt;
import no.nav.ung.sak.ytelse.RapporterteInntekter;
import no.nav.ung.sak.ytelse.uttalelse.BrukersUttalelseForRegisterinntekt;

import java.math.BigDecimal;
import java.util.Set;

public class FinnKontrollresultatForIkkeGodkjentUttalelse {

static KontrollResultat finnKontrollresultatForIkkeGodkjentUttalelse(LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter, LocalDateTimeline<BrukersUttalelseForRegisterinntekt> relevantIkkeGodkjentUttalelse) {
final var registerInntektTidslinje = gjeldendeRapporterteInntekter.mapValue(RapporterteInntekter::getRegisterRapporterteInntekter);
final var ikkeGodkjentUttalelseResultater = relevantIkkeGodkjentUttalelse.combine(registerInntektTidslinje, (di, uttalelse, register) -> {
if (!harDiff(uttalelse.getValue().registerInntekt(), register != null ? register.getValue() : Set.of())) {
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_AKSJONSPUNKT);
} else {
return new LocalDateSegment<>(di, KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST);
}
}, LocalDateTimeline.JoinStyle.LEFT_JOIN);

if (!ikkeGodkjentUttalelseResultater.filterValue(it -> it == KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST).isEmpty()) {
return KontrollResultat.OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST;
} else if (!ikkeGodkjentUttalelseResultater.filterValue(it -> it == KontrollResultat.OPPRETT_AKSJONSPUNKT).isEmpty()) {
return KontrollResultat.OPPRETT_AKSJONSPUNKT;
}

return KontrollResultat.OPPRETT_AKSJONSPUNKT;
}

static boolean harDiff(Set<RapportertInntekt> registerInntekFraUttalelse, Set<RapportertInntekt> gjeldendeRegisterinntekt) {
final var totalInntektFraUttalelse = summerInntekter(registerInntekFraUttalelse);
final var totalGjeldendeRegisterInntekt = summerInntekter(gjeldendeRegisterinntekt);
return totalInntektFraUttalelse.compareTo(totalGjeldendeRegisterInntekt) != 0;
}

private static BigDecimal summerInntekter(Set<RapportertInntekt> registerinntektFraUttalelse) {
return registerinntektFraUttalelse.stream()
.map(RapportertInntekt::beløp)
.reduce(BigDecimal::add)
.orElse(BigDecimal.ZERO);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;

public enum KontrollResultat {
BRUK_INNTEKT_FRA_BRUKER,
OPPRETT_AKSJONSPUNKT,
OPPRETT_OPPGAVE_TIL_BRUKER,
OPPRETT_OPPGAVE_TIL_BRUKER_MED_NY_FRIST,
SETT_PÅ_VENT_TIL_RAPPORTERINGSFRIST

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import no.nav.ung.sak.behandlingskontroll.*;
import no.nav.ung.sak.perioder.ProsessTriggerPeriodeUtleder;
import no.nav.ung.sak.ytelse.RapportertInntektMapper;
import no.nav.ung.sak.ytelse.uttalelse.RegisterinntektUttalelseTjeneste;

import static no.nav.ung.kodeverk.behandling.BehandlingStegType.KONTROLLER_REGISTER_INNTEKT;
import static no.nav.ung.kodeverk.behandling.FagsakYtelseType.UNGDOMSYTELSE;

@ApplicationScoped
@BehandlingStegRef(value = KONTROLLER_REGISTER_INNTEKT)
@BehandlingTypeRef
@FagsakYtelseTypeRef(UNGDOMSYTELSE)
public class KontrollerInntektSteg implements BehandlingSteg {

private ProsessTriggerPeriodeUtleder prosessTriggerPeriodeUtleder;
private RapportertInntektMapper rapportertInntektMapper;
private RegisterinntektUttalelseTjeneste registerinntektUttalelseTjeneste;


@Inject
public KontrollerInntektSteg(ProsessTriggerPeriodeUtleder prosessTriggerPeriodeUtleder,
RapportertInntektMapper rapportertInntektMapper,
RegisterinntektUttalelseTjeneste registerinntektUttalelseTjeneste) {
this.prosessTriggerPeriodeUtleder = prosessTriggerPeriodeUtleder;
this.rapportertInntektMapper = rapportertInntektMapper;
this.registerinntektUttalelseTjeneste = registerinntektUttalelseTjeneste;
}

public KontrollerInntektSteg() {
}

@Override
public BehandleStegResultat utførSteg(BehandlingskontrollKontekst kontekst) {

final var rapporterteInntekterTidslinje = rapportertInntektMapper.mapAlleGjeldendeRegisterOgBrukersInntekter(kontekst.getBehandlingId());
final var prosessTriggerTidslinje = prosessTriggerPeriodeUtleder.utledTidslinje(kontekst.getBehandlingId());
final var uttalelser = registerinntektUttalelseTjeneste.hentUttalelser(kontekst.getBehandlingId());
final var registerinntekterForIkkeGodkjentUttalelse = rapportertInntektMapper.finnRegisterinntekterForUttalelse(kontekst.getBehandlingId(), uttalelser);


final var kontrollResultat = KontrollerInntektTjeneste.utførKontroll(prosessTriggerTidslinje, rapporterteInntekterTidslinje, registerinntekterForIkkeGodkjentUttalelse);

return BehandleStegResultat.utførtUtenAksjonspunkter(
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll;

import no.nav.fpsak.tidsserie.LocalDateTimeline;
import no.nav.ung.kodeverk.behandling.BehandlingÅrsakType;
import no.nav.ung.sak.ytelse.RapporterteInntekter;
import no.nav.ung.sak.ytelse.uttalelse.BrukersUttalelseForRegisterinntekt;
import no.nav.ung.sak.ytelse.uttalelse.Status;

import java.util.Set;

import static no.nav.ung.sak.domene.behandling.steg.registerinntektkontroll.FinnKontrollresultatForIkkeGodkjentUttalelse.finnKontrollresultatForIkkeGodkjentUttalelse;

public class KontrollerInntektTjeneste {



public static KontrollResultat utførKontroll(LocalDateTimeline<Set<BehandlingÅrsakType>> prosessTriggerTidslinje,
LocalDateTimeline<RapporterteInntekter> gjeldendeRapporterteInntekter,
LocalDateTimeline<BrukersUttalelseForRegisterinntekt> uttalelseTidslinje) {

// Sjekker først om vi har relevante årsaker
final var tidslinjeRelevanteÅrsaker = prosessTriggerTidslinje.filterValue(it -> it.contains(BehandlingÅrsakType.RE_RAPPORTERING_INNTEKT) || it.contains(BehandlingÅrsakType.RE_KONTROLL_REGISTER_INNTEKT));
final var harIkkePassertRapporteringsfrist = tidslinjeRelevanteÅrsaker.filterValue(it -> !it.contains(BehandlingÅrsakType.RE_KONTROLL_REGISTER_INNTEKT));
// Dersom vi ikkje har passert rapporteringsfrist (ikkje har kontroll-årsak) så skal vi vente til rapporteringsfrist
if (!harIkkePassertRapporteringsfrist.isEmpty()) {
return KontrollResultat.SETT_PÅ_VENT_TIL_RAPPORTERINGSFRIST;
}

final var relevantIkkeGodkjentUttalelse = uttalelseTidslinje.filterValue(it -> it.status().equals(Status.BEKREFTET) && !it.uttalelse().erEndringenGodkjent()).intersection(tidslinjeRelevanteÅrsaker);
if (!relevantIkkeGodkjentUttalelse.isEmpty()) {
return finnKontrollresultatForIkkeGodkjentUttalelse(gjeldendeRapporterteInntekter, relevantIkkeGodkjentUttalelse);
}

final var opprettOppgaveTilBrukerMedNyFrist = Avviksvurdering.gjørAvviksvurderingMotRegisterinntekt(gjeldendeRapporterteInntekter, uttalelseTidslinje, tidslinjeRelevanteÅrsaker);
return opprettOppgaveTilBrukerMedNyFrist.orElse(KontrollResultat.BRUK_INNTEKT_FRA_BRUKER);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ void setUp() {
inntektArbeidYtelseTjeneste = new AbakusInMemoryInntektArbeidYtelseTjeneste();
ungdomsprogramPeriodeRepository = new UngdomsprogramPeriodeRepository(entityManager);
behandlingRepository = new BehandlingRepository(entityManager);
final var ytelseperiodeUtleder = new YtelseperiodeUtleder(
new UngdomsprogramPeriodeTjeneste(ungdomsprogramPeriodeRepository),
behandlingRepository);
beregnYtelseSteg = new BeregnYtelseSteg(ungdomsytelseGrunnlagRepository,
tilkjentYtelseRepository,
new RapportertInntektMapper(inntektArbeidYtelseTjeneste),
new YtelseperiodeUtleder(
new UngdomsprogramPeriodeTjeneste(ungdomsprogramPeriodeRepository),
behandlingRepository));
new RapportertInntektMapper(inntektArbeidYtelseTjeneste, ytelseperiodeUtleder),
ytelseperiodeUtleder);

fagsakRepository = new FagsakRepository(entityManager);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ void testLagTidslinjeMedTomGodkjentTidslinje() {

LocalDateTimeline<RapporterteInntekter> rapportertInntektTidslinje = new LocalDateTimeline<>(List.of(
new LocalDateSegment<>(LocalDate.of(2023, 1, 15), LocalDate.of(2023, 2, 15),
new RapporterteInntekter(Set.of(new RapportertInntekt(InntektType.ARBEIDSTAKER_ELLER_FRILANSER, BigDecimal.valueOf(50000)))))
new RapporterteInntekter(
Set.of(new RapportertInntekt(InntektType.ARBEIDSTAKER_ELLER_FRILANSER, BigDecimal.valueOf(50000))),
Set.of()))
));

// Call the method under test
Expand Down Expand Up @@ -114,7 +116,9 @@ void testLagTidslinjeUtenRapportertInntekt() {

final var rapportertInntekt = BigDecimal.valueOf(150);
LocalDateTimeline<RapporterteInntekter> rapportertInntektTidslinje = new LocalDateTimeline<>(List.of(
new LocalDateSegment<>(fom, tom, new RapporterteInntekter(Set.of(new RapportertInntekt(InntektType.ARBEIDSTAKER_ELLER_FRILANSER, rapportertInntekt))))
new LocalDateSegment<>(fom, tom, new RapporterteInntekter(
Set.of(new RapportertInntekt(InntektType.ARBEIDSTAKER_ELLER_FRILANSER, rapportertInntekt)),
Set.of()))
));

// Act
Expand Down
Loading