Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returns required - Setup page (3 of 7) #737

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions app/controllers/return-requirements.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
const NoReturnsRequiredService = require('../services/return-requirements/no-returns-required.service.js')
const SelectReasonService = require('../services/return-requirements/reason.service.js')
const SessionModel = require('../models/session.model.js')
const SetupService = require('../services/return-requirements/setup.service.js')
const StartDateService = require('../services/return-requirements/start-date.service.js')
const SubmitNoReturnsRequiredService = require('../services/return-requirements/submit-no-returns-required.service.js')
const SubmitReasonService = require('../services/return-requirements/submit-reason.service.js')
const SubmitSetupService = require('../services/return-requirements/submit-setup.service.js')
const SubmitStartDateService = require('../services/return-requirements/submit-start-date.service.js')

async function abstractionPeriod (request, h) {
Expand Down Expand Up @@ -154,12 +156,10 @@ async function returnsCycle (request, h) {
async function setup (request, h) {
const { sessionId } = request.params

const session = await SessionModel.query().findById(sessionId)
const pageData = await SetupService.go(sessionId)

return h.view('return-requirements/setup.njk', {
activeNavBar: 'search',
pageTitle: 'How do you want to set up the return requirement?',
...session
...pageData
})
}

Expand Down Expand Up @@ -270,6 +270,12 @@ async function submitReturnsCycle (request, h) {
async function submitSetup (request, h) {
const { sessionId } = request.params

const pageData = await SubmitSetupService.go(sessionId, request.payload)

if (pageData.error) {
return h.view('return-requirements/setup.njk', pageData)
}

return h.redirect(`/system/return-requirements/${sessionId}/purpose`)
}

Expand Down
19 changes: 19 additions & 0 deletions app/presenters/return-requirements/setup.presenter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict'

/**
* Formats data for the `/return-requirements/{sessionId}/setup` page
* @module SetupPresenter
*/

function go (session) {
const data = {
id: session.id,
licenceRef: session.data.licence.licenceRef
}

return data
}

module.exports = {
go
}
33 changes: 33 additions & 0 deletions app/services/return-requirements/setup.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict'

/**
* Orchestrates fetching and presenting the data for `/return-requirements/{sessionId}/setup` page
* @module SetupService
*/
const SetupPresenter = require('../../presenters/return-requirements/setup.presenter.js')
const SessionModel = require('../../models/session.model.js')

/**
* Orchestrates fetching and presenting the data for `/return-requirements/{sessionId}/setup` page
*
* Supports generating the data needed for the select reason page in the return requirements setup journey. It
* fetches the current session record and combines it with the radio buttons and other information needed for the form.
*
* @param {string} id - The UUID for return requirement setup session record
*
* @returns {Promise<Object>} page data needed by the view template
*/
async function go (sessionId) {
const session = await SessionModel.query().findById(sessionId)
const formattedData = SetupPresenter.go(session)

return {
activeNavBar: 'search',
pageTitle: 'How do you want to set up the return requirement?',
...formattedData
}
}

module.exports = {
go
}
57 changes: 57 additions & 0 deletions app/services/return-requirements/submit-setup.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict'

/**
* Orchestrates validating the data for `/return-requirements/{sessionId}/setup` page
* @module SubmitSetupService
*/

const SessionModel = require('../../models/session.model.js')
const SetupPresenter = require('../../presenters/return-requirements/setup.presenter.js')
const SetupValidator = require('../../validators/return-requirements/setup.validator.js')

/**
* Orchestrates validating the data for `/return-requirements/{sessionId}/setup` page
*
* It first retrieves the session instance for the returns requirements journey in progress.
*
* The validation result is then combined with the output of the presenter to generate the page data needed by the view.
* If there was a validation error the controller will re-render the page so needs this information. If all is well the
* controller will redirect to the next page in the journey.
*
* @param {string} sessionId - The id of the current session
* @param {Object} payload - The submitted form data
*
* @returns {Promise<Object>} The page data for the reason page
*/
async function go (sessionId, payload) {
const session = await SessionModel.query().findById(sessionId)

const validationResult = _validate(payload)

const formattedData = SetupPresenter.go(session, payload)

return {
activeNavBar: 'search',
error: validationResult,
pageTitle: 'How do you want to set up the return requirement?',
...formattedData
}
}

function _validate (payload) {
const validation = SetupValidator.go(payload)

if (!validation.error) {
return null
}

const { message } = validation.error.details[0]

return {
text: message
}
}

module.exports = {
go
}
41 changes: 41 additions & 0 deletions app/validators/return-requirements/setup.validator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict'

/**
* Validates data submitted for the `/return-requirements/{sessionId}/setup` page
* @module SetupValidator
*/

const Joi = require('joi')

const VALID_VALUES = [
'use_abstraction_data',
'copy_an_existing_return_requirement'
]

/**
* Validates data submitted for the `/return-requirements/{sessionId}/setup` page
*
* @param {Object} payload - The payload from the request to be validated
*
* @returns {Object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If
* any errors are found the `error:` property will also exist detailing what the issues were
*/
function go (data) {
const errorMessage = 'Select how you want to set up the return requirement'
const schema = Joi.object({
setup: Joi.string()
.required()
.valid(...VALID_VALUES)
.messages({
'any.required': errorMessage,
'any.only': errorMessage,
'string.empty': errorMessage
})
})

return schema.validate(data, { abortEarly: false })
}

module.exports = {
go
}
49 changes: 41 additions & 8 deletions app/views/return-requirements/setup.njk
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{% extends 'layout.njk' %}
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
{% from "govuk/components/radios/macro.njk" import govukRadios %}

{% set rootLink = "/system/return-requirements/" + id %}

Expand All @@ -9,20 +11,51 @@
{{
govukBackLink({
text: 'Back',
href: rootLink + "/reason"
href: rootLink + '/reason'
})
}}
{% endblock %}

{% block content %}
{# Main heading #}
{% if error %}
{{ govukErrorSummary({
titleText: "There is a problem",
errorList: [
{
text: error.text,
href: "#setup-error"
}
]
}) }}
{% endif %}

<div class="govuk-body">
<h1 class="govuk-heading-xl govuk-!-margin-bottom-3">{{ pageTitle }}</h1>
</div>
<form method="post">
{{ govukRadios({
name: "setup",
errorMessage: error,
fieldset: {
legend: {
html: '<span class="govuk-caption-l">Licence ' + licenceRef + '</span>' + pageTitle,
isPageHeading: true,
classes: "govuk-fieldset__legend--l govuk-!-margin-bottom-6"
}
},
items: [
{
value: "use_abstraction_data",
text: "Start by using abstraction data",
checked: false
},
{
value: "copy_an_existing_return_requirement",
text: "Copy an existing return requirement",
checked: false
}
]
}) }}

<form method="post">
<div class="govuk-body">
{{ govukButton({ text: "Continue" }) }}
</div>
</form>
</form>
</div>
{% endblock %}
8 changes: 7 additions & 1 deletion test/controllers/return-requirements.controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ const { expect } = Code

// Things we need to stub
const NoReturnsRequiredService = require('../../app/services/return-requirements/no-returns-required.service.js')
const StartDateService = require('../../app/services/return-requirements/start-date.service.js')
const SelectReasonService = require('../../app/services/return-requirements/reason.service.js')
const SetupService = require('../../app/services/return-requirements/setup.service.js')
const StartDateService = require('../../app/services/return-requirements/start-date.service.js')

// For running our service
const { init } = require('../../app/server.js')
Expand Down Expand Up @@ -179,6 +180,11 @@ describe('Return requirements controller', () => {
})

describe('GET /return-requirements/{sessionId}/setup', () => {
beforeEach(async () => {
Sinon.stub(SetupService, 'go').resolves({
id: '8702b98f-ae51-475d-8fcc-e049af8b8d38', pageTitle: 'How do you want to set up the return requirement?'
})
})
describe('when the request succeeds', () => {
it('returns the page successfully', async () => {
const response = await server.inject(_options('setup'))
Expand Down
39 changes: 39 additions & 0 deletions test/presenters/return-requirements/setup.presenter.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict'

// Test framework dependencies
const Lab = require('@hapi/lab')
const Code = require('@hapi/code')

const { describe, it, beforeEach } = exports.lab = Lab.script()
const { expect } = Code

// Thing under test
const SetupPresenter = require('../../../app/presenters/return-requirements/setup.presenter.js')

describe('Setup presenter', () => {
let session

beforeEach(() => {
session = {
id: 'f1288f6c-8503-4dc1-b114-75c408a14bd0',
data: {
licence: {
id: 'ea53bfc6-740d-46c5-9558-fc8cabfc6c1f',
licenceRef: '01/123',
licenceHolder: 'Astro Boy'
}
}
}
})

describe('when provided with a populated session', () => {
it('correctly presents the data', () => {
const result = SetupPresenter.go(session)

expect(result).to.equal({
id: 'f1288f6c-8503-4dc1-b114-75c408a14bd0',
licenceRef: '01/123'
})
})
})
})
53 changes: 53 additions & 0 deletions test/services/return-requirements/setup.service.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict'

// Test framework dependencies
const Lab = require('@hapi/lab')
const Code = require('@hapi/code')

const { describe, it, beforeEach } = exports.lab = Lab.script()
const { expect } = Code

// Test helpers
const DatabaseHelper = require('../../support/helpers/database.helper.js')
const SessionHelper = require('../../support/helpers/session.helper.js')

// Thing under test
const SetupService = require('../../../app/services/return-requirements/setup.service.js')

describe('Select Reason service', () => {
let session

beforeEach(async () => {
await DatabaseHelper.clean()
session = await SessionHelper.add({
data: {
licence: {
id: '8b7f78ba-f3ad-4cb6-a058-78abc4d1383d',
currentVersionStartDate: '2023-01-01T00:00:00.000Z',
endDate: null,
licenceRef: '01/ABC',
licenceHolder: 'Astro Boy',
startDate: '2022-04-01T00:00:00.000Z'
}
}
})
})

describe('when called', () => {
it('fetches the current setup session record', async () => {
const result = await SetupService.go(session.id)

expect(result.id).to.equal(session.id)
})

it('returns page data for the view', async () => {
const result = await SetupService.go(session.id)

expect(result).to.equal({
activeNavBar: 'search',
pageTitle: 'How do you want to set up the return requirement?',
licenceRef: '01/ABC'
}, { skip: ['id'] })
})
})
})
Loading
Loading