Skip to content

Commit

Permalink
feat(j-s): Deliver defender info to robot for indictment cases (#15191)
Browse files Browse the repository at this point in the history
* feat(j-s): Deliver defender info to robot for indictment cases

* Update deliverIndictmentDefenderInfoToCourt.spec.ts

* Update court.service.ts

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
unakb and kodiakhq[bot] authored Jun 12, 2024
1 parent 878c6c8 commit e9b5864
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 47 deletions.
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 }
})
}

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 }
})
}

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))

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', () => {
// 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

0 comments on commit e9b5864

Please sign in to comment.