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

Complete Select existing return requirement page #895

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
17 changes: 11 additions & 6 deletions app/controllers/return-requirements.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const AgreementsExceptionsService = require('../services/return-requirements/agr
const CancelService = require('../services/return-requirements/cancel.service.js')
const CheckService = require('../services/return-requirements/check.service.js')
const DeleteNoteService = require('../services/return-requirements/delete-note.service.js')
const ExistingService = require('../services/return-requirements/existing.service.js')
const FrequencyCollectedService = require('../services/return-requirements/frequency-collected.service.js')
const FrequencyReportedService = require('../services/return-requirements/frequency-reported.service.js')
const NoReturnsRequiredService = require('../services/return-requirements/no-returns-required.service.js')
Expand All @@ -21,7 +22,6 @@ const RemoveService = require('../services/return-requirements/remove.service.js
const ReturnsCycleService = require('../services/return-requirements/returns-cycle.service.js')
const SelectPurposeService = require('../services/return-requirements/purpose.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 SiteDescriptionService = require('../services/return-requirements/site-description.service.js')
const StartDateService = require('../services/return-requirements/start-date.service.js')
Expand All @@ -30,6 +30,7 @@ const SubmitAdditionalSubmissionOptionsService = require('../services/return-req
const SubmitAgreementsExceptions = require('../services/return-requirements/submit-agreements-exceptions.service.js')
const SubmitCancel = require('../services/return-requirements/submit-cancel.service.js')
const SubmitCheckService = require('../services/return-requirements/submit-check.service.js')
const SubmitExistingService = require('../services/return-requirements/submit-existing.service.js')
const SubmitFrequencyCollectedService = require('../services/return-requirements/submit-frequency-collected.service.js')
const SubmitFrequencyReportedService = require('../services/return-requirements/submit-frequency-reported.service.js')
const SubmitNoReturnsRequiredService = require('../services/return-requirements/submit-no-returns-required.service.js')
Expand Down Expand Up @@ -120,12 +121,10 @@ async function deleteNote (request, h) {
async function existing (request, h) {
const { sessionId } = request.params

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

return h.view('return-requirements/existing.njk', {
activeNavBar: 'search',
pageTitle: 'Select an existing return requirement from',
...session
...pageData
})
}

Expand Down Expand Up @@ -307,7 +306,13 @@ async function submitCheck (request, h) {
}

async function submitExisting (request, h) {
const { sessionId } = request.params
const { params: { sessionId }, payload } = request

const pageData = await SubmitExistingService.go(sessionId, payload)

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

return h.redirect(`/system/return-requirements/${sessionId}/check`)
}
Expand Down
46 changes: 46 additions & 0 deletions app/presenters/return-requirements/existing.presenter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict'

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

const { formatLongDate } = require('../base.presenter.js')
const { returnRequirementReasons } = require('../../lib/static-lookups.lib.js')

/**
* Formats data for the `/return-requirements/{sessionId}/existing` page
*
* @param {module:SessionModel} session - The returns requirements session instance
*
* @returns {Object} The data formatted for the view template
*/
function go (session) {
const { id: sessionId, licence } = session

return {
existingOptions: _existingOptions(licence.returnVersions),
licenceRef: licence.licenceRef,
sessionId
}
}

function _existingOptions (returnVersions) {
return returnVersions.map((returnVersion) => {
const { id, reason, startDate } = returnVersion

// NOTE: because the session data is stored in a JSONB field when we get the instance from the DB the date values
// are in JS Date format (string). So, we have to convert it to a date before calling `formatLongDate()`
const dateObj = new Date(startDate)
const formattedStartDate = formatLongDate(dateObj)

return {
value: id,
text: reason ? `${formattedStartDate} - ${returnRequirementReasons[reason]}` : formattedStartDate
}
})
}

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

/**
* Orchestrates fetching and presenting the data for `/return-requirements/{sessionId}/existing` page
* @module ExistingService
*/

const ExistingPresenter = require('../../presenters/return-requirements/existing.presenter.js')
const SessionModel = require('../../models/session.model.js')

/**
* Orchestrates fetching and presenting the data for `/return-requirements/{sessionId}/existing` page
*
* Supports generating the data needed for the existing page in the return requirements setup journey. It fetches the
* current session record and from it determines what radio buttons to display to the user.
*
* @param {string} sessionId - The UUID of the current session
*
* @returns {Promise<Object>} The view data for the purpose page
*/
async function go (sessionId) {
const session = await SessionModel.query().findById(sessionId)

const formattedData = ExistingPresenter.go(session)

return {
activeNavBar: 'search',
pageTitle: 'Select an existing requirements for returns from',
...formattedData
}
}

module.exports = {
go
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
'use strict'

/**
* Fetches existing return requirements to be copied from
* @module FetchExistingRequirementsService
*/

const ReturnVersionModel = require('../../models/return-version.model.js')

const FREQUENCIES = {
day: 'daily',
week: 'weekly',
fortnight: 'fortnightly',
month: 'monthly',
quarter: 'quarterly',
year: 'yearly'
}

/**
* Fetches existing return requirements to be copied from
*
* In the returns setup journey we allow users to select the option to create new requirements by copying from them
* from an existing return version. This service fetches the selected return version and its requirements
*
* @param {string} returnVersionId - The UUID of the selected return version to copy requirements from
*
* @returns {Promise<Object>} The return version and its linked return requirements, plus their points and purposes
*/
async function go (returnVersionId) {
const returnVersion = await _fetch(returnVersionId)

return _transformForSetup(returnVersion)
}

function _agreementExceptions (returnRequirement) {
const { fiftySixException, gravityFill, reabstraction, twoPartTariff } = returnRequirement
const agreementsExceptions = []

if (fiftySixException) {
agreementsExceptions.push('56-returns-exception')
}

if (gravityFill) {
agreementsExceptions.push('gravity-fill')
}

if (reabstraction) {
agreementsExceptions.push('transfer-re-abstraction-scheme')
}

if (twoPartTariff) {
agreementsExceptions.push('two-part-tariff')
}

if (agreementsExceptions.length === 0) {
agreementsExceptions.push('none')
}

return agreementsExceptions
}

async function _fetch (returnVersionId) {
return ReturnVersionModel.query()
.findById(returnVersionId)
.select([
'id'
])
.withGraphFetched('returnRequirements')
.modifyGraph('returnRequirements', (builder) => {
builder.select([
'id',
'abstractionPeriodEndDay',
'abstractionPeriodEndMonth',
'abstractionPeriodStartDay',
'abstractionPeriodStartMonth',
'collectionFrequency',
'fiftySixException',
'gravityFill',
'reabstraction',
'reportingFrequency',
'siteDescription',
'summer',
'twoPartTariff'
])
})
.withGraphFetched('returnRequirements.returnRequirementPoints')
.modifyGraph('returnRequirements.returnRequirementPoints', (builder) => {
builder.select([
'id',
'naldPointId'
])
})
.withGraphFetched('returnRequirements.returnRequirementPurposes')
.modifyGraph('returnRequirements.returnRequirementPurposes', (builder) => {
builder.select([
'id',
'purposeId'
])
})
}

function _points (returnRequirementPoints) {
return returnRequirementPoints.map((returnRequirementPoint) => {
return returnRequirementPoint.naldPointId.toString()
})
}

function _purposes (returnRequirementPurposes) {
return returnRequirementPurposes.map((returnRequirementPurpose) => {
return returnRequirementPurpose.purposeId
})
}

function _transformForSetup (returnVersion) {
const { returnRequirements } = returnVersion

return returnRequirements.map((returnRequirement) => {
const {
abstractionPeriodEndDay,
abstractionPeriodEndMonth,
abstractionPeriodStartDay,
abstractionPeriodStartMonth,
collectionFrequency,
reportingFrequency,
returnRequirementPoints,
returnRequirementPurposes,
siteDescription,
summer
} = returnRequirement

return {
points: _points(returnRequirementPoints),
purposes: _purposes(returnRequirementPurposes),
returnsCycle: summer ? 'summer' : 'winter-and-all-year',
siteDescription,
abstractionPeriod: {
'end-abstraction-period-day': abstractionPeriodEndDay,
'end-abstraction-period-month': abstractionPeriodEndMonth,
'start-abstraction-period-day': abstractionPeriodStartDay,
'start-abstraction-period-month': abstractionPeriodStartMonth
},
frequencyReported: FREQUENCIES[reportingFrequency],
frequencyCollected: FREQUENCIES[collectionFrequency],
agreementsExceptions: _agreementExceptions(returnRequirement)
}
})
}

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

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

const ExistingPresenter = require('../../presenters/return-requirements/existing.presenter.js')
const ExistingValidator = require('../../validators/return-requirements/existing.validator.js')
const FetchExistingRequirementsService = require('./fetch-existing-requirements.service.js')
const SessionModel = require('../../models/session.model.js')

/**
* Orchestrates validating the data for `/return-requirements/{sessionId}/existing` 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 after the existing return requirements have been saved to
* the session.
*
* @param {string} sessionId - The UUID of the current session
* @param {Object} payload - The submitted form data
*
* @returns {Promise<Object>} If no errors an empty object else the page data for the existing page including the
* validation error details
*/
async function go (sessionId, payload) {
const session = await SessionModel.query().findById(sessionId)

const validationResult = _validate(payload, session)

if (!validationResult) {
const existingReturnRequirements = await FetchExistingRequirementsService.go(payload.existing)

await _save(session, existingReturnRequirements)

return {}
}

const formattedData = ExistingPresenter.go(session)

return {
activeNavBar: 'search',
error: validationResult,
pageTitle: 'Select an existing requirements for returns from',
...formattedData
}
}

async function _save (session, existingReturnRequirements) {
session.requirements = existingReturnRequirements

return session.$update()
}

function _validate (payload, session) {
const { licence: { returnVersions } } = session

const validation = ExistingValidator.go(payload, returnVersions)

if (!validation.error) {
return null
}

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

return {
text: message
}
}

module.exports = {
go
}
10 changes: 4 additions & 6 deletions app/services/return-requirements/submit-setup.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,15 @@ async function go (sessionId, payload) {
}

function _redirect (setup) {
let endpoint

if (setup === 'use-abstraction-data') {
endpoint = 'check'
return 'check'
}

if (setup === 'set-up-manually') {
endpoint = 'purpose/0'
if (setup === 'use-existing-requirements') {
return 'existing'
}

return endpoint
return 'purpose/0'
}

async function _save (session, payload) {
Expand Down
Loading
Loading