Skip to content

Commit

Permalink
Støtte for håndtering av utenlandsopphold i uttak. (#364)
Browse files Browse the repository at this point in the history
* Støtte for håndtering av utenlandsopphold i uttak.

* Flere tester for utenlandsopphold + bugfix.

* Ny test og feilretting ifm telling av utenlandsperioder.

* Lagt på feature toggle
  • Loading branch information
frodeli authored Jan 10, 2022
1 parent e1eb1db commit 2de71ef
Show file tree
Hide file tree
Showing 16 changed files with 285 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ enum class KnekkpunktType {
BARNETS_DØDSFALL,
BARNETS_DØDSFALL_SLUTT_PÅ_RETT,
SØKERS_ALDER,
KRAVPRIORITETSPERIODE
KRAVPRIORITETSPERIODE,
UTENLANDSOPPHOLD
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package no.nav.pleiepengerbarn.uttak.kontrakter

enum class UtenlandsoppholdÅrsak {
BARNET_INNLAGT_I_HELSEINSTITUSJON_FOR_NORSK_OFFENTLIG_REGNING,
BARNET_INNLAGT_I_HELSEINSTITUSJON_DEKKET_ETTER_AVTALE_MED_ET_ANNET_LAND_OM_TRYGD,
INGEN
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ data class Uttaksgrunnlag (
@JsonProperty("tilsynsperioder") val tilsynsperioder: Map<LukketPeriode, Duration> = mapOf(),
@JsonProperty("beredskapsperioder") val beredskapsperioder: Map<LukketPeriode, Utfall> = mapOf(),
@JsonProperty("nattevåksperioder") val nattevåksperioder: Map<LukketPeriode, Utfall> = mapOf(),
@JsonProperty("kravprioritetForBehandlinger") val kravprioritetForBehandlinger: Map<LukketPeriode, List<BehandlingUUID>> = mapOf()

@JsonProperty("kravprioritetForBehandlinger") val kravprioritetForBehandlinger: Map<LukketPeriode, List<BehandlingUUID>> = mapOf(),
@JsonProperty("utenlandsoppholdperioder") val utenlandsoppholdperioder: Map<LukketPeriode, UtenlandsoppholdInfo> = mapOf()
)

@JsonIgnoreProperties(ignoreUnknown = true)
Expand All @@ -44,4 +44,12 @@ data class Vilkårsperiode(
data class SøktUttak(
@JsonProperty("periode") val periode: LukketPeriode,
@JsonProperty("oppgittTilsyn") val oppgittTilsyn: Duration? = null
)

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.ANY)
data class UtenlandsoppholdInfo(
@JsonProperty("utenlandsoppholdÅrsak") val utenlandsoppholdÅrsak: UtenlandsoppholdÅrsak,
@JsonProperty("landkode") val landkode: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package no.nav.pleiepengerbarn.uttak.kontrakter
import com.fasterxml.jackson.annotation.*
import java.time.Duration

typealias Uttaksperiode = Map.Entry<LukketPeriode, UttaksperiodeInfo>

enum class Utfall {
OPPFYLT,
IKKE_OPPFYLT
Expand Down Expand Up @@ -74,7 +72,8 @@ data class UttaksperiodeInfo @JsonCreator constructor(
@JsonProperty("annenPart") val annenPart: AnnenPart,
@JsonProperty("nattevåk") val nattevåk: Utfall?,
@JsonProperty("beredskap") val beredskap: Utfall?,
@JsonProperty("endringsstatus") val endringsstatus: Endringsstatus? = null
@JsonProperty("endringsstatus") val endringsstatus: Endringsstatus? = null,
@JsonProperty("utenlandsoppholdUtenÅrsak") val utenlandsoppholdUtenÅrsak: Boolean = false
) {

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum class Årsak(val oppfylt: Boolean) {
LOVBESTEMT_FERIE(false),
BARNETS_DØDSFALL(false),
INNGANGSVILKÅR_IKKE_OPPFYLT(false),
FOR_LAV_INNTEKT(false)
FOR_LAV_INNTEKT(false),
FOR_MANGE_DAGER_UTENLANDSOPPHOLD(false)

}
4 changes: 4 additions & 0 deletions nais/dev-fss-k9saksbehandling.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,7 @@ spec:
value: "true"
- name: APPDYNAMICS_AGENT_ACCOUNT_NAME
value: NON-PROD

# Feature toggles
- name: UTENLANDSOPPHOLD_REGEL
value: "true"
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal object KnekkpunktUtleder {
finnForKravprioritet(knekkpunkMap, regelGrunnlag.kravprioritetForBehandlinger.keys)
finnForBarnsDød(knekkpunkMap, regelGrunnlag.barn)
finnForTrukketUttak(knekkpunkMap, regelGrunnlag.trukketUttak)
finnForUtenlandsopphold(knekkpunkMap, regelGrunnlag.utenlandsoppholdperioder.keys)

val knekkpunkter = mutableListOf<Knekkpunkt>()
knekkpunkMap.forEach { (key, value) ->
Expand All @@ -43,6 +44,10 @@ internal object KnekkpunktUtleder {
return knekkpunkter.toSortedSet(compareBy { it.knekk })
}

private fun finnForUtenlandsopphold(knekkpunkMap: MutableMap<LocalDate, MutableSet<KnekkpunktType>>, utenlandsopphold: Set<LukketPeriode>) {
utenlandsopphold.forEach {finnForPeriode(knekkpunkMap, it, KnekkpunktType.UTENLANDSOPPHOLD)}
}

private fun finnForTrukketUttak(knekkpunkMap: MutableMap<LocalDate, MutableSet<KnekkpunktType>>, trukketUttak: List<LukketPeriode>) {
trukketUttak.forEach {periode -> finnForPeriode(knekkpunkMap, periode, KnekkpunktType.TRUKKET_UTTAK)}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal object UttaksplanRegler {

private val UttaksplanRegler = linkedSetOf(
InngangsvilkårIkkeOppfyltRegel(),
UtenlandsoppholdRegel()
// NB: erstartet inntil videre med BarnsDødPeriodeRegel
// BarnsDødRegel()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package no.nav.pleiepengerbarn.uttak.regler.delregler

import no.nav.fpsak.tidsserie.LocalDateSegment
import no.nav.fpsak.tidsserie.LocalDateTimeline
import no.nav.pleiepengerbarn.uttak.kontrakter.*
import no.nav.pleiepengerbarn.uttak.regler.NULL_PROSENT
import no.nav.pleiepengerbarn.uttak.regler.domene.RegelGrunnlag
import no.nav.pleiepengerbarn.uttak.regler.kontrakter_ext.overlapperDelvis
import no.nav.pleiepengerbarn.uttak.regler.kontrakter_ext.virkedager
import java.time.DayOfWeek
import java.time.LocalDate

private const val MAX_DAGER_PER_ÅR = 8 * 5

internal class UtenlandsoppholdRegel : UttaksplanRegel {


override fun kjør(uttaksplan: Uttaksplan, grunnlag: RegelGrunnlag): Uttaksplan {

val featureToggleUtenlandsoppholdRgel = System.getenv("UTENLANDSOPPHOLD_REGEL").toBoolean()
if (!featureToggleUtenlandsoppholdRgel) {
return uttaksplan
}

val nyePerioder = mutableMapOf<LukketPeriode, UttaksperiodeInfo>()
val utenlandsdagerFraForrigeUttaksplan = grunnlag.finnUtenlandsdager()

var brukteDager = 0
val sortertePerioder = uttaksplan.perioder.keys.toList().sortedBy { it.fom }
sortertePerioder.forEach { periode ->
val info = uttaksplan.perioder[periode]
?: throw IllegalStateException("Dette skal ikke kunne skje. Alle perioder skal finnes i map.")
if (info.utfall == Utfall.OPPFYLT && grunnlag.overlapperMedUtenlandsoppholdUtenGyldigÅrsak(periode)) {
val avklartePerioder = periode.avklarPeriode(utenlandsdagerFraForrigeUttaksplan, brukteDager)
avklartePerioder.forEach { (nyPeriode, utenlandsoppholdInnvilget) ->
if (utenlandsoppholdInnvilget) {
nyePerioder[nyPeriode] = info.copy(utenlandsoppholdUtenÅrsak = true)
brukteDager += nyPeriode.virkedager()
} else {
nyePerioder[nyPeriode] = info.settIkkeInnvilgetPgaUtenlandsopphold()
}
}
} else {
nyePerioder[periode] = info
}
}
return uttaksplan.copy(perioder = nyePerioder)
}

}

private fun RegelGrunnlag.overlapperMedUtenlandsoppholdUtenGyldigÅrsak(periode: LukketPeriode): Boolean {
return this.utenlandsoppholdperioder.any {periode.overlapperDelvis(it.key) && it.value.utenlandsoppholdÅrsak == UtenlandsoppholdÅrsak.INGEN}
}

private fun UttaksperiodeInfo.settIkkeInnvilgetPgaUtenlandsopphold(): UttaksperiodeInfo {
val årsaker = setOf(Årsak.FOR_MANGE_DAGER_UTENLANDSOPPHOLD)
val oppdaterteUtbetalingsgrader = this.utbetalingsgrader.map {it.copy(utbetalingsgrad = NULL_PROSENT)}
return this.copy(utfall = Utfall.IKKE_OPPFYLT, uttaksgrad = NULL_PROSENT, årsaker = årsaker, utbetalingsgrader = oppdaterteUtbetalingsgrader)
}

private fun LukketPeriode.avklarPeriode(utenlandsdager: Set<LocalDate>, brukteDager: Int): Map<LukketPeriode, Boolean> {

val segmenter = mutableListOf<LocalDateSegment<Boolean>>()

val antallFraTidligereUttaksplan = utenlandsdager.mellom(this.fom.minusYears(1), this.fom.minusDays(1))

var brukteDagerPåDennePerioden = 0
this.stream().forEach { dato ->
val forbrukteDager = antallFraTidligereUttaksplan + brukteDager + brukteDagerPåDennePerioden
if (forbrukteDager < MAX_DAGER_PER_ÅR) {
segmenter.add(LocalDateSegment(dato, dato, true))
brukteDagerPåDennePerioden++
} else {
segmenter.add(LocalDateSegment(dato, dato, false))
}
}
val nyePerioder = LocalDateTimeline(segmenter).compress()

return nyePerioder.toSegments().associate {LukketPeriode(it.fom, it.tom) to it.value}
}

private fun Set<LocalDate>.mellom(fom: LocalDate, tom: LocalDate) = this.count { it in fom..tom }

private fun RegelGrunnlag.finnUtenlandsdager(): Set<LocalDate> {
if (this.forrigeUttaksplan == null) {
return setOf()
}
return this.forrigeUttaksplan.perioder
.filter {it.value.utenlandsoppholdUtenÅrsak}
.flatMap {it.key.tilDatoer()}
.toSet()
}

private fun LukketPeriode.tilDatoer(): Set<LocalDate> {
val datoer = mutableSetOf<LocalDate>()
this.stream().forEach {
if (it.dayOfWeek !in listOf(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY)) {
datoer.add(it)
}
}
return datoer
}

private fun LukketPeriode.stream() = fom.datesUntil(tom.plusDays(1))
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ data class RegelGrunnlag(
val forrigeUttaksplan: Uttaksplan? = null,
val beredskapsperioder: Map<LukketPeriode, Utfall> = mapOf(),
val nattevåksperioder: Map<LukketPeriode, Utfall> = mapOf(),
val kravprioritetForBehandlinger: Map<LukketPeriode, List<UUID>> = mapOf()
val kravprioritetForBehandlinger: Map<LukketPeriode, List<UUID>> = mapOf(),
val utenlandsoppholdperioder: Map<LukketPeriode, UtenlandsoppholdInfo> = mapOf()
) {

internal fun finnArbeidPerArbeidsforhold(periode: LukketPeriode): Map<Arbeidsforhold, ArbeidsforholdPeriodeInfo> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import no.nav.fpsak.tidsserie.LocalDateTimeline
import no.nav.pleiepengerbarn.uttak.kontrakter.LukketPeriode
import no.nav.pleiepengerbarn.uttak.kontrakter.SøktUttak
import java.lang.IllegalArgumentException
import java.time.DayOfWeek

internal fun LukketPeriode.overlapperHelt(annen: LukketPeriode) =
(fom == annen.fom || fom.isBefore(annen.fom)) &&
Expand All @@ -27,3 +28,15 @@ fun Collection<LukketPeriode>.sjekkOmOverlapp(): Boolean {
}
return false
}

internal fun LukketPeriode.virkedager(): Int {
var nåværende = fom
var antall = 0
while (!nåværende.isAfter(tom)) {
if (nåværende.dayOfWeek !in listOf(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY)) {
antall++
}
nåværende = nåværende.plusDays(1)
}
return antall
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ object GrunnlagMapper {
forrigeUttaksplan = forrigeUttaksplan,
beredskapsperioder = uttaksgrunnlag.beredskapsperioder,
nattevåksperioder = uttaksgrunnlag.nattevåksperioder,
kravprioritetForBehandlinger = kravprioritetForBehandlinger
kravprioritetForBehandlinger = kravprioritetForBehandlinger,
utenlandsoppholdperioder = uttaksgrunnlag.utenlandsoppholdperioder
)
}

Expand Down
10 changes: 10 additions & 0 deletions server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@
</delimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<environmentVariables>
<UTENLANDSOPPHOLD_REGEL>true</UTENLANDSOPPHOLD_REGEL>
</environmentVariables>
</configuration>
</plugin>

</plugins>
<resources>
<resource>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ internal class UttaksperiodeRepository {
pleiebehov, etablert_tilsyn, andre_sokeres_tilsyn, tilgjengelig_for_soker,
uttaksgrad, aarsaker, utfall, sokers_tapte_arbeidstid, oppgitt_tilsyn,
inngangsvilkar, knekkpunkt_typer, kilde_behandling_uuid, annen_part, overse_etablert_tilsyn_arsak,
nattevåk, beredskap, andre_sokeres_tilsyn_reberegnet, endringsstatus
nattevåk, beredskap, andre_sokeres_tilsyn_reberegnet, endringsstatus, utenlandsopphold_uten_aarsak
from uttaksperiode
where uttaksresultat_id = :uttaksresultat_id
""".trimIndent()
Expand Down Expand Up @@ -90,7 +90,8 @@ internal class UttaksperiodeRepository {
annenPart = AnnenPart.valueOf(rs.getString("annen_part")),
nattevåk = tilUtfall(rs.getString("nattevåk")),
beredskap = tilUtfall(rs.getString("beredskap")),
endringsstatus = endringsstatus
endringsstatus = endringsstatus,
utenlandsoppholdUtenÅrsak = rs.getBoolean("utenlandsopphold_uten_aarsak")
)
)
}
Expand Down Expand Up @@ -127,11 +128,11 @@ internal class UttaksperiodeRepository {
insert into
uttaksperiode (id, uttaksresultat_id, fom, tom, pleiebehov, etablert_tilsyn, andre_sokeres_tilsyn, andre_sokeres_tilsyn_reberegnet,
tilgjengelig_for_soker, uttaksgrad, aarsaker, utfall, sokers_tapte_arbeidstid, oppgitt_tilsyn, inngangsvilkar, knekkpunkt_typer,
kilde_behandling_uuid, annen_part, overse_etablert_tilsyn_arsak, nattevåk, beredskap, endringsstatus)
kilde_behandling_uuid, annen_part, overse_etablert_tilsyn_arsak, nattevåk, beredskap, endringsstatus, utenlandsopphold_uten_aarsak)
values(nextval('seq_uttaksperiode'), :uttaksresultat_id, :fom, :tom, :pleiebehov, :etablert_tilsyn, :andre_sokeres_tilsyn, :andre_sokeres_tilsyn_reberegnet,
:tilgjengelig_for_soker, :uttaksgrad, :aarsaker, :utfall::utfall, :sokers_tapte_arbeidstid, :oppgitt_tilsyn, :inngangsvilkar, :knekkpunkt_typer,
:kilde_behandling_uuid, :annen_part::annen_part, :overse_etablert_tilsyn_arsak::overse_etablert_tilsyn_arsak,
:nattevåk::utfall, :beredskap::utfall, :endringsstatus::endringsstatus)
:nattevåk::utfall, :beredskap::utfall, :endringsstatus::endringsstatus, :utenlandsopphold_uten_aarsak)
""".trimIndent()
val keyHolder = GeneratedKeyHolder()
Expand All @@ -157,6 +158,7 @@ internal class UttaksperiodeRepository {
.addValue("nattevåk", info.nattevåk?.name, Types.OTHER)
.addValue("beredskap", info.beredskap?.name, Types.OTHER)
.addValue("endringsstatus", info.endringsstatus?.name, Types.OTHER)
.addValue("utenlandsopphold_uten_aarsak", info.utenlandsoppholdUtenÅrsak)

jdbcTemplate.update(sql, params, keyHolder, arrayOf("id"))
return keyHolder.key as Long
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

ALTER TABLE uttaksperiode ADD COLUMN utenlandsopphold_uten_aarsak boolean NOT NULL DEFAULT false;
Loading

0 comments on commit 2de71ef

Please sign in to comment.