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

Attesteringsendepunkter til å ligne det vanlige redigeringsløpet #1361

Merged
merged 2 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ fun Route.sakBrev(dto2ApiService: Dto2ApiService, brevredigeringService: Brevred
put<Api.OppdaterBrevRequest>("/{brevId}") { request ->
val brevId = call.parameters.getOrFail<Long>("brevId")
val sak: Pen.SakSelection = call.attributes[SakKey]
val frigiReservasjon = call.parameters["frigiReservasjon"].toBoolean()

brevredigeringService.oppdaterBrev(
saksId = sak.saksId,
brevId = brevId,
nyeSaksbehandlerValg = request.saksbehandlerValg,
nyttRedigertbrev = request.redigertBrev,
signatur = request.signatur,
frigiReservasjon = frigiReservasjon,
)?.onOk { brev -> call.respond(HttpStatusCode.OK, dto2ApiService.toApi(brev)) }
?.onError { message, statusCode ->
logger.error("$statusCode - Feil ved oppdatering av brev ${brevId}: $message")
Expand Down Expand Up @@ -132,16 +134,32 @@ fun Route.sakBrev(dto2ApiService: Dto2ApiService, brevredigeringService: Brevred
}

route("/{brevId}/attestering") {
post<Api.OppdaterAttesteringRequest> { request ->
get {
val sak: Pen.SakSelection = call.attributes[SakKey]
val brevId = call.parameters.getOrFail<Long>("brevId")
val reserver = call.parameters["reserver"].toBoolean()

brevredigeringService.hentBrevAttestering(sak.saksId, brevId, reserver)
?.onOk { call.respond(HttpStatusCode.OK, dto2ApiService.toApi(it)) }
?.onError { message, statusCode ->
call.application.log.error("$statusCode - Feil ved henting av brev: $message")
call.respond(HttpStatusCode.InternalServerError, "Feil ved henting av brev.")
}
?: call.respond(HttpStatusCode.NotFound, "Fant ikke brev med id: $brevId")
}

put<Api.OppdaterAttesteringRequest> { request ->
val brevId = call.parameters.getOrFail<Long>("brevId")
val sak: Pen.SakSelection = call.attributes[SakKey]
val frigiReservasjon = call.parameters["frigiReservasjon"].toBoolean()

brevredigeringService.oppdaterBrev(
brevredigeringService.attester(
saksId = sak.saksId,
brevId = brevId,
nyeSaksbehandlerValg = request.saksbehandlerValg,
nyttRedigertbrev = request.redigertBrev,
signaturAttestant = request.signaturAttestant,
frigiReservasjon = frigiReservasjon,
)?.onOk { brev -> call.respond(HttpStatusCode.OK, dto2ApiService.toApi(brev)) }
?.onError { message, statusCode ->
logger.error("$statusCode - Feil ved oppdatering av attestering ${brevId}: $message")
Expand All @@ -151,14 +169,6 @@ fun Route.sakBrev(dto2ApiService: Dto2ApiService, brevredigeringService: Brevred
}
}

// TODO: Flytt inn under /attestering
post("/{brevId}/attester") {
brevredigeringService.attester(brevId = call.parameters.getOrFail<Long>("brevId"), saksId = call.attributes[SakKey].saksId)
?.onOk { call.respondBytes(it, ContentType.Application.Pdf, HttpStatusCode.OK) }
?.onError { message, _ -> call.respond(HttpStatusCode.InternalServerError, message) }
?: call.respond(HttpStatusCode.NotFound, "Fant ikke brev")
}

post("/{brevId}/pdf/send") {
val brevId = call.parameters.getOrFail<Long>("brevId")
val sak: Pen.SakSelection = call.attributes[SakKey]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ class BrevredigeringService(
nyeSaksbehandlerValg: SaksbehandlerValg?,
nyttRedigertbrev: Edit.Letter?,
signatur: String? = null,
signaturAttestant: String? = null,
frigiReservasjon: Boolean = false,
): ServiceResult<Dto.Brevredigering>? =
hentBrevMedReservasjon(brevId = brevId, saksId = saksId) {
Expand All @@ -149,7 +148,6 @@ class BrevredigeringService(
brev = brevDto,
saksbehandlerValg = nyeSaksbehandlerValg ?: brevDto.saksbehandlerValg,
signaturSignerende = signatur ?: brevDto.info.signaturSignerende,
signaturAttestant = signaturAttestant ?: brevDto.info.signaturAttestant,
).map { rendretBrev ->
val principal = PrincipalInContext.require()
transaction {
Expand All @@ -159,7 +157,6 @@ class BrevredigeringService(
saksbehandlerValg = nyeSaksbehandlerValg ?: brevDto.saksbehandlerValg
sistRedigertAvNavIdent = principal.navIdent
signatur?.also { signaturSignerende = it }
signaturAttestant?.also { this.signaturAttestant = it }
if (frigiReservasjon) {
redigeresAvNavIdent = null
}
Expand All @@ -178,15 +175,16 @@ class BrevredigeringService(
hentBrevMedReservasjon(brevId = brevId, saksId = saksId) {
// Før brevet kan markeres som `laastForRedigering` (klar til sending) så må det valideres at brevet faktisk er klar til sending.
if (laastForRedigering == true) {
validerErFerdigRedigert(brevDto)
brevDto.validerErFerdigRedigert()
}

transaction {
brevDb.apply {
laastForRedigering?.also { this.laastForRedigering = it }
distribusjonstype?.also { this.distribusjonstype = it }
mottaker?.also { this.mottaker?.oppdater(mottaker) ?: Mottaker.new(brevId) { oppdater(mottaker) } }
}.also { Brevredigering.reload(it, true) }.toDto()
brevDb.laastForRedigering = laastForRedigering ?: brevDb.laastForRedigering
brevDb.distribusjonstype = distribusjonstype ?: brevDb.distribusjonstype
mottaker?.also { brevDb.mottaker?.oppdater(it) ?: Mottaker.new(brevId) { oppdater(it) } }
brevDb.redigeresAvNavIdent = null

Brevredigering.reload(brevDb, true)?.toDto()
}
}

Expand Down Expand Up @@ -244,6 +242,29 @@ class BrevredigeringService(
?.let { Ok(it) }
}

suspend fun hentBrevAttestering(saksId: Long, brevId: Long, reserverForRedigering: Boolean = false): ServiceResult<Dto.Brevredigering>? =
if (reserverForRedigering) {
hentBrevMedReservasjon(brevId = brevId, saksId = saksId) {
val principal = PrincipalInContext.require()
val signaturAttestant = brevDb.signaturAttestant
?: navansattService.hentNavansatt(principal.navIdent.id)?.let { "${it.fornavn} ${it.etternavn}" }
?: principal.fullName

if (brevDb.signaturAttestant == null) {
transaction { brevDb.signaturAttestant = signaturAttestant }
}

rendreBrev(brev = brevDto, signaturAttestant = signaturAttestant).map { rendretBrev ->
transaction {
brevDb.apply { redigertBrev = brevDto.redigertBrev.updateEditedLetter(rendretBrev) }.toDto()
}
}
}
} else {
transaction { Brevredigering.findByIdAndSaksId(brevId, saksId)?.toDto() }
?.let { Ok(it) }
}

fun hentBrevForSak(saksId: Long): List<Dto.BrevInfo> =
transaction {
Brevredigering.find { BrevredigeringTable.saksId eq saksId }
Expand Down Expand Up @@ -277,36 +298,44 @@ class BrevredigeringService(
}
}

suspend fun attester(saksId: Long, brevId: Long): ServiceResult<ByteArray>? {
if (!Features.attestant.isEnabled()) {
logger.debug("Attestering er skrudd av")
return hentEllerOpprettPdf(saksId, brevId)
}

val userPrincipal = PrincipalInContext.require()

return hentBrevMedReservasjon(brevId = brevId, saksId = saksId) {
validerErFerdigRedigert(brevDto)
validerKanAttestere(brevDto, userPrincipal)
suspend fun attester(
saksId: Long,
brevId: Long,
nyeSaksbehandlerValg: SaksbehandlerValg?,
nyttRedigertbrev: Edit.Letter?,
signaturAttestant: String?,
frigiReservasjon: Boolean = false,
): ServiceResult<Dto.Brevredigering>? =
hentBrevMedReservasjon(brevId = brevId, saksId = saksId) {
val principal = PrincipalInContext.require()
brevDto.validerErFerdigRedigert()
brevDto.validerKanAttestere(principal)

val signaturAttestant = brevDto.info.signaturAttestant
?: userPrincipal.navIdent.let { navansattService.hentNavansatt(it.id)?.navn }
?: userPrincipal.fullName
val signaturAttestant = signaturAttestant
?: brevDto.info.signaturAttestant
?: navansattService.hentNavansatt(principal.navIdent.id)?.let { "${it.fornavn} ${it.etternavn}" }
?: principal.fullName

rendreBrev(
brev = brevDto,
signaturAttestant = signaturAttestant
saksbehandlerValg = nyeSaksbehandlerValg,
signaturAttestant = signaturAttestant,
).map { rendretBrev ->
transaction {
brevDb.apply {
redigertBrev = brevDto.redigertBrev.updateEditedLetter(rendretBrev)
this.attestertAvNavIdent = userPrincipal.navIdent
redigertBrev = (nyttRedigertbrev ?: brevDto.redigertBrev).updateEditedLetter(rendretBrev)
sistredigert = Instant.now().truncatedTo(ChronoUnit.MILLIS)
saksbehandlerValg = nyeSaksbehandlerValg ?: brevDto.saksbehandlerValg
sistRedigertAvNavIdent = principal.navIdent
this.attestertAvNavIdent = principal.navIdent
this.signaturAttestant = signaturAttestant
if (frigiReservasjon) {
redigeresAvNavIdent = null
}
}.toDto()
}
}.then { opprettPdf(it) }
}
}
}

suspend fun sendBrev(saksId: Long, brevId: Long): ServiceResult<Pen.BestillBrevResponse>? {
val (brev, document) = transaction {
Expand All @@ -317,7 +346,7 @@ class BrevredigeringService(
if (!brev.info.laastForRedigering) {
throw BrevIkkeKlartTilSendingException("Brev må være markert som klar til sending")
}
validerErFerdigRedigert(brev)
brev.validerErFerdigRedigert()

val template = brevbakerService.getRedigerbarTemplate(brev.info.brevkode)

Expand Down Expand Up @@ -357,7 +386,7 @@ class BrevredigeringService(

private suspend fun validerVedtaksbrevAttestert(brev: Dto.Brevredigering, brevtype: LetterMetadata.Brevtype) {
if (Features.attestant.isEnabled() && brevtype == LetterMetadata.Brevtype.VEDTAKSBREV && brev.info.attestertAv == null) {
throw BrevIkkeKlartTilSendingException("Brevet ${brev.info.id} er ikke attestert.")
throw BrevIkkeKlartTilSendingException("Brev med id ${brev.info.id} er ikke attestert.")
}
}

Expand Down Expand Up @@ -505,25 +534,6 @@ class BrevredigeringService(
}
}

private fun validerErFerdigRedigert(brev: Dto.Brevredigering): Boolean =
brev.redigertBrev.klarTilSending() || throw BrevIkkeKlartTilSendingException("Brevet inneholder fritekst-felter som ikke er endret")

private fun validerKanAttestere(brev: Dto.Brevredigering, userPrincipal: UserPrincipal) {
if (!userPrincipal.isInGroup(ADGroups.attestant)) {
throw BrevredigeringException.HarIkkeAttestantrolleException(
"Bruker ${userPrincipal.navIdent} har ikke attestantrolle, brev ${brev.info.id}",
)
}
if (userPrincipal.navIdent == brev.info.opprettetAv) {
throw BrevredigeringException.KanIkkeAttestereEgetBrevException(
"Bruker ${userPrincipal.navIdent} prøver å attestere sitt eget brev, brev ${brev.info.id}",
)
}
if (brev.info.attestertAv != null && brev.info.attestertAv != userPrincipal.navIdent) {
throw BrevredigeringException.AlleredeAttestertException("Brev ${brev.info.id} er allerede attestert av ${brev.info.attestertAv}")
}
}

private fun Mottaker.oppdater(mottaker: Dto.Mottaker?) =
if (mottaker != null) {
type = mottaker.type
Expand All @@ -543,6 +553,25 @@ class BrevredigeringService(
}
}

private fun Dto.Brevredigering.validerErFerdigRedigert(): Boolean =
redigertBrev.klarTilSending() || throw BrevIkkeKlartTilSendingException("Brevet inneholder fritekst-felter som ikke er endret")

private fun Dto.Brevredigering.validerKanAttestere(userPrincipal: UserPrincipal) {
if (!userPrincipal.isInGroup(ADGroups.attestant)) {
throw BrevredigeringException.HarIkkeAttestantrolleException(
"Bruker ${userPrincipal.navIdent} har ikke attestantrolle, brev ${info.id}",
)
}
if (userPrincipal.navIdent == info.opprettetAv) {
throw BrevredigeringException.KanIkkeAttestereEgetBrevException(
"Bruker ${userPrincipal.navIdent} prøver å attestere sitt eget brev, brev ${info.id}",
)
}
if (info.attestertAv != null && info.attestertAv != userPrincipal.navIdent) {
throw BrevredigeringException.AlleredeAttestertException("Brev ${info.id} er allerede attestert av ${info.attestertAv}")
}
}

private fun SaksbehandlerValg.tilbakestill(modelSpec: TemplateModelSpecification): SaksbehandlerValg {
val saksbehandlerValgSpec = modelSpec.types[modelSpec.letterModelTypeName]?.get("saksbehandlerValg")
?.let { if (it is TemplateModelSpecification.FieldType.Object) it.typeName else null }
Expand Down
Loading