From 3e6f5c2c44f013774fa1da1c7e962739efce5d1a Mon Sep 17 00:00:00 2001 From: ldlharper Date: Mon, 16 Oct 2023 10:43:59 +0100 Subject: [PATCH] ADJUST1-11 View additional days awarded. (#75) * ADJUST1-11 View additional days awarded. * ADJUST11 linting. * ADJUST1-11 View additional days titles. --- server/@types/AdaTypes.ts | 6 ++ server/routes/additionalDaysAwardedRoutes.ts | 23 ++++++ server/routes/index.ts | 1 + .../additionalDaysAwardedService.test.ts | 73 ++++++++++++++++++- .../services/additionalDaysAwardedService.ts | 43 ++++++++++- server/views/macros/adaTable.njk | 72 +++++++++++------- .../adjustments/additional-days/intercept.njk | 2 +- .../additional-days/review-and-approve.njk | 33 +++++++-- .../additional-days/review-and-submit.njk | 2 +- .../additional-days/review-prospective.njk | 9 ++- .../adjustments/additional-days/view.njk | 30 ++++++++ 11 files changed, 256 insertions(+), 38 deletions(-) create mode 100644 server/views/pages/adjustments/additional-days/view.njk diff --git a/server/@types/AdaTypes.ts b/server/@types/AdaTypes.ts index 905cef80..12f9c2c6 100644 --- a/server/@types/AdaTypes.ts +++ b/server/@types/AdaTypes.ts @@ -35,6 +35,11 @@ type AdasToReview = { intercept: AdaIntercept } +type AdasToView = { + awarded: AdasByDateCharged[] + totalAwarded: number +} + type PadasToReview = { prospective: AdasByDateCharged[] totalProspective: number @@ -57,4 +62,5 @@ export { AdaStatus, ChargeStatus, PadasToReview, + AdasToView, } diff --git a/server/routes/additionalDaysAwardedRoutes.ts b/server/routes/additionalDaysAwardedRoutes.ts index 24cf9a24..732a7c39 100644 --- a/server/routes/additionalDaysAwardedRoutes.ts +++ b/server/routes/additionalDaysAwardedRoutes.ts @@ -182,4 +182,27 @@ export default class AdditionalDaysAwardedRoutes { } as Message return res.redirect(`/${nomsId}/success?message=${JSON.stringify(message)}`) } + + public view: RequestHandler = async (req, res): Promise => { + const { caseloads, token, username } = res.locals.user + const { nomsId } = req.params + const prisonerDetail = await this.prisonerService.getPrisonerDetail(nomsId, caseloads, token) + const startOfSentenceEnvelope = await this.prisonerService.getStartOfSentenceEnvelope( + prisonerDetail.bookingId, + token, + ) + const adas = await this.additionalDaysAwardedService.viewAdjustments( + nomsId, + startOfSentenceEnvelope, + username, + token, + ) + + return res.render('pages/adjustments/additional-days/view', { + model: { + prisonerDetail, + adas, + }, + }) + } } diff --git a/server/routes/index.ts b/server/routes/index.ts index eb030720..58eefc17 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -44,6 +44,7 @@ export default function routes(service: Services): Router { post('/:nomsId/additional-days/review-and-approve', additionalDaysAwardedRoutes.approve) get('/:nomsId/additional-days/review-and-submit', additionalDaysAwardedRoutes.reviewAndSubmit) post('/:nomsId/additional-days/review-and-submit', additionalDaysAwardedRoutes.submit) + get('/:nomsId/additional-days/view', additionalDaysAwardedRoutes.view) get('/:nomsId/:adjustmentTypeUrl/view', adjustmentRoutes.view) get('/:nomsId/:adjustmentTypeUrl/remove/:id', adjustmentRoutes.remove) diff --git a/server/services/additionalDaysAwardedService.test.ts b/server/services/additionalDaysAwardedService.test.ts index 8b77de1d..5a6a5f88 100644 --- a/server/services/additionalDaysAwardedService.test.ts +++ b/server/services/additionalDaysAwardedService.test.ts @@ -5,7 +5,7 @@ import AdditionalDaysAwardedService from './additionalDaysAwardedService' import TokenStore from '../data/tokenStore' import config from '../config' import { AdjudicationSearchResponse, IndividualAdjudication } from '../@types/adjudications/adjudicationTypes' -import { AdaIntercept, AdasToReview, PadasToReview } from '../@types/AdaTypes' +import { AdaIntercept, AdasToReview, AdasToView, PadasToReview } from '../@types/AdaTypes' import { Adjustment } from '../@types/adjustments/adjustmentsTypes' import { PrisonApiPrisoner } from '../@types/prisonApi/prisonClientTypes' import AdditionalDaysAwardedStoreService from './additionalDaysApprovalStoreService' @@ -423,6 +423,77 @@ describe('Additional Days Added Service', () => { } as AdasToReview) }) + it('View adjustments for adjudications awarded.', async () => { + const nomsId = 'AA1234A' + adjudicationsApi + .get('/adjudications/AA1234A/adjudications?size=1000', '') + .reply(200, threeAdjudicationsSearchResponse) + adjudicationsApi.get('/adjudications/AA1234A/charge/1525916', '').reply(200, adjudicationOne) + adjudicationsApi.get('/adjudications/AA1234A/charge/1525917', '').reply(200, adjudicationTwoConsecutiveToOne) + adjudicationsApi.get('/adjudications/AA1234A/charge/1525918', '').reply(200, adjudicationThreeConcurrentToOne) + adjustmentApi.get(`/adjustments?person=${nomsId}`).reply(200, [ + { + id: 'c5b61b4e-8b47-4dfc-b88b-5eb58fc04691', + person: 'AA1234A', + bookingId: 1234, + adjustmentType: 'ADDITIONAL_DAYS_AWARDED', + fromDate: '2023-08-03', + days: 10, + additionalDaysAwarded: { adjudicationId: [1525916, 1525917, 1525918] }, + }, + ]) + const startOfSentenceEnvelope = new Date('2023-01-01') + + const adasToView: AdasToView = await adaService.viewAdjustments( + nomsId, + startOfSentenceEnvelope, + 'username', + token, + ) + + expect(adasToView).toEqual({ + awarded: [ + { + dateChargeProved: new Date('2023-08-03'), + charges: [ + { + chargeNumber: 1525916, + dateChargeProved: new Date('2023-08-03'), + days: 5, + heardAt: 'Moorland (HMP & YOI)', + status: 'AWARDED_OR_PENDING', + toBeServed: 'Forthwith', + sequence: 15, + }, + { + chargeNumber: 1525917, + dateChargeProved: new Date('2023-08-03'), + days: 5, + heardAt: 'Moorland (HMP & YOI)', + status: 'AWARDED_OR_PENDING', + toBeServed: 'Consecutive to 1525916', + sequence: 16, + consecutiveToSequence: 15, + }, + { + chargeNumber: 1525918, + dateChargeProved: new Date('2023-08-03'), + days: 5, + heardAt: 'Moorland (HMP & YOI)', + status: 'AWARDED_OR_PENDING', + toBeServed: 'Concurrent', + sequence: 17, + }, + ], + total: 10, + status: 'AWARDED', + adjustmentId: 'c5b61b4e-8b47-4dfc-b88b-5eb58fc04691', + }, + ], + totalAwarded: 10, + } as AdasToView) + }) + it('Get adjudication where adjustment has been quashed', async () => { const nomsId = 'AA1234A' adjudicationsApi diff --git a/server/services/additionalDaysAwardedService.ts b/server/services/additionalDaysAwardedService.ts index e4f4b4b1..ac2df145 100644 --- a/server/services/additionalDaysAwardedService.ts +++ b/server/services/additionalDaysAwardedService.ts @@ -3,7 +3,15 @@ import dayjs from 'dayjs' import AdjudicationClient from '../api/adjudicationsClient' import { AdjudicationSearchResponse, IndividualAdjudication, Sanction } from '../@types/adjudications/adjudicationTypes' import { HmppsAuthClient } from '../data' -import { Ada, AdaIntercept, AdasByDateCharged, AdasToReview, ChargeStatus, PadasToReview } from '../@types/AdaTypes' +import { + Ada, + AdaIntercept, + AdasByDateCharged, + AdasToReview, + AdasToView, + ChargeStatus, + PadasToReview, +} from '../@types/AdaTypes' import AdjustmentsClient from '../api/adjustmentsClient' import { PrisonApiPrisoner } from '../@types/prisonApi/prisonClientTypes' import { Adjustment } from '../@types/adjustments/adjustmentsTypes' @@ -56,6 +64,39 @@ export default class AdditionalDaysAwardedService { private readonly additionalDaysAwardedStoreService: AdditionalDaysAwardedStoreService, ) {} + public async viewAdjustments( + nomsId: string, + startOfSentenceEnvelope: Date, + username: string, + token: string, + ): Promise { + const allAdaAdjustments = (await new AdjustmentsClient(token).findByPerson(nomsId)).filter( + it => it.adjustmentType === 'ADDITIONAL_DAYS_AWARDED', + ) + const existingAdasWithChargeIds = allAdaAdjustments.filter(it => it.additionalDaysAwarded) + const systemToken = await this.hmppsAuthClient.getSystemClientToken(username) + const adjudicationClient = new AdjudicationClient(systemToken) + const adjudications: AdjudicationSearchResponse = await adjudicationClient.getAdjudications(nomsId) + const individualAdjudications = await Promise.all( + adjudications.results.content.map(async it => { + return adjudicationClient.getAdjudication(nomsId, it.adjudicationNumber) + }), + ) + const adas: Ada[] = this.getAdas(individualAdjudications, startOfSentenceEnvelope) + const awardedOrPending: AdasByDateCharged[] = this.getAdasByDateCharged(adas, 'AWARDED_OR_PENDING') + let { awarded } = this.filterAdasByMatchingAdjustment(awardedOrPending, existingAdasWithChargeIds) + const allProspective: AdasByDateCharged[] = this.getAdasByDateCharged(adas, 'PROSPECTIVE') + const { awarded: prospectiveAwarded } = this.filterAdasByMatchingAdjustment( + allProspective, + existingAdasWithChargeIds, + ) + + awarded = awarded.concat(prospectiveAwarded) + const totalAwarded: number = this.getTotalDays(awarded) + + return { awarded, totalAwarded } + } + public async getAdasToApprove( req: Request, nomsId: string, diff --git a/server/views/macros/adaTable.njk b/server/views/macros/adaTable.njk index 63cfd4b6..be70e357 100644 --- a/server/views/macros/adaTable.njk +++ b/server/views/macros/adaTable.njk @@ -1,24 +1,36 @@ -{% macro adaTable(tableId, adas, total, mainTitle, emptyTitle, checkboxes) %} - {% if adas | length %} - {% if mainTitle %} -

{{ mainTitle }}

+{# +This macro creates a table of ADAs. It has the following params + +tableId: required, id of the table +adas: required, the data to display +total: required, the total number of days. +mainTitle: optional, title above table +emptyTitle: optional, displayed if table is empty +checkboxes: optional, defaults to false, does table have checkboxes +hideStatuses: optional, defaults to false , should the status of the ada be displayed +totalText: optional, defaults to 'Total' , the text displayed next to the total. +#} +{% macro adaTable(params) %} + {% if params.adas | length %} + {% if params.mainTitle %} +

{{ params.mainTitle }}

{% endif %} - +
- {% if checkboxes %} + {% if params.checkboxes %} {% endif %} - + - {% for ada in adas %} + {% for ada in params.adas %} - {% if checkboxes %} + {% if params.checkboxes %} {% endif %} - - {% if not checkboxes %} + {% if not params.checkboxes %} - - + + {% endif %}
Select adjudication Date charge provedDate charge proved Charge details
{% set isoDate = ada.dateChargeProved | date("YYYY-MM-DD") %} @@ -30,17 +42,19 @@
+ {{ ada.dateChargeProved | date("DD MMM YYYY") }} - + - - + {% if not params.hideStatuses %} + + {% endif %} + {% for charge in ada.charges %} @@ -53,16 +67,18 @@ - + {% if not params.hideStatuses %} + + {% endif %} - + {% endfor %}
Charge numberCharge number To be served Heard atStatusDaysStatusDays
{{ charge.heardAt }} - {% if not checkboxes %} - {{ ada.status }} - {% endif %} - {% if charge.status === 'PROSPECTIVE' %} - {{ charge.status }} - {% endif %} - + {% if not params.checkboxes %} + {{ ada.status }} + {% endif %} + {% if charge.status === 'PROSPECTIVE' %} + {{ charge.status }} + {% endif %} + {{ charge.days }}{{ charge.days }}
@@ -71,17 +87,19 @@ {% endfor %}
Total{{ total }} + {{params.totalText if params.totalText else 'Total'}} + {{ params.total }}
- {% if checkboxes %} + {% if params.checkboxes %}
@@ -92,6 +110,6 @@
{% endif %} {% else %} -

{{ emptyTitle }}

+

{{ params.emptyTitle }}

{% endif %} {% endmacro %} \ No newline at end of file diff --git a/server/views/pages/adjustments/additional-days/intercept.njk b/server/views/pages/adjustments/additional-days/intercept.njk index c099eacb..12b57f84 100644 --- a/server/views/pages/adjustments/additional-days/intercept.njk +++ b/server/views/pages/adjustments/additional-days/intercept.njk @@ -2,7 +2,7 @@ {% from "../../../macros/adaTable.njk" import adaTable %} {% from "govuk/components/button/macro.njk" import govukButton %} -{% set pageTitle = applicationName + " - Review additional days awarded" %} +{% set pageTitle = applicationName + " - Review adjustment information" %} {% set mainClasses = "app-container govuk-body" %} {% block content %} diff --git a/server/views/pages/adjustments/additional-days/review-and-approve.njk b/server/views/pages/adjustments/additional-days/review-and-approve.njk index 7d8b5f67..801c3a81 100644 --- a/server/views/pages/adjustments/additional-days/review-and-approve.njk +++ b/server/views/pages/adjustments/additional-days/review-and-approve.njk @@ -2,7 +2,7 @@ {% from "../../../macros/adaTable.njk" import adaTable %} {% from "govuk/components/button/macro.njk" import govukButton %} -{% set pageTitle = applicationName + " - Review additional days awarded" %} +{% set pageTitle = applicationName + " - Review and approve ADAs" %} {% set mainClasses = "app-container govuk-body" %} {% block content %} @@ -32,20 +32,43 @@ {% if adasToReview.intercept.type != 'FIRST_TIME'%}

Awarded ADAs

- {{ adaTable('awarded-adas', adasToReview.awarded, adasToReview.totalAwarded, 'Awarded ADAs will be included in the calculation.', model.prisonerDetail.firstName | title + ' ' + model.prisonerDetail.lastName | title + ' has no ADAs that are applicable to the current sentences.') }} + {{ adaTable({ + tableId: 'awarded-adas', + adas: adasToReview.awarded, + total: adasToReview.totalAwarded, + mainTitle: 'Awarded ADAs will be included in the calculation.', + emptyTitle: model.prisonerDetail.firstName | title + ' ' + model.prisonerDetail.lastName | title + ' has no ADAs that are applicable to the current sentences.' + }) + }} {% endif %} {% if adasToReview.suspended | length %}

Suspended ADAs

- {{ adaTable('suspended-adas', adasToReview.suspended, adasToReview.totalSuspended, 'Suspended ADAs will not be included in the calculation.') }} + {{ adaTable({ + tableId: 'suspended-adas', + adas: adasToReview.suspended, + total: adasToReview.totalSuspended, + mainTitle: 'Suspended ADAs will not be included in the calculation.' + }) }} {% endif %}

Awarded ADAs pending approval

- {{ adaTable('awaiting-approval-adas', adasToReview.awaitingApproval, adasToReview.totalAwaitingApproval, 'Once you have reviewed and approved the ADAs pending approval, they will be added to the sentence calculation.', 'No ADA records waiting for approval exist for this offender') }} + {{ adaTable({ + tableId: 'awaiting-approval-adas', + adas: adasToReview.awaitingApproval, + total: adasToReview.totalAwaitingApproval, + mainTitle: 'Once you have reviewed and approved the ADAs pending approval, they will be added to the sentence calculation.', + emptyTitle: 'No ADA records waiting for approval exist for this offender' + }) }} {% if adasToReview.quashed | length %}

Review and approve quashed ADAs

- {{ adaTable('quashed-approval-adas', adasToReview.quashed, adasToReview.totalQuashed, 'Once you have reviewed and approved the quashed ADAs, they will not be included in the sentence calculation') }} + {{ adaTable({ + tableId: 'quashed-approval-adas', + adas: adasToReview.quashed, + total: adasToReview.totalQuashed, + mainTitle: 'Once you have reviewed and approved the quashed ADAs, they will not be included in the sentence calculation' + }) }} {% endif %}
diff --git a/server/views/pages/adjustments/additional-days/review-and-submit.njk b/server/views/pages/adjustments/additional-days/review-and-submit.njk index c9e71ffa..f6203779 100644 --- a/server/views/pages/adjustments/additional-days/review-and-submit.njk +++ b/server/views/pages/adjustments/additional-days/review-and-submit.njk @@ -2,7 +2,7 @@ {% from "govuk/components/table/macro.njk" import govukTable %} {% from "govuk/components/button/macro.njk" import govukButton %} -{% set pageTitle = applicationName + " - Review additional days awarded" %} +{% set pageTitle = applicationName + " - Review and submit ADAs" %} {% set mainClasses = "app-container govuk-body" %} {% block content %} diff --git a/server/views/pages/adjustments/additional-days/review-prospective.njk b/server/views/pages/adjustments/additional-days/review-prospective.njk index 5a61124c..fcc04ce5 100644 --- a/server/views/pages/adjustments/additional-days/review-prospective.njk +++ b/server/views/pages/adjustments/additional-days/review-prospective.njk @@ -3,7 +3,7 @@ {% from "govuk/components/button/macro.njk" import govukButton %} {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %} -{% set pageTitle = applicationName + " - Review additional days awarded" %} +{% set pageTitle = applicationName + " - Review PADAs" %} {% set mainClasses = "app-container govuk-body" %} {% block content %} @@ -38,7 +38,12 @@
- {{ adaTable('prospective-adas', padasToReview.prospective, padasToReview.totalProspective, null, null, true) }} + {{ adaTable({ + tableId:'prospective-adas', + adas: padasToReview.prospective, + total: padasToReview.totalProspective, + checkboxes: true + }) }} {{ govukButton({ text: "Continue", diff --git a/server/views/pages/adjustments/additional-days/view.njk b/server/views/pages/adjustments/additional-days/view.njk new file mode 100644 index 00000000..659e26a3 --- /dev/null +++ b/server/views/pages/adjustments/additional-days/view.njk @@ -0,0 +1,30 @@ +{% extends "../../../partials/layout.njk" %} +{% from "../../../macros/adaTable.njk" import adaTable %} +{% from "govuk/components/button/macro.njk" import govukButton %} + +{% set pageTitle = applicationName + " - ADA details" %} +{% set mainClasses = "app-container govuk-body" %} + +{% block content %} + + Back + +
+
+
+

+ Adjust release dates + ADA details +

+ {{ adaTable({ + tableId:'awarded-adas', + adas: model.adas.awarded, + total: model.adas.totalAwarded, + hideStatuses: true, + totalText: 'Total ADAs taken into calculation' + }) }} + +
+
+
+{% endblock %} \ No newline at end of file