Skip to content

Commit

Permalink
Send udelte samtalereferat til oversikten (#897)
Browse files Browse the repository at this point in the history
* legg til funksjonalitet for melding til oversikten

* Legg til TODOs på steder der vi må agere

* Legg til sql-fil for oversikt-tabell

* Test at når udelte referater opprettes sendes melding til oversikten

* Fiks testoppsett

* Legg til TODOs på steder i koden der vi må sende melding

* WIP: Send startmelding

* WIP: Test at vi putter melding i utboksen

* Test sending av startmelding

* Send melding til oversikten

Signed-off-by: Henrik uran <[email protected]>

* Rensk opp ny databasetabell mellom hver test

* WIP: Lagre sendingsUuid

* oppdater flyway script for meldinger til oversikten for udelt samtalereferat

* legg til operasjon for melding til oversikten, og rename repository til dao

* legg til melding key for møte

* legg til håndtering av caser for melding til oversikten for møte og samtalereferat

* Set ny  meldinguuid

* cleanup håndtering av caser for melding til oversikten og bigquery

* Implementer lagret oversikten melding

* WIP: Ha egen mappingtabell for oversiktenmeldinger og aktiviteter

* Lag ID på ny tabell

* Lagre meldingKeyUuid i koblingstabell

* Legg til composite key opå meldingstabell

* Tilpass at hverken melding_key eller aktivitet_id er unike

* Fiks småting for at koden skal kjøre

* Fjern test som ikke er relevant

* Legg til enhetstest av oversiktenMelding

* legg til producer for sending av melding på kafka

* legg til funksjonalitet for å lagre stoppmelding om udelt samtalereferat

* Logg hvis meldingKey ikke eksisterer

* når samtalereferat deles med bruker sendes  top melding til oversikten test

Signed-off-by: Henrik uran <[email protected]>

* Test stoppmelding

* Legg til nytt testcase

* Bruk producer

* WIP: Test oversiktenService

* Fiks service tester

* Fiks navn på topic

* Test at melding blir markert som sendt

* Legg publisering av meldinger bak feature toggle

* Errorhåndtering

* endre schedule til hver time

* Legg til topic i application properties for test

* Legg til tabell i ryddeliste

* cleanup imports

---------

Signed-off-by: Henrik uran <[email protected]>
Co-authored-by: erikb <[email protected]>
Co-authored-by: Mads Lee Giil <[email protected]>
Co-authored-by: Henrik uran <[email protected]>
  • Loading branch information
4 people authored Dec 20, 2024
1 parent 666c7c8 commit 8746e73
Show file tree
Hide file tree
Showing 19 changed files with 743 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import no.nav.veilarbaktivitet.aktivitet.feil.EndringAvHistoriskAktivitetException;
import no.nav.veilarbaktivitet.eventsLogger.BigQueryClient;
import no.nav.veilarbaktivitet.eventsLogger.EventType;
import no.nav.veilarbaktivitet.oversikten.OversiktenService;
import no.nav.veilarbaktivitet.person.Person;
import no.nav.veilarbaktivitet.person.PersonService;
import org.slf4j.Logger;
Expand All @@ -31,6 +32,7 @@ public class AktivitetAppService {
private final MetricService metricService;
private final PersonService personService;
private final BigQueryClient bigQueryClient;
private final OversiktenService oversiktenService;

private static final Set<AktivitetTypeData> TYPER_SOM_KAN_ENDRES_EKSTERNT = new HashSet<>(Arrays.asList(
AktivitetTypeData.EGENAKTIVITET,
Expand Down Expand Up @@ -102,6 +104,16 @@ private static boolean erReferatetEndretForDetErPublisert(AktivitetData aktivite
return !aktivitetData.getMoteData().isReferatPublisert() && referatEndret;
}

private boolean referatErDeltMedBruker(AktivitetData nyAktivitet) {
if(nyAktivitet.getMoteData() == null) return false;
return nyAktivitet.getMoteData().isReferatPublisert();
}

private boolean nyopprettetAktivitetKanHaReferat(AktivitetData nyAktivitet) {
var aktivitetstyperSomKanHaReferatNårAktivitetOpprettes = List.of(AktivitetTypeData.SAMTALEREFERAT);
return aktivitetstyperSomKanHaReferatNårAktivitetOpprettes.contains(nyAktivitet.getAktivitetType());
}

@Transactional
public AktivitetData opprettNyAktivitet(AktivitetData aktivitetData) {

Expand All @@ -113,8 +125,14 @@ public AktivitetData opprettNyAktivitet(AktivitetData aktivitetData) {
}

AktivitetData nyAktivitet = aktivitetService.opprettAktivitet(aktivitetData);
if (nyAktivitet.getAktivitetType() == AktivitetTypeData.SAMTALEREFERAT || nyAktivitet.getAktivitetType() == AktivitetTypeData.MOTE) {
bigQueryClient.logEvent(nyAktivitet, EventType.SAMTALEREFERAT_OPPRETTET);

if (nyopprettetAktivitetKanHaReferat(nyAktivitet)) {
if (referatErDeltMedBruker(nyAktivitet)) {
bigQueryClient.logEvent(nyAktivitet, EventType.SAMTALEREFERAT_OPPRETTET_OG_DELT_MED_BRUKER);
} else {
bigQueryClient.logEvent(nyAktivitet, EventType.SAMTALEREFERAT_OPPRETTET);
oversiktenService.lagreStartMeldingOmUdeltSamtalereferatIUtboks(nyAktivitet.getAktorId(), nyAktivitet.getId());
}
}

// dette er gjort på grunn av KVP
Expand Down Expand Up @@ -229,21 +247,39 @@ public AktivitetData oppdaterReferat(AktivitetData aktivitet) {
final var originalAktivitet = hentAktivitet(aktivitet.getId());
kanEndreAktivitetGuard(originalAktivitet, aktivitet.getVersjon(), aktivitet.getAktorId());

var oppdatertAktivtiet = aktivitetService.oppdaterReferat(
originalAktivitet,
aktivitet
);
var oppdatertAktivitet = aktivitetService.oppdaterReferat(originalAktivitet, aktivitet);

var maybeEventType = hentEventTypePåSamtalereferat(originalAktivitet, aktivitet);
maybeEventType.ifPresent(eventType -> {
bigQueryClient.logEvent(oppdatertAktivitet, eventType);
sendMeldingTilOversikten(oppdatertAktivitet, eventType);
});
return oppdatertAktivitet;
}

if(!originalAktivitet.getMoteData().isReferatPublisert() && oppdatertAktivtiet.getMoteData().isReferatPublisert()) {
bigQueryClient.logEvent(oppdatertAktivtiet, EventType.SAMTALEREFERAT_DELT_MED_BRUKER);
private void sendMeldingTilOversikten(AktivitetData aktivitet, EventType eventType) {
if (eventType == EventType.SAMTALEREFERAT_OPPRETTET) { // Kan kun skje for aktivitetstype "Møte"
oversiktenService.lagreStartMeldingOmUdeltSamtalereferatIUtboks(aktivitet.getAktorId(), aktivitet.getId());
} else if (eventType == EventType.SAMTALEREFERAT_DELT_MED_BRUKER) {
oversiktenService.lagreStoppMeldingOmUdeltSamtalereferatIUtboks(aktivitet.getAktorId(), aktivitet.getId());
}
}

private Optional<EventType> hentEventTypePåSamtalereferat(AktivitetData originalAktivitet, AktivitetData oppdatertAktivitet) {
var forrigeReferat = Optional.ofNullable(originalAktivitet.getMoteData()).map(it -> it.getReferat()).orElse("");
var nesteReferat = Optional.ofNullable(oppdatertAktivtiet.getMoteData()).map(it -> it.getReferat()).orElse("");
if (forrigeReferat.isEmpty() && !nesteReferat.isEmpty() && oppdatertAktivtiet.getAktivitetType() == AktivitetTypeData.MOTE ) {
bigQueryClient.logEvent(oppdatertAktivtiet, EventType.SAMTALEREFERAT_FIKK_INNHOLD);
}
var nesteReferat = Optional.ofNullable(oppdatertAktivitet.getMoteData()).map(it -> it.getReferat()).orElse("");

return oppdatertAktivtiet;
}
var referatHarNåFåttInnhold = forrigeReferat.isEmpty() && !nesteReferat.isEmpty();
var referatHarNåBlittDeltMedBruker = !originalAktivitet.getMoteData().isReferatPublisert() && oppdatertAktivitet.getMoteData().isReferatPublisert();

if (referatHarNåFåttInnhold && !referatHarNåBlittDeltMedBruker) {
return Optional.of(EventType.SAMTALEREFERAT_OPPRETTET);
} else if (referatHarNåFåttInnhold && referatHarNåBlittDeltMedBruker) {
return Optional.of(EventType.SAMTALEREFERAT_OPPRETTET_OG_DELT_MED_BRUKER);
} else if (!referatHarNåFåttInnhold && referatHarNåBlittDeltMedBruker) {
return Optional.of(EventType.SAMTALEREFERAT_DELT_MED_BRUKER);
} else {
return Optional.empty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ public class MoteData {

String referat;
boolean referatPublisert;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,6 @@ class AktivitetsplanController(
@RequestBody aktivitet: AktivitetDTO,
@RequestParam(required = false, defaultValue = "false") automatisk: Boolean
): AktivitetDTO {
return internOpprettAktivitet(aktivitet, automatisk)
}

fun internOpprettAktivitet(aktivitet: AktivitetDTO, automatisk: Boolean): AktivitetDTO {
return aktivitetDataMapperService.mapTilAktivitetData(aktivitet)
.withAutomatiskOpprettet(automatisk)
.let { aktivitetData -> appService.opprettNyAktivitet(aktivitetData) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package no.nav.veilarbaktivitet.config

import com.fasterxml.jackson.annotation.JsonInclude
import no.nav.veilarbaktivitet.aktivitet.feil.*
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ControllerAdvice
Expand All @@ -13,6 +14,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep

@ControllerAdvice
class HttpExceptionHandler : ResponseEntityExceptionHandler() {
val log = LoggerFactory.getLogger(HttpExceptionHandler::class.java)

@ExceptionHandler(value = [EndringAvAktivitetException::class])
fun handleException(e: EndringAvAktivitetException, request: WebRequest): ResponseEntity<Response> {
Expand All @@ -32,6 +34,15 @@ class HttpExceptionHandler : ResponseEntityExceptionHandler() {
.body(Response(statusCode = e.statusCode.value(), message = e.reason))
}

@ExceptionHandler(value = [RuntimeException::class])
fun handleRuntimeException(e: RuntimeException, request: WebRequest): ResponseEntity<Response> {
val statusKode = HttpStatus.INTERNAL_SERVER_ERROR.value()
log.error("Feil i håndtering av kall", e)
return ResponseEntity
.status(statusKode)
.body(Response(statusCode = statusKode, message = "Noe gikk galt"))
}

@JsonInclude(JsonInclude.Include.NON_NULL)
data class Response(
val message: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum class EventType {
SAMTALEREFERAT_OPPRETTET,
SAMTALEREFERAT_FIKK_INNHOLD,
SAMTALEREFERAT_DELT_MED_BRUKER,
SAMTALEREFERAT_OPPRETTET_OG_DELT_MED_BRUKER,
}

data class SamtalereferatPublisertFordeling(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package no.nav.veilarbaktivitet.oversikten

import java.time.LocalDateTime

data class OversiktenMelding(
val personID: String,
val avsender: String = "veilarbaktivitet",
val kategori: Kategori,
val operasjon: Operasjon,
val hendelse: Hendelse
) {
companion object {
private fun baseUrlVeilarbpersonflate(erProd: Boolean) =
if (erProd) "https://veilarbpersonflate.intern.nav.no" else "https://veilarbpersonflate.ansatt.dev.nav.no"

fun forUdeltSamtalereferat(fnr: String, operasjon: Operasjon, erProd: Boolean) = OversiktenMelding(
personID = fnr,
kategori = Kategori.UDELT_SAMTALEREFERAT,
operasjon = operasjon,
hendelse = Hendelse(
beskrivelse = "Bruker har et udelt samtalereferat",
dato = LocalDateTime.now(),
lenke = "${baseUrlVeilarbpersonflate(erProd)}/aktivitetsplan",
)
)
}

data class Hendelse (
val beskrivelse: String,
val dato: LocalDateTime,
val lenke: String,
val detaljer: String? = null,
)

enum class Kategori {
UDELT_SAMTALEREFERAT
}

enum class Operasjon {
START,
OPPDATER,
STOPP
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package no.nav.veilarbaktivitet.oversikten

import no.nav.veilarbaktivitet.aktivitet.AktivitetId
import org.springframework.jdbc.core.RowMapper
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
import org.springframework.stereotype.Repository
import java.sql.ResultSet
import java.util.*

@Repository
open class OversiktenMeldingAktivitetMappingDAO(private val template: NamedParameterJdbcTemplate) {

open fun lagreKoblingMellomOversiktenMeldingOgAktivitet(oversiktenMeldingKey: MeldingKey, aktivitetId: AktivitetId, kategori: OversiktenMelding.Kategori) {
val sql = """
insert into oversikten_melding_aktivitet_mapping (oversikten_melding_key, aktivitet_id, kategori)
values (:oversiktenMeldingKey, :aktivitetId, :kategori::OVERSIKTEN_KATEGORI)
""".trimIndent()
val params = MapSqlParameterSource()
.addValue("oversiktenMeldingKey", oversiktenMeldingKey)
.addValue("aktivitetId", aktivitetId)
.addValue("kategori", kategori.name)
template.update(sql, params)
}

open fun hentMeldingKeyForAktivitet(aktivitetId: AktivitetId, kategori: OversiktenMelding.Kategori) : UUID? {
val sql = """
select oversikten_melding_key
from oversikten_melding_aktivitet_mapping
where aktivitet_id = :aktivitetId and kategori = :kategori::OVERSIKTEN_KATEGORI
""".trimIndent()

val params = mapOf("aktivitetId" to aktivitetId, "kategori" to kategori.name)

return template.queryForObject(sql, params, rowMapper)
}

open val rowMapper = RowMapper { rs: ResultSet, rowNum: Int ->
rs.getObject("oversikten_melding_key", UUID::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package no.nav.veilarbaktivitet.oversikten

import no.nav.common.types.identer.Fnr
import java.time.ZonedDateTime
import java.util.*

open class OversiktenMeldingMedMetadata(
val meldingKey: MeldingKey,
val fnr: Fnr,
val opprettet: ZonedDateTime = ZonedDateTime.now(),
val tidspunktSendt: ZonedDateTime? = null,
val utsendingStatus: UtsendingStatus = UtsendingStatus.SKAL_SENDES,
val meldingSomJson: String,
val kategori: OversiktenMelding.Kategori,
val operasjon: OversiktenMelding.Operasjon,
)

class LagretOversiktenMeldingMedMetadata(
val id: Long,
meldingKey: MeldingKey,
fnr: Fnr,
opprettet: ZonedDateTime,
tidspunktSendt: ZonedDateTime?,
utsendingStatus: UtsendingStatus,
meldingSomJson: String,
kategori: OversiktenMelding.Kategori,
operasjon: OversiktenMelding.Operasjon
) : OversiktenMeldingMedMetadata(
meldingKey = meldingKey,
fnr = fnr,
opprettet = opprettet,
tidspunktSendt = tidspunktSendt,
utsendingStatus = utsendingStatus,
meldingSomJson = meldingSomJson,
kategori = kategori,
operasjon = operasjon
)

typealias MeldingKey = UUID

enum class UtsendingStatus {
SKAL_SENDES,
SENDT,
SKAL_IKKE_SENDES
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package no.nav.veilarbaktivitet.oversikten

import no.nav.common.types.identer.Fnr
import no.nav.veilarbaktivitet.config.database.Database
import no.nav.veilarbaktivitet.veilarbdbutil.VeilarbAktivitetSqlParameterSource
import org.springframework.jdbc.core.RowMapper
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
import org.springframework.jdbc.support.GeneratedKeyHolder
import org.springframework.stereotype.Repository
import java.sql.ResultSet
import java.util.*

@Repository
open class OversiktenMeldingMedMetadataDAO(
private val jdbc: NamedParameterJdbcTemplate
) {
open fun lagre(oversiktenMeldingMedMetadata: OversiktenMeldingMedMetadata): Long {
val sql = """
INSERT INTO oversikten_melding_med_metadata (
fnr, opprettet, utsending_status, melding, kategori, melding_key, operasjon)
VALUES ( :fnr, :opprettet, :utsending_status::OVERSIKTEN_UTSENDING_STATUS, :melding::json, :kategori::OVERSIKTEN_KATEGORI, :melding_key, :operasjon::OVERSIKTEN_OPERASJON)
""".trimIndent()

val params = VeilarbAktivitetSqlParameterSource().apply {
addValue("fnr", oversiktenMeldingMedMetadata.fnr.get())
addValue("opprettet", oversiktenMeldingMedMetadata.opprettet)
addValue("utsending_status", oversiktenMeldingMedMetadata.utsendingStatus.name)
addValue("melding", oversiktenMeldingMedMetadata.meldingSomJson)
addValue("kategori", oversiktenMeldingMedMetadata.kategori.name)
addValue("melding_key", oversiktenMeldingMedMetadata.meldingKey)
addValue("operasjon", oversiktenMeldingMedMetadata.operasjon.name)
}

val keyHolder = GeneratedKeyHolder()
jdbc.update(sql, params, keyHolder, arrayOf("id"))

return keyHolder.key?.toLong() ?: throw IllegalStateException("Kunne ikke hente ut nøkkel til lagret melding")
}

open fun hentAlleSomSkalSendes(): List<LagretOversiktenMeldingMedMetadata> {
val sql = """
SELECT * FROM oversikten_melding_med_metadata WHERE utsending_status = 'SKAL_SENDES'
""".trimIndent()

return jdbc.query(sql, rowMapper)
}

open fun markerSomSendt(id: Long) {
val sql = """
UPDATE oversikten_melding_med_metadata
SET utsending_status = 'SENDT',
tidspunkt_sendt = now()
WHERE id = :id
""".trimIndent()

val params = VeilarbAktivitetSqlParameterSource().apply {
addValue("id", id)
}

jdbc.update(sql, params)
}

open fun hent(id : Long) : LagretOversiktenMeldingMedMetadata? {
val sql = """
SELECT * FROM oversikten_melding_med_metadata WHERE id = :id
""".trimIndent()

val params = VeilarbAktivitetSqlParameterSource().apply {
addValue("id", id)
}

return jdbc.queryForObject(sql, params, rowMapper)
}

open val rowMapper = RowMapper { rs: ResultSet, rowNum: Int ->
LagretOversiktenMeldingMedMetadata(
id = rs.getLong("id"),
fnr = Fnr.of(rs.getString("fnr")),
opprettet = Database.hentZonedDateTime(rs, "opprettet"),
tidspunktSendt = Database.hentZonedDateTime(rs, "tidspunkt_sendt"),
utsendingStatus = UtsendingStatus.valueOf(rs.getString("utsending_status")),
meldingSomJson = rs.getString("melding"),
kategori = OversiktenMelding.Kategori.valueOf(rs.getString("kategori")),
meldingKey = UUID.fromString(rs.getString("melding_key")),
operasjon = OversiktenMelding.Operasjon.valueOf(rs.getString("operasjon")),
)
}
}
Loading

0 comments on commit 8746e73

Please sign in to comment.