Skip to content

Commit

Permalink
feat(j-s): Indictment sent or withdrawn from prison notifications (#1…
Browse files Browse the repository at this point in the history
…6943)

* Add a send to fmst button that routes to a page

* Remove unused code

* Add UI

* Create event log when indictment is sent to FMSt

* Create event log when indictment is sent to FMSt

* Create event log when indictment is sent to FMSt

* Refactor

* Refactor

* Refactor

* Updates FMST queries

* Refactor

* Refactor

* Refactor

* Refactor

* Add DefendantEventLog table

* Refactor

* Send sentToPrisonAdminDate to client

* Show sent to prison admin date on info cards

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Frontend: Upload file to prison admin

* Frontend: Upload file to prison admin

* Add SentToPrisonAdmin tag in cases list for PP

* Merge

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* Refactor

* chore(j-s): Notifications to prison when indictment sent or withdrawn

* fix(j-s): Test fix

* chore: charts update dirty files

* fix(j-s): Tests

* chore: nx format:write update dirty files

* Refactor

* Remove caseId from defendant event log table

* Remove caseId from defendant event log table

* Revert

* Remove unused code

* Refactor

* Removes unused event type

* Removes the defendant event log from the api

* Moves defendant event log to defendant model

* Fixes backend case retrieval

* test(j-s): add missing test

* fix(j-s): Tests

* Update civilClaimantNotification.service.ts

* Reorders notification types to group related type together

---------

Co-authored-by: Ívar Oddsson <[email protected]>
Co-authored-by: Guðjón Guðjónsson <[email protected]>
Co-authored-by: andes-it <[email protected]>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
5 people authored Nov 27, 2024
1 parent ede53ec commit 14a7777
Show file tree
Hide file tree
Showing 25 changed files with 546 additions and 60 deletions.
2 changes: 2 additions & 0 deletions apps/judicial-system/backend/infra/judicial-system-backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ export const serviceSetup = (): ServiceBuilder<'judicial-system-backend'> =>
EMAIL_REPLY_TO_NAME: '/k8s/judicial-system/EMAIL_REPLY_TO_NAME',
PRISON_EMAIL: '/k8s/judicial-system/PRISON_EMAIL',
PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL',
PRISON_ADMIN_INDICTMENT_EMAILS:
'/k8s/judicial-system/PRISON_ADMIN_INDICTMENT_EMAILS',
AUTH_JWT_SECRET: '/k8s/judicial-system/AUTH_JWT_SECRET',
ADMIN_USERS: '/k8s/judicial-system/ADMIN_USERS',
BACKEND_ACCESS_TOKEN: '/k8s/judicial-system/BACKEND_ACCESS_TOKEN',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ export class DefendantService {
return message
}

private getMessagesForIndictmentToPrisonAdminChanges(
defendant: Defendant,
): Message {
const messageType =
defendant.isSentToPrisonAdmin === true
? DefendantNotificationType.INDICTMENT_SENT_TO_PRISON_ADMIN
: DefendantNotificationType.INDICTMENT_WITHDRAWN_FROM_PRISON_ADMIN

const message = {
type: MessageType.DEFENDANT_NOTIFICATION,
caseId: defendant.caseId,
elementId: defendant.id,
body: {
type: messageType,
},
}

return message
}

private getUpdatedDefendant(
numberOfAffectedRows: number,
defendants: Defendant[],
Expand Down Expand Up @@ -143,19 +163,19 @@ export class DefendantService {
return
}

const messages: Message[] = []

if (
updatedDefendant.isDefenderChoiceConfirmed &&
!oldDefendant.isDefenderChoiceConfirmed
) {
// Defender choice was just confirmed by the court
const messages: Message[] = [
{
type: MessageType.DELIVERY_TO_COURT_INDICTMENT_DEFENDER,
user,
caseId: theCase.id,
elementId: updatedDefendant.id,
},
]
messages.push({
type: MessageType.DELIVERY_TO_COURT_INDICTMENT_DEFENDER,
user,
caseId: theCase.id,
elementId: updatedDefendant.id,
})

if (
updatedDefendant.defenderChoice === DefenderChoice.CHOOSE ||
Expand All @@ -171,9 +191,20 @@ export class DefendantService {
})
}
}
} else if (
updatedDefendant.isSentToPrisonAdmin !== undefined &&
updatedDefendant.isSentToPrisonAdmin !== oldDefendant.isSentToPrisonAdmin
) {
messages.push(
this.getMessagesForIndictmentToPrisonAdminChanges(updatedDefendant),
)
}

return this.messageService.sendMessagesToQueue(messages)
if (messages.length === 0) {
return
}

return this.messageService.sendMessagesToQueue(messages)
}

async createForNewCase(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,58 @@ describe('DefendantController - Update', () => {
},
)

describe('defendant in indictment is sent to prison admin', () => {
const defendantUpdate = { isSentToPrisonAdmin: true }
const updatedDefendant = { ...defendant, ...defendantUpdate }

beforeEach(async () => {
const mockUpdate = mockDefendantModel.update as jest.Mock
mockUpdate.mockResolvedValueOnce([1, [updatedDefendant]])

await givenWhenThen(defendantUpdate, CaseType.INDICTMENT, caseId)
})

it('should queue messages', () => {
expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledWith([
{
type: MessageType.DEFENDANT_NOTIFICATION,
caseId,
elementId: defendantId,
body: {
type: DefendantNotificationType.INDICTMENT_SENT_TO_PRISON_ADMIN,
},
},
])
expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledTimes(1)
})
})

describe('defendant in indictment is withdrawn from prison admin', () => {
const defendantUpdate = { isSentToPrisonAdmin: false }
const updatedDefendant = { ...defendant, ...defendantUpdate }

beforeEach(async () => {
const mockUpdate = mockDefendantModel.update as jest.Mock
mockUpdate.mockResolvedValueOnce([1, [updatedDefendant]])

await givenWhenThen(defendantUpdate, CaseType.INDICTMENT, caseId)
})

it('should queue messages for indictment withdrawn from prison admin', () => {
expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledWith([
{
type: MessageType.DEFENDANT_NOTIFICATION,
caseId,
elementId: defendantId,
body: {
type: DefendantNotificationType.INDICTMENT_WITHDRAWN_FROM_PRISON_ADMIN,
},
},
])
expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledTimes(1)
})
})

describe('defendant update fails', () => {
let then: Then

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ import { InstitutionNotificationDto } from './dto/institutionNotification.dto'
import { NotificationDispatchDto } from './dto/notificationDispatch.dto'
import { SubpoenaNotificationDto } from './dto/subpoenaNotification.dto'
import { DeliverResponse } from './models/deliver.response'
import { CaseNotificationService } from './caseNotification.service'
import { CivilClaimantNotificationService } from './civilClaimantNotification.service'
import { DefendantNotificationService } from './defendantNotification.service'
import { InstitutionNotificationService } from './institutionNotification.service'
import { CaseNotificationService } from './services/caseNotification/caseNotification.service'
import { CivilClaimantNotificationService } from './services/civilClaimantNotification/civilClaimantNotification.service'
import { DefendantNotificationService } from './services/defendantNotification/defendantNotification.service'
import { InstitutionNotificationService } from './services/institutionNotification/institutionNotification.service'
import { SubpoenaNotificationService } from './services/subpoenaNotification/subpoenaNotification.service'
import { NotificationDispatchService } from './notificationDispatch.service'
import { SubpoenaNotificationService } from './subpoenaNotification.service'

@UseGuards(TokenGuard)
@Controller('api/internal')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export const notificationModuleConfig = defineConfig({
replyToName: env.required('EMAIL_REPLY_TO_NAME', 'Réttarvörslugátt'),
prisonEmail: env.required('PRISON_EMAIL', ''),
prisonAdminEmail: env.required('PRISON_ADMIN_EMAIL', ''),
prisonAdminIndictmentEmails: env.required(
'PRISON_ADMIN_INDICTMENT_EMAILS',
'',
),
courtsEmails: env.requiredJSON('COURTS_EMAILS', {}) as {
[key: string]: string
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import {
UserModule,
} from '../index'
import { Notification } from './models/notification.model'
import { CaseNotificationService } from './caseNotification.service'
import { CivilClaimantNotificationService } from './civilClaimantNotification.service'
import { DefendantNotificationService } from './defendantNotification.service'
import { InstitutionNotificationService } from './institutionNotification.service'
import { CaseNotificationService } from './services/caseNotification/caseNotification.service'
import { CivilClaimantNotificationService } from './services/civilClaimantNotification/civilClaimantNotification.service'
import { DefendantNotificationService } from './services/defendantNotification/defendantNotification.service'
import { InstitutionNotificationService } from './services/institutionNotification/institutionNotification.service'
import { SubpoenaNotificationService } from './services/subpoenaNotification/subpoenaNotification.service'
import { InternalNotificationController } from './internalNotification.controller'
import { NotificationController } from './notification.controller'
import { NotificationService } from './notification.service'
import { NotificationDispatchService } from './notificationDispatch.service'
import { SubpoenaNotificationService } from './subpoenaNotification.service'

@Module({
imports: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,20 @@ import {
formatProsecutorCourtDateEmailNotification,
formatProsecutorReadyForCourtEmailNotification,
formatProsecutorReceivedByCourtSmsNotification,
} from '../../formatters'
import { notifications } from '../../messages'
import { type Case, DateLog } from '../case'
import { CourtService } from '../court'
} from '../../../../formatters'
import { notifications } from '../../../../messages'
import { type Case, DateLog } from '../../../case'
import { CourtService } from '../../../court'
import {
type CivilClaimant,
type Defendant,
DefendantService,
} from '../defendant'
import { EventService } from '../event'
import { DeliverResponse } from './models/deliver.response'
import { Notification, Recipient } from './models/notification.model'
import { BaseNotificationService } from './baseNotification.service'
import { notificationModuleConfig } from './notification.config'
} from '../../../defendant'
import { EventService } from '../../../event'
import { BaseNotificationService } from '../../baseNotification.service'
import { DeliverResponse } from '../../models/deliver.response'
import { Notification, Recipient } from '../../models/notification.model'
import { notificationModuleConfig } from '../../notification.config'

interface Attachment {
filename: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import { DEFENDER_INDICTMENT_ROUTE } from '@island.is/judicial-system/consts'
import { capitalize } from '@island.is/judicial-system/formatters'
import { CivilClaimantNotificationType } from '@island.is/judicial-system/types'

import { Case } from '../case'
import { CivilClaimant } from '../defendant'
import { EventService } from '../event'
import { DeliverResponse } from './models/deliver.response'
import { Notification, Recipient } from './models/notification.model'
import { BaseNotificationService } from './baseNotification.service'
import { Case } from '../../../case'
import { CivilClaimant } from '../../../defendant'
import { EventService } from '../../../event'
import { BaseNotificationService } from '../../baseNotification.service'
import { DeliverResponse } from '../../models/deliver.response'
import { Notification, Recipient } from '../../models/notification.model'
import { notificationModuleConfig } from '../../notification.config'
import { strings } from './civilClaimantNotification.strings'
import { notificationModuleConfig } from './notification.config'

@Injectable()
export class CivilClaimantNotificationService extends BaseNotificationService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import {
isIndictmentCase,
} from '@island.is/judicial-system/types'

import { Case } from '../case'
import { Defendant } from '../defendant'
import { EventService } from '../event'
import { DeliverResponse } from './models/deliver.response'
import { Notification, Recipient } from './models/notification.model'
import { BaseNotificationService } from './baseNotification.service'
import { Case } from '../../../case'
import { Defendant } from '../../../defendant'
import { EventService } from '../../../event'
import { BaseNotificationService } from '../../baseNotification.service'
import { DeliverResponse } from '../../models/deliver.response'
import { Notification, Recipient } from '../../models/notification.model'
import { notificationModuleConfig } from '../../notification.config'
import { strings } from './defendantNotification.strings'
import { notificationModuleConfig } from './notification.config'

@Injectable()
export class DefendantNotificationService extends BaseNotificationService {
Expand Down Expand Up @@ -179,6 +179,80 @@ export class DefendantNotificationService extends BaseNotificationService {
return { delivered: true }
}

private sendIndictmentSentToPrisonAdminNotification(theCase: Case) {
const formattedSubject = this.formatMessage(
strings.indictmentSentToPrisonAdminSubject,
{
courtCaseNumber: theCase.courtCaseNumber,
},
)

const formattedBody = this.formatMessage(
strings.indictmentSentToPrisonAdminBody,
{
courtCaseNumber: theCase.courtCaseNumber,
linkStart: `<a href="${this.config.clientUrl}${ROUTE_HANDLER_ROUTE}/${theCase.id}">`,
linkEnd: '</a>',
},
)

// We want to send separate emails to each recipient
const to = this.config.email.prisonAdminIndictmentEmails
.split(',')
.map((email) => email.trim())
.map((email) => {
return {
name: 'Fangelsismálastofnun',
email,
}
})

return this.sendEmails(
theCase,
DefendantNotificationType.INDICTMENT_SENT_TO_PRISON_ADMIN,
formattedSubject,
formattedBody,
to,
)
}

private sendIndictmentWithdrawnFromPrisonAdminNotification(theCase: Case) {
const courtCaseNumber = theCase.courtCaseNumber

const formattedSubject = this.formatMessage(
strings.indictmentWithdrawnFromPrisonAdminSubject,
{
courtCaseNumber,
},
)

const formattedBody = this.formatMessage(
strings.indictmentWithdrawnFromPrisonAdminBody,
{
courtCaseNumber,
},
)

// We want to send separate emails to each recipient
const to = this.config.email.prisonAdminIndictmentEmails
.split(',')
.map((email) => email.trim())
.map((email) => {
return {
name: 'Fangelsismálastofnun',
email,
}
})

return this.sendEmails(
theCase,
DefendantNotificationType.INDICTMENT_WITHDRAWN_FROM_PRISON_ADMIN,
formattedSubject,
formattedBody,
to,
)
}

private sendNotification(
notificationType: DefendantNotificationType,
theCase: Case,
Expand All @@ -189,6 +263,10 @@ export class DefendantNotificationService extends BaseNotificationService {
return this.sendDefendantSelectedDefenderNotification(theCase)
case DefendantNotificationType.DEFENDER_ASSIGNED:
return this.sendDefenderAssignedNotification(theCase, defendant)
case DefendantNotificationType.INDICTMENT_SENT_TO_PRISON_ADMIN:
return this.sendIndictmentSentToPrisonAdminNotification(theCase)
case DefendantNotificationType.INDICTMENT_WITHDRAWN_FROM_PRISON_ADMIN:
return this.sendIndictmentWithdrawnFromPrisonAdminNotification(theCase)
default:
throw new InternalServerErrorException(
`Invalid notification type: ${notificationType}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,29 @@ export const strings = {
description:
'Body of the notification when a defender is assigned a confirmed as a defender in indictment cases',
}),
indictmentSentToPrisonAdminSubject: defineMessage({
id: 'judicial.system.backend:defendant_notifications.indictment_sent_to_prison_admin_subject',
defaultMessage: 'Mál {courtCaseNumber} til fullnustu',
description:
'Titill í tilkynningu til FMST þegar mál er sent til fullnustu',
}),
indictmentSentToPrisonAdminBody: defineMessage({
id: 'judicial.system.backend:defendant_notifications.indictment_sent_to_prison_admin_body',
defaultMessage:
'Ríkissaksóknari hefur sent mál {courtCaseNumber} til fullnustu.<br /><br />Skjöl málsins eru aðgengileg á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}.',
description: 'Texti í tilkynningu til FMST þegar mál er sent til fullnustu',
}),
indictmentWithdrawnFromPrisonAdminSubject: defineMessage({
id: 'judicial.system.backend:defendant_notifications.indictment_withdrawn_from_prison_admin_subject',
defaultMessage: 'Mál {courtCaseNumber} afturkallað úr fullnustu',
description:
'Titill í tilkynningu til FMST þegar mál er afturkallað úr fullnustu',
}),
indictmentWithdrawnFromPrisonAdminBody: defineMessage({
id: 'judicial.system.backend:defendant_notifications.indictment_withdrawn_from_prison_admin_body',
defaultMessage:
'Ríkissaksóknari hefur afturkallað mál {courtCaseNumber} úr fullnustu.',
description:
'Texti í tilkynningu til FMST þegar mál er afturkallað úr fullnustu',
}),
}
Loading

0 comments on commit 14a7777

Please sign in to comment.