Skip to content

Commit 18cfd28

Browse files
TSFF-1202: Aksjonspunktoppdaterer for kontrollaksjonspunkt ved avvik (#248)
* TSFF-1202: Aksjonpunktoppdaterer for bekreftelse av inntekt * TSFF-1202: Feiler dersom det ikkje finnes inntekt fra bruker for periode der brukers inntekt er valgt * TSFF-1202: Legger på assert for at minst en everdi er satt * TSFF-1202: Utvider ikkje tidslinje for perioder som ikkje er rapportert fra register * TSFF-1202: Fikser test * ung-sak.openapi.json updated by build pipeline skip-checks:true --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent f724172 commit 18cfd28

File tree

19 files changed

+681
-192
lines changed

19 files changed

+681
-192
lines changed

behandlingslager/domene/src/main/java/no/nav/ung/sak/behandlingslager/tilkjentytelse/KontrollertInntektPeriode.java

+21-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package no.nav.ung.sak.behandlingslager.tilkjentytelse;
22

33
import jakarta.persistence.*;
4+
import no.nav.ung.kodeverk.kontroll.KontrollertInntektKilde;
5+
import no.nav.ung.kodeverk.kontroll.KontrollertInntektKildeKodeverdiConverter;
46
import no.nav.ung.sak.behandlingslager.BaseEntitet;
57
import no.nav.ung.sak.behandlingslager.PostgreSQLRangeType;
68
import no.nav.ung.sak.behandlingslager.Range;
@@ -29,8 +31,11 @@ public class KontrollertInntektPeriode extends BaseEntitet {
2931
@Column(name = "ytelse")
3032
private BigDecimal ytelse;
3133

32-
protected KontrollertInntektPeriode() {
33-
}
34+
@Convert(converter = KontrollertInntektKildeKodeverdiConverter.class)
35+
@Column(name = "kilde", nullable = false)
36+
private KontrollertInntektKilde kilde;
37+
38+
3439

3540
KontrollertInntektPeriode(KontrollertInntektPeriode eksisterende) {
3641
this.periode = Range.closed(eksisterende.getPeriode().getFomDato(), eksisterende.getPeriode().getTomDato());
@@ -40,10 +45,12 @@ protected KontrollertInntektPeriode() {
4045

4146
private KontrollertInntektPeriode(DatoIntervallEntitet periode,
4247
BigDecimal arbeidsinntekt,
43-
BigDecimal ytelse) {
48+
BigDecimal ytelse,
49+
KontrollertInntektKilde kilde) {
4450
this.periode = Range.closed(periode.getFomDato(), periode.getTomDato());
4551
this.arbeidsinntekt = arbeidsinntekt;
4652
this.ytelse = ytelse;
53+
this.kilde = kilde;
4754
}
4855

4956
public DatoIntervallEntitet getPeriode() {
@@ -58,6 +65,10 @@ public BigDecimal getYtelse() {
5865
return ytelse;
5966
}
6067

68+
public KontrollertInntektKilde getKilde() {
69+
return kilde;
70+
}
71+
6172
public static Builder ny() {
6273
return new Builder();
6374
}
@@ -67,6 +78,7 @@ public static class Builder {
6778
private DatoIntervallEntitet periode;
6879
private BigDecimal arbeidsinntekt;
6980
private BigDecimal ytelse;
81+
private KontrollertInntektKilde kilde;
7082

7183
private Builder() {}
7284

@@ -88,9 +100,14 @@ public Builder medYtelse(BigDecimal ytelse) {
88100
return this;
89101
}
90102

103+
public Builder medKilde(KontrollertInntektKilde kilde) {
104+
this.kilde = kilde;
105+
return this;
106+
}
107+
91108

92109
public KontrollertInntektPeriode build() {
93-
return new KontrollertInntektPeriode(periode, arbeidsinntekt, ytelse);
110+
return new KontrollertInntektPeriode(periode, arbeidsinntekt, ytelse, kilde);
94111
}
95112

96113

behandlingsprosess/src/main/java/no/nav/ung/sak/domene/behandling/steg/registerinntektkontroll/KontrollerInntektSteg.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public KontrollerInntektSteg() {
5959

6060
return switch (kontrollResultat) {
6161
case BRUK_INNTEKT_FRA_BRUKER -> {
62-
kontrollerteInntektperioderTjeneste.opprettKontrollerteInntekterPerioder(kontekst.getBehandlingId(), rapporterteInntekterTidslinje.mapValue(RapporterteInntekter::getBrukerRapporterteInntekter), prosessTriggerTidslinje);
62+
kontrollerteInntektperioderTjeneste.opprettKontrollerteInntekterPerioderFraBruker(kontekst.getBehandlingId(), rapporterteInntekterTidslinje.mapValue(RapporterteInntekter::getBrukerRapporterteInntekter), prosessTriggerTidslinje);
6363
yield BehandleStegResultat.utførtUtenAksjonspunkter();
6464
}
6565
case OPPRETT_AKSJONSPUNKT -> BehandleStegResultat.utførtMedAksjonspunkter(List.of(AksjonspunktDefinisjon.KONTROLLER_INNTEKT));

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.time.temporal.TemporalAdjusters;
88
import java.util.List;
99

10+
import no.nav.ung.kodeverk.kontroll.KontrollertInntektKilde;
1011
import no.nav.ung.sak.behandlingslager.tilkjentytelse.KontrollertInntektPeriode;
1112
import no.nav.ung.sak.behandlingslager.tilkjentytelse.TilkjentYtelsePeriode;
1213
import no.nav.ung.sak.ytelse.KontrollerteInntektperioderTjeneste;
@@ -99,7 +100,10 @@ void skal_opprette_tilkjent_ytelse_med_sporing_og_input() {
99100

100101
@Test
101102
void skal_få_tilkjent_ytelse_i_periode_uten_inntekt_med_gjenomført_kontroll() {
102-
final var kontrollertInntektPeriode = KontrollertInntektPeriode.ny().medPeriode(DatoIntervallEntitet.fraOgMedTilOgMed(FOM.plusMonths(1).withDayOfMonth(1), FOM.plusMonths(1).with(TemporalAdjusters.lastDayOfMonth()))).build();
103+
final var kontrollertInntektPeriode = KontrollertInntektPeriode.ny()
104+
.medPeriode(DatoIntervallEntitet.fraOgMedTilOgMed(FOM.plusMonths(1).withDayOfMonth(1), FOM.plusMonths(1).with(TemporalAdjusters.lastDayOfMonth())))
105+
.medKilde(KontrollertInntektKilde.BRUKER)
106+
.build();
103107
tilkjentYtelseRepository.lagre(behandling.getId(), List.of(kontrollertInntektPeriode));
104108
final var behandleStegResultat = beregnYtelseSteg.utførSteg(new BehandlingskontrollKontekst(behandling.getFagsakId(), behandling.getAktørId(), behandlingRepository.taSkriveLås(behandling.getId())));
105109
final var tilkjentYtelse = tilkjentYtelseRepository.hentTilkjentYtelse(behandling.getId());

domenetjenester/beregning-ytelse/src/main/java/no/nav/ung/sak/ytelse/KontrollerteInntektperioderTjeneste.java

+21-10
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
import no.nav.fpsak.tidsserie.LocalDateSegmentCombinator;
77
import no.nav.fpsak.tidsserie.LocalDateTimeline;
88
import no.nav.ung.kodeverk.behandling.BehandlingÅrsakType;
9+
import no.nav.ung.kodeverk.kontroll.KontrollertInntektKilde;
910
import no.nav.ung.sak.behandlingslager.tilkjentytelse.KontrollertInntektPeriode;
1011
import no.nav.ung.sak.behandlingslager.tilkjentytelse.TilkjentYtelseRepository;
1112
import no.nav.ung.sak.domene.typer.tid.DatoIntervallEntitet;
13+
import no.nav.ung.sak.perioder.ProsessTriggerPeriodeUtleder;
1214

1315
import java.math.BigDecimal;
1416
import java.util.HashSet;
1517
import java.util.List;
18+
import java.util.Optional;
1619
import java.util.Set;
1720

1821
/**
@@ -25,14 +28,21 @@ public class KontrollerteInntektperioderTjeneste {
2528

2629
private final TilkjentYtelseRepository tilkjentYtelseRepository;
2730

31+
2832
@Inject
2933
public KontrollerteInntektperioderTjeneste(TilkjentYtelseRepository tilkjentYtelseRepository) {
3034
this.tilkjentYtelseRepository = tilkjentYtelseRepository;
3135
}
3236

33-
public void opprettKontrollerteInntekterPerioder(Long behandlingId, LocalDateTimeline<Set<RapportertInntekt>> inntektTidslinje, LocalDateTimeline<Set<BehandlingÅrsakType>> prosesstriggerTidslinje) {
37+
public void opprettKontrollerteInntekterPerioderFraBruker(Long behandlingId, LocalDateTimeline<Set<RapportertInntekt>> inntektTidslinje, LocalDateTimeline<Set<BehandlingÅrsakType>> prosesstriggerTidslinje) {
38+
final var relevantePerioderForKontroll = prosesstriggerTidslinje.filterValue(it -> it.contains(BehandlingÅrsakType.RE_KONTROLL_REGISTER_INNTEKT));
39+
final var kontrollertePerioder = mapTilKontrollerteInntektperioder(inntektTidslinje.mapValue(it -> new RapportertInntektOgKilde(KontrollertInntektKilde.BRUKER, it)), relevantePerioderForKontroll, Optional.of(KontrollertInntektKilde.BRUKER));
40+
tilkjentYtelseRepository.lagre(behandlingId, kontrollertePerioder);
41+
}
42+
43+
public void opprettKontrollerteInntekterPerioderFraRegister(Long behandlingId, LocalDateTimeline<RapportertInntektOgKilde> inntektTidslinje, LocalDateTimeline<Set<BehandlingÅrsakType>> prosesstriggerTidslinje) {
3444
final var relevantePerioderForKontroll = prosesstriggerTidslinje.filterValue(it -> it.contains(BehandlingÅrsakType.RE_KONTROLL_REGISTER_INNTEKT));
35-
final var kontrollertePerioder = mapTilKontrollerteInntektperioder(inntektTidslinje, relevantePerioderForKontroll);
45+
final var kontrollertePerioder = mapTilKontrollerteInntektperioder(inntektTidslinje, relevantePerioderForKontroll, Optional.empty());
3646
tilkjentYtelseRepository.lagre(behandlingId, kontrollertePerioder);
3747
}
3848

@@ -53,23 +63,24 @@ public LocalDateTimeline<Set<RapportertInntekt>> hentTidslinje(Long behandlingId
5363
.orElse(LocalDateTimeline.empty());
5464
}
5565

56-
private static List<KontrollertInntektPeriode> mapTilKontrollerteInntektperioder(LocalDateTimeline<Set<RapportertInntekt>> inntektTidslinje, LocalDateTimeline<Set<BehandlingÅrsakType>> relevantePerioderForKontroll) {
57-
return relevantePerioderForKontroll.combine(inntektTidslinje, lagTomListeForIngenInntekter(), LocalDateTimeline.JoinStyle.LEFT_JOIN)
66+
private static List<KontrollertInntektPeriode> mapTilKontrollerteInntektperioder(LocalDateTimeline<RapportertInntektOgKilde> inntektTidslinje, LocalDateTimeline<Set<BehandlingÅrsakType>> relevantePerioderForKontroll, Optional<KontrollertInntektKilde> defaultKilde) {
67+
return relevantePerioderForKontroll.combine(inntektTidslinje, lagTomListeForIngenInntekter(defaultKilde), LocalDateTimeline.JoinStyle.LEFT_JOIN)
5868
.toSegments().stream().map(
5969
s -> KontrollertInntektPeriode.ny()
6070
.medPeriode(DatoIntervallEntitet.fraOgMedTilOgMed(s.getFom(), s.getTom()))
61-
.medArbeidsinntekt(finnInntektAvType(s, InntektType.ARBEIDSTAKER_ELLER_FRILANSER))
62-
.medYtelse(finnInntektAvType(s, InntektType.YTELSE))
71+
.medArbeidsinntekt(finnInntektAvType(s.getValue().rapporterteInntekter(), InntektType.ARBEIDSTAKER_ELLER_FRILANSER))
72+
.medYtelse(finnInntektAvType(s.getValue().rapporterteInntekter(), InntektType.YTELSE))
73+
.medKilde(s.getValue().kilde())
6374
.build()
6475
).toList();
6576
}
6677

67-
private static LocalDateSegmentCombinator<Set<BehandlingÅrsakType>, Set<RapportertInntekt>, Set<RapportertInntekt>> lagTomListeForIngenInntekter() {
68-
return (di, lhs, rhs) -> rhs != null ? new LocalDateSegment<>(di, Set.of()) : rhs;
78+
private static LocalDateSegmentCombinator<Set<BehandlingÅrsakType>, RapportertInntektOgKilde, RapportertInntektOgKilde> lagTomListeForIngenInntekter(Optional<KontrollertInntektKilde> kilde) {
79+
return (di, lhs, rhs) -> rhs == null ? new LocalDateSegment<>(di, new RapportertInntektOgKilde(kilde.orElseThrow(() -> new IllegalStateException("Forventer å få default kilde dersom tidslinjen med inntekter ikke dekker alle perioder til vurdering")), Set.of())) : rhs;
6980
}
7081

71-
private static BigDecimal finnInntektAvType(LocalDateSegment<Set<RapportertInntekt>> s, InntektType inntektType) {
72-
return s.getValue().stream()
82+
private static BigDecimal finnInntektAvType(Set<RapportertInntekt> s, InntektType inntektType) {
83+
return s.stream()
7384
.filter(it -> it.inntektType().equals(inntektType))
7485
.map(RapportertInntekt::beløp)
7586
.reduce(BigDecimal::add)

domenetjenester/beregning-ytelse/src/main/java/no/nav/ung/sak/ytelse/RapportertInntektMapper.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ private LocalDateTimeline<BrukersUttalelseForRegisterinntekt> finnRegisterinntek
9090
}
9191

9292
private static LocalDateTimeline<Set<RapportertInntekt>> finnRegisterInntektTidslinje(LocalDateTimeline<Boolean> ytelseTidslinje, Map<InntektType, List<Inntektspost>> grupperteInntekter) {
93-
final var registerTidslinje = new LocalDateTimeline<Set<RapportertInntekt>>(Set.of());
93+
var registerTidslinje = new LocalDateTimeline<Set<RapportertInntekt>>(Set.of());
9494

9595
for (var intervall : ytelseTidslinje.getLocalDateIntervals()) {
9696

9797
final var tidslinjeForPeriode = finnRegisterinntektForPeriode(grupperteInntekter, intervall);
98-
registerTidslinje.crossJoin(tidslinjeForPeriode);
98+
registerTidslinje = registerTidslinje.crossJoin(tidslinjeForPeriode);
9999

100100
}
101101
return registerTidslinje;
@@ -122,6 +122,9 @@ private static LocalDateTimeline<Set<RapportertInntekt>> finnRegisterinntektForP
122122
.ifPresent(inntekterForPeriode::add);
123123

124124

125+
if (inntekterForPeriode.isEmpty()) {
126+
return LocalDateTimeline.empty();
127+
}
125128
final var tidslinjeForPeriode = new LocalDateTimeline<Set<RapportertInntekt>>(intervall, inntekterForPeriode);
126129
return tidslinjeForPeriode;
127130
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package no.nav.ung.sak.ytelse;
2+
3+
import no.nav.ung.kodeverk.arbeidsforhold.InntektsKilde;
4+
import no.nav.ung.kodeverk.kontroll.KontrollertInntektKilde;
5+
6+
import java.util.Set;
7+
8+
public record RapportertInntektOgKilde(KontrollertInntektKilde kilde, Set<RapportertInntekt> rapporterteInntekter) {
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package no.nav.ung.kodeverk.kontroll;
2+
3+
import no.nav.ung.kodeverk.api.Kodeverdi;
4+
5+
import java.util.LinkedHashMap;
6+
import java.util.Map;
7+
8+
public enum KontrollertInntektKilde implements Kodeverdi {
9+
10+
BRUKER("BRUKER", "Bruker"),
11+
REGISTER("REGISTER", "Register"),
12+
SAKSBEHANDLER("SAKSBEHANDLER", "Saksbehandler");
13+
14+
15+
private static final Map<String, KontrollertInntektKilde> KODER = new LinkedHashMap<>();
16+
17+
static {
18+
for (var v : values()) {
19+
if (KODER.putIfAbsent(v.kode, v) != null) {
20+
throw new IllegalArgumentException("Duplikat : " + v.kode);
21+
}
22+
}
23+
}
24+
25+
private String kode;
26+
private String navn;
27+
28+
KontrollertInntektKilde(String kode, String navn) {
29+
this.kode = kode;
30+
this.navn = navn;
31+
}
32+
33+
public static KontrollertInntektKilde fraKode(String kode) {
34+
if (kode == null) {
35+
return null;
36+
}
37+
var ad = KODER.get(kode);
38+
if (ad == null) {
39+
throw new IllegalArgumentException("Ukjent KontrollertInntektKilde: " + kode);
40+
}
41+
return ad;
42+
}
43+
44+
45+
@Override
46+
public String getKode() {
47+
return kode;
48+
}
49+
50+
@Override
51+
public String getOffisiellKode() {
52+
return getKode();
53+
}
54+
55+
@Override
56+
public String getKodeverk() {
57+
return "UNG_KONTROLLERT_INNTEKT_KILDE";
58+
}
59+
60+
@Override
61+
public String getNavn() {
62+
return navn;
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package no.nav.ung.kodeverk.kontroll;
2+
3+
import jakarta.persistence.AttributeConverter;
4+
import jakarta.persistence.Converter;
5+
import no.nav.ung.kodeverk.ungdomsytelse.sats.UngdomsytelseSatsType;
6+
7+
@Converter(autoApply = true)
8+
public class KontrollertInntektKildeKodeverdiConverter implements AttributeConverter<KontrollertInntektKilde, String> {
9+
10+
@Override
11+
public String convertToDatabaseColumn(KontrollertInntektKilde attribute) {
12+
return attribute == null ? null : attribute.getKode();
13+
}
14+
15+
@Override
16+
public KontrollertInntektKilde convertToEntityAttribute(String dbData) {
17+
return dbData == null ? null : KontrollertInntektKilde.fraKode(dbData);
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package no.nav.ung.sak.kontrakt.kontroll;
2+
3+
public enum BrukKontrollertInntektValg {
4+
BRUK_BRUKERS_INNTEKT,
5+
BRUK_REGISTER_INNTEKT,
6+
MANUELT_FASTSATT
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package no.nav.ung.sak.kontrakt.kontroll;
2+
3+
import com.fasterxml.jackson.annotation.*;
4+
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
5+
import jakarta.validation.Valid;
6+
import jakarta.validation.constraints.Max;
7+
import jakarta.validation.constraints.Min;
8+
import jakarta.validation.constraints.NotNull;
9+
import jakarta.validation.constraints.Size;
10+
import no.nav.ung.kodeverk.behandling.aksjonspunkt.AksjonspunktKodeDefinisjon;
11+
import no.nav.ung.kodeverk.kontroll.KontrollertInntektKilde;
12+
import no.nav.ung.sak.kontrakt.aksjonspunkt.BekreftetAksjonspunktDto;
13+
14+
import java.math.BigDecimal;
15+
import java.util.List;
16+
17+
@JsonIgnoreProperties(ignoreUnknown = true)
18+
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
19+
@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
20+
@JsonTypeName(AksjonspunktKodeDefinisjon.KONTROLLER_INNTEKT_KODE)
21+
public class FastsettInntektDto extends BekreftetAksjonspunktDto {
22+
23+
@JsonProperty(value = "perioder")
24+
@Size(min = 1, max = 12)
25+
@Valid
26+
private List<FastsettInntektPeriodeDto> perioder;
27+
28+
public FastsettInntektDto() {
29+
// For Jackson
30+
}
31+
32+
public FastsettInntektDto(String begrunnelse, List<FastsettInntektPeriodeDto> perioder) { // NOSONAR
33+
super(begrunnelse);
34+
this.perioder = perioder;
35+
}
36+
37+
public List<FastsettInntektPeriodeDto> getPerioder() {
38+
return perioder;
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package no.nav.ung.sak.kontrakt.kontroll;
2+
3+
import com.fasterxml.jackson.annotation.*;
4+
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
5+
import jakarta.validation.Valid;
6+
import jakarta.validation.constraints.NotNull;
7+
import no.nav.ung.kodeverk.behandling.aksjonspunkt.AksjonspunktKodeDefinisjon;
8+
import no.nav.ung.sak.kontrakt.aksjonspunkt.BekreftetAksjonspunktDto;
9+
import no.nav.ung.sak.typer.Periode;
10+
11+
@JsonIgnoreProperties(ignoreUnknown = true)
12+
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
13+
@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
14+
public class FastsettInntektPeriodeDto {
15+
16+
@JsonProperty(value = "periode", required = true)
17+
@NotNull
18+
@Valid
19+
private Periode periode;
20+
21+
@JsonProperty(value = "refusjon", required = false)
22+
@Valid
23+
private ManueltFastsattInntektDto inntekt;
24+
25+
@JsonProperty(value = "valg", required = true)
26+
@NotNull
27+
@Valid
28+
private BrukKontrollertInntektValg valg;
29+
30+
public FastsettInntektPeriodeDto() {
31+
// For Jackson
32+
}
33+
34+
public FastsettInntektPeriodeDto(Periode periode, ManueltFastsattInntektDto inntekt, BrukKontrollertInntektValg valg) { // NOSONAR
35+
this.periode = periode;
36+
this.inntekt = inntekt;
37+
this.valg = valg;
38+
}
39+
40+
public Periode getPeriode() {
41+
return periode;
42+
}
43+
44+
public ManueltFastsattInntektDto getInntekt() {
45+
return inntekt;
46+
}
47+
48+
public BrukKontrollertInntektValg getValg() {
49+
return valg;
50+
}
51+
}

0 commit comments

Comments
 (0)