From aded5f44136020ead1cb7aae187785bb1790051e Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Tue, 28 Jan 2025 09:43:18 +0100 Subject: [PATCH 1/9] Lager egen kontrakt for innrapportering av inntekt for ungdomsytelsen --- .../ytelse/ung/v1/OppgittInntekt.java" | 122 ++++++++++++++++++ .../ytelse/ung/v1/Ungdomsytelse.java" | 30 +---- .../v1/UngdomsytelseInntektrapportering.java" | 31 +++++ .../ung/v1/inntekt/InntektForPeriode.java" | 89 +++++++++++++ .../ytelse/ung/YtelseEksempel.java" | 9 +- .../ytelse/ung/v1/ValideringTest.java" | 23 +--- 6 files changed, 247 insertions(+), 57 deletions(-) create mode 100644 "soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" create mode 100644 "soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" create mode 100644 "soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/inntekt/InntektForPeriode.java" diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" new file mode 100644 index 00000000..d627517c --- /dev/null +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" @@ -0,0 +1,122 @@ +package no.nav.k9.søknad.ytelse.ung.v1; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotNull; +import no.nav.k9.søknad.felles.type.Periode; +import no.nav.k9.søknad.ytelse.ung.v1.inntekt.InntektForPeriode; + +import java.time.LocalDate; +import java.util.*; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE) +public class OppgittInntekt { + + /** + * Inntekter i periode som arbeidstaker og/eller frilans + */ + @JsonProperty(value = "arbeidstakerOgFrilansInntekter") + @Valid + @NotNull + private NavigableSet arbeidstakerOgFrilansInntekter; + + /** + * Inntekter i periode som selvstendig næringsdrivende. + */ + @JsonProperty(value = "næringsinntekter") + @Valid + @NotNull + private NavigableSet næringsinntekter; + + /** + * Inntekter i periode som ytelse + */ + @JsonProperty(value = "ytelser") + @Valid + @NotNull + private NavigableSet ytelser; + + + @JsonCreator + public OppgittInntekt(@JsonProperty(value = "arbeidstakerOgFrilansInntekter") Set arbeidstakerOgFrilansInntekter, + @JsonProperty(value = "næringsinntekter") Set næringsinntekter, + @JsonProperty(value = "ytelser") Set ytelser) { + this.arbeidstakerOgFrilansInntekter = (arbeidstakerOgFrilansInntekter == null) ? Collections.emptyNavigableSet() + : Collections.unmodifiableNavigableSet(new TreeSet<>(arbeidstakerOgFrilansInntekter)); + this.næringsinntekter = (næringsinntekter == null) ? Collections.emptyNavigableSet() + : Collections.unmodifiableNavigableSet(new TreeSet<>(næringsinntekter)); + this.ytelser = (ytelser == null) ? Collections.emptyNavigableSet() + : Collections.unmodifiableNavigableSet(new TreeSet<>(ytelser)); + } + + public static Builder builder() { + return new Builder(); + } + + public NavigableSet getArbeidstakerOgFrilansInntekter() { + return arbeidstakerOgFrilansInntekter; + } + + public NavigableSet getNæringsinntekter() { + return næringsinntekter; + } + + public NavigableSet getYtelser() { + return ytelser; + } + + public static final class Builder { + private Set arbeidstakerOgFrilansInntekter = new LinkedHashSet<>(); + private Set næringsinntekter = new LinkedHashSet<>(); + private Set ytelser = new LinkedHashSet<>(); + + private Builder() { + } + + public Builder medArbeidstakerOgFrilansinntekter(Set inntekter) { + arbeidstakerOgFrilansInntekter.addAll(inntekter); + return this; + } + + public Builder medNæringsinntekter(Set inntekter) { + næringsinntekter.addAll(inntekter); + return this; + } + + public Builder medYtelser(Set inntekter) { + ytelser.addAll(inntekter); + return this; + } + + public OppgittInntekt build() { + return new OppgittInntekt(arbeidstakerOgFrilansInntekter, næringsinntekter, ytelser); + } + } + + @AssertTrue(message = "Perioder for inntekt kan ikke overlappe") + public boolean isHarIngenOverlappendePerioder() { + return harIngenOverlapp(arbeidstakerOgFrilansInntekter) && harIngenOverlapp(næringsinntekter) && harIngenOverlapp(ytelser); + } + + private boolean harIngenOverlapp(NavigableSet set) { + final var iterator = set.iterator(); + // Initialiserer til første mulige periode + var prev = new Periode(LocalDate.MIN, LocalDate.MIN); + // Siden settet er av typen NavigableSet (sortert) trenger vi kun å sjekke forrige element i lista + while (iterator.hasNext()) { + final var next = iterator.next(); + if (prev.inneholder(next.getPeriode())) { + return false; + } + prev = next.getPeriode(); + } + return true; + } + + +} diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" index 87dfc819..b58e6448 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" @@ -9,6 +9,7 @@ import no.nav.k9.søknad.TidUtils; import no.nav.k9.søknad.felles.Feil; import no.nav.k9.søknad.felles.Versjon; +import no.nav.k9.søknad.felles.opptjening.OpptjeningAktivitet; import no.nav.k9.søknad.felles.type.Periode; import no.nav.k9.søknad.felles.type.Person; import no.nav.k9.søknad.felles.validering.periode.GyldigPeriode; @@ -32,10 +33,6 @@ public class Ungdomsytelse implements Ytelse { @NotNull private List<@NotNull @GyldigPeriode(krevFomDato = true) Periode> søknadsperiode = new ArrayList<>(); - @JsonProperty(value = "inntekt") - @DecimalMin("0.00") - @DecimalMax("1000000.00") - private BigDecimal inntekt; @Override public Type getType() { @@ -87,17 +84,7 @@ public Person getAnnenPart() { .min(LocalDate::compareTo) .orElseThrow(); - if (søknadType == UngSøknadstype.DELTAKELSE_SØKNAD) { - return new Periode(fom, TidUtils.TIDENES_ENDE); // Deltakelse har ingen sluttdato - } - - final var tom = perioder - .stream() - .map(Periode::getTilOgMed) - .filter(Objects::nonNull) - .max(LocalDate::compareTo) - .orElse(null); - return new Periode(fom, tom); + return new Periode(fom, TidUtils.TIDENES_ENDE); // Deltakelse har ingen sluttdato } public List getSøknadsperiodeList() { @@ -109,15 +96,6 @@ public Person getAnnenPart() { }).toList(); } - public BigDecimal getInntekt() { - return inntekt; - } - - public Ungdomsytelse medInntekt(BigDecimal inntekt) { - this.inntekt = Objects.requireNonNull(inntekt, "inntekt"); - return this; - } - public Ungdomsytelse medSøknadsperiode(List søknadsperiodeList) { this.søknadsperiode.addAll(Objects.requireNonNull(søknadsperiodeList, "søknadsperiodeList")); return this; @@ -132,8 +110,4 @@ public Ungdomsytelse medInntekt(BigDecimal inntekt) { return søknadType; } - public Ungdomsytelse medSøknadType(UngSøknadstype søknadType) { - this.søknadType = Objects.requireNonNull(søknadType, "søknadType"); - return this; - } } diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" new file mode 100644 index 00000000..ce181eaf --- /dev/null +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" @@ -0,0 +1,31 @@ +package no.nav.k9.søknad.ytelse.ung.v1; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +import java.util.Objects; + +public class UngdomsytelseInntektrapportering { + + private UngSøknadstype søknadType = UngSøknadstype.RAPPORTERING_SØKNAD; + + @JsonProperty(value = "inntekter", required = true) + @Valid + @NotNull + private OppgittInntekt inntekter; + + public OppgittInntekt getInntekter() { + return inntekter; + } + + public UngdomsytelseInntektrapportering medInntekter(OppgittInntekt inntekter) { + this.inntekter = Objects.requireNonNull(inntekter, "inntekt"); + return this; + } + + public UngSøknadstype getSøknadType() { + return søknadType; + } + +} diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/inntekt/InntektForPeriode.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/inntekt/InntektForPeriode.java" new file mode 100644 index 00000000..9a641dd8 --- /dev/null +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/inntekt/InntektForPeriode.java" @@ -0,0 +1,89 @@ +package no.nav.k9.søknad.ytelse.ung.v1.inntekt; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import no.nav.k9.søknad.felles.type.Periode; +import no.nav.k9.søknad.felles.validering.periode.GyldigPeriode; + +import java.math.BigDecimal; +import java.util.Objects; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE) +public class InntektForPeriode implements Comparable { + + private static final String MIN = "0.00"; + private static final String MAX = "1000000.00"; + + private static final BigDecimal MAX_VAL = new BigDecimal(MAX); + + @JsonProperty(value = "beløp", required = true) + @Valid + @NotNull + @DecimalMin(MIN) + @DecimalMax(MAX) + @JsonFormat(shape = Shape.STRING) + private BigDecimal beløp; + + @JsonProperty(value = "periode", required = true) + @Valid + @NotNull + @GyldigPeriode(krevFomDato = true, krevTomDato = true) + private Periode periode; + + @JsonCreator + public InntektForPeriode(@JsonProperty(value = "beløp", required = true) BigDecimal beløp, + @JsonProperty(value = "periode", required = true) Periode periode) { + this.beløp = Objects.requireNonNull(beløp, "beløp"); + this.periode = Objects.requireNonNull(periode, "periode"); + if (BigDecimal.ZERO.compareTo(beløp) > 0) { + throw new IllegalArgumentException("Beløp [" + beløp + "] kan ikke være < 0"); + } else if (MAX_VAL.compareTo(beløp) < 0) { + throw new IllegalArgumentException("Beløp [" + beløp + "] kan ikke være > " + MAX_VAL); + } + + if (periode.getFraOgMed() == null || periode.getTilOgMed() == null) { + throw new IllegalArgumentException("Periode må ha både tom-dato og fom-dato satt"); + } + } + + public BigDecimal getBeløp() { + return beløp; + } + + public Periode getPeriode() { + return periode; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || obj.getClass() != this.getClass()) + return false; + var other = (InntektForPeriode) obj; + return Objects.equals(beløp, other.beløp) && Objects.equals(periode, other.periode); + } + + @Override + public int hashCode() { + return Objects.hash(beløp, periode); + } + + @Override + public String toString() { + return "InntektForPeriode{" + + "beløp=" + beløp + + ", periode=" + periode + + '}'; + } + + @Override + public int compareTo(InntektForPeriode o) { + return this.getPeriode().compareTo(o.getPeriode()); + } +} diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" index 0e84173a..8acd6e14 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" @@ -1,18 +1,13 @@ package no.nav.k9.søknad.ytelse.ung; import no.nav.k9.søknad.felles.type.Periode; -import no.nav.k9.søknad.ytelse.ung.v1.UngSøknadstype; import no.nav.k9.søknad.ytelse.ung.v1.Ungdomsytelse; -import java.math.BigDecimal; - public class YtelseEksempel { - public static Ungdomsytelse komplettYtelseMedSøknadsperiode(Periode søknadsperiode, BigDecimal inntekt, UngSøknadstype søknadstype) { + public static Ungdomsytelse komplettYtelseMedSøknadsperiode(Periode søknadsperiode) { return new Ungdomsytelse() - .medSøknadsperiode(søknadsperiode) - .medInntekt(inntekt) - .medSøknadType(søknadstype); + .medSøknadsperiode(søknadsperiode); } } diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValideringTest.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValideringTest.java" index 6c1ec4e5..70e223e0 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValideringTest.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValideringTest.java" @@ -5,7 +5,6 @@ import no.nav.k9.søknad.ytelse.ung.YtelseEksempel; import org.junit.jupiter.api.Test; -import java.math.BigDecimal; import java.time.LocalDate; class ValideringTest { @@ -13,28 +12,8 @@ class ValideringTest { @Test void verifiserHentingAvSøknadsperiodeUtenTomDatoIkkeFeiler() { var søknadsperiode = new Periode(LocalDate.now(), null); - var ytelse = YtelseEksempel.komplettYtelseMedSøknadsperiode(søknadsperiode, BigDecimal.valueOf(1000), UngSøknadstype.DELTAKELSE_SØKNAD); + var ytelse = YtelseEksempel.komplettYtelseMedSøknadsperiode(søknadsperiode); ValiderUtil.verifyIngenFeil(SøknadEksempel.søknad(ytelse)); } - @Test - void verifiserInntektUnderNullFeiler() { - var søknadsperiode = new Periode(LocalDate.now(), LocalDate.now()); - var ytelse = YtelseEksempel.komplettYtelseMedSøknadsperiode(søknadsperiode, BigDecimal.valueOf(-1000), UngSøknadstype.DELTAKELSE_SØKNAD); - ValiderUtil.verifyHarFeil(SøknadEksempel.søknad(ytelse)); - } - - @Test - void verifiserInntektOverGrenseFeiler() { - var søknadsperiode = new Periode(LocalDate.now(), LocalDate.now()); - var ytelse = YtelseEksempel.komplettYtelseMedSøknadsperiode(søknadsperiode, BigDecimal.valueOf(1000001.00), UngSøknadstype.DELTAKELSE_SØKNAD); - ValiderUtil.verifyHarFeil(SøknadEksempel.søknad(ytelse)); - } - - @Test - void verifiserSøknadPeriodeUtenTilOgMedForRapporteringssøknadFeiler() { - var søknadsperiode = new Periode(LocalDate.now(), null); - var ytelse = YtelseEksempel.komplettYtelseMedSøknadsperiode(søknadsperiode, BigDecimal.valueOf(1000), UngSøknadstype.RAPPORTERING_SØKNAD); - ValiderUtil.verifyHarFeil(SøknadEksempel.søknad(ytelse)); - } } From 800e9abd39707fce5cf7757a4da37eb8c7f8a7a1 Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Tue, 28 Jan 2025 12:14:11 +0100 Subject: [PATCH 2/9] Legger til felter for innsending og validator --- .../S\303\270knadValidator.java" | 10 +- .../ytelse/ung/v1/Ungdomsytelse.java" | 4 - .../v1/UngdomsytelseInntektrapportering.java" | 202 +++++++++++++++++- ...msytelseInntektrapporteringValidator.java" | 43 ++++ .../UngdomsytelseS\303\270knadValidator.java" | 11 - 5 files changed, 242 insertions(+), 28 deletions(-) create mode 100644 "soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapporteringValidator.java" diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/S\303\270knadValidator.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/S\303\270knadValidator.java" index 4da83548..bc8850cb 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/S\303\270knadValidator.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/S\303\270knadValidator.java" @@ -23,15 +23,15 @@ public void forsikreValidert(S søknad) { * Felles validering av felter på søknad. Må kalles eksplisitt på av * subklassene til denne klassen hvis den skal brukes, * - * @param søknad Søknaden som valideres. + * @param innsending Innsendingen som valideres. * @param feil En liste der eventuelt feil skal legges til. */ - public final void validerFelterPåSøknad(Søknad søknad, List feil) { - validerMottattDato(søknad, feil); - validerVersjon(søknad.getVersjon(), feil); + public final void validerFelterPåSøknad(Innsending innsending, List feil) { + validerMottattDato(innsending, feil); + validerVersjon(innsending.getVersjon(), feil); } - private void validerMottattDato(Søknad søknad, List feil) { + private void validerMottattDato(Innsending søknad, List feil) { final int maximumClockSkewSeconds = 10; if (søknad.getMottattDato() != null && søknad.getMottattDato() diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" index b58e6448..6b6e2ca7 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" @@ -3,13 +3,10 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; -import jakarta.validation.constraints.DecimalMax; -import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.NotNull; import no.nav.k9.søknad.TidUtils; import no.nav.k9.søknad.felles.Feil; import no.nav.k9.søknad.felles.Versjon; -import no.nav.k9.søknad.felles.opptjening.OpptjeningAktivitet; import no.nav.k9.søknad.felles.type.Periode; import no.nav.k9.søknad.felles.type.Person; import no.nav.k9.søknad.felles.validering.periode.GyldigPeriode; @@ -17,7 +14,6 @@ import no.nav.k9.søknad.ytelse.Ytelse; import no.nav.k9.søknad.ytelse.YtelseValidator; -import java.math.BigDecimal; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" index ce181eaf..c48e35d7 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" @@ -1,31 +1,217 @@ package no.nav.k9.søknad.ytelse.ung.v1; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonManagedReference; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import no.nav.k9.søknad.Innsending; +import no.nav.k9.søknad.JsonUtils; +import no.nav.k9.søknad.Søknad; +import no.nav.k9.søknad.felles.DtoKonstanter; +import no.nav.k9.søknad.felles.Kildesystem; +import no.nav.k9.søknad.felles.Versjon; +import no.nav.k9.søknad.felles.personopplysninger.Søker; +import no.nav.k9.søknad.felles.type.*; +import no.nav.k9.søknad.ytelse.Ytelse; -import java.util.Objects; +import java.io.IOException; +import java.time.ZonedDateTime; +import java.util.*; -public class UngdomsytelseInntektrapportering { +public class UngdomsytelseInntektrapportering implements Innsending { private UngSøknadstype søknadType = UngSøknadstype.RAPPORTERING_SØKNAD; - @JsonProperty(value = "inntekter", required = true) @Valid @NotNull + @JsonProperty(value = "søknadId", required = true) + private SøknadId søknadId; + + @Valid + @NotNull + @JsonProperty(value = "versjon", required = true) + private Versjon versjon; + + @Valid + @NotNull + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DtoKonstanter.DATO_TID_FORMAT, timezone = DtoKonstanter.TIDSSONE) + @JsonProperty(value = "mottattDato", required = true) + private ZonedDateTime mottattDato; + + @Valid + @NotNull + @JsonProperty(value = "søker", required = true) + private Søker søker; + + @Valid + @JsonProperty(value = "språk", required = false) + private Språk språk = Språk.NORSK_BOKMÅL; + + @JsonManagedReference + @Valid + @NotNull + @JsonProperty(value = "ytelse", required = true) private OppgittInntekt inntekter; - public OppgittInntekt getInntekter() { - return inntekter; + @Valid + @JsonProperty(value = "kildesystem", required = true) + @NotNull + private Kildesystem kildesystem; + + + + @JsonCreator + public UngdomsytelseInntektrapportering(@JsonProperty(value = "søknadId", required = true) @Valid @NotNull SøknadId søknadId, + @JsonProperty(value = "versjon", required = true) @Valid @NotNull Versjon versjon, + @JsonProperty(value = "mottattDato", required = true) @Valid @NotNull ZonedDateTime mottattDato, + @JsonProperty(value = "søker", required = true) @Valid @NotNull Søker søker, + @JsonProperty(value = "språk", required = false) @Valid Språk språk, + @JsonProperty(value = "inntekter", required = true) @Valid @NotNull OppgittInntekt inntekter) { + this.søknadId = Objects.requireNonNull(søknadId, "søknadId"); + this.versjon = Objects.requireNonNull(versjon, "versjon"); + this.mottattDato = Objects.requireNonNull(mottattDato, "mottattDato"); + this.søker = Objects.requireNonNull(søker, "søker"); + this.inntekter = Objects.requireNonNull(inntekter, "inntekter"); + this.språk = språk; } - public UngdomsytelseInntektrapportering medInntekter(OppgittInntekt inntekter) { - this.inntekter = Objects.requireNonNull(inntekter, "inntekt"); - return this; + public UngdomsytelseInntektrapportering(@JsonProperty(value = "søknadId", required = true) @Valid @NotNull SøknadId søknadId, + @JsonProperty(value = "versjon", required = true) @Valid @NotNull Versjon versjon, + @JsonProperty(value = "mottattDato", required = true) @Valid @NotNull ZonedDateTime mottattDato, + @JsonProperty(value = "søker", required = true) @Valid @NotNull Søker søker, + @JsonProperty(value = "inntekter", required = true) @Valid @NotNull OppgittInntekt inntekter) { + this(søknadId, versjon, mottattDato, søker, Språk.NORSK_BOKMÅL, inntekter); } public UngSøknadstype getSøknadType() { return søknadType; } + @Override + public SøknadId getSøknadId() { + return søknadId; + } + + @Override + public Versjon getVersjon() { + return versjon; + } + + @Override + public ZonedDateTime getMottattDato() { + return mottattDato; + } + + public Språk getSpråk() { + return språk; + } + + @Override + public Søker getSøker() { + return søker; + } + + @SuppressWarnings("unchecked") + public Y getInntekter() { + return (Y) inntekter; + } + + public Kildesystem getKildesystem() { + return kildesystem; + } + + public void setSøknadId(SøknadId søknadId) { + this.søknadId = Objects.requireNonNull(søknadId, "søknadId"); + } + + public void setVersjon(Versjon versjon) { + this.versjon = Objects.requireNonNull(versjon);; + } + + public void setMottattDato(ZonedDateTime mottattDato) { + this.mottattDato = Objects.requireNonNull(mottattDato, "mottattDato"); + } + + public void setSøker(Søker søker) { + this.søker = Objects.requireNonNull(søker, "søker"); + } + + public void setInntekter(OppgittInntekt inntekter) { + this.inntekter = Objects.requireNonNull(inntekter, "inntekter"); + } + + public void setKildesystem(Kildesystem kildesystem) { + this.kildesystem = kildesystem; + } + + public UngdomsytelseInntektrapportering medMottattDato(ZonedDateTime mottattDato) { + this.mottattDato = Objects.requireNonNull(mottattDato, "mottattDato"); + return this; + } + + public UngdomsytelseInntektrapportering medSpråk(Språk språk) { + this.språk = språk; + return this; + } + + public UngdomsytelseInntektrapportering medSøknadId(String søknadId) { + this.søknadId = new SøknadId(Objects.requireNonNull(søknadId, "søknadId")); + return this; + } + + public UngdomsytelseInntektrapportering medSøknadId(SøknadId søknadId) { + this.søknadId = Objects.requireNonNull(søknadId, "søknadId"); + return this; + } + + public UngdomsytelseInntektrapportering medVersjon(String versjon) { + this.versjon = new Versjon(Objects.requireNonNull(versjon, "versjon")); + return this; + } + + public UngdomsytelseInntektrapportering medVersjon(Versjon versjon) { + this.versjon = Objects.requireNonNull(versjon, "versjon"); + return this; + } + + public UngdomsytelseInntektrapportering medSøker(Søker søker) { + this.søker = Objects.requireNonNull(søker, "søker"); + return this; + } + + public UngdomsytelseInntektrapportering medInntekter(OppgittInntekt inntekter) { + this.inntekter = Objects.requireNonNull(inntekter, "inntekter"); + return this; + } + + public UngdomsytelseInntektrapportering medKildesystem(Kildesystem kildesystem) { + this.kildesystem = kildesystem; + return this; + } + + public static final class SerDes { + private SerDes() { + } + + public static String serialize(Søknad søknad) { + return JsonUtils.toString(søknad); + } + + public static Søknad deserialize(String søknad) { + return JsonUtils.fromString(søknad, Søknad.class); + } + + public static Søknad deserialize(ObjectNode node) { + try { + return JsonUtils.getObjectMapper().treeToValue(node, Søknad.class); + } catch (IOException e) { + throw new IllegalArgumentException("Kunne ikke konvertere til Søknad.class", e); + } + } + + } } diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapporteringValidator.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapporteringValidator.java" new file mode 100644 index 00000000..97921089 --- /dev/null +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapporteringValidator.java" @@ -0,0 +1,43 @@ +package no.nav.k9.søknad.ytelse.ung.v1; + +import jakarta.validation.Validation; +import jakarta.validation.ValidatorFactory; +import no.nav.k9.søknad.Søknad; +import no.nav.k9.søknad.SøknadValidator; +import no.nav.k9.søknad.felles.Feil; +import no.nav.k9.søknad.felles.type.Periode; +import no.nav.k9.søknad.felles.validering.AvbrytendeValideringsfeil; + +import java.util.List; +import java.util.stream.Collectors; + +public class UngdomsytelseInntektrapporteringValidator extends SøknadValidator { + + private static final ValidatorFactory VALIDATOR_FACTORY = Validation.buildDefaultValidatorFactory(); + + @Override + public List valider(UngdomsytelseInntektrapportering søknad) { + List feil = validerSøknadsfelter(søknad); + return feil; + } + + + public List valider(UngdomsytelseInntektrapportering søknad, List gyldigeEndringsperioder) { + return validerSøknadsfelter(søknad); + } + + private List validerSøknadsfelter(UngdomsytelseInntektrapportering søknad) { + var validate = VALIDATOR_FACTORY.getValidator().validate(søknad); + + List feil = validate.stream() + .map(Feil::toFeil) + .collect(Collectors.toList()); + + if (AvbrytendeValideringsfeil.harAvbrytendeValideringsfeil(validate)) { + return feil; + } + + validerFelterPåSøknad(søknad, feil); + return feil; + } +} diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" index f9856de8..3ce2009a 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" @@ -18,17 +18,6 @@ public class UngdomsytelseSøknadValidator extends SøknadValidator { @Override public List valider(Søknad søknad) { List feil = validerSøknadsfelter(søknad); - validerYtelse(søknad, feil); - return feil; - } - - private List validerYtelse(Søknad søknad, List feil) { - Ungdomsytelse ytelse = søknad.getYtelse(); - - if (ytelse.getSøknadType() == UngSøknadstype.RAPPORTERING_SØKNAD && ytelse.getSøknadsperiode().getTilOgMed() == null) { - feil.add(new Feil("søknadsperiode.tilOgMed", PÅKREVD, "Rapporteringssøknad må ha en sluttdato")); - } - return feil; } From d3fac2852b61e074c22eb8465588a483c0a970c1 Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Tue, 28 Jan 2025 12:16:44 +0100 Subject: [PATCH 3/9] Legger til nullsjekk for inntekter --- .../s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" index d627517c..c5008173 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" @@ -79,17 +79,23 @@ private Builder() { } public Builder medArbeidstakerOgFrilansinntekter(Set inntekter) { - arbeidstakerOgFrilansInntekter.addAll(inntekter); + if (inntekter != null) { + arbeidstakerOgFrilansInntekter.addAll(inntekter); + } return this; } public Builder medNæringsinntekter(Set inntekter) { - næringsinntekter.addAll(inntekter); + if (inntekter != null) { + næringsinntekter.addAll(inntekter); + } return this; } public Builder medYtelser(Set inntekter) { - ytelser.addAll(inntekter); + if (inntekter != null) { + ytelser.addAll(inntekter); + } return this; } From 45e4024e71e01a7fbba0f1117aa26ee60b554bf5 Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Tue, 28 Jan 2025 12:37:31 +0100 Subject: [PATCH 4/9] Fikser validering av overlapp --- .../ytelse/ung/v1/OppgittInntekt.java" | 2 +- .../v1/UngdomsytelseInntektrapportering.java" | 26 +++--- .../InntektrapporteringValideringTest.java" | 81 +++++++++++++++++++ .../ytelse/ung/v1/ValiderUtil.java" | 22 +++++ 4 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 "soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" index c5008173..67f82db5 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" @@ -116,7 +116,7 @@ private boolean harIngenOverlapp(NavigableSet set) { // Siden settet er av typen NavigableSet (sortert) trenger vi kun å sjekke forrige element i lista while (iterator.hasNext()) { final var next = iterator.next(); - if (prev.inneholder(next.getPeriode())) { + if (!prev.getTilOgMed().isBefore(next.getPeriode().getFraOgMed())) { return false; } prev = next.getPeriode(); diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" index c48e35d7..4dc1cbfb 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" @@ -54,23 +54,22 @@ public class UngdomsytelseInntektrapportering implements Innsending { @JsonManagedReference @Valid @NotNull - @JsonProperty(value = "ytelse", required = true) + @JsonProperty(value = "inntekter", required = true) private OppgittInntekt inntekter; @Valid @JsonProperty(value = "kildesystem", required = true) @NotNull - private Kildesystem kildesystem; - + private Kildesystem kildesystem = Kildesystem.SØKNADSDIALOG; @JsonCreator public UngdomsytelseInntektrapportering(@JsonProperty(value = "søknadId", required = true) @Valid @NotNull SøknadId søknadId, - @JsonProperty(value = "versjon", required = true) @Valid @NotNull Versjon versjon, - @JsonProperty(value = "mottattDato", required = true) @Valid @NotNull ZonedDateTime mottattDato, - @JsonProperty(value = "søker", required = true) @Valid @NotNull Søker søker, - @JsonProperty(value = "språk", required = false) @Valid Språk språk, - @JsonProperty(value = "inntekter", required = true) @Valid @NotNull OppgittInntekt inntekter) { + @JsonProperty(value = "versjon", required = true) @Valid @NotNull Versjon versjon, + @JsonProperty(value = "mottattDato", required = true) @Valid @NotNull ZonedDateTime mottattDato, + @JsonProperty(value = "søker", required = true) @Valid @NotNull Søker søker, + @JsonProperty(value = "språk", required = false) @Valid Språk språk, + @JsonProperty(value = "inntekter", required = true) @Valid @NotNull OppgittInntekt inntekter) { this.søknadId = Objects.requireNonNull(søknadId, "søknadId"); this.versjon = Objects.requireNonNull(versjon, "versjon"); this.mottattDato = Objects.requireNonNull(mottattDato, "mottattDato"); @@ -80,10 +79,10 @@ public UngdomsytelseInntektrapportering(@JsonProperty(value = "søknadId", requi } public UngdomsytelseInntektrapportering(@JsonProperty(value = "søknadId", required = true) @Valid @NotNull SøknadId søknadId, - @JsonProperty(value = "versjon", required = true) @Valid @NotNull Versjon versjon, - @JsonProperty(value = "mottattDato", required = true) @Valid @NotNull ZonedDateTime mottattDato, - @JsonProperty(value = "søker", required = true) @Valid @NotNull Søker søker, - @JsonProperty(value = "inntekter", required = true) @Valid @NotNull OppgittInntekt inntekter) { + @JsonProperty(value = "versjon", required = true) @Valid @NotNull Versjon versjon, + @JsonProperty(value = "mottattDato", required = true) @Valid @NotNull ZonedDateTime mottattDato, + @JsonProperty(value = "søker", required = true) @Valid @NotNull Søker søker, + @JsonProperty(value = "inntekter", required = true) @Valid @NotNull OppgittInntekt inntekter) { this(søknadId, versjon, mottattDato, søker, Språk.NORSK_BOKMÅL, inntekter); } @@ -129,7 +128,8 @@ public Kildesystem getKildesystem() { } public void setVersjon(Versjon versjon) { - this.versjon = Objects.requireNonNull(versjon);; + this.versjon = Objects.requireNonNull(versjon); + ; } public void setMottattDato(ZonedDateTime mottattDato) { diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" new file mode 100644 index 00000000..f3038281 --- /dev/null +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" @@ -0,0 +1,81 @@ +package no.nav.k9.søknad.ytelse.ung.v1; + +import no.nav.k9.søknad.felles.Versjon; +import no.nav.k9.søknad.felles.personopplysninger.Søker; +import no.nav.k9.søknad.felles.type.NorskIdentitetsnummer; +import no.nav.k9.søknad.felles.type.Periode; +import no.nav.k9.søknad.felles.type.SøknadId; +import no.nav.k9.søknad.ytelse.ung.SøknadEksempel; +import no.nav.k9.søknad.ytelse.ung.v1.inntekt.InntektForPeriode; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.Set; + +class InntektrapporteringValideringTest { + + @Test + void verifiserInntektrapporteringUtenInntekterFeilerIkke() { + var inntektrapportering = inntektRapportering(OppgittInntekt.builder().build()); + ValiderUtil.verifyIngenFeil(inntektrapportering); + } + + @Test + void verifiserInntektrapporteringMedEnInntektFeilerIkke() { + final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now())); + var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt)); + ValiderUtil.verifyIngenFeil(inntektrapportering); + } + + @Test + void verifiserInntektrapporteringMedToIkkeOverlappendeInntekterFeilerIkke() { + final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now())); + final var inntekt2 = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); + var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt, inntekt2)); + ValiderUtil.verifyIngenFeil(inntektrapportering); + } + + @Test + void verifiserInntektrapporteringMedToOverlappendeInntekterSomStarterSamtidigFeiler() { + final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now())); + final var inntekt2 = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now().plusDays(1))); + var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt, inntekt2)); + ValiderUtil.verifyHarFeil(inntektrapportering); + } + + @Test + void verifiserInntektrapporteringMedToOverlappendeInntekterSomSlutterSamtidigFeiler() { + final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now().plusDays(1))); + final var inntekt2 = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); + var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt2, inntekt)); + ValiderUtil.verifyHarFeil(inntektrapportering); + } + + @Test + void verifiserInntektrapporteringMedToOverlappendeInntekterDerDenEneErInneholdtIDenAndreFeiler() { + final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now().plusDays(3))); + final var inntekt2 = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); + var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt, inntekt2)); + ValiderUtil.verifyHarFeil(inntektrapportering); + } + + + + private static OppgittInntekt lagOppgittInntekt(InntektForPeriode... inntekt) { + return OppgittInntekt.builder().medArbeidstakerOgFrilansinntekter(Set.of(inntekt)).build(); + } + + + private static UngdomsytelseInntektrapportering inntektRapportering(OppgittInntekt inntekter) { + return new UngdomsytelseInntektrapportering( + new SøknadId("1"), + new Versjon("6.0.1"), + ZonedDateTime.now(), + new Søker(NorskIdentitetsnummer.of("22222222222")), + inntekter + ); + } + +} diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValiderUtil.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValiderUtil.java" index fe1e29ee..03840a7e 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValiderUtil.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValiderUtil.java" @@ -13,6 +13,8 @@ public class ValiderUtil { private static final UngdomsytelseSøknadValidator validatorSøknad = new UngdomsytelseSøknadValidator(); + private static final UngdomsytelseInntektrapporteringValidator inntektrapporteringValidator = new UngdomsytelseInntektrapporteringValidator(); + public static List verifyHarFeil(Søknad søknad) { final List feil = valider(søknad); @@ -20,6 +22,12 @@ public static List verifyHarFeil(Søknad søknad) { return feil; } + public static List verifyHarFeil(UngdomsytelseInntektrapportering inntektrapportering) { + final List feil = valider(inntektrapportering); + assertThat(feil).isNotEmpty(); + return feil; + } + public static List verifyHarFeil(Søknad søknad, List endringsperioder) { final List feil = valider(søknad, endringsperioder); assertThat(feil).isNotEmpty(); @@ -32,6 +40,12 @@ public static List verifyIngenFeil(Søknad søknad) { return feil; } + public static List verifyIngenFeil(UngdomsytelseInntektrapportering inntektrapportering) { + final List feil = valider(inntektrapportering); + assertThat(feil).isEmpty(); + return feil; + } + public static List verifyIngenFeil(Søknad søknad, List gyldigEndringsInterval) { final List feil = valider(søknad, gyldigEndringsInterval); assertThat(feil).isEmpty(); @@ -46,6 +60,14 @@ public static List valider(Søknad søknad) { } } + public static List valider(UngdomsytelseInntektrapportering inntektrapportering) { + try { + return inntektrapporteringValidator.valider(inntektrapportering); + } catch (ValideringsFeil ex) { + return ex.getFeil(); + } + } + public static List valider(Søknad søknad, List gyldigEndringsInterval) { try { return validatorSøknad.valider(søknad, gyldigEndringsInterval); From 97c9676f7851ecc1cbff0303e1f5c63d9af44e83 Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Wed, 29 Jan 2025 13:32:13 +0100 Subject: [PATCH 5/9] Legger inntektsrapportering inn i ytelse --- .../ytelse/ung/v1/OppgittInntekt.java" | 81 ++----- .../ung/v1/OppgittInntektForPeriode.java" | 133 +++++++++++ .../ytelse/ung/v1/Ungdomsytelse.java" | 51 ++-- .../v1/UngdomsytelseInntektrapportering.java" | 217 ------------------ ...msytelseInntektrapporteringValidator.java" | 43 ---- .../UngdomsytelseS\303\270knadValidator.java" | 11 + .../ytelse/ung/YtelseEksempel.java" | 7 +- .../InntektrapporteringValideringTest.java" | 40 ++-- .../ytelse/ung/v1/ValiderUtil.java" | 20 -- .../ytelse/ung/v1/ValideringTest.java" | 5 +- 10 files changed, 222 insertions(+), 386 deletions(-) create mode 100644 "soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntektForPeriode.java" delete mode 100644 "soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" delete mode 100644 "soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapporteringValidator.java" diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" index 67f82db5..17818de7 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntekt.java" @@ -7,8 +7,8 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import no.nav.k9.søknad.felles.type.Periode; -import no.nav.k9.søknad.ytelse.ung.v1.inntekt.InntektForPeriode; import java.time.LocalDate; import java.util.*; @@ -20,96 +20,59 @@ public class OppgittInntekt { /** * Inntekter i periode som arbeidstaker og/eller frilans */ - @JsonProperty(value = "arbeidstakerOgFrilansInntekter") + @JsonProperty(value = "oppgittePeriodeinntekter") @Valid @NotNull - private NavigableSet arbeidstakerOgFrilansInntekter; - - /** - * Inntekter i periode som selvstendig næringsdrivende. - */ - @JsonProperty(value = "næringsinntekter") - @Valid - @NotNull - private NavigableSet næringsinntekter; - - /** - * Inntekter i periode som ytelse - */ - @JsonProperty(value = "ytelser") - @Valid - @NotNull - private NavigableSet ytelser; - + @Size(min = 1) + private NavigableSet<@NotNull OppgittInntektForPeriode> oppgittePeriodeinntekter; @JsonCreator - public OppgittInntekt(@JsonProperty(value = "arbeidstakerOgFrilansInntekter") Set arbeidstakerOgFrilansInntekter, - @JsonProperty(value = "næringsinntekter") Set næringsinntekter, - @JsonProperty(value = "ytelser") Set ytelser) { - this.arbeidstakerOgFrilansInntekter = (arbeidstakerOgFrilansInntekter == null) ? Collections.emptyNavigableSet() - : Collections.unmodifiableNavigableSet(new TreeSet<>(arbeidstakerOgFrilansInntekter)); - this.næringsinntekter = (næringsinntekter == null) ? Collections.emptyNavigableSet() - : Collections.unmodifiableNavigableSet(new TreeSet<>(næringsinntekter)); - this.ytelser = (ytelser == null) ? Collections.emptyNavigableSet() - : Collections.unmodifiableNavigableSet(new TreeSet<>(ytelser)); + public OppgittInntekt(@JsonProperty(value = "oppgittePeriodeinntekter") Set oppgittePeriodeinntekter) { + this.oppgittePeriodeinntekter = (oppgittePeriodeinntekter == null) ? Collections.emptyNavigableSet() + : Collections.unmodifiableNavigableSet(new TreeSet<>(oppgittePeriodeinntekter)); } public static Builder builder() { return new Builder(); } - public NavigableSet getArbeidstakerOgFrilansInntekter() { - return arbeidstakerOgFrilansInntekter; - } - - public NavigableSet getNæringsinntekter() { - return næringsinntekter; + public NavigableSet getOppgittePeriodeinntekter() { + return oppgittePeriodeinntekter; } - public NavigableSet getYtelser() { - return ytelser; + public Periode getMinMaksPeriode() { + final var first = oppgittePeriodeinntekter.first(); + final var last = oppgittePeriodeinntekter.last(); + return new Periode(first.getPeriode().getFraOgMed(), last.getPeriode().getTilOgMed()); } public static final class Builder { - private Set arbeidstakerOgFrilansInntekter = new LinkedHashSet<>(); - private Set næringsinntekter = new LinkedHashSet<>(); - private Set ytelser = new LinkedHashSet<>(); + private Set oppgittePeriodeinntekter = new LinkedHashSet<>(); private Builder() { } - public Builder medArbeidstakerOgFrilansinntekter(Set inntekter) { - if (inntekter != null) { - arbeidstakerOgFrilansInntekter.addAll(inntekter); - } - return this; - } - - public Builder medNæringsinntekter(Set inntekter) { + public Builder medOppgittePeriodeinntekter(Set inntekter) { if (inntekter != null) { - næringsinntekter.addAll(inntekter); - } - return this; - } - - public Builder medYtelser(Set inntekter) { - if (inntekter != null) { - ytelser.addAll(inntekter); + oppgittePeriodeinntekter.addAll(inntekter); } return this; } public OppgittInntekt build() { - return new OppgittInntekt(arbeidstakerOgFrilansInntekter, næringsinntekter, ytelser); + if (oppgittePeriodeinntekter.isEmpty()) { + throw new IllegalStateException("Må oppgi minst en periodeinntekt"); + } + return new OppgittInntekt(oppgittePeriodeinntekter); } } @AssertTrue(message = "Perioder for inntekt kan ikke overlappe") public boolean isHarIngenOverlappendePerioder() { - return harIngenOverlapp(arbeidstakerOgFrilansInntekter) && harIngenOverlapp(næringsinntekter) && harIngenOverlapp(ytelser); + return harIngenOverlapp(oppgittePeriodeinntekter); } - private boolean harIngenOverlapp(NavigableSet set) { + private boolean harIngenOverlapp(@Valid @NotNull NavigableSet<@NotNull OppgittInntektForPeriode> set) { final var iterator = set.iterator(); // Initialiserer til første mulige periode var prev = new Periode(LocalDate.MIN, LocalDate.MIN); diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntektForPeriode.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntektForPeriode.java" new file mode 100644 index 00000000..43f17ed6 --- /dev/null +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/OppgittInntektForPeriode.java" @@ -0,0 +1,133 @@ +package no.nav.k9.søknad.ytelse.ung.v1; + +import com.fasterxml.jackson.annotation.*; +import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import no.nav.k9.søknad.felles.type.Periode; +import no.nav.k9.søknad.felles.validering.periode.GyldigPeriode; +import no.nav.k9.søknad.ytelse.ung.v1.inntekt.InntektForPeriode; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.*; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE) +public class OppgittInntektForPeriode implements Comparable { + + private static final String MIN = "0.00"; + private static final String MAX = "10000000.00"; + + @JsonProperty(value = "periode", required = true) + @Valid + @NotNull + @GyldigPeriode(krevFomDato = true, krevTomDato = true) + private Periode periode; + + @JsonProperty(value = "arbeidstakerOgFrilansInntekt", required = false) + @Valid + @DecimalMin(MIN) + @DecimalMax(MAX) + @JsonFormat(shape = JsonFormat.Shape.STRING) + private BigDecimal arbeidstakerOgFrilansInntekt; + + @JsonProperty(value = "næringsinntekt", required = false) + @Valid + @DecimalMin(MIN) + @DecimalMax(MAX) + @JsonFormat(shape = JsonFormat.Shape.STRING) + private BigDecimal næringsinntekt; + + @JsonProperty(value = "ytelse", required = false) + @Valid + @DecimalMin(MIN) + @DecimalMax(MAX) + @JsonFormat(shape = JsonFormat.Shape.STRING) + private BigDecimal ytelse; + + + @JsonCreator + public OppgittInntektForPeriode(@JsonProperty(value = "arbeidstakerOgFrilansInntekt") BigDecimal arbeidstakerOgFrilansInntekt, + @JsonProperty(value = "næringsinntekt") BigDecimal næringsinntekt, + @JsonProperty(value = "ytelse") BigDecimal ytelse, + @JsonProperty(value = "periode") Periode periode) { + this.arbeidstakerOgFrilansInntekt = arbeidstakerOgFrilansInntekt; + this.næringsinntekt = næringsinntekt; + this.ytelse = ytelse; + this.periode = periode; + } + + public static Builder builder(Periode periode) { + return new Builder(periode); + } + + public Periode getPeriode() { + return periode; + } + + public BigDecimal getArbeidstakerOgFrilansInntekt() { + return arbeidstakerOgFrilansInntekt; + } + + public BigDecimal getNæringsinntekt() { + return næringsinntekt; + } + + public BigDecimal getYtelse() { + return ytelse; + } + + @Override + public int compareTo(OppgittInntektForPeriode o) { + return this.periode.compareTo(o.periode); + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + OppgittInntektForPeriode that = (OppgittInntektForPeriode) o; + return Objects.equals(periode, that.periode) && + Objects.equals(arbeidstakerOgFrilansInntekt, that.arbeidstakerOgFrilansInntekt) && + Objects.equals(næringsinntekt, that.næringsinntekt) && + Objects.equals(ytelse, that.ytelse); + } + + @Override + public int hashCode() { + return Objects.hash(periode, arbeidstakerOgFrilansInntekt, næringsinntekt, ytelse); + } + + public static final class Builder { + private BigDecimal arbeidstakerOgFrilansInntekt; + private BigDecimal næringsinntekt; + private BigDecimal ytelse; + private Periode periode; + + private Builder(Periode periode) { + this.periode = periode; + } + + public Builder medArbeidstakerOgFrilansinntekt(BigDecimal inntekt) { + this.arbeidstakerOgFrilansInntekt = inntekt; + return this; + } + + public Builder medNæringsinntekt(BigDecimal inntekt) { + this.næringsinntekt = inntekt; + return this; + } + + public Builder medYtelse(BigDecimal inntekt) { + this.ytelse = inntekt; + return this; + } + + public OppgittInntektForPeriode build() { + return new OppgittInntektForPeriode(arbeidstakerOgFrilansInntekt, næringsinntekt, ytelse, periode); + } + } + +} diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" index 6b6e2ca7..420aa673 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" @@ -9,7 +9,6 @@ import no.nav.k9.søknad.felles.Versjon; import no.nav.k9.søknad.felles.type.Periode; import no.nav.k9.søknad.felles.type.Person; -import no.nav.k9.søknad.felles.validering.periode.GyldigPeriode; import no.nav.k9.søknad.ytelse.DataBruktTilUtledning; import no.nav.k9.søknad.ytelse.Ytelse; import no.nav.k9.søknad.ytelse.YtelseValidator; @@ -27,8 +26,12 @@ public class Ungdomsytelse implements Ytelse { @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) @JsonProperty(value = "søknadsperiode", required = true) @NotNull - private List<@NotNull @GyldigPeriode(krevFomDato = true) Periode> søknadsperiode = new ArrayList<>(); + private List<@NotNull LocalDate> søktFraDatoer = new ArrayList<>(); + @Valid + @NotNull + @JsonProperty(value = "inntekter", required = true) + private OppgittInntekt inntekter; @Override public Type getType() { @@ -72,36 +75,44 @@ public Person getAnnenPart() { @Override public Periode getSøknadsperiode() { - final List perioder = new ArrayList<>(søknadsperiode); + if (søknadType.equals(UngSøknadstype.RAPPORTERING_SØKNAD)) { + return inntekter.getMinMaksPeriode(); + } else if (søknadType.equals(UngSøknadstype.DELTAKELSE_SØKNAD)) { + final var fom = søktFraDatoer + .stream() + .min(LocalDate::compareTo) + .orElseThrow(); + + return new Periode(fom, TidUtils.TIDENES_ENDE); // Deltakelse har ingen sluttdato + } + throw new IllegalStateException("Kunne ikke finne periode for søknadtype " + søknadType); - final var fom = perioder - .stream() - .map(Periode::getFraOgMed) - .min(LocalDate::compareTo) - .orElseThrow(); + } - return new Periode(fom, TidUtils.TIDENES_ENDE); // Deltakelse har ingen sluttdato + public OppgittInntekt getInntekter() { + return inntekter; } - public List getSøknadsperiodeList() { - return søknadsperiode == null ? null : søknadsperiode.stream().map(p -> { - if (p.getTilOgMed() == null) { - return new Periode(p.getFraOgMed(), TidUtils.TIDENES_ENDE); - } - return p; - }).toList(); + public List getStartdatoer() { + return søktFraDatoer; } - public Ungdomsytelse medSøknadsperiode(List søknadsperiodeList) { - this.søknadsperiode.addAll(Objects.requireNonNull(søknadsperiodeList, "søknadsperiodeList")); + public Ungdomsytelse medStartdatoer(List startdatoer) { + this.søktFraDatoer.addAll(Objects.requireNonNull(startdatoer, "startdatoer")); return this; } - public Ungdomsytelse medSøknadsperiode(Periode søknadsperiode) { - this.søknadsperiode.add(Objects.requireNonNull(søknadsperiode, "søknadsperiode")); + public Ungdomsytelse medStartdato(LocalDate startdato) { + this.søktFraDatoer.add(Objects.requireNonNull(startdato, "startdato")); return this; } + public Ungdomsytelse medInntekter(OppgittInntekt inntekter) { + this.inntekter = Objects.requireNonNull(inntekter, "inntekter"); + return this; + } + + public UngSøknadstype getSøknadType() { return søknadType; } diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" deleted file mode 100644 index 4dc1cbfb..00000000 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapportering.java" +++ /dev/null @@ -1,217 +0,0 @@ -package no.nav.k9.søknad.ytelse.ung.v1; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonManagedReference; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.node.ObjectNode; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import no.nav.k9.søknad.Innsending; -import no.nav.k9.søknad.JsonUtils; -import no.nav.k9.søknad.Søknad; -import no.nav.k9.søknad.felles.DtoKonstanter; -import no.nav.k9.søknad.felles.Kildesystem; -import no.nav.k9.søknad.felles.Versjon; -import no.nav.k9.søknad.felles.personopplysninger.Søker; -import no.nav.k9.søknad.felles.type.*; -import no.nav.k9.søknad.ytelse.Ytelse; - -import java.io.IOException; -import java.time.ZonedDateTime; -import java.util.*; - -public class UngdomsytelseInntektrapportering implements Innsending { - - private UngSøknadstype søknadType = UngSøknadstype.RAPPORTERING_SØKNAD; - - @Valid - @NotNull - @JsonProperty(value = "søknadId", required = true) - private SøknadId søknadId; - - @Valid - @NotNull - @JsonProperty(value = "versjon", required = true) - private Versjon versjon; - - @Valid - @NotNull - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DtoKonstanter.DATO_TID_FORMAT, timezone = DtoKonstanter.TIDSSONE) - @JsonProperty(value = "mottattDato", required = true) - private ZonedDateTime mottattDato; - - @Valid - @NotNull - @JsonProperty(value = "søker", required = true) - private Søker søker; - - @Valid - @JsonProperty(value = "språk", required = false) - private Språk språk = Språk.NORSK_BOKMÅL; - - @JsonManagedReference - @Valid - @NotNull - @JsonProperty(value = "inntekter", required = true) - private OppgittInntekt inntekter; - - @Valid - @JsonProperty(value = "kildesystem", required = true) - @NotNull - private Kildesystem kildesystem = Kildesystem.SØKNADSDIALOG; - - - @JsonCreator - public UngdomsytelseInntektrapportering(@JsonProperty(value = "søknadId", required = true) @Valid @NotNull SøknadId søknadId, - @JsonProperty(value = "versjon", required = true) @Valid @NotNull Versjon versjon, - @JsonProperty(value = "mottattDato", required = true) @Valid @NotNull ZonedDateTime mottattDato, - @JsonProperty(value = "søker", required = true) @Valid @NotNull Søker søker, - @JsonProperty(value = "språk", required = false) @Valid Språk språk, - @JsonProperty(value = "inntekter", required = true) @Valid @NotNull OppgittInntekt inntekter) { - this.søknadId = Objects.requireNonNull(søknadId, "søknadId"); - this.versjon = Objects.requireNonNull(versjon, "versjon"); - this.mottattDato = Objects.requireNonNull(mottattDato, "mottattDato"); - this.søker = Objects.requireNonNull(søker, "søker"); - this.inntekter = Objects.requireNonNull(inntekter, "inntekter"); - this.språk = språk; - } - - public UngdomsytelseInntektrapportering(@JsonProperty(value = "søknadId", required = true) @Valid @NotNull SøknadId søknadId, - @JsonProperty(value = "versjon", required = true) @Valid @NotNull Versjon versjon, - @JsonProperty(value = "mottattDato", required = true) @Valid @NotNull ZonedDateTime mottattDato, - @JsonProperty(value = "søker", required = true) @Valid @NotNull Søker søker, - @JsonProperty(value = "inntekter", required = true) @Valid @NotNull OppgittInntekt inntekter) { - this(søknadId, versjon, mottattDato, søker, Språk.NORSK_BOKMÅL, inntekter); - } - - public UngSøknadstype getSøknadType() { - return søknadType; - } - - @Override - public SøknadId getSøknadId() { - return søknadId; - } - - @Override - public Versjon getVersjon() { - return versjon; - } - - @Override - public ZonedDateTime getMottattDato() { - return mottattDato; - } - - public Språk getSpråk() { - return språk; - } - - @Override - public Søker getSøker() { - return søker; - } - - @SuppressWarnings("unchecked") - public Y getInntekter() { - return (Y) inntekter; - } - - public Kildesystem getKildesystem() { - return kildesystem; - } - - public void setSøknadId(SøknadId søknadId) { - this.søknadId = Objects.requireNonNull(søknadId, "søknadId"); - } - - public void setVersjon(Versjon versjon) { - this.versjon = Objects.requireNonNull(versjon); - ; - } - - public void setMottattDato(ZonedDateTime mottattDato) { - this.mottattDato = Objects.requireNonNull(mottattDato, "mottattDato"); - } - - public void setSøker(Søker søker) { - this.søker = Objects.requireNonNull(søker, "søker"); - } - - public void setInntekter(OppgittInntekt inntekter) { - this.inntekter = Objects.requireNonNull(inntekter, "inntekter"); - } - - public void setKildesystem(Kildesystem kildesystem) { - this.kildesystem = kildesystem; - } - - public UngdomsytelseInntektrapportering medMottattDato(ZonedDateTime mottattDato) { - this.mottattDato = Objects.requireNonNull(mottattDato, "mottattDato"); - return this; - } - - public UngdomsytelseInntektrapportering medSpråk(Språk språk) { - this.språk = språk; - return this; - } - - public UngdomsytelseInntektrapportering medSøknadId(String søknadId) { - this.søknadId = new SøknadId(Objects.requireNonNull(søknadId, "søknadId")); - return this; - } - - public UngdomsytelseInntektrapportering medSøknadId(SøknadId søknadId) { - this.søknadId = Objects.requireNonNull(søknadId, "søknadId"); - return this; - } - - public UngdomsytelseInntektrapportering medVersjon(String versjon) { - this.versjon = new Versjon(Objects.requireNonNull(versjon, "versjon")); - return this; - } - - public UngdomsytelseInntektrapportering medVersjon(Versjon versjon) { - this.versjon = Objects.requireNonNull(versjon, "versjon"); - return this; - } - - public UngdomsytelseInntektrapportering medSøker(Søker søker) { - this.søker = Objects.requireNonNull(søker, "søker"); - return this; - } - - public UngdomsytelseInntektrapportering medInntekter(OppgittInntekt inntekter) { - this.inntekter = Objects.requireNonNull(inntekter, "inntekter"); - return this; - } - - public UngdomsytelseInntektrapportering medKildesystem(Kildesystem kildesystem) { - this.kildesystem = kildesystem; - return this; - } - - public static final class SerDes { - private SerDes() { - } - - public static String serialize(Søknad søknad) { - return JsonUtils.toString(søknad); - } - - public static Søknad deserialize(String søknad) { - return JsonUtils.fromString(søknad, Søknad.class); - } - - public static Søknad deserialize(ObjectNode node) { - try { - return JsonUtils.getObjectMapper().treeToValue(node, Søknad.class); - } catch (IOException e) { - throw new IllegalArgumentException("Kunne ikke konvertere til Søknad.class", e); - } - } - - } -} diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapporteringValidator.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapporteringValidator.java" deleted file mode 100644 index 97921089..00000000 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseInntektrapporteringValidator.java" +++ /dev/null @@ -1,43 +0,0 @@ -package no.nav.k9.søknad.ytelse.ung.v1; - -import jakarta.validation.Validation; -import jakarta.validation.ValidatorFactory; -import no.nav.k9.søknad.Søknad; -import no.nav.k9.søknad.SøknadValidator; -import no.nav.k9.søknad.felles.Feil; -import no.nav.k9.søknad.felles.type.Periode; -import no.nav.k9.søknad.felles.validering.AvbrytendeValideringsfeil; - -import java.util.List; -import java.util.stream.Collectors; - -public class UngdomsytelseInntektrapporteringValidator extends SøknadValidator { - - private static final ValidatorFactory VALIDATOR_FACTORY = Validation.buildDefaultValidatorFactory(); - - @Override - public List valider(UngdomsytelseInntektrapportering søknad) { - List feil = validerSøknadsfelter(søknad); - return feil; - } - - - public List valider(UngdomsytelseInntektrapportering søknad, List gyldigeEndringsperioder) { - return validerSøknadsfelter(søknad); - } - - private List validerSøknadsfelter(UngdomsytelseInntektrapportering søknad) { - var validate = VALIDATOR_FACTORY.getValidator().validate(søknad); - - List feil = validate.stream() - .map(Feil::toFeil) - .collect(Collectors.toList()); - - if (AvbrytendeValideringsfeil.harAvbrytendeValideringsfeil(validate)) { - return feil; - } - - validerFelterPåSøknad(søknad, feil); - return feil; - } -} diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" index 3ce2009a..1a30d008 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" @@ -18,6 +18,7 @@ public class UngdomsytelseSøknadValidator extends SøknadValidator { @Override public List valider(Søknad søknad) { List feil = validerSøknadsfelter(søknad); + validerYtelse(søknad, feil); return feil; } @@ -25,6 +26,16 @@ public List valider(Søknad søknad, List gyldigeEndringsperioder return validerSøknadsfelter(søknad); } + private List validerYtelse(Søknad søknad, List feil) { + Ungdomsytelse ytelse = søknad.getYtelse(); + + if (ytelse.getSøknadType() == UngSøknadstype.DELTAKELSE_SØKNAD && (ytelse.getStartdatoer() == null || ytelse.getStartdatoer().isEmpty())) { + feil.add(new Feil("søktFraDatoer", PÅKREVD, "Rapporteringssøknad må ha en sluttdato")); + } + + return feil; + } + private List validerSøknadsfelter(Søknad søknad) { var validate = VALIDATOR_FACTORY.getValidator().validate(søknad); diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" index 8acd6e14..6d2d74e7 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" @@ -1,13 +1,14 @@ package no.nav.k9.søknad.ytelse.ung; -import no.nav.k9.søknad.felles.type.Periode; import no.nav.k9.søknad.ytelse.ung.v1.Ungdomsytelse; +import java.time.LocalDate; + public class YtelseEksempel { - public static Ungdomsytelse komplettYtelseMedSøknadsperiode(Periode søknadsperiode) { + public static Ungdomsytelse komplettYtelseMedSøknadsperiode(LocalDate fraOgMed) { return new Ungdomsytelse() - .medSøknadsperiode(søknadsperiode); + .medStartdato(fraOgMed); } } diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" index f3038281..af984eab 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" @@ -1,11 +1,11 @@ package no.nav.k9.søknad.ytelse.ung.v1; +import no.nav.k9.søknad.Søknad; import no.nav.k9.søknad.felles.Versjon; import no.nav.k9.søknad.felles.personopplysninger.Søker; import no.nav.k9.søknad.felles.type.NorskIdentitetsnummer; import no.nav.k9.søknad.felles.type.Periode; import no.nav.k9.søknad.felles.type.SøknadId; -import no.nav.k9.søknad.ytelse.ung.SøknadEksempel; import no.nav.k9.søknad.ytelse.ung.v1.inntekt.InntektForPeriode; import org.junit.jupiter.api.Test; @@ -16,65 +16,63 @@ class InntektrapporteringValideringTest { - @Test - void verifiserInntektrapporteringUtenInntekterFeilerIkke() { - var inntektrapportering = inntektRapportering(OppgittInntekt.builder().build()); - ValiderUtil.verifyIngenFeil(inntektrapportering); - } - @Test void verifiserInntektrapporteringMedEnInntektFeilerIkke() { - final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now())); + final var inntekt = lagInntekt(new Periode(LocalDate.now(), LocalDate.now())); var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt)); ValiderUtil.verifyIngenFeil(inntektrapportering); } @Test void verifiserInntektrapporteringMedToIkkeOverlappendeInntekterFeilerIkke() { - final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now())); - final var inntekt2 = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); + final var inntekt = lagInntekt(new Periode(LocalDate.now(), LocalDate.now())); + final var inntekt2 = lagInntekt(new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt, inntekt2)); ValiderUtil.verifyIngenFeil(inntektrapportering); } @Test void verifiserInntektrapporteringMedToOverlappendeInntekterSomStarterSamtidigFeiler() { - final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now())); - final var inntekt2 = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now().plusDays(1))); + final var inntekt = lagInntekt(new Periode(LocalDate.now(), LocalDate.now())); + final var inntekt2 = lagInntekt(new Periode(LocalDate.now(), LocalDate.now().plusDays(1))); var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt, inntekt2)); ValiderUtil.verifyHarFeil(inntektrapportering); } @Test void verifiserInntektrapporteringMedToOverlappendeInntekterSomSlutterSamtidigFeiler() { - final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now().plusDays(1))); - final var inntekt2 = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); + final var inntekt = lagInntekt(new Periode(LocalDate.now(), LocalDate.now().plusDays(1))); + final var inntekt2 = lagInntekt(new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt2, inntekt)); ValiderUtil.verifyHarFeil(inntektrapportering); } + private static OppgittInntektForPeriode lagInntekt(Periode periode) { + return OppgittInntektForPeriode.builder(periode).build(); + } + @Test void verifiserInntektrapporteringMedToOverlappendeInntekterDerDenEneErInneholdtIDenAndreFeiler() { - final var inntekt = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now(), LocalDate.now().plusDays(3))); - final var inntekt2 = new InntektForPeriode(BigDecimal.TEN, new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); + final var inntekt = lagInntekt(new Periode(LocalDate.now(), LocalDate.now().plusDays(3))); + final var inntekt2 = lagInntekt(new Periode(LocalDate.now().plusDays(1), LocalDate.now().plusDays(1))); var inntektrapportering = inntektRapportering(lagOppgittInntekt(inntekt, inntekt2)); ValiderUtil.verifyHarFeil(inntektrapportering); } - private static OppgittInntekt lagOppgittInntekt(InntektForPeriode... inntekt) { - return OppgittInntekt.builder().medArbeidstakerOgFrilansinntekter(Set.of(inntekt)).build(); + private static OppgittInntekt lagOppgittInntekt(OppgittInntektForPeriode... inntekt) { + return OppgittInntekt.builder().medOppgittePeriodeinntekter(Set.of(inntekt)).build(); } - private static UngdomsytelseInntektrapportering inntektRapportering(OppgittInntekt inntekter) { - return new UngdomsytelseInntektrapportering( + private static Søknad inntektRapportering(OppgittInntekt inntekter) { + return new Søknad( new SøknadId("1"), new Versjon("6.0.1"), ZonedDateTime.now(), new Søker(NorskIdentitetsnummer.of("22222222222")), - inntekter + new Ungdomsytelse().medInntekter(inntekter) ); } diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValiderUtil.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValiderUtil.java" index 03840a7e..644bd07b 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValiderUtil.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValiderUtil.java" @@ -13,7 +13,6 @@ public class ValiderUtil { private static final UngdomsytelseSøknadValidator validatorSøknad = new UngdomsytelseSøknadValidator(); - private static final UngdomsytelseInntektrapporteringValidator inntektrapporteringValidator = new UngdomsytelseInntektrapporteringValidator(); public static List verifyHarFeil(Søknad søknad) { @@ -22,12 +21,6 @@ public static List verifyHarFeil(Søknad søknad) { return feil; } - public static List verifyHarFeil(UngdomsytelseInntektrapportering inntektrapportering) { - final List feil = valider(inntektrapportering); - assertThat(feil).isNotEmpty(); - return feil; - } - public static List verifyHarFeil(Søknad søknad, List endringsperioder) { final List feil = valider(søknad, endringsperioder); assertThat(feil).isNotEmpty(); @@ -40,12 +33,6 @@ public static List verifyIngenFeil(Søknad søknad) { return feil; } - public static List verifyIngenFeil(UngdomsytelseInntektrapportering inntektrapportering) { - final List feil = valider(inntektrapportering); - assertThat(feil).isEmpty(); - return feil; - } - public static List verifyIngenFeil(Søknad søknad, List gyldigEndringsInterval) { final List feil = valider(søknad, gyldigEndringsInterval); assertThat(feil).isEmpty(); @@ -60,13 +47,6 @@ public static List valider(Søknad søknad) { } } - public static List valider(UngdomsytelseInntektrapportering inntektrapportering) { - try { - return inntektrapporteringValidator.valider(inntektrapportering); - } catch (ValideringsFeil ex) { - return ex.getFeil(); - } - } public static List valider(Søknad søknad, List gyldigEndringsInterval) { try { diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValideringTest.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValideringTest.java" index 70e223e0..0e3fc04b 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValideringTest.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/ValideringTest.java" @@ -1,6 +1,5 @@ package no.nav.k9.søknad.ytelse.ung.v1; -import no.nav.k9.søknad.felles.type.Periode; import no.nav.k9.søknad.ytelse.ung.SøknadEksempel; import no.nav.k9.søknad.ytelse.ung.YtelseEksempel; import org.junit.jupiter.api.Test; @@ -11,8 +10,8 @@ class ValideringTest { @Test void verifiserHentingAvSøknadsperiodeUtenTomDatoIkkeFeiler() { - var søknadsperiode = new Periode(LocalDate.now(), null); - var ytelse = YtelseEksempel.komplettYtelseMedSøknadsperiode(søknadsperiode); + final var fom = LocalDate.now(); + var ytelse = YtelseEksempel.komplettYtelseMedSøknadsperiode(fom); ValiderUtil.verifyIngenFeil(SøknadEksempel.søknad(ytelse)); } From e8a525710e3c4d9df323d6b2b002d3e596d3a5a3 Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Wed, 29 Jan 2025 13:36:38 +0100 Subject: [PATCH 6/9] =?UTF-8?q?Endrer=20tilbake=20til=20S=C3=B8knad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nav/k9/s\303\270knad/S\303\270knadValidator.java" | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/S\303\270knadValidator.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/S\303\270knadValidator.java" index bc8850cb..4da83548 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/S\303\270knadValidator.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/S\303\270knadValidator.java" @@ -23,15 +23,15 @@ public void forsikreValidert(S søknad) { * Felles validering av felter på søknad. Må kalles eksplisitt på av * subklassene til denne klassen hvis den skal brukes, * - * @param innsending Innsendingen som valideres. + * @param søknad Søknaden som valideres. * @param feil En liste der eventuelt feil skal legges til. */ - public final void validerFelterPåSøknad(Innsending innsending, List feil) { - validerMottattDato(innsending, feil); - validerVersjon(innsending.getVersjon(), feil); + public final void validerFelterPåSøknad(Søknad søknad, List feil) { + validerMottattDato(søknad, feil); + validerVersjon(søknad.getVersjon(), feil); } - private void validerMottattDato(Innsending søknad, List feil) { + private void validerMottattDato(Søknad søknad, List feil) { final int maximumClockSkewSeconds = 10; if (søknad.getMottattDato() != null && søknad.getMottattDato() From ed3a0a0e4be06ae58eb8835e6f75216ff6391fe2 Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Wed, 29 Jan 2025 13:46:26 +0100 Subject: [PATCH 7/9] =?UTF-8?q?Setter=20rapporteringgs=C3=B8knad=20i=20tes?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" | 6 ++++++ .../ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" | 2 +- .../ytelse/ung/v1/InntektrapporteringValideringTest.java" | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" index 420aa673..10eb10cd 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" @@ -113,6 +113,12 @@ public Ungdomsytelse medInntekter(OppgittInntekt inntekter) { } + public Ungdomsytelse medSøknadType(UngSøknadstype søknadType) { + this.søknadType = Objects.requireNonNull(søknadType, "søknadType"); + return this; + } + + public UngSøknadstype getSøknadType() { return søknadType; } diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" index 1a30d008..0ae44130 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/UngdomsytelseS\303\270knadValidator.java" @@ -30,7 +30,7 @@ private List validerYtelse(Søknad søknad, List feil) { Ungdomsytelse ytelse = søknad.getYtelse(); if (ytelse.getSøknadType() == UngSøknadstype.DELTAKELSE_SØKNAD && (ytelse.getStartdatoer() == null || ytelse.getStartdatoer().isEmpty())) { - feil.add(new Feil("søktFraDatoer", PÅKREVD, "Rapporteringssøknad må ha en sluttdato")); + feil.add(new Feil("søktFraDatoer", PÅKREVD, "Deltakelsesøknad må sette minst en startdato")); } return feil; diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" index af984eab..4e4e8144 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/InntektrapporteringValideringTest.java" @@ -72,7 +72,7 @@ private static OppgittInntekt lagOppgittInntekt(OppgittInntektForPeriode... innt new Versjon("6.0.1"), ZonedDateTime.now(), new Søker(NorskIdentitetsnummer.of("22222222222")), - new Ungdomsytelse().medInntekter(inntekter) + new Ungdomsytelse().medInntekter(inntekter).medSøknadType(UngSøknadstype.RAPPORTERING_SØKNAD) ); } From 427fd2ae2650e886d48f4d6958d141ded1db90e6 Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Wed, 29 Jan 2025 13:47:49 +0100 Subject: [PATCH 8/9] =?UTF-8?q?Setter=20deltakelses=C3=B8knad=20i=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" index 6d2d74e7..55a3b0fd 100644 --- "a/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" +++ "b/soknad/src/test/java/no/nav/k9/s\303\270knad/ytelse/ung/YtelseEksempel.java" @@ -1,5 +1,6 @@ package no.nav.k9.søknad.ytelse.ung; +import no.nav.k9.søknad.ytelse.ung.v1.UngSøknadstype; import no.nav.k9.søknad.ytelse.ung.v1.Ungdomsytelse; import java.time.LocalDate; @@ -9,6 +10,7 @@ public class YtelseEksempel { public static Ungdomsytelse komplettYtelseMedSøknadsperiode(LocalDate fraOgMed) { return new Ungdomsytelse() - .medStartdato(fraOgMed); + .medStartdato(fraOgMed) + .medSøknadType(UngSøknadstype.DELTAKELSE_SØKNAD); } } From c58e3e17e697beae8613d702b94646129fa0181a Mon Sep 17 00:00:00 2001 From: Espen Velsvik Date: Wed, 29 Jan 2025 13:53:33 +0100 Subject: [PATCH 9/9] Fjerner not null contraint fra inntekt --- .../no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" | 1 - 1 file changed, 1 deletion(-) diff --git "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" index 10eb10cd..c08e19c1 100644 --- "a/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" +++ "b/soknad/src/main/java/no/nav/k9/s\303\270knad/ytelse/ung/v1/Ungdomsytelse.java" @@ -29,7 +29,6 @@ public class Ungdomsytelse implements Ytelse { private List<@NotNull LocalDate> søktFraDatoer = new ArrayList<>(); @Valid - @NotNull @JsonProperty(value = "inntekter", required = true) private OppgittInntekt inntekter;