Skip to content

Commit

Permalink
ADJUST1-283 Edit functionality for an existing Remands period dates (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
yasinmustafa authored Dec 13, 2023
1 parent 53fec21 commit 0587986
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 82 deletions.
2 changes: 2 additions & 0 deletions server/model/remandDatesModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ export default class RemandDatesModel {
public prisonerDetail: PrisonApiPrisoner,
public adjustments: SessionAdjustment[],
public form: RemandDatesForm,
public addOrEdit: string = null,
) {}

public backlink(): string {
if (this.addOrEdit === 'edit') return `/${this.prisonerDetail.offenderNo}/remand/edit/${this.id}`
if (this.adjustments.length > 1 || this.adjustments[0].complete) {
return `/${this.prisonerDetail.offenderNo}/remand/review`
}
Expand Down
190 changes: 115 additions & 75 deletions server/routes/remandRoutes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,84 +131,105 @@ describe('Adjustment routes tests', () => {
})
})

it('POST /{nomsId}/remand/dates/add valid', () => {
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
adjustmentsService.validate.mockResolvedValue([])
return request(app)
.post(`/${NOMS_ID}/remand/dates/add/${SESSION_ID}`)
.send({
'from-day': '5',
'from-month': '4',
'from-year': '2023',
'to-day': '20',
'to-month': '4',
'to-year': '2023',
})
.type('form')
.expect(302)
.expect('Location', `/${NOMS_ID}/remand/offences/add/${SESSION_ID}`)
})
describe('POST /{nomsId}/remand/dates/:addOrEdit validation tests', () => {
const addLink = `/${NOMS_ID}/remand/offences/add/${SESSION_ID}`
const editLink = `/${NOMS_ID}/remand/edit/${SESSION_ID}`

it('POST /{nomsId}/remand/dates/add empty form validation', () => {
const adjustments = {}
adjustments[SESSION_ID] = blankAdjustment
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getAll.mockReturnValue(adjustments)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
return request(app)
.post(`/${NOMS_ID}/remand/dates/add/${SESSION_ID}`)
.expect('Content-Type', /html/)
.expect(res => {
expect(res.text).toContain('This date must include a valid day, month and year')
})
})
test.each`
addOrEdit | redirectLocation
${'add'} | ${addLink}
${'edit'} | ${editLink}
`('POST of dates when content is valid redirects correctly', async ({ addOrEdit, redirectLocation }) => {
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
adjustmentsService.validate.mockResolvedValue([])
return request(app)
.post(`/${NOMS_ID}/remand/dates/${addOrEdit}/${SESSION_ID}`)
.send({
'from-day': '5',
'from-month': '4',
'from-year': '2023',
'to-day': '20',
'to-month': '4',
'to-year': '2023',
})
.type('form')
.expect(302)
.expect('Location', redirectLocation)
})

it('POST /{nomsId}/remand/dates/add to date after from', () => {
const adjustments = {}
adjustments[SESSION_ID] = blankAdjustment
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getAll.mockReturnValue(adjustments)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
return request(app)
.post(`/${NOMS_ID}/remand/dates/add/${SESSION_ID}`)
.send({
'from-day': '5',
'from-month': '4',
'from-year': '2023',
'to-day': '20',
'to-month': '3',
'to-year': '2023',
})
.type('form')
.expect('Content-Type', /html/)
.expect(res => {
expect(res.text).toContain('The first day of remand must be before the last day of remand.')
})
})
test.each`
addOrEdit
${'add'}
${'edit'}
`('POST /{nomsId}/remand/dates/add empty form validation', async ({ addOrEdit }) => {
const adjustments = {}
adjustments[SESSION_ID] = blankAdjustment
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getAll.mockReturnValue(adjustments)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
return request(app)
.post(`/${NOMS_ID}/remand/dates/${addOrEdit}/${SESSION_ID}`)
.expect('Content-Type', /html/)
.expect(res => {
expect(res.text).toContain('This date must include a valid day, month and year')
})
})

it('POST /{nomsId}/remand/dates/add dates in future', () => {
const adjustments = {}
adjustments[SESSION_ID] = blankAdjustment
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getAll.mockReturnValue(adjustments)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
return request(app)
.post(`/${NOMS_ID}/remand/dates/add/${SESSION_ID}`)
.send({
'from-day': '5',
'from-month': '4',
'from-year': (dayjs().year() + 1).toString(),
'to-day': '20',
'to-month': '4',
'to-year': (dayjs().year() + 1).toString(),
})
.type('form')
.expect('Content-Type', /html/)
.expect(res => {
expect(res.text).toContain('The first day of remand must not be in the future.')
expect(res.text).toContain('The last day of remand must not be in the future.')
})
test.each`
addOrEdit
${'add'}
${'edit'}
`('POST /{nomsId}/remand/dates/add to date after from', async ({ addOrEdit }) => {
const adjustments = {}
adjustments[SESSION_ID] = blankAdjustment
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getAll.mockReturnValue(adjustments)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
return request(app)
.post(`/${NOMS_ID}/remand/dates/${addOrEdit}/${SESSION_ID}`)
.send({
'from-day': '5',
'from-month': '4',
'from-year': '2023',
'to-day': '20',
'to-month': '3',
'to-year': '2023',
})
.type('form')
.expect('Content-Type', /html/)
.expect(res => {
expect(res.text).toContain('The first day of remand must be before the last day of remand.')
})
})

test.each`
addOrEdit
${'add'}
${'edit'}
`('POST /{nomsId}/remand/dates/:addOrEdit dates in future', async ({ addOrEdit }) => {
const adjustments = {}
adjustments[SESSION_ID] = blankAdjustment
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getAll.mockReturnValue(adjustments)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
return request(app)
.post(`/${NOMS_ID}/remand/dates/${addOrEdit}/${SESSION_ID}`)
.send({
'from-day': '5',
'from-month': '4',
'from-year': (dayjs().year() + 1).toString(),
'to-day': '20',
'to-month': '4',
'to-year': (dayjs().year() + 1).toString(),
})
.type('form')
.expect('Content-Type', /html/)
.expect(res => {
expect(res.text).toContain('The first day of remand must not be in the future.')
expect(res.text).toContain('The last day of remand must not be in the future.')
})
})
})

it('GET /{nomsId}/remand/offences/add', () => {
Expand Down Expand Up @@ -438,4 +459,23 @@ describe('Adjustment routes tests', () => {
expect(res.text).toContain('Doing a crime')
})
})

it('GET /{nomsId}/remand/dates/edit', () => {
const adjustments = {}
adjustmentsService.get.mockResolvedValue(adjustmentWithDatesAndCharges)
prisonerService.getPrisonerDetail.mockResolvedValue(stubbedPrisonerData)
adjustmentsStoreService.getAll.mockReturnValue(adjustments)
adjustmentsStoreService.getById.mockReturnValue(blankAdjustment)
return request(app)
.get(`/${NOMS_ID}/remand/dates/edit/${ADJUSTMENT_ID}`)
.expect('Content-Type', /html/)
.expect(res => {
expect(res.text).toContain('Anon')
expect(res.text).toContain('Nobody')
expect(res.text).toContain(`<a href="/${NOMS_ID}/remand/edit/9991" class="govuk-back-link">Back</a>`)
expect(res.text).toContain('Remand start date')
expect(res.text).toContain('Remand end date')
expect(res.text).toContain('Continue')
})
})
})
20 changes: 16 additions & 4 deletions server/routes/remandRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default class RemandRoutes {
const form = RemandDatesForm.fromAdjustment(adjustment)

return res.render('pages/adjustments/remand/dates', {
model: new RemandDatesModel(id, prisonerDetail, adjustments, form),
model: new RemandDatesModel(id, prisonerDetail, adjustments, form, addOrEdit),
})
}

Expand All @@ -71,12 +71,15 @@ export default class RemandRoutes {
if (adjustmentForm.errors.length) {
const adjustments = Object.values(this.adjustmentsStoreService.getAll(req, nomsId))
return res.render('pages/adjustments/remand/dates', {
model: new RemandDatesModel(id, prisonerDetail, adjustments, adjustmentForm),
model: new RemandDatesModel(id, prisonerDetail, adjustments, adjustmentForm, addOrEdit),
})
}

const adjustment = this.adjustmentsStoreService.getById(req, nomsId, id)
this.adjustmentsStoreService.store(req, nomsId, id, adjustmentForm.toAdjustment(adjustment))
if (addOrEdit === 'edit') {
return res.redirect(`/${nomsId}/remand/edit/${id}`)
}

if (adjustment.complete) {
return res.redirect(`/${nomsId}/remand/review`)
Expand Down Expand Up @@ -278,6 +281,7 @@ export default class RemandRoutes {
it => it.adjustmentType === 'REMAND',
)
const sentencesAndOffences = await this.prisonerService.getSentencesAndOffences(prisonerDetail.bookingId, token)
this.adjustmentsStoreService.clear(req, nomsId)

// TODO copied this code in from the generic View route - need to double check what it's used for WIP
// Can be removed from the generic route once done
Expand Down Expand Up @@ -305,10 +309,18 @@ export default class RemandRoutes {
const { caseloads, token } = res.locals.user
const { nomsId, id } = req.params
const prisonerDetail = await this.prisonerService.getPrisonerDetail(nomsId, caseloads, token)
const adjustment = await this.adjustmentsService.get(id, token)
const sessionAdjustment = this.adjustmentsStoreService.getById(req, nomsId, id)

const adjustment = sessionAdjustment || (await this.adjustmentsService.get(id, token))
this.adjustmentsStoreService.store(req, nomsId, id, adjustment)
const sentencesAndOffences = await this.prisonerService.getSentencesAndOffences(prisonerDetail.bookingId, token)

return res.render('pages/adjustments/remand/edit', {
model: new RemandChangeModel(prisonerDetail, adjustment, sentencesAndOffences),
model: new RemandChangeModel(
prisonerDetail,
{ ...adjustment, daysBetween: daysBetween(new Date(adjustment.fromDate), new Date(adjustment.toDate)) },
sentencesAndOffences,
),
})
}
}
4 changes: 2 additions & 2 deletions server/views/pages/adjustments/remand/dates.njk
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l">
<span class="govuk-caption-xl">Adjust release dates</span>
Enter remand dates
{% if model.addOrEdit === 'edit' %} Edit {% else %} Enter {% endif %} remand dates
</h1>
</div>
</div>
Expand Down Expand Up @@ -90,7 +90,7 @@
{{ govukButton({
text: "Cancel",
classes: "govuk-button--secondary",
href: "/" + model.prisonerDetail.offenderNo
href: model.backlink() if model.addOrEdit === 'edit' else "/" + model.prisonerDetail.offenderNo
}) }}
</div>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The params are wrapped inside the attributes object and are as follows:
actions: {
items: [
{
href: '#',
href: '/' + offenderNo + '/remand/dates/edit/' + adjustment.id,
text: "Edit"
}
]
Expand Down

0 comments on commit 0587986

Please sign in to comment.