Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Legger til mulighet for innrapportering av inntekt for ungdomsytelsen #484

Merged
merged 9 commits into from
Jan 29, 2025
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
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 jakarta.validation.constraints.Size;
import no.nav.k9.søknad.felles.type.Periode;

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 = "oppgittePeriodeinntekter")
@Valid
@NotNull
@Size(min = 1)
private NavigableSet<@NotNull OppgittInntektForPeriode> oppgittePeriodeinntekter;

@JsonCreator
public OppgittInntekt(@JsonProperty(value = "oppgittePeriodeinntekter") Set<OppgittInntektForPeriode> oppgittePeriodeinntekter) {
this.oppgittePeriodeinntekter = (oppgittePeriodeinntekter == null) ? Collections.emptyNavigableSet()
: Collections.unmodifiableNavigableSet(new TreeSet<>(oppgittePeriodeinntekter));
}

public static Builder builder() {
return new Builder();
}

public NavigableSet<OppgittInntektForPeriode> getOppgittePeriodeinntekter() {
return oppgittePeriodeinntekter;
}

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<OppgittInntektForPeriode> oppgittePeriodeinntekter = new LinkedHashSet<>();

private Builder() {
}

public Builder medOppgittePeriodeinntekter(Set<OppgittInntektForPeriode> inntekter) {
if (inntekter != null) {
oppgittePeriodeinntekter.addAll(inntekter);
}
return this;
}

public OppgittInntekt build() {
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(oppgittePeriodeinntekter);
}

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);
// 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.getTilOgMed().isBefore(next.getPeriode().getFraOgMed())) {
return false;
}
prev = next.getPeriode();
}
return true;
}


}
Original file line number Diff line number Diff line change
@@ -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<OppgittInntektForPeriode> {

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);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,16 @@
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.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;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -30,12 +26,11 @@ 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<>();

@JsonProperty(value = "inntekt")
@DecimalMin("0.00")
@DecimalMax("1000000.00")
private BigDecimal inntekt;
@Valid
@JsonProperty(value = "inntekter", required = true)
private OppgittInntekt inntekter;

@Override
public Type getType() {
Expand Down Expand Up @@ -79,61 +74,52 @@ public Person getAnnenPart() {

@Override
public Periode getSøknadsperiode() {
final List<Periode> perioder = new ArrayList<>(søknadsperiode);

final var fom = perioder
.stream()
.map(Periode::getFraOgMed)
.min(LocalDate::compareTo)
.orElseThrow();
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();

if (søknadType == UngSøknadstype.DELTAKELSE_SØKNAD) {
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 tom = perioder
.stream()
.map(Periode::getTilOgMed)
.filter(Objects::nonNull)
.max(LocalDate::compareTo)
.orElse(null);
return new Periode(fom, tom);
}

public List<Periode> 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 OppgittInntekt getInntekter() {
return inntekter;
}

public BigDecimal getInntekt() {
return inntekt;
public List<LocalDate> getStartdatoer() {
return søktFraDatoer;
}

public Ungdomsytelse medInntekt(BigDecimal inntekt) {
this.inntekt = Objects.requireNonNull(inntekt, "inntekt");
public Ungdomsytelse medStartdatoer(List<LocalDate> startdatoer) {
this.søktFraDatoer.addAll(Objects.requireNonNull(startdatoer, "startdatoer"));
return this;
}

public Ungdomsytelse medSøknadsperiode(List<Periode> søknadsperiodeList) {
this.søknadsperiode.addAll(Objects.requireNonNull(søknadsperiodeList, "søknadsperiodeList"));
public Ungdomsytelse medStartdato(LocalDate startdato) {
this.søktFraDatoer.add(Objects.requireNonNull(startdato, "startdato"));
return this;
}

public Ungdomsytelse medSøknadsperiode(Periode søknadsperiode) {
this.søknadsperiode.add(Objects.requireNonNull(søknadsperiode, "søknadsperiode"));
public Ungdomsytelse medInntekter(OppgittInntekt inntekter) {
this.inntekter = Objects.requireNonNull(inntekter, "inntekter");
return this;
}

public UngSøknadstype getSøknadType() {
return søknadType;
}

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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ public List<Feil> valider(Søknad søknad) {
return feil;
}

public List<Feil> valider(Søknad søknad, List<Periode> gyldigeEndringsperioder) {
return validerSøknadsfelter(søknad);
}

private List<Feil> validerYtelse(Søknad søknad, List<Feil> 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øknadha en sluttdato"));
if (ytelse.getSøknadType() == UngSøknadstype.DELTAKELSE_SØKNAD && (ytelse.getStartdatoer() == null || ytelse.getStartdatoer().isEmpty())) {
feil.add(new Feil("søktFraDatoer", PÅKREVD, "Deltakelsesøknadsette minst en startdato"));
}

return feil;
}

public List<Feil> valider(Søknad søknad, List<Periode> gyldigeEndringsperioder) {
return validerSøknadsfelter(søknad);
}

private List<Feil> validerSøknadsfelter(Søknad søknad) {
var validate = VALIDATOR_FACTORY.getValidator().validate(søknad);

Expand Down
Loading
Loading