From a93ba04109e158831b0b2e4dcc39085aedf9e095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frode=20Lind=C3=A5s?= Date: Wed, 9 Oct 2024 14:17:35 +0200 Subject: [PATCH] =?UTF-8?q?Lagt=20p=C3=A5=20st=C3=B8tte=20for=20optimistis?= =?UTF-8?q?k=20l=C3=A5sing.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/no/nav/aap/oppgave/OppgaveDto.kt | 2 + .../kotlin/no/nav/aap/oppgave/OppgaveId.kt | 6 +++ .../nav/aap/oppgave/plukk/NesteOppgaveDto.kt | 1 + .../kotlin/no/nav/aap/oppgave/OppgaveId.kt | 4 -- .../no/nav/aap/oppgave/OppgaveRepository.kt | 52 +++++++++++++------ .../oppdater/OppdaterOppgaveService.kt | 10 ++-- .../aap/oppgave/plukk/PlukkOppgaveService.kt | 2 +- .../oppgave/plukk/ReserverOppgaveService.kt | 13 ++--- .../nav/aap/oppgave/OppgaveRepositoryTest.kt | 11 ++-- ...__Nytt_felt_versjon_p\303\245_oppgave.sql" | 1 + 10 files changed, 67 insertions(+), 35 deletions(-) create mode 100644 api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/OppgaveId.kt delete mode 100644 app/src/main/kotlin/no/nav/aap/oppgave/OppgaveId.kt create mode 100644 "dbflyway/src/main/resources/flyway/V1.5__Nytt_felt_versjon_p\303\245_oppgave.sql" diff --git a/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/OppgaveDto.kt b/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/OppgaveDto.kt index 979cde5..77e2096 100644 --- a/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/OppgaveDto.kt +++ b/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/OppgaveDto.kt @@ -20,6 +20,7 @@ data class OppgaveDto( val opprettetTidspunkt: LocalDateTime, val endretAv: String? = null, val endretTidspunkt: LocalDateTime? = null, + val versjon: Long = 0 ) { init { if (journalpostId == null) { @@ -37,4 +38,5 @@ data class OppgaveDto( this.avklaringsbehovKode ) } + } diff --git a/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/OppgaveId.kt b/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/OppgaveId.kt new file mode 100644 index 0000000..2575cc3 --- /dev/null +++ b/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/OppgaveId.kt @@ -0,0 +1,6 @@ +package no.nav.aap.oppgave + +data class OppgaveId( + val id: Long, + val versjon: Long +) \ No newline at end of file diff --git a/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/plukk/NesteOppgaveDto.kt b/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/plukk/NesteOppgaveDto.kt index eecebc8..5893c7f 100644 --- a/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/plukk/NesteOppgaveDto.kt +++ b/api-kontrakt/src/main/kotlin/no/nav/aap/oppgave/plukk/NesteOppgaveDto.kt @@ -4,5 +4,6 @@ import no.nav.aap.oppgave.AvklaringsbehovReferanseDto data class NesteOppgaveDto( val oppgaveId: Long, + val oppgaveVersjon: Long, val avklaringsbehovReferanse: AvklaringsbehovReferanseDto, ) diff --git a/app/src/main/kotlin/no/nav/aap/oppgave/OppgaveId.kt b/app/src/main/kotlin/no/nav/aap/oppgave/OppgaveId.kt deleted file mode 100644 index bf4647e..0000000 --- a/app/src/main/kotlin/no/nav/aap/oppgave/OppgaveId.kt +++ /dev/null @@ -1,4 +0,0 @@ -package no.nav.aap.oppgave - -@JvmInline -value class OppgaveId(val id: Long) \ No newline at end of file diff --git a/app/src/main/kotlin/no/nav/aap/oppgave/OppgaveRepository.kt b/app/src/main/kotlin/no/nav/aap/oppgave/OppgaveRepository.kt index f6377cd..aee93c5 100644 --- a/app/src/main/kotlin/no/nav/aap/oppgave/OppgaveRepository.kt +++ b/app/src/main/kotlin/no/nav/aap/oppgave/OppgaveRepository.kt @@ -44,7 +44,7 @@ class OppgaveRepository(private val connection: DBConnection) { setLocalDateTime(9, oppgaveDto.opprettetTidspunkt) } } - return OppgaveId(id) + return OppgaveId(id, 0L) } fun hentOppgave(avklaringsbehovReferanse: AvklaringsbehovReferanseDto): OppgaveDto? { @@ -109,8 +109,6 @@ class OppgaveRepository(private val connection: DBConnection) { } } - - fun gjenåpneOppgave(oppgaveId: OppgaveId, ident: String) { val query = """ UPDATE @@ -118,16 +116,21 @@ class OppgaveRepository(private val connection: DBConnection) { SET STATUS = 'OPPRETTET', ENDRET_AV = ?, - ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP + ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP, + VERSJON = VERSJON + 1 WHERE ID = ? AND - STATUS != 'OPPRETTET' + STATUS != 'OPPRETTET' AND + VERSJON = ? + """.trimIndent() connection.execute(query) { setParams { setString(1, ident) setLong(2, oppgaveId.id) + setLong(3, oppgaveId.versjon) } + setResultValidator { require(it == 1) } } } @@ -140,17 +143,20 @@ class OppgaveRepository(private val connection: DBConnection) { ENDRET_AV = ?, ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP, RESERVERT_AV = NULL, - RESERVERT_TIDSPUNKT = NULL - + RESERVERT_TIDSPUNKT = NULL, + VERSJON = VERSJON + 1 WHERE ID = ? AND - STATUS != 'AVSLUTTET' + STATUS != 'AVSLUTTET' AND + VERSJON = ? """.trimIndent() connection.execute(query) { setParams { setString(1, ident) setLong(2, oppgaveId.id) + setLong(3, oppgaveId.versjon) } + setResultValidator { require(it == 1) } } } @@ -162,23 +168,27 @@ class OppgaveRepository(private val connection: DBConnection) { RESERVERT_AV = NULL, RESERVERT_TIDSPUNKT = NULL, ENDRET_AV = ?, - ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP + ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP, + VERSJON = VERSJON + 1 WHERE ID = ? AND - STATUS != 'AVSLUTTET' + STATUS != 'AVSLUTTET' AND + VERSJON = ? """.trimIndent() connection.execute(query) { setParams { setString(1, ident) setLong(2, oppgaveId.id) + setLong(3, oppgaveId.versjon) } + setResultValidator { require(it == 1) } } } fun finnNesteOppgave(filterDto: FilterDto): NesteOppgaveDto? { val hentNesteOppgaveQuery = """ SELECT - ID, SAKSNUMMER, BEHANDLING_REF, JOURNALPOST_ID, AVKLARINGSBEHOV_TYPE + ID, VERSJON, SAKSNUMMER, BEHANDLING_REF, JOURNALPOST_ID, AVKLARINGSBEHOV_TYPE FROM OPPGAVE WHERE @@ -193,6 +203,7 @@ class OppgaveRepository(private val connection: DBConnection) { setRowMapper { NesteOppgaveDto( oppgaveId = it.getLong("ID"), + oppgaveVersjon = it.getLong("VERSJON"), AvklaringsbehovReferanseDto( saksnummer = it.getStringOrNull("SAKSNUMMER"), referanse = it.getUUIDOrNull("BEHANDLING_REF"), @@ -213,8 +224,11 @@ class OppgaveRepository(private val connection: DBConnection) { RESERVERT_AV = ?, RESERVERT_TIDSPUNKT = CURRENT_TIMESTAMP, ENDRET_AV = ?, - ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP - WHERE ID = ? + ENDRET_TIDSPUNKT = CURRENT_TIMESTAMP, + VERSJON = VERSJON + 1 + WHERE + ID = ? AND + VERSJON = ? """.trimIndent() connection.execute(updaterOppgaveReservasjonQuery) { @@ -222,7 +236,9 @@ class OppgaveRepository(private val connection: DBConnection) { setString(1, reservertAvIdent) setString(2, ident) setLong(3, oppgaveId.id) + setLong(4, oppgaveId.versjon) } + setResultValidator { require(it == 1) } } } @@ -270,7 +286,7 @@ class OppgaveRepository(private val connection: DBConnection) { val journalpostIdClause = if (avklaringsbehovReferanse.journalpostId != null) "JOURNALPOST_ID = ?" else "JOURNALPOST_ID IS NULL" val oppgaverForReferanseQuery = """ SELECT - ID + ID, VERSJON FROM OPPGAVE WHERE @@ -290,7 +306,7 @@ class OppgaveRepository(private val connection: DBConnection) { setString(index++, avklaringsbehovReferanse.avklaringsbehovKode) } setRowMapper { row -> - OppgaveId(row.getLong("ID")) + OppgaveId(row.getLong("ID"), row.getLong("VERSJON")) } } if (oppgaver.size > 1) { @@ -325,7 +341,8 @@ class OppgaveRepository(private val connection: DBConnection) { opprettetAv = row.getString("OPPRETTET_AV"), opprettetTidspunkt = row.getLocalDateTime("OPPRETTET_TIDSPUNKT"), endretAv = row.getStringOrNull("ENDRET_AV"), - endretTidspunkt = row.getLocalDateTimeOrNull("ENDRET_TIDSPUNKT") + endretTidspunkt = row.getLocalDateTimeOrNull("ENDRET_TIDSPUNKT"), + versjon = row.getLong("VERSJON"), ) } @@ -344,7 +361,8 @@ class OppgaveRepository(private val connection: DBConnection) { OPPRETTET_AV, OPPRETTET_TIDSPUNKT, ENDRET_AV, - ENDRET_TIDSPUNKT + ENDRET_TIDSPUNKT, + VERSJON """.trimIndent() } diff --git a/app/src/main/kotlin/no/nav/aap/oppgave/oppdater/OppdaterOppgaveService.kt b/app/src/main/kotlin/no/nav/aap/oppgave/oppdater/OppdaterOppgaveService.kt index 199e307..d9496c4 100644 --- a/app/src/main/kotlin/no/nav/aap/oppgave/oppdater/OppdaterOppgaveService.kt +++ b/app/src/main/kotlin/no/nav/aap/oppgave/oppdater/OppdaterOppgaveService.kt @@ -89,14 +89,14 @@ class OppdaterOppgaveService(private val connection: DBConnection) { ) { val eksisterendeOppgave = oppgaveMap[avklaringsbehov.avklaringsbehovKode] if (eksisterendeOppgave != null && eksisterendeOppgave.status == no.nav.aap.oppgave.verdityper.Status.AVSLUTTET) { - oppgaveRepo.gjenåpneOppgave(OppgaveId(eksisterendeOppgave.id!!), "Kelvin") + oppgaveRepo.gjenåpneOppgave(eksisterendeOppgave.oppgaveId(), "Kelvin") if (avklaringsbehov.status in setOf( AvklaringsbehovStatus.SENDT_TILBAKE_FRA_KVALITETSSIKRER, AvklaringsbehovStatus.SENDT_TILBAKE_FRA_BESLUTTER) ) { val sistEndretAv = avklaringsbehov.sistEndretAv() if (sistEndretAv != null && sistEndretAv != "Kelvin") { - oppgaveRepo.reserverOppgave(OppgaveId(eksisterendeOppgave.id!!), "Kelvin", sistEndretAv) + oppgaveRepo.reserverOppgave(eksisterendeOppgave.oppgaveId(), "Kelvin", sistEndretAv) } } } @@ -138,7 +138,7 @@ class OppdaterOppgaveService(private val connection: DBConnection) { private fun avslutteOppgaver(oppgaver: List, oppgaveRepo: OppgaveRepository) { oppgaver .filter { it.status != no.nav.aap.oppgave.verdityper.Status.AVSLUTTET } - .forEach { oppgaveRepo.avsluttOppgave(OppgaveId(it.id!!), "Kelvin") } + .forEach { oppgaveRepo.avsluttOppgave(it.oppgaveId(), "Kelvin") } } private fun OppgaveOppdatering.hvemLøsteForrigeAvklaringsbehov(): Pair? { @@ -179,7 +179,9 @@ class OppdaterOppgaveService(private val connection: DBConnection) { avklaringsbehovKode = avklaringsbehovKode.kode, behandlingstype = behandlingstype, opprettetAv = ident, - opprettetTidspunkt = LocalDateTime.now() + opprettetTidspunkt = LocalDateTime.now(), ) } + + private fun OppgaveDto.oppgaveId() = OppgaveId(this.id!!, this.versjon) } \ No newline at end of file diff --git a/app/src/main/kotlin/no/nav/aap/oppgave/plukk/PlukkOppgaveService.kt b/app/src/main/kotlin/no/nav/aap/oppgave/plukk/PlukkOppgaveService.kt index 54e3944..5813274 100644 --- a/app/src/main/kotlin/no/nav/aap/oppgave/plukk/PlukkOppgaveService.kt +++ b/app/src/main/kotlin/no/nav/aap/oppgave/plukk/PlukkOppgaveService.kt @@ -42,7 +42,7 @@ class PlukkOppgaveService(val connection: DBConnection) { ) if (harTilgang) { - oppgaveRepo.reserverOppgave(OppgaveId(nesteOppgave.oppgaveId), ident, ident) + oppgaveRepo.reserverOppgave(OppgaveId(nesteOppgave.oppgaveId, nesteOppgave.oppgaveVersjon), ident, ident) } } diff --git a/app/src/main/kotlin/no/nav/aap/oppgave/plukk/ReserverOppgaveService.kt b/app/src/main/kotlin/no/nav/aap/oppgave/plukk/ReserverOppgaveService.kt index a6cdc09..18ab2c1 100644 --- a/app/src/main/kotlin/no/nav/aap/oppgave/plukk/ReserverOppgaveService.kt +++ b/app/src/main/kotlin/no/nav/aap/oppgave/plukk/ReserverOppgaveService.kt @@ -43,21 +43,22 @@ class ReserverOppgaveService(val connection: DBConnection) { if (harTilgang) { val oppgaveRepo = OppgaveRepository(connection) oppgaverSomSkalReserveres.forEach { - oppgaveRepo.reserverOppgave(OppgaveId(it.id), ident, ident) + oppgaveRepo.reserverOppgave(it, ident, ident) } return oppgaverSomSkalReserveres } return listOf() } - fun reserverOppgaveUtenTilgangskontroll( - avklaringsbehovReferanse: AvklaringsbehovReferanseDto, - ident: String - ): List { + /** + * Reserver oppgave uten kall mot tilgangkontroll - brukes når oppgave skal reserveres av behandlingsprosess uten + * uten noen innloggingskontekst. + */ + fun reserverOppgaveUtenTilgangskontroll(avklaringsbehovReferanse: AvklaringsbehovReferanseDto, ident: String): List { val oppgaveRepo = OppgaveRepository(connection) val oppgaverSomSkalReserveres = oppgaveRepo.hentÅpneOppgaver(avklaringsbehovReferanse) oppgaverSomSkalReserveres.forEach { - oppgaveRepo.reserverOppgave(OppgaveId(it.id), ident, ident) + oppgaveRepo.reserverOppgave(it, ident, ident) } return oppgaverSomSkalReserveres } diff --git a/app/src/test/kotlin/no/nav/aap/oppgave/OppgaveRepositoryTest.kt b/app/src/test/kotlin/no/nav/aap/oppgave/OppgaveRepositoryTest.kt index b077f45..672963f 100644 --- a/app/src/test/kotlin/no/nav/aap/oppgave/OppgaveRepositoryTest.kt +++ b/app/src/test/kotlin/no/nav/aap/oppgave/OppgaveRepositoryTest.kt @@ -91,11 +91,16 @@ class OppgaveRepositoryTest { reserverOppgave(oppgaveId2, "bruker2") reserverOppgave(oppgaveId3, "bruker1") reserverOppgave(oppgaveId4, "bruker1") - avsluttOppgave(oppgaveId4) + + val mineOppgaverFørAvslutt = mineOppgave("bruker1") + assertThat(mineOppgaverFørAvslutt).hasSize(3) + + val oppgaveSomSkalAvsluttes = mineOppgaverFørAvslutt.first { it.id == oppgaveId4.id } + avsluttOppgave(OppgaveId(oppgaveSomSkalAvsluttes.id!!, oppgaveSomSkalAvsluttes.versjon)) InitTestDatabase.dataSource.transaction { connection -> val oppgaver = OppgaveRepository(connection).hentMineOppgaver("bruker1") - assertThat(oppgaver.size).isEqualTo(2) + assertThat(oppgaver).hasSize(2) } } @@ -107,7 +112,7 @@ class OppgaveRepositoryTest { var mineOppgaver = mineOppgave("saksbehandler1") assertThat(mineOppgaver).hasSize(1) - avreserverOppgave(oppgaveId, "saksbehandler1") + avreserverOppgave(OppgaveId(mineOppgaver.first().id!!, mineOppgaver.first().versjon), "saksbehandler1") mineOppgaver = mineOppgave("saksbehandler1") assertThat(mineOppgaver).hasSize(0) } diff --git "a/dbflyway/src/main/resources/flyway/V1.5__Nytt_felt_versjon_p\303\245_oppgave.sql" "b/dbflyway/src/main/resources/flyway/V1.5__Nytt_felt_versjon_p\303\245_oppgave.sql" new file mode 100644 index 0000000..86eccc1 --- /dev/null +++ "b/dbflyway/src/main/resources/flyway/V1.5__Nytt_felt_versjon_p\303\245_oppgave.sql" @@ -0,0 +1 @@ +ALTER TABLE OPPGAVE ADD COLUMN VERSJON BIGINT DEFAULT 0 NOT NULL; \ No newline at end of file