Skip to content

Commit

Permalink
Lagt inn caching i DB for valutakurser fra ECB (#4058)
Browse files Browse the repository at this point in the history
Co-authored-by: marius-nav <[email protected]>
  • Loading branch information
hensol and marius-nav authored Oct 11, 2023
1 parent f57e02d commit 1dfeeea
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@ package no.nav.familie.ba.sak.integrasjoner.ecb

import no.nav.familie.ba.sak.common.del
import no.nav.familie.ba.sak.common.tilKortString
import no.nav.familie.ba.sak.integrasjoner.ecb.domene.ECBValutakursCache
import no.nav.familie.ba.sak.integrasjoner.ecb.domene.ECBValutakursCacheRepository
import no.nav.familie.valutakurs.Frequency
import no.nav.familie.valutakurs.ValutakursRestClient
import no.nav.familie.valutakurs.domene.ExchangeRate
import no.nav.familie.valutakurs.domene.exchangeRateForCurrency
import no.nav.familie.valutakurs.exception.ValutakursClientException
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Import
import org.springframework.stereotype.Service
import java.math.BigDecimal
import java.time.LocalDate

@Service
@Import(ValutakursRestClient::class)
class ECBService(private val ecbClient: ValutakursRestClient) {
class ECBService(private val ecbClient: ValutakursRestClient, private val ecbValutakursCacheRepository: ECBValutakursCacheRepository) {

private val logger: Logger = LoggerFactory.getLogger(ECBService::class.java)

/**
* @param utenlandskValuta valutaen vi skal konvertere til NOK
Expand All @@ -23,19 +29,36 @@ class ECBService(private val ecbClient: ValutakursRestClient) {
*/
@Throws(ECBServiceException::class)
fun hentValutakurs(utenlandskValuta: String, kursDato: LocalDate): BigDecimal {
try {
val exchangeRates =
ecbClient.hentValutakurs(Frequency.Daily, listOf(ECBConstants.NOK, utenlandskValuta), kursDato)
validateExchangeRates(utenlandskValuta, kursDato, exchangeRates)
val valutakursNOK = exchangeRates.exchangeRateForCurrency(ECBConstants.NOK)!!
if (utenlandskValuta == ECBConstants.EUR) {
return valutakursNOK.exchangeRate
val valutakurs = ecbValutakursCacheRepository.findByValutakodeAndValutakursdato(utenlandskValuta, kursDato)
if (valutakurs == null) {
logger.info("Henter valutakurs for $utenlandskValuta$kursDato")
try {
val exchangeRates =
ecbClient.hentValutakurs(Frequency.Daily, listOf(ECBConstants.NOK, utenlandskValuta), kursDato)
validateExchangeRates(utenlandskValuta, kursDato, exchangeRates)
val valutakursNOK = exchangeRates.exchangeRateForCurrency(ECBConstants.NOK)!!
if (utenlandskValuta == ECBConstants.EUR) {
ecbValutakursCacheRepository.save(ECBValutakursCache(kurs = valutakursNOK.exchangeRate, valutakode = utenlandskValuta, valutakursdato = kursDato))
return valutakursNOK.exchangeRate
}
val valutakursUtenlandskValuta = exchangeRates.exchangeRateForCurrency(utenlandskValuta)!!
ecbValutakursCacheRepository.save(
ECBValutakursCache(
kurs = beregnValutakurs(
valutakursUtenlandskValuta.exchangeRate,
valutakursNOK.exchangeRate,
),
valutakode = utenlandskValuta,
valutakursdato = kursDato,
),
)
return beregnValutakurs(valutakursUtenlandskValuta.exchangeRate, valutakursNOK.exchangeRate)
} catch (e: ValutakursClientException) {
throw ECBServiceException(e.message, e)
}
val valutakursUtenlandskValuta = exchangeRates.exchangeRateForCurrency(utenlandskValuta)!!
return beregnValutakurs(valutakursUtenlandskValuta.exchangeRate, valutakursNOK.exchangeRate)
} catch (e: ValutakursClientException) {
throw ECBServiceException(e.message, e)
}
logger.info("Valutakurs ble hentet fra cache for $utenlandskValuta$kursDato")
return valutakurs.kurs
}

private fun beregnValutakurs(valutakursUtenlandskValuta: BigDecimal, valutakursNOK: BigDecimal) =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package no.nav.familie.ba.sak.integrasjoner.ecb.domene

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.EntityListeners
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.SequenceGenerator
import jakarta.persistence.Table
import no.nav.familie.ba.sak.common.BaseEntitet
import no.nav.familie.ba.sak.sikkerhet.RollestyringMotDatabase
import java.math.BigDecimal
import java.time.LocalDate

@EntityListeners(RollestyringMotDatabase::class)
@Entity(name = "EcbValutakursCache")
@Table(name = "ECBVALUTAKURSCACHE")
data class ECBValutakursCache(

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ecbvalutakurscache_seq_generator")
@SequenceGenerator(name = "ecbvalutakurscache_seq_generator", sequenceName = "ecbvalutakurscache_seq", allocationSize = 50)
val id: Long = 0,

@Column(name = "valutakursdato", columnDefinition = "DATE")
val valutakursdato: LocalDate? = null,

@Column(name = "valutakode")
val valutakode: String? = null,

@Column(name = "kurs", nullable = false)
val kurs: BigDecimal,
) : BaseEntitet()
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package no.nav.familie.ba.sak.integrasjoner.ecb.domene

import org.springframework.data.jpa.repository.JpaRepository
import java.time.LocalDate

interface ECBValutakursCacheRepository : JpaRepository<ECBValutakursCache, Long> {
fun findByValutakodeAndValutakursdato(valutakode: String, valutakursdato: LocalDate): ECBValutakursCache?
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package no.nav.familie.ba.sak.internal

import no.nav.familie.ba.sak.common.secureLogger
import no.nav.familie.ba.sak.integrasjoner.ecb.ECBService
import no.nav.familie.ba.sak.integrasjoner.familieintegrasjoner.IntegrasjonClient
import no.nav.familie.ba.sak.integrasjoner.oppgave.domene.OppgaveRepository
import no.nav.familie.ba.sak.kjerne.autovedtak.småbarnstillegg.RestartAvSmåbarnstilleggService
Expand All @@ -15,7 +16,10 @@ import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.math.BigDecimal
import java.time.LocalDate
import java.util.UUID
import kotlin.concurrent.thread

Expand All @@ -27,6 +31,7 @@ class ForvalterController(
private val integrasjonClient: IntegrasjonClient,
private val restartAvSmåbarnstilleggService: RestartAvSmåbarnstilleggService,
private val forvalterService: ForvalterService,
private val ecbService: ECBService,
) {
private val logger: Logger = LoggerFactory.getLogger(ForvalterController::class.java)

Expand Down Expand Up @@ -111,6 +116,11 @@ class ForvalterController(
return ResponseEntity.ok(Pair("callId", callId))
}

@GetMapping("/hentValutakurs/")
fun finnFagsakerSomSkalAvsluttes(@RequestParam valuta: String, @RequestParam dato: LocalDate): ResponseEntity<BigDecimal> {
return ResponseEntity.ok(ecbService.hentValutakurs(valuta, dato))
}

@GetMapping("/finnÅpneFagsakerMedFlereMigreringsbehandlingerOgLøpendeSakIInfotrygd")
fun finnÅpneFagsakerMedFlereMigreringsbehandlingerOgLøpendeSakIInfotrygd(): ResponseEntity<List<Pair<Long, String>>> {
val åpneFagsakerMedFlereMigreringsbehandlingerOgLøpendeSakIInfotrygd =
Expand Down
15 changes: 15 additions & 0 deletions src/main/resources/db/migration/V253__ecb_valutakurs_cache.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE TABLE ecbvalutakurscache
(
ID BIGINT NOT NULL PRIMARY KEY,
VALUTAKURSDATO TIMESTAMP(3) DEFAULT null,
VALUTAKODE VARCHAR DEFAULT null,
KURS DECIMAL DEFAULT null,
VERSJON BIGINT DEFAULT 0 NOT NULL,
OPPRETTET_AV VARCHAR DEFAULT 'VL' NOT NULL,
OPPRETTET_TID TIMESTAMP(3) DEFAULT localtimestamp NOT NULL,
ENDRET_AV VARCHAR,
ENDRET_TID TIMESTAMP(3)
);

CREATE SEQUENCE ecbvalutakurscache_seq INCREMENT BY 50 START WITH 1 NO CYCLE;
CREATE INDEX valutakode_valutadato_idx ON ecbvalutakurscache (VALUTAKURSDATO, VALUTAKODE);
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.MockK
import io.mockk.junit5.MockKExtension
import io.mockk.unmockkAll
import no.nav.familie.ba.sak.integrasjoner.ecb.domene.ECBValutakursCache
import no.nav.familie.ba.sak.integrasjoner.ecb.domene.ECBValutakursCacheRepository
import no.nav.familie.valutakurs.Frequency
import no.nav.familie.valutakurs.ValutakursRestClient
import no.nav.familie.valutakurs.domene.ECBExchangeRate
Expand All @@ -31,6 +33,9 @@ class ECBServiceTest {
@MockK
private lateinit var ecbClient: ValutakursRestClient

@MockK
private lateinit var ECBValutakursCacheRepository: ECBValutakursCacheRepository

@InjectMockKs
private lateinit var ecbService: ECBService

Expand All @@ -47,6 +52,8 @@ class ECBServiceTest {
listOf(Pair("NOK", BigDecimal.valueOf(10.337)), Pair("SEK", BigDecimal.valueOf(10.6543))),
valutakursDato.toString(),
)
every { ECBValutakursCacheRepository.findByValutakodeAndValutakursdato(any(), any()) } returns null
every { ECBValutakursCacheRepository.save(any()) } returns ECBValutakursCache(kurs = BigDecimal.valueOf(10.6543), valutakode = "SEK", valutakursdato = valutakursDato)
every {
ecbClient.hentValutakurs(
Frequency.Daily,
Expand All @@ -66,6 +73,7 @@ class ECBServiceTest {
listOf(Pair("NOK", BigDecimal.valueOf(10.337))),
valutakursDato.toString(),
)
every { ECBValutakursCacheRepository.findByValutakodeAndValutakursdato(any(), any()) } returns null
every {
ecbClient.hentValutakurs(
Frequency.Daily,
Expand All @@ -84,6 +92,7 @@ class ECBServiceTest {
listOf(Pair("NOK", BigDecimal.valueOf(10.337)), Pair("SEK", BigDecimal.valueOf(10.6543))),
valutakursDato.minusDays(1).toString(),
)
every { ECBValutakursCacheRepository.findByValutakodeAndValutakursdato(any(), any()) } returns null
every {
ecbClient.hentValutakurs(
Frequency.Daily,
Expand All @@ -103,6 +112,8 @@ class ECBServiceTest {
listOf(Pair("NOK", BigDecimal.valueOf(9.4567))),
valutakursDato.toString(),
)
every { ECBValutakursCacheRepository.findByValutakodeAndValutakursdato(any(), any()) } returns null
every { ECBValutakursCacheRepository.save(any()) } returns ECBValutakursCache(kurs = BigDecimal.valueOf(9.4567), valutakode = "EUR", valutakursdato = valutakursDato)
every {
ecbClient.hentValutakurs(
Frequency.Daily,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package no.nav.familie.ba.sak.integrasjoner.ecb

import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.junit5.MockKExtension
import io.mockk.verify
import no.nav.familie.ba.sak.config.AbstractSpringIntegrationTest
import no.nav.familie.ba.sak.config.DatabaseCleanupService
import no.nav.familie.ba.sak.integrasjoner.ecb.domene.ECBValutakursCacheRepository
import no.nav.familie.valutakurs.Frequency
import no.nav.familie.valutakurs.ValutakursRestClient
import no.nav.familie.valutakurs.domene.ECBExchangeRate
import no.nav.familie.valutakurs.domene.ECBExchangeRateDate
import no.nav.familie.valutakurs.domene.ECBExchangeRateKey
import no.nav.familie.valutakurs.domene.ECBExchangeRateValue
import no.nav.familie.valutakurs.domene.ECBExchangeRatesData
import no.nav.familie.valutakurs.domene.ECBExchangeRatesDataSet
import no.nav.familie.valutakurs.domene.ECBExchangeRatesForCurrency
import no.nav.familie.valutakurs.domene.toExchangeRates
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import java.math.BigDecimal
import java.time.LocalDate

@ExtendWith(MockKExtension::class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ECBIntegrationTest : AbstractSpringIntegrationTest() {

@MockK
private lateinit var ecbClient: ValutakursRestClient

@Autowired
private lateinit var ecbService: ECBService

@Autowired
private lateinit var ecbValutakursCacheRepository: ECBValutakursCacheRepository

@Autowired
private lateinit var databaseCleanupService: DatabaseCleanupService

@BeforeEach
fun setUp() {
ecbService = ECBService(
ecbClient = ecbClient,
ecbValutakursCacheRepository = ecbValutakursCacheRepository,
)
databaseCleanupService.truncate()
}

@Test
fun `Skal teste at valutakurs hentes fra cache dersom valutakursen allerede er hentet fra ECB`() {
val valutakursDato = LocalDate.of(2022, 7, 20)
val ecbExchangeRatesData = createECBResponse(
Frequency.Daily,
listOf(Pair("NOK", BigDecimal.valueOf(9.4567))),
valutakursDato.toString(),
)
every {
ecbClient.hentValutakurs(
any(),
any(),
any(),
)
} returns ecbExchangeRatesData.toExchangeRates()

ecbService.hentValutakurs("EUR", valutakursDato)
val valutakurs = ecbValutakursCacheRepository.findByValutakodeAndValutakursdato("EUR", valutakursDato)
assertEquals(valutakurs!!.kurs, BigDecimal.valueOf(9.4567))
ecbService.hentValutakurs("EUR", valutakursDato)
verify(exactly = 1) {
ecbClient.hentValutakurs(
any(),
any(),
any(),
)
}
}

private fun createECBResponse(
frequency: Frequency,
exchangeRates: List<Pair<String, BigDecimal>>,
exchangeRateDate: String,
): ECBExchangeRatesData {
return ECBExchangeRatesData(
ECBExchangeRatesDataSet(
exchangeRates.map {
ECBExchangeRatesForCurrency(
listOf(
ECBExchangeRateKey("CURRENCY", it.first),
ECBExchangeRateKey("FREQ", frequency.toFrequencyParam()),
),
listOf(
ECBExchangeRate(
ECBExchangeRateDate(exchangeRateDate),
ECBExchangeRateValue((it.second)),
),
),
)
},
),
)
}
}

0 comments on commit 1dfeeea

Please sign in to comment.