Skip to content

Commit bf83949

Browse files
authored
Legger til mulighet for innrapportering av inntekt for ungdomsytelsen (#484)
* Lager egen kontrakt for innrapportering av inntekt for ungdomsytelsen * Legger til felter for innsending og validator * Legger til nullsjekk for inntekter * Fikser validering av overlapp * Legger inntektsrapportering inn i ytelse * Endrer tilbake til Søknad * Setter rapporteringgsøknad i test * Setter deltakelsesøknad i test * Fjerner not null contraint fra inntekt
1 parent 0481b1f commit bf83949

9 files changed

+434
-78
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package no.nav.k9.søknad.ytelse.ung.v1;
2+
3+
import com.fasterxml.jackson.annotation.JsonAutoDetect;
4+
import com.fasterxml.jackson.annotation.JsonCreator;
5+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
6+
import com.fasterxml.jackson.annotation.JsonProperty;
7+
import jakarta.validation.Valid;
8+
import jakarta.validation.constraints.AssertTrue;
9+
import jakarta.validation.constraints.NotNull;
10+
import jakarta.validation.constraints.Size;
11+
import no.nav.k9.søknad.felles.type.Periode;
12+
13+
import java.time.LocalDate;
14+
import java.util.*;
15+
16+
@JsonIgnoreProperties(ignoreUnknown = true)
17+
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE)
18+
public class OppgittInntekt {
19+
20+
/**
21+
* Inntekter i periode som arbeidstaker og/eller frilans
22+
*/
23+
@JsonProperty(value = "oppgittePeriodeinntekter")
24+
@Valid
25+
@NotNull
26+
@Size(min = 1)
27+
private NavigableSet<@NotNull OppgittInntektForPeriode> oppgittePeriodeinntekter;
28+
29+
@JsonCreator
30+
public OppgittInntekt(@JsonProperty(value = "oppgittePeriodeinntekter") Set<OppgittInntektForPeriode> oppgittePeriodeinntekter) {
31+
this.oppgittePeriodeinntekter = (oppgittePeriodeinntekter == null) ? Collections.emptyNavigableSet()
32+
: Collections.unmodifiableNavigableSet(new TreeSet<>(oppgittePeriodeinntekter));
33+
}
34+
35+
public static Builder builder() {
36+
return new Builder();
37+
}
38+
39+
public NavigableSet<OppgittInntektForPeriode> getOppgittePeriodeinntekter() {
40+
return oppgittePeriodeinntekter;
41+
}
42+
43+
public Periode getMinMaksPeriode() {
44+
final var first = oppgittePeriodeinntekter.first();
45+
final var last = oppgittePeriodeinntekter.last();
46+
return new Periode(first.getPeriode().getFraOgMed(), last.getPeriode().getTilOgMed());
47+
}
48+
49+
public static final class Builder {
50+
private Set<OppgittInntektForPeriode> oppgittePeriodeinntekter = new LinkedHashSet<>();
51+
52+
private Builder() {
53+
}
54+
55+
public Builder medOppgittePeriodeinntekter(Set<OppgittInntektForPeriode> inntekter) {
56+
if (inntekter != null) {
57+
oppgittePeriodeinntekter.addAll(inntekter);
58+
}
59+
return this;
60+
}
61+
62+
public OppgittInntekt build() {
63+
if (oppgittePeriodeinntekter.isEmpty()) {
64+
throw new IllegalStateException("Må oppgi minst en periodeinntekt");
65+
}
66+
return new OppgittInntekt(oppgittePeriodeinntekter);
67+
}
68+
}
69+
70+
@AssertTrue(message = "Perioder for inntekt kan ikke overlappe")
71+
public boolean isHarIngenOverlappendePerioder() {
72+
return harIngenOverlapp(oppgittePeriodeinntekter);
73+
}
74+
75+
private boolean harIngenOverlapp(@Valid @NotNull NavigableSet<@NotNull OppgittInntektForPeriode> set) {
76+
final var iterator = set.iterator();
77+
// Initialiserer til første mulige periode
78+
var prev = new Periode(LocalDate.MIN, LocalDate.MIN);
79+
// Siden settet er av typen NavigableSet (sortert) trenger vi kun å sjekke forrige element i lista
80+
while (iterator.hasNext()) {
81+
final var next = iterator.next();
82+
if (!prev.getTilOgMed().isBefore(next.getPeriode().getFraOgMed())) {
83+
return false;
84+
}
85+
prev = next.getPeriode();
86+
}
87+
return true;
88+
}
89+
90+
91+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package no.nav.k9.søknad.ytelse.ung.v1;
2+
3+
import com.fasterxml.jackson.annotation.*;
4+
import jakarta.validation.Valid;
5+
import jakarta.validation.constraints.AssertTrue;
6+
import jakarta.validation.constraints.DecimalMax;
7+
import jakarta.validation.constraints.DecimalMin;
8+
import jakarta.validation.constraints.NotNull;
9+
import no.nav.k9.søknad.felles.type.Periode;
10+
import no.nav.k9.søknad.felles.validering.periode.GyldigPeriode;
11+
import no.nav.k9.søknad.ytelse.ung.v1.inntekt.InntektForPeriode;
12+
13+
import java.math.BigDecimal;
14+
import java.time.LocalDate;
15+
import java.util.*;
16+
17+
@JsonIgnoreProperties(ignoreUnknown = true)
18+
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE)
19+
public class OppgittInntektForPeriode implements Comparable<OppgittInntektForPeriode> {
20+
21+
private static final String MIN = "0.00";
22+
private static final String MAX = "10000000.00";
23+
24+
@JsonProperty(value = "periode", required = true)
25+
@Valid
26+
@NotNull
27+
@GyldigPeriode(krevFomDato = true, krevTomDato = true)
28+
private Periode periode;
29+
30+
@JsonProperty(value = "arbeidstakerOgFrilansInntekt", required = false)
31+
@Valid
32+
@DecimalMin(MIN)
33+
@DecimalMax(MAX)
34+
@JsonFormat(shape = JsonFormat.Shape.STRING)
35+
private BigDecimal arbeidstakerOgFrilansInntekt;
36+
37+
@JsonProperty(value = "næringsinntekt", required = false)
38+
@Valid
39+
@DecimalMin(MIN)
40+
@DecimalMax(MAX)
41+
@JsonFormat(shape = JsonFormat.Shape.STRING)
42+
private BigDecimal næringsinntekt;
43+
44+
@JsonProperty(value = "ytelse", required = false)
45+
@Valid
46+
@DecimalMin(MIN)
47+
@DecimalMax(MAX)
48+
@JsonFormat(shape = JsonFormat.Shape.STRING)
49+
private BigDecimal ytelse;
50+
51+
52+
@JsonCreator
53+
public OppgittInntektForPeriode(@JsonProperty(value = "arbeidstakerOgFrilansInntekt") BigDecimal arbeidstakerOgFrilansInntekt,
54+
@JsonProperty(value = "næringsinntekt") BigDecimal næringsinntekt,
55+
@JsonProperty(value = "ytelse") BigDecimal ytelse,
56+
@JsonProperty(value = "periode") Periode periode) {
57+
this.arbeidstakerOgFrilansInntekt = arbeidstakerOgFrilansInntekt;
58+
this.næringsinntekt = næringsinntekt;
59+
this.ytelse = ytelse;
60+
this.periode = periode;
61+
}
62+
63+
public static Builder builder(Periode periode) {
64+
return new Builder(periode);
65+
}
66+
67+
public Periode getPeriode() {
68+
return periode;
69+
}
70+
71+
public BigDecimal getArbeidstakerOgFrilansInntekt() {
72+
return arbeidstakerOgFrilansInntekt;
73+
}
74+
75+
public BigDecimal getNæringsinntekt() {
76+
return næringsinntekt;
77+
}
78+
79+
public BigDecimal getYtelse() {
80+
return ytelse;
81+
}
82+
83+
@Override
84+
public int compareTo(OppgittInntektForPeriode o) {
85+
return this.periode.compareTo(o.periode);
86+
}
87+
88+
@Override
89+
public boolean equals(Object o) {
90+
if (o == null || getClass() != o.getClass()) return false;
91+
OppgittInntektForPeriode that = (OppgittInntektForPeriode) o;
92+
return Objects.equals(periode, that.periode) &&
93+
Objects.equals(arbeidstakerOgFrilansInntekt, that.arbeidstakerOgFrilansInntekt) &&
94+
Objects.equals(næringsinntekt, that.næringsinntekt) &&
95+
Objects.equals(ytelse, that.ytelse);
96+
}
97+
98+
@Override
99+
public int hashCode() {
100+
return Objects.hash(periode, arbeidstakerOgFrilansInntekt, næringsinntekt, ytelse);
101+
}
102+
103+
public static final class Builder {
104+
private BigDecimal arbeidstakerOgFrilansInntekt;
105+
private BigDecimal næringsinntekt;
106+
private BigDecimal ytelse;
107+
private Periode periode;
108+
109+
private Builder(Periode periode) {
110+
this.periode = periode;
111+
}
112+
113+
public Builder medArbeidstakerOgFrilansinntekt(BigDecimal inntekt) {
114+
this.arbeidstakerOgFrilansInntekt = inntekt;
115+
return this;
116+
}
117+
118+
public Builder medNæringsinntekt(BigDecimal inntekt) {
119+
this.næringsinntekt = inntekt;
120+
return this;
121+
}
122+
123+
public Builder medYtelse(BigDecimal inntekt) {
124+
this.ytelse = inntekt;
125+
return this;
126+
}
127+
128+
public OppgittInntektForPeriode build() {
129+
return new OppgittInntektForPeriode(arbeidstakerOgFrilansInntekt, næringsinntekt, ytelse, periode);
130+
}
131+
}
132+
133+
}

soknad/src/main/java/no/nav/k9/søknad/ytelse/ung/v1/Ungdomsytelse.java

+28-42
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,16 @@
33
import com.fasterxml.jackson.annotation.JsonFormat;
44
import com.fasterxml.jackson.annotation.JsonProperty;
55
import jakarta.validation.Valid;
6-
import jakarta.validation.constraints.DecimalMax;
7-
import jakarta.validation.constraints.DecimalMin;
86
import jakarta.validation.constraints.NotNull;
97
import no.nav.k9.søknad.TidUtils;
108
import no.nav.k9.søknad.felles.Feil;
119
import no.nav.k9.søknad.felles.Versjon;
1210
import no.nav.k9.søknad.felles.type.Periode;
1311
import no.nav.k9.søknad.felles.type.Person;
14-
import no.nav.k9.søknad.felles.validering.periode.GyldigPeriode;
1512
import no.nav.k9.søknad.ytelse.DataBruktTilUtledning;
1613
import no.nav.k9.søknad.ytelse.Ytelse;
1714
import no.nav.k9.søknad.ytelse.YtelseValidator;
1815

19-
import java.math.BigDecimal;
2016
import java.time.LocalDate;
2117
import java.util.ArrayList;
2218
import java.util.List;
@@ -30,12 +26,11 @@ public class Ungdomsytelse implements Ytelse {
3026
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
3127
@JsonProperty(value = "søknadsperiode", required = true)
3228
@NotNull
33-
private List<@NotNull @GyldigPeriode(krevFomDato = true) Periode> søknadsperiode = new ArrayList<>();
29+
private List<@NotNull LocalDate> søktFraDatoer = new ArrayList<>();
3430

35-
@JsonProperty(value = "inntekt")
36-
@DecimalMin("0.00")
37-
@DecimalMax("1000000.00")
38-
private BigDecimal inntekt;
31+
@Valid
32+
@JsonProperty(value = "inntekter", required = true)
33+
private OppgittInntekt inntekter;
3934

4035
@Override
4136
public Type getType() {
@@ -79,61 +74,52 @@ public Person getAnnenPart() {
7974

8075
@Override
8176
public Periode getSøknadsperiode() {
82-
final List<Periode> perioder = new ArrayList<>(søknadsperiode);
83-
84-
final var fom = perioder
85-
.stream()
86-
.map(Periode::getFraOgMed)
87-
.min(LocalDate::compareTo)
88-
.orElseThrow();
77+
if (søknadType.equals(UngSøknadstype.RAPPORTERING_SØKNAD)) {
78+
return inntekter.getMinMaksPeriode();
79+
} else if (søknadType.equals(UngSøknadstype.DELTAKELSE_SØKNAD)) {
80+
final var fom = søktFraDatoer
81+
.stream()
82+
.min(LocalDate::compareTo)
83+
.orElseThrow();
8984

90-
if (søknadType == UngSøknadstype.DELTAKELSE_SØKNAD) {
9185
return new Periode(fom, TidUtils.TIDENES_ENDE); // Deltakelse har ingen sluttdato
9286
}
87+
throw new IllegalStateException("Kunne ikke finne periode for søknadtype " + søknadType);
9388

94-
final var tom = perioder
95-
.stream()
96-
.map(Periode::getTilOgMed)
97-
.filter(Objects::nonNull)
98-
.max(LocalDate::compareTo)
99-
.orElse(null);
100-
return new Periode(fom, tom);
10189
}
10290

103-
public List<Periode> getSøknadsperiodeList() {
104-
return søknadsperiode == null ? null : søknadsperiode.stream().map(p -> {
105-
if (p.getTilOgMed() == null) {
106-
return new Periode(p.getFraOgMed(), TidUtils.TIDENES_ENDE);
107-
}
108-
return p;
109-
}).toList();
91+
public OppgittInntekt getInntekter() {
92+
return inntekter;
11093
}
11194

112-
public BigDecimal getInntekt() {
113-
return inntekt;
95+
public List<LocalDate> getStartdatoer() {
96+
return søktFraDatoer;
11497
}
11598

116-
public Ungdomsytelse medInntekt(BigDecimal inntekt) {
117-
this.inntekt = Objects.requireNonNull(inntekt, "inntekt");
99+
public Ungdomsytelse medStartdatoer(List<LocalDate> startdatoer) {
100+
this.søktFraDatoer.addAll(Objects.requireNonNull(startdatoer, "startdatoer"));
118101
return this;
119102
}
120103

121-
public Ungdomsytelse medSøknadsperiode(List<Periode> søknadsperiodeList) {
122-
this.søknadsperiode.addAll(Objects.requireNonNull(søknadsperiodeList, "søknadsperiodeList"));
104+
public Ungdomsytelse medStartdato(LocalDate startdato) {
105+
this.søktFraDatoer.add(Objects.requireNonNull(startdato, "startdato"));
123106
return this;
124107
}
125108

126-
public Ungdomsytelse medSøknadsperiode(Periode søknadsperiode) {
127-
this.søknadsperiode.add(Objects.requireNonNull(søknadsperiode, "søknadsperiode"));
109+
public Ungdomsytelse medInntekter(OppgittInntekt inntekter) {
110+
this.inntekter = Objects.requireNonNull(inntekter, "inntekter");
128111
return this;
129112
}
130113

131-
public UngSøknadstype getSøknadType() {
132-
return søknadType;
133-
}
134114

135115
public Ungdomsytelse medSøknadType(UngSøknadstype søknadType) {
136116
this.søknadType = Objects.requireNonNull(søknadType, "søknadType");
137117
return this;
138118
}
119+
120+
121+
public UngSøknadstype getSøknadType() {
122+
return søknadType;
123+
}
124+
139125
}

soknad/src/main/java/no/nav/k9/søknad/ytelse/ung/v1/UngdomsytelseSøknadValidator.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,20 @@ public List<Feil> valider(Søknad søknad) {
2222
return feil;
2323
}
2424

25+
public List<Feil> valider(Søknad søknad, List<Periode> gyldigeEndringsperioder) {
26+
return validerSøknadsfelter(søknad);
27+
}
28+
2529
private List<Feil> validerYtelse(Søknad søknad, List<Feil> feil) {
2630
Ungdomsytelse ytelse = søknad.getYtelse();
2731

28-
if (ytelse.getSøknadType() == UngSøknadstype.RAPPORTERING_SØKNAD && ytelse.getSøknadsperiode().getTilOgMed() == null) {
29-
feil.add(new Feil("søknadsperiode.tilOgMed", PÅKREVD, "Rapporteringssøknadha en sluttdato"));
32+
if (ytelse.getSøknadType() == UngSøknadstype.DELTAKELSE_SØKNAD && (ytelse.getStartdatoer() == null || ytelse.getStartdatoer().isEmpty())) {
33+
feil.add(new Feil("søktFraDatoer", PÅKREVD, "Deltakelsesøknadsette minst en startdato"));
3034
}
3135

3236
return feil;
3337
}
3438

35-
public List<Feil> valider(Søknad søknad, List<Periode> gyldigeEndringsperioder) {
36-
return validerSøknadsfelter(søknad);
37-
}
38-
3939
private List<Feil> validerSøknadsfelter(Søknad søknad) {
4040
var validate = VALIDATOR_FACTORY.getValidator().validate(søknad);
4141

0 commit comments

Comments
 (0)