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

feat(j-s): Deliver defender info to robot for indictment cases #15191

Merged
merged 5 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -169,6 +169,31 @@ export class InternalCaseController {
)
}

@UseGuards(CaseExistsGuard, new CaseTypeGuard(indictmentCases))
@Post(
`case/:caseId/${
messageEndpoint[MessageType.DELIVERY_TO_COURT_INDICTMENT_DEFENDER]
}`,
)
@ApiOkResponse({
type: DeliverResponse,
description: 'Delivers indictment case defender info to court',
})
deliverIndictmentDefenderInfoToCourt(
@Param('caseId') caseId: string,
@CurrentCase() theCase: Case,
@Body() deliverDto: DeliverDto,
): Promise<DeliverResponse> {
this.logger.debug(
`Delivering the indictment defender info for case ${caseId} to court`,
)

return this.internalCaseService.deliverIndictmentDefenderInfoToCourt(
theCase,
deliverDto.user,
)
}

@UseGuards(CaseExistsGuard, new CaseTypeGuard(indictmentCases))
@Post(
`case/:caseId/${
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,73 @@ export class InternalCaseService {
})
}

async deliverIndictmentInfoToCourt(
theCase: Case,
user: TUser,
): Promise<DeliverResponse> {
const subtypeList = theCase.indictmentSubtypes
? Object.values(theCase.indictmentSubtypes).flat()
: []

const mappedSubtypes = subtypeList.flatMap((key) => courtSubtypes[key])

return this.courtService
.updateIndictmentCaseWithIndictmentInfo(
user,
theCase.id,
theCase.courtCaseNumber,
theCase.eventLogs?.find(
(eventLog) => eventLog.eventType === EventType.CASE_RECEIVED_BY_COURT,
)?.created,
theCase.eventLogs?.find(
(eventLog) => eventLog.eventType === EventType.INDICTMENT_CONFIRMED,
)?.created,
theCase.policeCaseNumbers[0],
mappedSubtypes,
theCase.defendants?.map((defendant) => ({
name: defendant.name,
nationalId: defendant.nationalId,
})),
theCase.prosecutor
? {
name: theCase.prosecutor.name,
nationalId: theCase.prosecutor.nationalId,
}
: undefined,
)
.then(() => ({ delivered: true }))
.catch((reason) => {
this.logger.error(
`Failed to update indictment case ${theCase.id} with indictment info`,
{ reason },
)

return { delivered: false }
})
}
unakb marked this conversation as resolved.
Show resolved Hide resolved

async deliverIndictmentDefenderInfoToCourt(
theCase: Case,
user: TUser,
): Promise<DeliverResponse> {
return this.courtService
.updateIndictmentWithDefenderInfo(
user,
theCase.id,
theCase.courtCaseNumber,
theCase.defendants,
)
.then(() => ({ delivered: true }))
.catch((reason) => {
this.logger.error(
`Failed to update indictment case ${theCase.id} with defender info`,
{ reason },
)

return { delivered: false }
})
unakb marked this conversation as resolved.
Show resolved Hide resolved
}
unakb marked this conversation as resolved.
Show resolved Hide resolved

async deliverCaseFilesRecordToCourt(
theCase: Case,
policeCaseNumber: string,
Expand Down Expand Up @@ -751,51 +818,6 @@ export class InternalCaseService {
})
}

async deliverIndictmentInfoToCourt(
theCase: Case,
user: TUser,
): Promise<DeliverResponse> {
const subtypeList = theCase.indictmentSubtypes
? Object.values(theCase.indictmentSubtypes).flat()
: []

const mappedSubtypes = subtypeList.flatMap((key) => courtSubtypes[key])

return this.courtService
.updateIndictmentCaseWithIndictmentInfo(
user,
theCase.id,
theCase.courtCaseNumber,
theCase.eventLogs?.find(
(eventLog) => eventLog.eventType === EventType.CASE_RECEIVED_BY_COURT,
)?.created,
theCase.eventLogs?.find(
(eventLog) => eventLog.eventType === EventType.INDICTMENT_CONFIRMED,
)?.created,
theCase.policeCaseNumbers[0],
mappedSubtypes,
theCase.defendants?.map((defendant) => ({
name: defendant.name,
nationalId: defendant.nationalId,
})),
theCase.prosecutor
? {
name: theCase.prosecutor.name,
nationalId: theCase.prosecutor.nationalId,
}
: undefined,
)
.then(() => ({ delivered: true }))
.catch((reason) => {
this.logger.error(
`Failed to update indictment case ${theCase.id} with indictment info`,
{ reason },
)

return { delivered: false }
})
}

private async deliverCaseToPoliceWithFiles(
theCase: Case,
user: TUser,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { uuid } from 'uuidv4'

import { CaseType, User } from '@island.is/judicial-system/types'

import { createTestingCaseModule } from '../createTestingCaseModule'

import { CourtService } from '../../../court'
import { DeliverDto } from '../../dto/deliver.dto'
import { Case } from '../../models/case.model'
import { DeliverResponse } from '../../models/deliver.response'

interface Then {
result?: DeliverResponse
error?: Error
}

type GivenWhenThen = (
caseId: string,
theCase: Case,
body: DeliverDto,
) => Promise<Then>

describe('InternalCaseController - Deliver indictment defender info to court', () => {
const user = { id: uuid() } as User
const caseId = uuid()
const courtCaseNumber = uuid()

const theCase = {
id: caseId,
type: CaseType.INDICTMENT,
courtCaseNumber,
defendants: [
{
name: 'Test Ákærði',
nationalId: '1234567890',
defenderNationalId: '1234567899',
defenderName: 'Test Verjandi',
defenderEmail: 'defenderEmail',
},
{
name: 'Test Ákærði 2',
nationalId: '1234567891',
defenderNationalId: '1234567898',
defenderName: 'Test Verjandi 2',
defenderEmail: 'defenderEmail2',
},
],
} as Case

let mockCourtService: jest.Mocked<CourtService>
let givenWhenThen: GivenWhenThen

beforeEach(async () => {
const { courtService, internalCaseController } =
await createTestingCaseModule()

mockCourtService = courtService as jest.Mocked<CourtService>
mockCourtService.updateIndictmentWithDefenderInfo.mockResolvedValue(uuid())

givenWhenThen = async (caseId: string, theCase: Case, body: DeliverDto) => {
const then = {} as Then

await internalCaseController
.deliverIndictmentDefenderInfoToCourt(caseId, theCase, body)
.then((result) => (then.result = result))
.catch((error) => (then.error = error))
unakb marked this conversation as resolved.
Show resolved Hide resolved
unakb marked this conversation as resolved.
Show resolved Hide resolved

return then
}
})

it('should deliver the defender information to court', async () => {
const then = await givenWhenThen(caseId, theCase, { user })

expect(
mockCourtService.updateIndictmentWithDefenderInfo,
).toHaveBeenCalledWith(
user,
theCase.id,
theCase.courtCaseNumber,
theCase.defendants,
)

expect(then.result).toEqual({ delivered: true })
expect(then.error).toBeUndefined()
})

it('should handle not deliver if error occurs', async () => {
const error = new Error('Service error')
mockCourtService.updateIndictmentWithDefenderInfo.mockRejectedValueOnce(
error,
)

const then = await givenWhenThen(caseId, theCase, { user })

expect(then.result).toEqual({ delivered: false })
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { CanActivate } from '@nestjs/common'

import { indictmentCases } from '@island.is/judicial-system/types'

import { CaseExistsGuard } from '../../guards/caseExists.guard'
import { CaseTypeGuard } from '../../guards/caseType.guard'
import { InternalCaseController } from '../../internalCase.controller'

describe('InternalCaseController - Deliver indictment defender info to court guards', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let guards: any[]

beforeEach(() => {
guards = Reflect.getMetadata(
'__guards__',
InternalCaseController.prototype.deliverIndictmentDefenderInfoToCourt,
)
})

it('should have two guards', () => {
expect(guards).toHaveLength(2)
})

describe('CaseExistsGuard', () => {
let guard: CanActivate

beforeEach(() => {
guard = new guards[0]()
})

it('should have CaseExistsGuard as guard 1', () => {
expect(guard).toBeInstanceOf(CaseExistsGuard)
})
})

describe('CaseTypeGuard', () => {
let guard: CanActivate

beforeEach(() => {
guard = guards[1]
})

it('should have CaseTypeGuard as guard 2', () => {
expect(guard).toBeInstanceOf(CaseTypeGuard)
expect(guard).toEqual({
allowedCaseTypes: indictmentCases,
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CaseExistsGuard } from '../../guards/caseExists.guard'
import { CaseTypeGuard } from '../../guards/caseType.guard'
import { InternalCaseController } from '../../internalCase.controller'

describe('InternalCaseController - Deliver indictment case to police guards', () => {
describe('InternalCaseController - Deliver indictment case info to court guards', () => {
unakb marked this conversation as resolved.
Show resolved Hide resolved
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let guards: any[]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from '@island.is/judicial-system/types'

import { nowFactory } from '../../factories'
import { Defendant } from '../defendant'
import { EventService } from '../event'
import { RobotLog } from './models/robotLog.model'
import { courtModuleConfig } from './court.config'
Expand Down Expand Up @@ -127,6 +128,7 @@ enum RobotEmailType {
APPEAL_CASE_CONCLUSION = 'APPEAL_CASE_CONCLUSION',
APPEAL_CASE_FILE = 'APPEAL_CASE_FILE',
NEW_INDICTMENT_INFO = 'INDICTMENT_INFO',
INDICTMENT_CASE_DEFENDER_INFO = 'INDICTMENT_CASE_DEFENDER_INFO',
}

@Injectable()
Expand Down Expand Up @@ -603,6 +605,44 @@ export class CourtService {
}
}

async updateIndictmentWithDefenderInfo(
user: User,
caseId: string,
courtCaseNumber?: string,
defendants?: Defendant[],
): Promise<unknown> {
try {
const defendantInfo = defendants?.map((defendant) => ({
nationalId: defendant.nationalId,
defenderName: defendant.defenderName,
defenderEmail: defendant.defenderEmail,
}))

const subject = `Ákæra - ${courtCaseNumber} - verjanda upplýsingar`
const content = JSON.stringify(defendantInfo)

return this.sendToRobot(
subject,
content,
RobotEmailType.INDICTMENT_CASE_DEFENDER_INFO,
caseId,
)
} catch (error) {
this.eventService.postErrorEvent(
'Failed to update indictment with defender info',
{
caseId,
actor: user.name,
institution: user.institution?.name,
courtCaseNumber,
},
error,
)

throw error
}
}

async updateAppealCaseWithReceivedDate(
user: User,
caseId: string,
Expand Down Expand Up @@ -784,7 +824,7 @@ export class CourtService {
.then((log) => [log.id, log.seqNumber])
}

private async sendToRobot(
async sendToRobot(
subject: string,
content: string,
type: RobotEmailType,
Expand Down
Loading
Loading