Skip to content

Commit

Permalink
ADJST-834 Making manual journey blocked for review remand tool. (#411)
Browse files Browse the repository at this point in the history
  • Loading branch information
ldlharper authored Sep 19, 2024
1 parent 3420a28 commit 49473a6
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 21 deletions.
11 changes: 11 additions & 0 deletions server/model/remandViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PrisonApiOffenderSentenceAndOffences } from '../@types/prisonApi/prison
import { offencesForRemandAdjustment } from '../utils/utils'
import UnusedDeductionsMessageViewModel from './unusedDeductionsMessageViewModel'
import { UnusedDeductionMessageType } from '../services/unusedDeductionsService'
import { IdentifyRemandDecision } from '../@types/identifyRemandPeriods/identifyRemandPeriodsTypes'

export default class RemandViewModel {
public adjustments: Adjustment[]
Expand All @@ -16,6 +17,8 @@ export default class RemandViewModel {
private sentencesAndOffences: PrisonApiOffenderSentenceAndOffences[],
unusedDeductionsMessageType: UnusedDeductionMessageType,
inactiveWhenDeletedAdjustments: Adjustment[],
public roles: string[],
public remandDecision: IdentifyRemandDecision,
) {
this.adjustments = allAdjustments.filter(it => it.adjustmentType === 'REMAND')
this.unusedDeductionMessage = new UnusedDeductionsMessageViewModel(
Expand Down Expand Up @@ -51,4 +54,12 @@ export default class RemandViewModel {
public totalDays() {
return this.adjustments.reduce((sum, it) => sum + it.days, 0)
}

public readonly() {
return this.hasIdentifyRemandRole() && this.remandDecision?.accepted !== false
}

private hasIdentifyRemandRole(): boolean {
return this.roles.indexOf('REMAND_IDENTIFIER') !== -1
}
}
1 change: 1 addition & 0 deletions server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function routes(service: Services): Router {
service.calculateReleaseDatesService,
service.paramStoreService,
service.unusedDeductionsService,
service.identifyRemandPeriodsService,
)

const additionalDaysAwardedRoutes = new AdditionalDaysAwardedRoutes(
Expand Down
50 changes: 49 additions & 1 deletion server/routes/remandRoutes.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import dayjs from 'dayjs'
import type { Express } from 'express'
import request from 'supertest'
import { appWithAllRoutes } from './testutils/appSetup'
import { appWithAllRoutes, user } from './testutils/appSetup'
import PrisonerService from '../services/prisonerService'
import AdjustmentsService from '../services/adjustmentsService'
import { PrisonApiOffence, PrisonApiOffenderSentenceAndOffences } from '../@types/prisonApi/prisonClientTypes'
Expand All @@ -16,20 +16,23 @@ import {
import { Adjustment } from '../@types/adjustments/adjustmentsTypes'
import ParamStoreService from '../services/paramStoreService'
import UnusedDeductionsService from '../services/unusedDeductionsService'
import IdentifyRemandPeriodsService from '../services/identifyRemandPeriodsService'

jest.mock('../services/adjustmentsService')
jest.mock('../services/prisonerService')
jest.mock('../services/calculateReleaseDatesService')
jest.mock('../services/adjustmentsStoreService')
jest.mock('../services/paramStoreService')
jest.mock('../services/unusedDeductionsService')
jest.mock('../services/identifyRemandPeriodsService')

const prisonerService = new PrisonerService(null) as jest.Mocked<PrisonerService>
const adjustmentsService = new AdjustmentsService(null) as jest.Mocked<AdjustmentsService>
const calculateReleaseDatesService = new CalculateReleaseDatesService(null) as jest.Mocked<CalculateReleaseDatesService>
const adjustmentsStoreService = new AdjustmentsStoreService() as jest.Mocked<AdjustmentsStoreService>
const paramStoreService = new ParamStoreService() as jest.Mocked<ParamStoreService>
const unusedDeductionsService = new UnusedDeductionsService(null, null) as jest.Mocked<UnusedDeductionsService>
const identifyRemandPeriodsService = new IdentifyRemandPeriodsService(null) as jest.Mocked<IdentifyRemandPeriodsService>

const NOMS_ID = 'ABC123'
const SESSION_ID = '123-abc'
Expand Down Expand Up @@ -121,9 +124,15 @@ const mockedUnusedDeductionCalculationResponse = {
validationMessages: [remandOverlapWithSentenceMessage],
} as UnusedDeductionCalculationResponse

const defaultUser = user
const userWithRemandRole = { ...user, roles: ['REMAND_IDENTIFIER'] }

let userInTest = defaultUser

let app: Express

beforeEach(() => {
userInTest = defaultUser
app = appWithAllRoutes({
services: {
prisonerService,
Expand All @@ -132,7 +141,9 @@ beforeEach(() => {
calculateReleaseDatesService,
paramStoreService,
unusedDeductionsService,
identifyRemandPeriodsService,
},
userSupplier: () => userInTest,
})
})

Expand All @@ -155,6 +166,43 @@ describe('Remand routes tests', () => {
expect(res.text).toContain('From 01 Jan 2023 to 10 Jan 2023')
expect(res.text).toContain('Doing a crime')
expect(res.text).toContain('Heard at Court 1')
expect(res.text).toContain('edit-remand')
expect(res.text).toContain('delete-remand')
expect(res.text).toContain('Add new')
})
})

it('GET /{nomsId}/remand/view will be readonly if identify remand role without remand decision', () => {
userInTest = userWithRemandRole
prisonerService.getSentencesAndOffencesFilteredForRemand.mockResolvedValue([sentenceAndOffenceBaseRecord])
unusedDeductionsService.getCalculatedUnusedDeductionsMessageAndAdjustments.mockResolvedValue([
'NONE',
[remandAdjustment],
])
return request(app)
.get(`/${NOMS_ID}/remand/view`)
.expect(200)
.expect(res => {
expect(res.text).not.toContain('edit-remand')
expect(res.text).not.toContain('delete-remand')
expect(res.text).not.toContain('Add new')
})
})
it('GET /{nomsId}/remand/view will not be readonly if identify remand role with rejected remand decision', () => {
userInTest = userWithRemandRole
prisonerService.getSentencesAndOffencesFilteredForRemand.mockResolvedValue([sentenceAndOffenceBaseRecord])
unusedDeductionsService.getCalculatedUnusedDeductionsMessageAndAdjustments.mockResolvedValue([
'NONE',
[remandAdjustment],
])
identifyRemandPeriodsService.getRemandDecision.mockResolvedValue({ accepted: false })
return request(app)
.get(`/${NOMS_ID}/remand/view`)
.expect(200)
.expect(res => {
expect(res.text).toContain('edit-remand')
expect(res.text).toContain('delete-remand')
expect(res.text).toContain('Add new')
})
})

Expand Down
15 changes: 14 additions & 1 deletion server/routes/remandRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import RemandChangeModel from '../model/remandChangeModel'
import ParamStoreService from '../services/paramStoreService'
import { Adjustment } from '../@types/adjustments/adjustmentsTypes'
import UnusedDeductionsService from '../services/unusedDeductionsService'
import IdentifyRemandPeriodsService from '../services/identifyRemandPeriodsService'

export default class RemandRoutes {
constructor(
Expand All @@ -32,6 +33,7 @@ export default class RemandRoutes {
private readonly calculateReleaseDatesService: CalculateReleaseDatesService,
private readonly paramStoreService: ParamStoreService,
private readonly unusedDeductionsService: UnusedDeductionsService,
private readonly identifyRemandPeriodsService: IdentifyRemandPeriodsService,
) {}

public add: RequestHandler = async (req, res): Promise<void> => {
Expand Down Expand Up @@ -314,7 +316,7 @@ export default class RemandRoutes {

public view: RequestHandler = async (req, res): Promise<void> => {
const { nomsId } = req.params
const { username } = res.locals.user
const { username, roles } = res.locals.user
const { prisonerNumber, bookingId } = res.locals.prisoner
const [unusedDeductionMessage, adjustments] =
await this.unusedDeductionsService.getCalculatedUnusedDeductionsMessageAndAdjustments(nomsId, bookingId, username)
Expand All @@ -332,13 +334,24 @@ export default class RemandRoutes {
? await this.adjustmentsService.findByPersonAndStatus(nomsId, 'INACTIVE_WHEN_DELETED', username)
: []

let remandDecision
if (roles.includes('REMAND_IDENTIFIER')) {
try {
remandDecision = await this.identifyRemandPeriodsService.getRemandDecision(nomsId, username)
} catch {
// Nothing to do, remand review won't be displayed.
}
}

return res.render('pages/adjustments/remand/view', {
model: new RemandViewModel(
prisonerNumber,
adjustments,
sentencesAndOffences,
unusedDeductionMessage,
inactiveDeletedAdjustments,
roles,
remandDecision,
),
})
}
Expand Down
28 changes: 15 additions & 13 deletions server/views/pages/adjustments/remand/partials/remandCard.njk
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
{% from "./remandOffence.njk" import offenceList %}

{% macro remandCard(adjustment, offenderNo, alternateSummaryListStyle) %}
{% macro remandCard(adjustment, offenderNo, alternateSummaryListStyle, showLinks) %}
{% if alternateSummaryListStyle %}
{% set summaryListClasses = "no-footer-summary-list" %}
{% else %}
Expand All @@ -12,18 +12,20 @@
<div class="adjustment-card full clear govuk-!-margin-bottom-4">
<div class="govuk-summary-card__title-wrapper adjustment-card-heading clear">
<h2 class="govuk-summary-card__title">{{'From ' + adjustment.fromDate | date("DD MMM YYYY") + ' to ' + adjustment.toDate | date("DD MMM YYYY")}}</h2>
<ul class="govuk-summary-card__actions">
<li class="govuk-summary-card__action">
<a data-qa="edit-remand" class="govuk-link" href="/{{ offenderNo }}/remand/edit/{{ adjustment.id }}">
Edit<span class="govuk-visually-hidden"> remand from {{adjustment.fromDate | date("DD MMM YYYY")}} to {{adjustment.toDate | date("DD MMM YYYY")}}</span>
</a>
</li>
<li class="govuk-summary-card__action">
<a data-qa="delete-remand" class="govuk-link" href="/{{ offenderNo }}/remand/remove/{{ adjustment.id }}">
Delete<span class="govuk-visually-hidden"> remand from {{adjustment.fromDate | date("DD MMM YYYY")}} to {{adjustment.toDate | date("DD MMM YYYY")}}</span>
</a>
</li>
</ul>
{% if showLinks != false %}
<ul class="govuk-summary-card__actions">
<li class="govuk-summary-card__action">
<a data-qa="edit-remand" class="govuk-link" href="/{{ offenderNo }}/remand/edit/{{ adjustment.id }}">
Edit<span class="govuk-visually-hidden"> remand from {{adjustment.fromDate | date("DD MMM YYYY")}} to {{adjustment.toDate | date("DD MMM YYYY")}}</span>
</a>
</li>
<li class="govuk-summary-card__action">
<a data-qa="delete-remand" class="govuk-link" href="/{{ offenderNo }}/remand/remove/{{ adjustment.id }}">
Delete<span class="govuk-visually-hidden"> remand from {{adjustment.fromDate | date("DD MMM YYYY")}} to {{adjustment.toDate | date("DD MMM YYYY")}}</span>
</a>
</li>
</ul>
{% endif %}
</div>
<div class="adjustment-card_content">
{{ govukSummaryList({
Expand Down
14 changes: 8 additions & 6 deletions server/views/pages/adjustments/remand/view.njk
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,16 @@

<div class="adjustment-card-container">
{% for adjustment in model.adjustmentsWithOffences() %}
{{ remandCard(adjustment, prisoner.prisonerNumber) }}
{{ remandCard(adjustment, prisoner.prisonerNumber, null, not model.readonly()) }}
{% endfor %}
</div>
<div class="govuk-!-margin-top-6">
<a href="/{{ prisoner.prisonerNumber }}/remand/add" class="govuk-button" data-module="govuk-button">
Add new
</a>
</div>
{% if not model.readonly() %}
<div class="govuk-!-margin-top-6">
<a href="/{{ prisoner.prisonerNumber }}/remand/add" class="govuk-button" data-module="govuk-button">
Add new
</a>
</div>
{% endif %}
</div>
</div>

Expand Down

0 comments on commit 49473a6

Please sign in to comment.