From 51f9da911f9d0e50145104e9d817c563b625f516 Mon Sep 17 00:00:00 2001 From: Neil Mills Date: Wed, 8 Jan 2025 17:20:34 +0000 Subject: [PATCH] MAN-36 requirement note ui changes and int tests completed --- .../e2e/licence-condition-note.cy.ts | 1 - integration_tests/e2e/requirement-note.cy.ts | 38 ++++++++ integration_tests/e2e/sentence.cy.ts | 52 ++++++++++- integration_tests/pages/page.ts | 2 +- integration_tests/pages/sentence.ts | 12 ++- server/data/masApiClient.ts | 12 +++ server/data/model/requirementNoteDetails.ts | 32 +++++++ server/data/model/sentenceDetails.ts | 9 ++ server/routes/sentence.ts | 27 ++++++ .../views/pages/address-book-professional.njk | 2 +- .../views/pages/appointments/appointment.njk | 2 +- server/views/pages/caseload/caseload.njk | 2 +- server/views/pages/handoff/delius.njk | 2 +- server/views/pages/handoff/oasys.njk | 2 +- server/views/pages/index.njk | 2 +- .../pages/personal-details/addresses.njk | 2 +- .../pages/personal-details/adjustments.njk | 2 +- .../pages/personal-details/circumstances.njk | 2 +- .../views/pages/personal-details/contact.njk | 2 +- server/views/pages/requirement-note.njk | 91 +++++++++++++++++++ server/views/pages/risk/flag.njk | 2 +- .../views/pages/risk/removed-risk-flags.njk | 2 +- server/views/pages/sentence.njk | 30 ++++-- server/views/pages/sentence/offences.njk | 2 +- server/views/partials/case.njk | 2 +- .../mappings/X000001-requirement-note-0.json | 44 +++++++++ wiremock/mappings/X000001-sentence.json | 30 +++++- 27 files changed, 381 insertions(+), 27 deletions(-) create mode 100644 integration_tests/e2e/requirement-note.cy.ts create mode 100644 server/data/model/requirementNoteDetails.ts create mode 100644 server/views/pages/requirement-note.njk create mode 100644 wiremock/mappings/X000001-requirement-note-0.json diff --git a/integration_tests/e2e/licence-condition-note.cy.ts b/integration_tests/e2e/licence-condition-note.cy.ts index 3a097829..d2932efc 100644 --- a/integration_tests/e2e/licence-condition-note.cy.ts +++ b/integration_tests/e2e/licence-condition-note.cy.ts @@ -4,7 +4,6 @@ import SentencePage from '../pages/sentence' context('Sentence', () => { it('Licence condition note page is rendered', () => { cy.visit('/case/X000001/sentence/licence-condition/7007/note/0') - const page = Page.verifyOnPage(SentencePage) page.headerCrn().should('contain.text', 'X000001') page.headerName().should('contain.text', 'Caroline Wolff') diff --git a/integration_tests/e2e/requirement-note.cy.ts b/integration_tests/e2e/requirement-note.cy.ts new file mode 100644 index 00000000..76786188 --- /dev/null +++ b/integration_tests/e2e/requirement-note.cy.ts @@ -0,0 +1,38 @@ +import Page from '../pages/page' +import SentencePage from '../pages/sentence' + +context('Sentence', () => { + it('Requirement note page is rendered', () => { + cy.visit('/case/X000001/sentence/requirement/F/note/0') + const page = Page.verifyOnPage(SentencePage) + page.headerCrn().should('contain.text', 'X000001') + page.headerName().should('contain.text', 'Caroline Wolff') + cy.get('[data-qa=pageHeading]').eq(0).should('contain.text', 'Sentence') + + cy.get(`[class=app-summary-card__header]`).within(() => + cy.get('h2').should('contain.text', '1 of 12 RAR days completed'), + ) + + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dt').should('have.length', 6)) + + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dd').should('have.length', 6)) + + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dt').eq(0).should('contain.text', 'Length of RAR')) + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dd').eq(0).should('contain.text', '12 days')) + + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dt').eq(1).should('contain.text', 'Completed RAR')) + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dd').eq(1).should('contain.text', '1 day')) + + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dt').eq(2).should('contain.text', 'Start date')) + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dd').eq(2).should('contain.text', '12 April 2024')) + + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dt').eq(3).should('contain.text', 'Note added by')) + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dd').eq(3).should('contain.text', 'Jon Jones')) + + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dt').eq(4).should('contain.text', 'Date added')) + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dd').eq(4).should('contain.text', '21 August 2024')) + + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dt').eq(5).should('contain.text', 'Note')) + cy.get(`[class=app-summary-card__body]`).within(() => cy.get('dd').eq(5).should('contain.text', '123456')) + }) +}) diff --git a/integration_tests/e2e/sentence.cy.ts b/integration_tests/e2e/sentence.cy.ts index 90c7c6e1..e8cb8846 100644 --- a/integration_tests/e2e/sentence.cy.ts +++ b/integration_tests/e2e/sentence.cy.ts @@ -7,7 +7,6 @@ context('Sentence', () => { const page = Page.verifyOnPage(SentencePage) page.headerCrn().should('contain.text', 'X000001') page.headerName().should('contain.text', 'Caroline Wolff') - cy.get('[data-qa=pageHeading]').eq(0).should('contain.text', 'Sentence') page.getTab('overview').should('contain.text', 'Overview') page.getTab('personalDetails').should('contain.text', 'Personal details') @@ -183,4 +182,55 @@ context('Sentence', () => { .getCardHeader('probationHistory') .within(() => cy.get('a').eq(1).invoke('attr', 'href').should('equal', '/case/X000001/address-book-professional')) }) + + it('Sentence page is rendered with requirements', () => { + cy.visit('/case/X000001/sentence?number=1') + const page = Page.verifyOnPage(SentencePage) + + cy.get(`[data-qa="sentenceCard"]`).within(() => cy.get('dt').eq(5).should('contain.text', 'Requirements')) + cy.get(`[data-qa="requirementsValue"]`).within(() => + cy.get('details').eq(0).should('contain.text', '1 of 12 RAR days completed'), + ) + cy.get(`[data-qa="requirementsValue"]`).within(() => + cy.get('details').eq(1).should('contain.text', 'Curfew (Electronic Monitored)'), + ) + cy.get(`[data-qa="requirementsValue"]`).within(() => + cy.get('details').eq(2).should('contain.text', 'Unpaid Work - Regular'), + ) + cy.get(`[data-qa="requirementsValue"] `).within(() => cy.get('details').eq(1).click()) + page.getRequirementLabel(2, 1).should('contain.text', 'Length') + page.getRequirementValue(2, 1).should('contain.text', '10 hours') + page.getRequirementLabel(2, 2).should('contain.text', 'Start date') + page.getRequirementValue(2, 2).should('contain.text', '12 January 2024') + page.getRequirementLabel(2, 3).should('contain.text', 'End date') + page.getRequirementValue(2, 3).should('contain.text', '9 January 2024') + page.getRequirementLabel(2, 4).should('contain.text', 'Result') + page.getRequirementValue(2, 4).should('contain.text', 'Expired (Normal)') + page.getRequirementLabel(2, 5).should('contain.text', 'Notes') + page.getRequirementValue(2, 5).should('contain.text', 'curfew notes') + page + .getRequirementValue(2, 5) + .find('p:nth-of-type(2)') + .should('contain.text', 'Comment added by Jon Jones on 21 August 2024') + page.getRequirementValue(2, 5).find('a').should('not.exist') + + cy.get(`[data-qa="requirementsValue"] `).within(() => cy.get('details').eq(0).click()) + page.getRequirementLabel(1, 1).should('contain.text', 'Length of RAR') + page.getRequirementValue(1, 1).should('contain.text', '12 days') + page.getRequirementLabel(1, 2).should('contain.text', 'Completed RAR') + page.getRequirementValue(1, 2).should('contain.text', '1 day') + page.getRequirementLabel(1, 3).should('contain.text', 'Start date') + page.getRequirementValue(1, 3).should('contain.text', '12 April 2024') + page.getRequirementLabel(1, 4).should('contain.text', 'Notes') + page.getRequirementValue(1, 4).should('contain.text', 'Requirement created automatically') + page.getRequirementValue(1, 4).should('not.contain.text', '123456') + page.getRequirementValue(1, 4).find('a').should('contain.text', 'View full note') + page + .getRequirementValue(1, 4) + .find('p:nth-of-type(2)') + .should('contain.text', 'Comment added by Jon Jones on 21 August 2024') + page.getRequirementValue(1, 4).find('a').click() + cy.get(`[data-qa="name"]`).should('contain.text', 'Caroline Wolff') + cy.get('.app-summary-card__header').should('contain.text', '1 of 12 RAR days completed') + }) }) diff --git a/integration_tests/pages/page.ts b/integration_tests/pages/page.ts index 16099f69..15379259 100644 --- a/integration_tests/pages/page.ts +++ b/integration_tests/pages/page.ts @@ -10,7 +10,7 @@ export default abstract class Page { } checkOnPage(): void { - cy.get('h1').contains(this.title) + cy.get('[data-qa=pageHeading]').contains(this.title) } signOut = (): PageElement => cy.get('[data-qa=signOut]') diff --git a/integration_tests/pages/sentence.ts b/integration_tests/pages/sentence.ts index 067617d6..84070377 100644 --- a/integration_tests/pages/sentence.ts +++ b/integration_tests/pages/sentence.ts @@ -1,7 +1,17 @@ -import Page from './page' +import Page, { PageElement } from './page' export default class SentencePage extends Page { constructor() { super('Sentence') } + + getRequirementLabel = (requirementIndex: number, index: number): PageElement => + cy.get( + `[data-qa="requirementsValue"] details:nth-of-type(${requirementIndex}) .govuk-summary-list__row:nth-of-type(${index}) dt`, + ) + + getRequirementValue = (requirementIndex: number, index: number): PageElement => + cy.get( + `[data-qa="requirementsValue"] details:nth-of-type(${requirementIndex}) .govuk-summary-list__row:nth-of-type(${index}) dd`, + ) } diff --git a/server/data/masApiClient.ts b/server/data/masApiClient.ts index aababb36..46ab6cc0 100644 --- a/server/data/masApiClient.ts +++ b/server/data/masApiClient.ts @@ -20,6 +20,7 @@ import { TeamCaseload, UserCaseload, UserTeam } from './model/caseload' import { ProfessionalContact } from './model/professionalContact' import { CaseAccess, UserAccess } from './model/caseAccess' import { LicenceConditionNoteDetails } from './model/licenceConditionNoteDetails' +import { RequirementNoteDetails } from './model/requirementNoteDetails' export default class MasApiClient extends RestClient { constructor(token: string) { @@ -57,6 +58,17 @@ export default class MasApiClient extends RestClient { }) } + async getSentenceRequirementNote( + crn: string, + requirementId: string, + noteId: string, + ): Promise { + return this.get({ + path: `/sentence/${crn}/requirement/${requirementId}/note/${noteId}`, + handle404: false, + }) + } + async getContacts(crn: string): Promise { return this.get({ path: `/sentence/${crn}/contacts`, handle404: false }) } diff --git a/server/data/model/requirementNoteDetails.ts b/server/data/model/requirementNoteDetails.ts new file mode 100644 index 00000000..1585e8af --- /dev/null +++ b/server/data/model/requirementNoteDetails.ts @@ -0,0 +1,32 @@ +import { PersonSummary } from './common' + +export interface RequirementNoteDetails { + personSummary: PersonSummary + requirement: Requirement +} + +export interface Requirement { + code: string + expectedStartDate?: string + actualStartDate: string + expectedEndDate?: string + actualEndDate?: string + terminationReason?: string + description: string + length: number + lengthUnitValue: string + requirementNote: RequirementNote + rar?: { + completed: number + scheduled: number + totalDays: number + } +} + +export interface RequirementNote { + id: string + createdBy: string + createdByDate: string + note: string + hasNotesBeenTruncated: boolean +} diff --git a/server/data/model/sentenceDetails.ts b/server/data/model/sentenceDetails.ts index 614608a6..7bee8c83 100644 --- a/server/data/model/sentenceDetails.ts +++ b/server/data/model/sentenceDetails.ts @@ -49,6 +49,14 @@ export interface Order { startDate: string } +export interface RequirementNote { + id: number + createdBy: string + createdByDate: string + note: string + hasNoteBeenTruncated: boolean +} + export interface Requirement { code: string expectedStartDate: string @@ -59,6 +67,7 @@ export interface Requirement { description: string codeDescription: string length: string + requirementNotes: RequirementNote[] notes: string rar: Rar } diff --git a/server/routes/sentence.ts b/server/routes/sentence.ts index 7dc4415e..0e646ee9 100644 --- a/server/routes/sentence.ts +++ b/server/routes/sentence.ts @@ -167,4 +167,31 @@ export default function sentenceRoutes(router: Router, { hmppsAuthClient }: Serv crn, }) }) + + get('/case/:crn/sentence/requirement/:requirementId/note/:noteId', async (req, res, _next) => { + const { crn, requirementId, noteId } = req.params + const token = await hmppsAuthClient.getSystemClientToken(res.locals.user.username) + + await auditService.sendAuditMessage({ + action: 'VIEW_MAS_SENTENCE_REQUIREMENT_NOTE', + who: res.locals.user.username, + subjectId: crn, + subjectType: 'CRN', + correlationId: v4(), + service: 'hmpps-manage-a-supervision-ui', + }) + + const masClient = new MasApiClient(token) + const tierClient = new TierApiClient(token) + + const [requirementNoteDetails, tierCalculation] = await Promise.all([ + masClient.getSentenceRequirementNote(crn, requirementId, noteId), + tierClient.getCalculationDetails(crn), + ]) + res.render('pages/requirement-note', { + requirementNoteDetails, + tierCalculation, + crn, + }) + }) } diff --git a/server/views/pages/address-book-professional.njk b/server/views/pages/address-book-professional.njk index 1e829dd7..cab7c6f9 100755 --- a/server/views/pages/address-book-professional.njk +++ b/server/views/pages/address-book-professional.njk @@ -27,7 +27,7 @@ {% endblock %} {% block content %} -

{{ title }}

+

{{ title }}

diff --git a/server/views/pages/appointments/appointment.njk b/server/views/pages/appointments/appointment.njk index 48f6e28f..00e01d1a 100644 --- a/server/views/pages/appointments/appointment.njk +++ b/server/views/pages/appointments/appointment.njk @@ -33,7 +33,7 @@ {% block content %}
-

+

{% include './_appointment-prefix.njk' %} {{ title }} diff --git a/server/views/pages/caseload/caseload.njk b/server/views/pages/caseload/caseload.njk index 56bc3432..ef5d6738 100644 --- a/server/views/pages/caseload/caseload.njk +++ b/server/views/pages/caseload/caseload.njk @@ -10,7 +10,7 @@ {% endif %}
-

+

{{ title }}

{% include "./caseload-nav.njk" %} diff --git a/server/views/pages/handoff/delius.njk b/server/views/pages/handoff/delius.njk index 5d0f0fe1..f01b63a6 100644 --- a/server/views/pages/handoff/delius.njk +++ b/server/views/pages/handoff/delius.njk @@ -24,7 +24,7 @@
-

{{title}}

+

{{title}}

You’ll need to use National Delius to:

    diff --git a/server/views/pages/handoff/oasys.njk b/server/views/pages/handoff/oasys.njk index e9322941..52cd4561 100644 --- a/server/views/pages/handoff/oasys.njk +++ b/server/views/pages/handoff/oasys.njk @@ -24,7 +24,7 @@
    -

    {{title}}

    +

    {{title}}

    You’ll need to use OASys to:

      diff --git a/server/views/pages/index.njk b/server/views/pages/index.njk index e9ca10af..52161dc0 100644 --- a/server/views/pages/index.njk +++ b/server/views/pages/index.njk @@ -4,7 +4,7 @@ {% set mainClasses = "app-container govuk-body" %} {% block content %} -

      Manage a Supervision

      +

      Manage a Supervision

      Not all cases are suitable for the Manage supervisions pilot. This service is only suitable for cases that have:

        diff --git a/server/views/pages/personal-details/addresses.njk b/server/views/pages/personal-details/addresses.njk index 61b716d6..904eaaf0 100644 --- a/server/views/pages/personal-details/addresses.njk +++ b/server/views/pages/personal-details/addresses.njk @@ -25,7 +25,7 @@ {% endblock %} {% block content %} -

        {{ title }}

        +

        {{ title }}