Skip to content

Commit

Permalink
feat(j-s): Send to prison admin (#16831)
Browse files Browse the repository at this point in the history
* 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

* 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

* Updates unit test

* Sets the sent to prison admin date to undefined it the defendant has not been sent to prison admin

* Fixes linting issues

* Updates unit tests

* Updates unit tests

* Updates unit tests

* Updates unit tests

---------

Co-authored-by: Guðjón Guðjónsson <[email protected]>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 25, 2024
1 parent e0596d3 commit 78bdd5b
Show file tree
Hide file tree
Showing 54 changed files with 855 additions and 265 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,9 @@ export class UpdateDefendantInput {
@IsOptional()
@Field(() => Boolean, { nullable: true })
readonly caseFilesSharedWithDefender?: boolean

@Allow()
@IsOptional()
@Field(() => Boolean, { nullable: true })
readonly isSentToPrisonAdmin?: boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,10 @@ export class Defendant {

@Field(() => Boolean, { nullable: true })
readonly caseFilesSharedWithDefender?: boolean

@Field(() => Boolean, { nullable: true })
readonly isSentToPrisonAdmin?: boolean

@Field(() => String, { nullable: true })
readonly sentToPrisonAdminDate?: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict'

module.exports = {
up(queryInterface, Sequelize) {
return queryInterface.sequelize.transaction((transaction) =>
queryInterface.addColumn(
'defendant',
'is_sent_to_prison_admin',
{
type: Sequelize.BOOLEAN,
allowNull: true,
},
{ transaction },
),
)
},

down(queryInterface) {
return queryInterface.sequelize.transaction((transaction) =>
queryInterface.removeColumn('defendant', 'is_sent_to_prison_admin', {
transaction,
}),
)
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict'

module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.sequelize.transaction((t) =>
queryInterface.createTable(
'defendant_event_log',
{
id: {
type: Sequelize.UUID,
primaryKey: true,
allowNull: false,
defaultValue: Sequelize.UUIDV4,
},
created: {
type: 'TIMESTAMP WITH TIME ZONE',
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
allowNull: false,
},
modified: {
type: 'TIMESTAMP WITH TIME ZONE',
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
allowNull: false,
},
case_id: {
type: Sequelize.UUID,
references: {
model: 'case',
key: 'id',
},
allowNull: false,
},
defendant_id: {
type: Sequelize.UUID,
references: {
model: 'defendant',
key: 'id',
},
allowNull: false,
},
event_type: {
type: Sequelize.STRING,
allowNull: false,
},
},
{ transaction: t },
),
)
},

down: (queryInterface) => {
return queryInterface.sequelize.transaction((t) =>
queryInterface.dropTable('defendant_event_log', { transaction: t }),
)
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
DEFENDER_ROUTE,
} from '@island.is/judicial-system/consts'
import {
capitalize,
enumerate,
formatCaseType,
formatDate,
Expand All @@ -14,11 +13,7 @@ import {
laws,
readableIndictmentSubtypes,
} from '@island.is/judicial-system/formatters'
import {
AdvocateType,
Gender,
UserRole,
} from '@island.is/judicial-system/types'
import { Gender, UserRole } from '@island.is/judicial-system/types'
import {
CaseCustodyRestrictions,
CaseLegalProvisions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
CaseType,
DateType,
dateTypes,
defendantEventTypes,
EventType,
eventTypes,
isCompletedCase,
Expand All @@ -59,7 +60,12 @@ import {
} from '../../formatters'
import { AwsS3Service } from '../aws-s3'
import { CourtService } from '../court'
import { CivilClaimant, Defendant, DefendantService } from '../defendant'
import {
CivilClaimant,
Defendant,
DefendantEventLog,
DefendantService,
} from '../defendant'
import { EventService } from '../event'
import { EventLog, EventLogService } from '../event-log'
import { CaseFile, FileService } from '../file'
Expand Down Expand Up @@ -285,6 +291,14 @@ export const include: Includeable[] = [
order: [['created', 'DESC']],
separate: true,
},
{
model: DefendantEventLog,
as: 'eventLogs',
required: false,
where: { eventType: defendantEventTypes },
order: [['created', 'DESC']],
separate: true,
},
],
separate: true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
CaseState,
CaseType,
EventType,
getIndictmentVerdictAppealDeadlineStatus,
IndictmentCaseReviewDecision,
isCourtOfAppealsUser,
isDefenceUser,
Expand Down Expand Up @@ -290,16 +289,10 @@ const canPrisonAdminUserAccessCase = (
return false
}

// Check defendant verdict appeal deadline access
const canAppealVerdict = true
const verdictInfo = (theCase.defendants || []).map<
[boolean, Date | undefined]
>((defendant) => [canAppealVerdict, defendant.verdictViewDate])

const [_, indictmentVerdictAppealDeadlineExpired] =
getIndictmentVerdictAppealDeadlineStatus(verdictInfo)

if (!indictmentVerdictAppealDeadlineExpired) {
// Check if a defendant has been sent to the prison admin
if (
!theCase.defendants?.some((defendant) => defendant.isSentToPrisonAdmin)
) {
return false
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
RequestSharedWithDefender,
restrictionCases,
UserRole,
VERDICT_APPEAL_WINDOW_DAYS,
} from '@island.is/judicial-system/types'

const getProsecutionUserCasesQueryFilter = (user: User): WhereOptions => {
Expand Down Expand Up @@ -215,12 +214,10 @@ const getPrisonAdminUserCasesQueryFilter = (): WhereOptions => {
indictment_ruling_decision: CaseIndictmentRulingDecision.RULING,
indictment_review_decision: IndictmentCaseReviewDecision.ACCEPT,
id: {
[Op.notIn]: Sequelize.literal(`
[Op.in]: Sequelize.literal(`
(SELECT case_id
FROM defendant
WHERE (verdict_appeal_date IS NOT NULL
OR verdict_view_date IS NULL
OR verdict_view_date > NOW() - INTERVAL '${VERDICT_APPEAL_WINDOW_DAYS} days'))
WHERE is_sent_to_prison_admin = true)
`),
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
RequestSharedWithDefender,
restrictionCases,
UserRole,
VERDICT_APPEAL_WINDOW_DAYS,
} from '@island.is/judicial-system/types'

import { getCasesQueryFilter } from '../cases.filter'
Expand Down Expand Up @@ -392,12 +391,10 @@ describe('getCasesQueryFilter', () => {
indictment_ruling_decision: CaseIndictmentRulingDecision.RULING,
indictment_review_decision: IndictmentCaseReviewDecision.ACCEPT,
id: {
[Op.notIn]: Sequelize.literal(`
[Op.in]: Sequelize.literal(`
(SELECT case_id
FROM defendant
WHERE (verdict_appeal_date IS NOT NULL
OR verdict_view_date IS NULL
OR verdict_view_date > NOW() - INTERVAL '${VERDICT_APPEAL_WINDOW_DAYS} days'))
WHERE is_sent_to_prison_admin = true)
`),
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,29 @@ describe.each(prisonSystemRoles)('prison admin user %s', (role) => {
describe.each(accessibleIndictmentCaseReviewDecisions)(
'accessible indictment case review decision %s',
(indictmentReviewDecision) => {
const theCase = {
type,
state,
indictmentRulingDecision,
indictmentReviewDecision,
} as Case
describe('no defendant has been sent to the prison admin', () => {
const theCase = {
type,
state,
indictmentRulingDecision,
indictmentReviewDecision,
defendants: [{}],
} as Case

verifyNoAccess(theCase, user)
})

describe('a defendant has been sent to the prison admin', () => {
const theCase = {
type,
state,
indictmentRulingDecision,
indictmentReviewDecision,
defendants: [{ isSentToPrisonAdmin: true }],
} as Case

verifyReadAccess(theCase, user)
verifyReadAccess(theCase, user)
})
},
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,23 @@ import {
NestInterceptor,
} from '@nestjs/common'

import { Defendant, DefendantEventLog } from '../../defendant'
import { Case } from '../models/case.model'
import { CaseString } from '../models/caseString.model'

export const transformDefendants = (defendants?: Defendant[]) => {
return defendants?.map((defendant) => ({
...defendant.toJSON(),
sentToPrisonAdminDate: defendant.isSentToPrisonAdmin
? DefendantEventLog.sentToPrisonAdminDate(defendant.eventLogs)?.created
: undefined,
}))
}

const transformCase = (theCase: Case) => {
return {
...theCase.toJSON(),
defendants: transformDefendants(theCase.defendants),
postponedIndefinitelyExplanation:
CaseString.postponedIndefinitelyExplanation(theCase.caseStrings),
civilDemands: CaseString.civilDemands(theCase.caseStrings),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IndictmentDecision } from '@island.is/judicial-system/types'
import { Case } from '../models/case.model'
import { CaseString } from '../models/caseString.model'
import { DateLog } from '../models/dateLog.model'
import { transformDefendants } from './case.interceptor'

@Injectable()
export class CaseListInterceptor implements NestInterceptor {
Expand All @@ -29,7 +30,7 @@ export class CaseListInterceptor implements NestInterceptor {
policeCaseNumbers: theCase.policeCaseNumbers,
state: theCase.state,
type: theCase.type,
defendants: theCase.defendants,
defendants: transformDefendants(theCase.defendants),
courtCaseNumber: theCase.courtCaseNumber,
decision: theCase.decision,
validToDate: theCase.validToDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
CaseNotificationType,
CaseState,
dateTypes,
defendantEventTypes,
eventTypes,
stringTypes,
UserRole,
Expand All @@ -34,6 +35,7 @@ import {
CivilClaimant,
CivilClaimantService,
Defendant,
DefendantEventLog,
DefendantService,
} from '../defendant'
import { EventLog } from '../event-log'
Expand Down Expand Up @@ -182,6 +184,14 @@ export const include: Includeable[] = [
order: [['created', 'DESC']],
separate: true,
},
{
model: DefendantEventLog,
as: 'eventLogs',
required: false,
where: { eventType: defendantEventTypes },
order: [['created', 'DESC']],
separate: true,
},
],
separate: true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { CaseModule } from '../case/case.module'
import { CourtModule } from '../court/court.module'
import { CivilClaimant } from './models/civilClaimant.model'
import { Defendant } from './models/defendant.model'
import { DefendantEventLog } from './models/defendantEventLog.model'
import { CivilClaimantController } from './civilClaimant.controller'
import { CivilClaimantService } from './civilClaimant.service'
import { DefendantController } from './defendant.controller'
Expand All @@ -18,7 +19,7 @@ import { InternalDefendantController } from './internalDefendant.controller'
MessageModule,
forwardRef(() => CourtModule),
forwardRef(() => CaseModule),
SequelizeModule.forFeature([Defendant, CivilClaimant]),
SequelizeModule.forFeature([Defendant, CivilClaimant, DefendantEventLog]),
],
controllers: [
DefendantController,
Expand Down
Loading

0 comments on commit 78bdd5b

Please sign in to comment.