Skip to content

Commit

Permalink
chore(j-s): Notifications to advocates in civil claims cases (#16264)
Browse files Browse the repository at this point in the history
* fix(j-s): Civil claimant view for courts

* feat(j-s): Judge can add and remove advocates

* Update civilClaimant.controller.ts

* Fixed key on Box

* Change DEFENDER_ASSIGNED to ADVOCATE_ASSIGNED

* Checkpoint

* Checkpoint

* Update string

* Add tests

* Rename defender -- advocate

* Rename defender -- advocate

* Fix typo: hmtl -- html

* Refactor tests

* Add promise handling to email sending

* Rename parameters

* Fix tests

* Reorder imports

* Fix texts

* Fix texts

* Fix texts

* Fix tests

* Use correct types

* Use correct types

---------

Co-authored-by: unakb <[email protected]>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 11, 2024
1 parent 4309e6f commit db83d3f
Show file tree
Hide file tree
Showing 17 changed files with 353 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'use strict'
const replaceEnum = require('sequelize-replace-enum-postgres').default

module.exports = {
up: (queryInterface) => {
// replaceEnum does not support transactions
return replaceEnum({
queryInterface,
tableName: 'notification',
columnName: 'type',
newValues: [
'HEADS_UP',
'READY_FOR_COURT',
'RECEIVED_BY_COURT',
'COURT_DATE',
'RULING',
'MODIFIED',
'REVOKED',
'ADVOCATE_ASSIGNED', // Changed value
'DEFENDANTS_NOT_UPDATED_AT_COURT',
'APPEAL_TO_COURT_OF_APPEALS',
'APPEAL_RECEIVED_BY_COURT',
'APPEAL_STATEMENT',
'APPEAL_COMPLETED',
'APPEAL_JUDGES_ASSIGNED',
'APPEAL_CASE_FILES_UPDATED',
'APPEAL_WITHDRAWN',
'INDICTMENT_DENIED',
'INDICTMENT_RETURNED',
'INDICTMENTS_WAITING_FOR_CONFIRMATION',
],
enumName: 'enum_notification_type',
})
},

down: (queryInterface) => {
// replaceEnum does not support transactions
return replaceEnum({
queryInterface,
tableName: 'notification',
columnName: 'type',
newValues: [
'HEADS_UP',
'READY_FOR_COURT',
'RECEIVED_BY_COURT',
'COURT_DATE',
'RULING',
'MODIFIED',
'REVOKED',
'DEFENDER_ASSIGNED',
'DEFENDANTS_NOT_UPDATED_AT_COURT',
'APPEAL_TO_COURT_OF_APPEALS',
'APPEAL_RECEIVED_BY_COURT',
'APPEAL_STATEMENT',
'APPEAL_COMPLETED',
'APPEAL_JUDGES_ASSIGNED',
'APPEAL_CASE_FILES_UPDATED',
'APPEAL_WITHDRAWN',
'INDICTMENT_DENIED',
'INDICTMENT_RETURNED',
'INDICTMENTS_WAITING_FOR_CONFIRMATION',
],
enumName: 'enum_notification_type',
})
},
}
54 changes: 40 additions & 14 deletions apps/judicial-system/backend/src/app/formatters/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import {
laws,
readableIndictmentSubtypes,
} from '@island.is/judicial-system/formatters'
import type { Gender, UserRole } from '@island.is/judicial-system/types'
import {
AdvocateType,
Gender,
UserRole,
} from '@island.is/judicial-system/types'
import {
CaseCustodyRestrictions,
CaseLegalProvisions,
Expand Down Expand Up @@ -664,23 +668,45 @@ export const formatCustodyRestrictions = (
})
}

export const formatDefenderAssignedEmailNotification = (
export const formatAdvocateAssignedEmailNotification = (
formatMessage: FormatMessage,
theCase: Case,
advocateType: AdvocateType,
overviewUrl?: string,
): SubjectAndBody => {
const subject = formatMessage(notifications.defenderAssignedEmail.subject, {
court: capitalize(theCase.court?.name ?? ''),
})

const body = formatMessage(notifications.defenderAssignedEmail.body, {
defenderHasAccessToRVG: Boolean(overviewUrl),
courtCaseNumber: capitalize(theCase.courtCaseNumber ?? ''),
court: theCase.court?.name ?? '',
courtName: theCase.court?.name.replace('dómur', 'dómi') ?? '',
linkStart: `<a href="${overviewUrl}">`,
linkEnd: '</a>',
})
const subject =
advocateType === AdvocateType.DEFENDER
? formatMessage(
notifications.advocateAssignedEmail.subjectAccessToCaseFiles,
{
court: capitalize(theCase.court?.name ?? ''),
},
)
: formatMessage(notifications.advocateAssignedEmail.subjectAccess, {
courtCaseNumber: theCase.courtCaseNumber,
})

const body =
advocateType === AdvocateType.DEFENDER
? formatMessage(
notifications.advocateAssignedEmail.bodyAccessToCaseFiles,
{
defenderHasAccessToRVG: Boolean(overviewUrl),
courtCaseNumber: capitalize(theCase.courtCaseNumber ?? ''),
court: theCase.court?.name ?? '',
courtName: theCase.court?.name.replace('dómur', 'dómi') ?? '',
linkStart: `<a href="${overviewUrl}">`,
linkEnd: '</a>',
},
)
: formatMessage(notifications.advocateAssignedEmail.bodyAccess, {
defenderHasAccessToRVG: Boolean(overviewUrl),
court: theCase.court?.name,
advocateType,
courtCaseNumber: capitalize(theCase.courtCaseNumber ?? ''),
linkStart: `<a href="${overviewUrl}">`,
linkEnd: '</a>',
})

return { body, subject }
}
Expand Down
2 changes: 1 addition & 1 deletion apps/judicial-system/backend/src/app/formatters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export {
formatProsecutorReceivedByCourtSmsNotification,
formatDefenderCourtDateLinkEmailNotification,
formatDefenderResubmittedToCourtEmailNotification,
formatDefenderAssignedEmailNotification,
formatAdvocateAssignedEmailNotification,
formatCourtIndictmentReadyForCourtEmailNotification,
formatDefenderRoute,
formatDefenderReadyForCourtEmailNotification,
Expand Down
22 changes: 17 additions & 5 deletions apps/judicial-system/backend/src/app/messages/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -607,19 +607,31 @@ export const notifications = {
'Notaður sem texti í tölvupósti til verjanda vegna breytingar á lengd gæslu/einangrunar/vistunar þar sem úrskurðað var í einangrun.',
},
}),
defenderAssignedEmail: defineMessages({
subject: {
id: 'judicial.system.backend:notifications.defender_assigned_email.subject',
advocateAssignedEmail: defineMessages({
subjectAccessToCaseFiles: {
id: 'judicial.system.backend:notifications.defender_assigned_email.subject_access_to_case_files',
defaultMessage: '{court} - aðgangur að málsgögnum',
description:
'Fyrirsögn í pósti til verjanda þegar hann er skráður á mál.',
},
body: {
id: 'judicial.system.backend:notifications.defender_assigned_email.body_v3',
subjectAccess: {
id: 'judicial.system.backend:notifications.defender_assigned_email.subject_access',
defaultMessage: 'Skráning í máli {courtCaseNumber}',
description:
'Fyrirsögn í pósti til verjanda þegar hann er skráður á mál.',
},
bodyAccessToCaseFiles: {
id: 'judicial.system.backend:notifications.defender_assigned_email.body_access_to_case_files',
defaultMessage:
'{court} hefur skráð þig verjanda í máli {courtCaseNumber}.<br /><br />{defenderHasAccessToRVG, select, true {Gögn málsins eru aðgengileg á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}} other {Þú getur nálgast gögn málsins hjá {courtName} ef þau hafa ekki þegar verið afhent}}.',
description: 'Texti í pósti til verjanda þegar hann er skráður á mál.',
},
bodyAccess: {
id: 'judicial.system.backend:notifications.defender_assigned_email.body_access',
defaultMessage:
'{court} hefur skráð þig {advocateType, select, LAWYER {lögmann einkaréttarkröfuhafa} LEGAL_RIGHTS_PROTECTOR {réttargæslumann einkaréttarkröfuhafa} other {verjanda}} í máli {courtCaseNumber}.<br /><br />{defenderHasAccessToRVG, select, true {Sjá nánar á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}} other {Þú getur nálgast málið hjá {courtName}.}}.',
description: 'Texti í pósti til verjanda þegar hann er skráður á mál.',
},
}),
defendantsNotUpdatedAtCourt: defineMessages({
subject: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const districtCourtJudgeNotificationRule: RolesRule = {
dtoField: 'type',
dtoFieldValues: [
NotificationType.COURT_DATE,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
],
}

Expand All @@ -39,7 +39,7 @@ export const districtCourtRegistrarNotificationRule: RolesRule = {
dtoField: 'type',
dtoFieldValues: [
NotificationType.COURT_DATE,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
],
}

Expand All @@ -50,7 +50,7 @@ export const districtCourtAssistantNotificationRule: RolesRule = {
dtoField: 'type',
dtoFieldValues: [
NotificationType.COURT_DATE,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
],
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
lowercase,
} from '@island.is/judicial-system/formatters'
import {
AdvocateType,
CaseAppealRulingDecision,
CaseCustodyRestrictions,
CaseDecision,
Expand All @@ -50,13 +51,13 @@ import {
} from '@island.is/judicial-system/types'

import {
formatAdvocateAssignedEmailNotification,
formatCourtHeadsUpSmsNotification,
formatCourtIndictmentReadyForCourtEmailNotification,
formatCourtOfAppealJudgeAssignedEmailNotification,
formatCourtReadyForCourtSmsNotification,
formatCourtResubmittedToCourtSmsNotification,
formatCourtRevokedSmsNotification,
formatDefenderAssignedEmailNotification,
formatDefenderCourtDateEmailNotification,
formatDefenderCourtDateLinkEmailNotification,
formatDefenderReadyForCourtEmailNotification,
Expand Down Expand Up @@ -1518,18 +1519,18 @@ export class InternalNotificationService extends BaseNotificationService {
}
//#endregion

//#region DEFENDER_ASSIGNED notifications */
private shouldSendDefenderAssignedNotification(
//#region ADVOCATE_ASSIGNED notifications */
private shouldSendAdvocateAssignedNotification(
theCase: Case,
defenderEmail?: string,
advocateEmail?: string,
): boolean {
if (!defenderEmail) {
if (!advocateEmail) {
return false
}
if (isIndictmentCase(theCase.type)) {
const hasSentNotificationBefore = this.hasReceivedNotification(
NotificationType.DEFENDER_ASSIGNED,
defenderEmail,
NotificationType.ADVOCATE_ASSIGNED,
advocateEmail,
theCase.notifications,
)

Expand All @@ -1550,7 +1551,7 @@ export class InternalNotificationService extends BaseNotificationService {
[
NotificationType.READY_FOR_COURT,
NotificationType.COURT_DATE,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
],
theCase.defenderEmail,
theCase.notifications,
Expand All @@ -1564,30 +1565,32 @@ export class InternalNotificationService extends BaseNotificationService {
return true
}

private sendDefenderAssignedNotification(
private sendAdvocateAssignedNotification(
theCase: Case,
defenderNationalId?: string,
defenderName?: string,
defenderEmail?: string,
advocateType: AdvocateType,
advocateNationalId?: string,
advocateName?: string,
advocateEmail?: string,
): Promise<Recipient> {
const { subject, body } = formatDefenderAssignedEmailNotification(
const { subject, body } = formatAdvocateAssignedEmailNotification(
this.formatMessage,
theCase,
defenderNationalId &&
advocateType,
advocateNationalId &&
formatDefenderRoute(this.config.clientUrl, theCase.type, theCase.id),
)

return this.sendEmail(
subject,
body,
defenderName,
defenderEmail,
advocateName,
advocateEmail,
undefined,
Boolean(defenderNationalId) === false,
Boolean(advocateNationalId) === false,
)
}

private async sendDefenderAssignedNotifications(
private async sendAdvocateAssignedNotifications(
theCase: Case,
): Promise<DeliverResponse> {
const promises: Promise<Recipient>[] = []
Expand All @@ -1597,27 +1600,61 @@ export class InternalNotificationService extends BaseNotificationService {
theCase.defendants ?? [],
(d: Defendant) => d.defenderEmail,
)

for (const defendant of uniqDefendants) {
const { defenderEmail, defenderNationalId, defenderName } = defendant

const shouldSend = this.shouldSendDefenderAssignedNotification(
const shouldSend = this.shouldSendAdvocateAssignedNotification(
theCase,
defenderEmail,
)

if (shouldSend === true) {
promises.push(
this.sendDefenderAssignedNotification(
this.sendAdvocateAssignedNotification(
theCase,
AdvocateType.DEFENDER,
defenderNationalId,
defenderName,
defenderEmail,
),
)
}
}

if (theCase.civilClaimants) {
for (const civilClaimant of theCase.civilClaimants) {
const {
spokespersonEmail,
spokespersonIsLawyer,
spokespersonName,
spokespersonNationalId,
hasSpokesperson,
} = civilClaimant

const shouldSend =
this.shouldSendAdvocateAssignedNotification(
theCase,
spokespersonEmail,
) && hasSpokesperson

if (shouldSend === true) {
promises.push(
this.sendAdvocateAssignedNotification(
theCase,
spokespersonIsLawyer
? AdvocateType.LAWYER
: AdvocateType.LEGAL_RIGHTS_PROTECTOR,
spokespersonNationalId,
spokespersonName,
spokespersonEmail,
),
)
}
}
}
} else if (DateLog.arraignmentDate(theCase.dateLogs)?.date) {
const shouldSend = this.shouldSendDefenderAssignedNotification(
const shouldSend = this.shouldSendAdvocateAssignedNotification(
theCase,
theCase.defenderEmail,
)
Expand All @@ -1636,7 +1673,7 @@ export class InternalNotificationService extends BaseNotificationService {

return this.recordNotification(
theCase.id,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
recipients,
)
}
Expand Down Expand Up @@ -2528,8 +2565,8 @@ export class InternalNotificationService extends BaseNotificationService {
return this.sendModifiedNotifications(theCase, user)
case NotificationType.REVOKED:
return this.sendRevokedNotifications(theCase)
case NotificationType.DEFENDER_ASSIGNED:
return this.sendDefenderAssignedNotifications(theCase)
case NotificationType.ADVOCATE_ASSIGNED:
return this.sendAdvocateAssignedNotifications(theCase)
case NotificationType.DEFENDANTS_NOT_UPDATED_AT_COURT:
return this.sendDefendantsNotUpdatedAtCourtNotifications(theCase)
case NotificationType.APPEAL_TO_COURT_OF_APPEALS:
Expand Down
Loading

0 comments on commit db83d3f

Please sign in to comment.