diff --git a/apps/judicial-system/backend/src/app/modules/case/case.service.ts b/apps/judicial-system/backend/src/app/modules/case/case.service.ts index a61fa38030a2..c1e609eecd63 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.service.ts @@ -629,6 +629,21 @@ export class CaseService { return this.messageService.sendMessagesToQueue(messages) } + private addMessagesForIndictmentCourtRoleAssigned( + theCase: Case, + user: TUser, + assignedNationalId: string, + ): Promise { + return this.messageService.sendMessagesToQueue([ + { + type: MessageType.DELIVERY_TO_COURT_INDICTMENT_COURT_ROLES, + user, + caseId: theCase.id, + elementId: assignedNationalId, + }, + ]) + } + private addMessagesForCourtCaseConnectionToQueue( theCase: Case, user: TUser, @@ -1203,6 +1218,30 @@ export class CaseService { } } + if ( + isIndictmentCase(updatedCase.type) && + ![ + CaseState.DRAFT, + CaseState.SUBMITTED, + CaseState.WAITING_FOR_CONFIRMATION, + ].includes(updatedCase.state) + ) { + const updatedRole = + updatedCase.judge?.nationalId !== theCase.judge?.nationalId + ? updatedCase.judge + : updatedCase.registrar?.nationalId !== theCase.registrar?.nationalId + ? updatedCase.registrar + : null + + if (updatedRole?.nationalId) { + await this.addMessagesForIndictmentCourtRoleAssigned( + updatedCase, + user, + updatedRole.nationalId, + ) + } + } + // This only applies to restriction cases if (updatedCase.appealCaseNumber) { if (updatedCase.appealCaseNumber !== theCase.appealCaseNumber) { diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts index 4733cf4cbd67..91a289472ed0 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts @@ -194,6 +194,33 @@ export class InternalCaseController { ) } + @UseGuards(CaseExistsGuard, new CaseTypeGuard(indictmentCases)) + @Post( + `case/:caseId/${ + messageEndpoint[MessageType.DELIVERY_TO_COURT_INDICTMENT_COURT_ROLES] + }/:nationalId`, + ) + @ApiOkResponse({ + type: DeliverResponse, + description: 'Delivers assigned roles in indictment case to court', + }) + deliverIndictmentAssignedRoleToCourt( + @Param('caseId') caseId: string, + @CurrentCase() theCase: Case, + @Body() deliverDto: DeliverDto, + @Param('nationalId') nationalId: string, + ): Promise { + this.logger.debug( + `Delivering the assigned roles of indictment case ${caseId} to court`, + ) + + return this.internalCaseService.deliverIndictmentAssignedRolesToCourt( + theCase, + deliverDto.user, + nationalId, + ) + } + @UseGuards(CaseExistsGuard, new CaseTypeGuard(indictmentCases)) @Post( `case/:caseId/${ diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts index 3f1330ed5351..10271556cc3c 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts @@ -612,6 +612,41 @@ export class InternalCaseService { }) } + async deliverIndictmentAssignedRolesToCourt( + theCase: Case, + user: TUser, + nationalId?: string, + ): Promise { + const assignedRole = + theCase.judge?.nationalId === nationalId + ? { + name: theCase.judge?.name, + role: UserRole.DISTRICT_COURT_JUDGE, + } + : theCase.registrar?.nationalId === nationalId + ? { + name: theCase.registrar?.name, + role: UserRole.DISTRICT_COURT_REGISTRAR, + } + : {} + + return this.courtService + .updateIndictmentCaseWithAssignedRoles( + user, + theCase.id, + theCase.courtCaseNumber, + assignedRole, + ) + .then(() => ({ delivered: true })) + .catch((reason) => { + this.logger.error( + `Failed to update indictment case ${theCase.id} with assigned roles`, + { reason }, + ) + + return { delivered: false } + }) + } async deliverCaseFilesRecordToCourt( theCase: Case, policeCaseNumber: string, diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentAssignedRolesToCourt.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentAssignedRolesToCourt.spec.ts new file mode 100644 index 000000000000..49ccd3ee532a --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentAssignedRolesToCourt.spec.ts @@ -0,0 +1,86 @@ +import { uuid } from 'uuidv4' + +import { CaseType, User, UserRole } from '@island.is/judicial-system/types' + +import { createTestingCaseModule } from '../createTestingCaseModule' + +import { CourtService } from '../../../court' +import { Case } from '../../models/case.model' +import { DeliverResponse } from '../../models/deliver.response' + +interface Then { + result: DeliverResponse + error: Error +} + +type GivenWhenThen = ( + caseId: string, + theCase: Case, + nationalId: string, +) => Promise + +describe('InternalCaseController - Deliver assigned roles for indictment case to court', () => { + const user = { id: uuid() } as User + const caseId = uuid() + const courtCaseNumber = uuid() + + const theCase = { + id: caseId, + type: CaseType.INDICTMENT, + courtCaseNumber, + judge: { name: 'Test Dómari', nationalId: '0101010101' }, + registrar: { name: 'Test Ritari', nationalId: '0202020202' }, + } as Case + + let mockCourtService: CourtService + let givenWhenThen: GivenWhenThen + + beforeAll(async () => { + const { courtService, internalCaseController } = + await createTestingCaseModule() + + mockCourtService = courtService + const mockUpdateIndictmentCaseWithAssignedRoles = + mockCourtService.updateIndictmentCaseWithAssignedRoles as jest.Mock + mockUpdateIndictmentCaseWithAssignedRoles.mockResolvedValue(uuid()) + + givenWhenThen = async ( + caseId: string, + theCase: Case, + nationalId: string, + ) => { + const then = {} as Then + + await internalCaseController + .deliverIndictmentAssignedRoleToCourt( + caseId, + theCase, + { user }, + nationalId, + ) + .then((result) => (then.result = result)) + .catch((error) => (then.error = error)) + + return then + } + }) + + describe('deliver assigned roles in indictment case to court', () => { + let then: Then + + beforeAll(async () => { + then = await givenWhenThen(caseId, theCase, '0101010101') + }) + + it('should deliver the assigned roles to the court', () => { + expect( + mockCourtService.updateIndictmentCaseWithAssignedRoles, + ).toHaveBeenCalledWith(user, theCase.id, theCase.courtCaseNumber, { + name: theCase.judge?.name, + role: UserRole.DISTRICT_COURT_JUDGE, + }) + + expect(then.result).toEqual({ delivered: true }) + }) + }) +}) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentAssignedRolesToCourtGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentAssignedRolesToCourtGuards.spec.ts new file mode 100644 index 000000000000..3d5c534a0e74 --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentAssignedRolesToCourtGuards.spec.ts @@ -0,0 +1,25 @@ +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 assigned roles in indictment case to court guards', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let guards: any[] + + beforeEach(() => { + guards = Reflect.getMetadata( + '__guards__', + InternalCaseController.prototype.deliverIndictmentAssignedRoleToCourt, + ) + }) + + it('should have the right guard configuration', () => { + expect(new guards[0]()).toBeInstanceOf(CaseExistsGuard) + expect(guards[1]).toBeInstanceOf(CaseTypeGuard) + expect(guards[1]).toEqual({ + allowedCaseTypes: indictmentCases, + }) + }) +}) diff --git a/apps/judicial-system/backend/src/app/modules/court/court.service.ts b/apps/judicial-system/backend/src/app/modules/court/court.service.ts index 1637d8e76534..3b51ff1fc7a4 100644 --- a/apps/judicial-system/backend/src/app/modules/court/court.service.ts +++ b/apps/judicial-system/backend/src/app/modules/court/court.service.ts @@ -12,7 +12,7 @@ import type { ConfigType } from '@island.is/nest/config' import { CourtClientService } from '@island.is/judicial-system/court-client' import { sanitize } from '@island.is/judicial-system/formatters' -import type { User } from '@island.is/judicial-system/types' +import type { User, UserRole } from '@island.is/judicial-system/types' import { CaseAppealRulingDecision, CaseDecision, @@ -128,6 +128,7 @@ enum RobotEmailType { APPEAL_CASE_CONCLUSION = 'APPEAL_CASE_CONCLUSION', APPEAL_CASE_FILE = 'APPEAL_CASE_FILE', NEW_INDICTMENT_INFO = 'INDICTMENT_INFO', + INDICTMENT_CASE_ASSIGNED_ROLES = 'INDICTMENT_CASE_ASSIGNED_ROLES', INDICTMENT_CASE_DEFENDER_INFO = 'INDICTMENT_CASE_DEFENDER_INFO', } @@ -643,6 +644,37 @@ export class CourtService { } } + async updateIndictmentCaseWithAssignedRoles( + user: User, + caseId: string, + courtCaseNumber?: string, + assignedRole?: { name?: string; role?: UserRole }, + ): Promise { + try { + const subject = `Ákæra - ${courtCaseNumber} - úthlutun` + const content = JSON.stringify(assignedRole) + + return this.sendToRobot( + subject, + content, + RobotEmailType.INDICTMENT_CASE_ASSIGNED_ROLES, + caseId, + ) + } catch (error) { + this.eventService.postErrorEvent( + 'Failed to update indictment case with assigned roles', + { + caseId, + actor: user.name, + courtCaseNumber, + }, + error, + ) + + throw error + } + } + async updateAppealCaseWithReceivedDate( user: User, caseId: string, diff --git a/libs/judicial-system/message/src/lib/message.ts b/libs/judicial-system/message/src/lib/message.ts index 07e728588336..a013586163ee 100644 --- a/libs/judicial-system/message/src/lib/message.ts +++ b/libs/judicial-system/message/src/lib/message.ts @@ -5,6 +5,7 @@ export enum MessageType { DELIVERY_TO_COURT_DEFENDANT = 'DELIVERY_TO_COURT_DEFENDANT', DELIVERY_TO_COURT_INDICTMENT = 'DELIVERY_TO_COURT_INDICTMENT', DELIVERY_TO_COURT_INDICTMENT_INFO = 'DELIVERY_TO_COURT_INDICTMENT_INFO', + DELIVERY_TO_COURT_INDICTMENT_COURT_ROLES = 'DELIVERY_TO_COURT_INDICTMENT_COURT_ROLES', DELIVERY_TO_COURT_INDICTMENT_DEFENDER = 'DELIVERY_TO_COURT_INDICTMENT_DEFENDER', DELIVERY_TO_COURT_CASE_FILE = 'DELIVERY_TO_COURT_CASE_FILE', DELIVERY_TO_COURT_CASE_FILES_RECORD = 'DELIVERY_TO_COURT_CASE_FILES_RECORD', @@ -32,6 +33,8 @@ export const messageEndpoint: { [key in MessageType]: string } = { DELIVERY_TO_COURT_PROSECUTOR: 'deliverProsecutorToCourt', DELIVERY_TO_COURT_DEFENDANT: 'deliverDefendantToCourt', DELIVERY_TO_COURT_INDICTMENT: 'deliverIndictmentToCourt', + DELIVERY_TO_COURT_INDICTMENT_COURT_ROLES: + 'deliverIndictmentCourtRolesToCourt', DELIVERY_TO_COURT_INDICTMENT_INFO: 'deliverIndictmentInfoToCourt', DELIVERY_TO_COURT_INDICTMENT_DEFENDER: 'deliverIndictmentDefenderToCourt', DELIVERY_TO_COURT_CASE_FILE: 'deliverCaseFileToCourt',