Skip to content

Commit

Permalink
Add View License Returns page (#967)
Browse files Browse the repository at this point in the history
https://eaflood.atlassian.net/browse/WATER-4444

The existing service handling view license is slow because it loads all the data for the tabs in one render. Work has been done previously to refactor the summary page to load only the summary information.

This change will introduce a returns controller, service and presenter to handle the view license returns page.

This will share the same view as the summary page and load the same 'common data' established in [previous work](#957).

---------

Co-authored-by: Alan Cruikshanks <[email protected]>
  • Loading branch information
jonathangoulding and Cruikshanks authored May 3, 2024
1 parent f1c4f95 commit 16caae5
Show file tree
Hide file tree
Showing 23 changed files with 555 additions and 18 deletions.
15 changes: 14 additions & 1 deletion app/controllers/licences.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
*/

const InitiateReturnRequirementSessionService = require('../services/return-requirements/initiate-return-requirement-session.service.js')
const ViewLicenceSummaryService = require('../services/licences/view-license-summary.service')
const ViewLicenceReturnsService = require('../services/licences/view-licence-returns.service')
const ViewLicenceSummaryService = require('../services/licences/view-licence-summary.service')

async function noReturnsRequired (request, h) {
const { id } = request.params
Expand Down Expand Up @@ -35,8 +36,20 @@ async function viewSummary (request, h) {
})
}

async function viewReturns (request, h) {
const { params: { id }, auth, query: { page = 1 } } = request

const data = await ViewLicenceReturnsService.go(id, auth, page)

return h.view('licences/view.njk', {
activeNavBar: 'search',
...data
})
}

module.exports = {
noReturnsRequired,
returnsRequired,
viewReturns,
viewSummary
}
58 changes: 58 additions & 0 deletions app/presenters/licences/view-licence-returns.presenter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict'

/**
* Formats common data for the `/licences/{id}/*` view licence pages
* @module ViewLicenceReturnsPresenter
*/

const { formatLongDate } = require('../base.presenter')

/**
* Formats common data for the `/licences/{id}/*` view licence pages
*
* @returns {Object} The data formatted for the view template
*/
function go (returnsData) {
const returns = _formatReturnToTableRow(returnsData.returns)

return {
activeTab: 'returns',
returns
}
}

function _formatPurpose (purpose) {
const [firstPurpose] = purpose

return firstPurpose.alias ? firstPurpose.alias : firstPurpose.tertiary.description
}

function _formatReturnToTableRow (returns) {
return returns.map((r) => {
return {
dates: `${formatLongDate(new Date(r.startDate))} to ${formatLongDate(new Date(r.endDate))}`,
description: r.metadata.description,
dueDate: formatLongDate(new Date(r.dueDate)),
id: r.id,
purpose: _formatPurpose(r.metadata.purposes),
reference: r.returnReference,
status: _formatStatus(r.status)
}
})
}

function _formatStatus (status) {
if (status === 'completed') {
return 'COMPLETE'
}

if (status === 'due') {
return 'OVERDUE'
}

return 'NO STATUS'
}

module.exports = {
go
}
6 changes: 4 additions & 2 deletions app/presenters/licences/view-licence.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ function go (licence, auth) {
includeInSrocBilling,
licenceName,
licenceRef,
registeredTo
registeredTo,
id
} = licence

return {
licenceId: id,
licenceName,
licenceRef,
notification: _determineNotificationBanner(includeInPresrocBilling, includeInSrocBilling),
Expand All @@ -36,7 +38,7 @@ function go (licence, auth) {
}

function _determineNotificationBanner (includeInPresrocBilling, includeInSrocBilling) {
const baseMessage = 'This license has been marked for the next supplementary bill run'
const baseMessage = 'This licence has been marked for the next supplementary bill run'

if (includeInPresrocBilling === 'yes' && includeInSrocBilling === true) {
return baseMessage + 's for the current and old charge schemes.'
Expand Down
13 changes: 11 additions & 2 deletions app/routes/licence.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,18 @@ const routes = [
path: '/licences/{id}/summary',
handler: LicencesController.viewSummary,
options: {
description: 'View a licence page'
description: 'View a licence summary page'
}
}, {
},
{
method: 'GET',
path: '/licences/{id}/returns',
handler: LicencesController.viewReturns,
options: {
description: 'View a licence returns page'
}
},
{
method: 'GET',
path: '/licences/{id}/no-returns-required',
handler: LicencesController.noReturnsRequired,
Expand Down
46 changes: 46 additions & 0 deletions app/services/licences/fetch-licence-returns.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict'

/**
* Fetches all return logs for a licence which is needed for the view '/licences/{id}/returns` page
* @module FetchLicenceReturnsService
*/

const ReturnLogModel = require('../../models/return-log.model')

const DatabaseConfig = require('../../../config/database.config')

/**
* Fetches all return logs for a licence which is needed for the view '/licences/{id}/returns` page
*
* @param {string} licenceId - The UUID for the licence to fetch
*
* @returns {Promise<Object>} the data needed to populate the view licence page's returns tab
*/
async function go (licenceId, page) {
const { results, total } = await _fetch(licenceId, page)

return { returns: results, pagination: { total } }
}

async function _fetch (licenceId, page) {
return ReturnLogModel.query()
.select([
'returnLogs.id',
'returnLogs.dueDate',
'returnLogs.endDate',
'returnLogs.metadata',
'returnLogs.returnReference',
'returnLogs.startDate',
'returnLogs.status'
])
.innerJoinRelated('licence')
.where('licence.id', licenceId)
.orderBy([
{ column: 'dueDate', order: 'desc' }
])
.page(page - 1, DatabaseConfig.defaultPageSize)
}

module.exports = {
go
}
1 change: 1 addition & 0 deletions app/services/licences/fetch-licence.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ async function _fetchLicence (id) {
const result = await LicenceModel.query()
.findById(id)
.select([
'id',
'include_in_presroc_billing',
'include_in_sroc_billing',
'licenceRef',
Expand Down
37 changes: 37 additions & 0 deletions app/services/licences/view-licence-returns.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict'

/**
* Orchestrates fetching and presenting the data needed for the licence summary page
* @module ViewLicenceSummaryService
*/

const FetchLicenceReturnsService = require('./fetch-licence-returns.service')
const ViewLicenceService = require('./view-licence.service')
const ViewLicenceReturnsPresenter = require('../../presenters/licences/view-licence-returns.presenter')
const PaginatorPresenter = require('../../presenters/paginator.presenter')

/**
* Orchestrates fetching and presenting the data needed for the licence summary page
*
* @param {string} licenceId - The UUID of the licence
*
* @returns {Promise<Object>} an object representing the `pageData` needed by the licence summary template.
*/
async function go (licenceId, auth, page) {
const commonData = await ViewLicenceService.go(licenceId, auth)

const returnsData = await FetchLicenceReturnsService.go(licenceId, page)
const pageData = ViewLicenceReturnsPresenter.go(returnsData)

const pagination = PaginatorPresenter.go(returnsData.pagination.total, Number(page), `/system/licences/${licenceId}/returns`)

return {
...pageData,
...commonData,
pagination
}
}

module.exports = {
go
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
*/

const FetchLicenceAbstractionConditionsService = require('./fetch-licence-abstraction-conditions.service.js')
const FetchLicenceSummaryService = require('./fetch-license-summary.service')
const ViewLicenceSummaryPresenter = require('../../presenters/licences/view-license-summary.presenter')
const FetchLicenceSummaryService = require('./fetch-licence-summary.service')
const ViewLicenceSummaryPresenter = require('../../presenters/licences/view-licence-summary.presenter')
const ViewLicenceService = require('./view-licence.service')

/**
Expand Down
54 changes: 54 additions & 0 deletions app/views/licences/tabs/returns.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{% from "govuk/components/pagination/macro.njk" import govukPagination %}
{% from "govuk/components/table/macro.njk" import govukTable %}
{% from "govuk/components/tag/macro.njk" import govukTag %}

{% macro formatStatus(status) %}
{% if status === 'COMPLETE' %}
{{ govukTag({
text: status,
classes: "govuk-tag--green"
}) }}

{% elseif status === 'OVERDUE' %}
{{ govukTag({
text: status,
classes: "govuk-tag--red"
}) }}
{% else %}
{{ status }}
{% endif %}
{% endmacro %}

<table class="govuk-table">
<h2 class="govuk-heading-l">Returns</h2>
{% if returns %}
<thead class="govuk-table__head">
<tr class="govuk-table__row">
<th scope="col" class="govuk-table__header">Return reference and dates</th>
<th scope="col" class="govuk-table__header">Purpose and description</th>
<th scope="col" class="govuk-table__header">Due date</th>
<th scope="col" class="govuk-table__header">Status</th>
</tr>
</thead>
<tbody class="govuk-table__body">
{% for return in returns %}
<tr class="govuk-table__row govuk-body-s">
<th class="govuk-table__cell">
<a href="/return/internal?returnId={{ return.id }}" class="govuk-link">{{ return.reference }} </a>
<p class="govuk-body-s"> {{ return.dates }}</p>
</th>
<td class="govuk-table__cell">{{ return.purpose }} <p class="govuk-body-s"> {{ return.description }}</p></td>
<td class="govuk-table__cell">{{ return.dueDate }}</td>
<td class="govuk-table__cell">{{ formatStatus(return.status) }}</td>
</tr>
{% endfor %}
</tbody>
{% else %}
<p>No returns found</p>
{% endif %}
</table>

{% if returns and pagination.numberOfPages > 1 %}
{{ govukPagination(pagination.component) }}
{% endif %}

3 changes: 3 additions & 0 deletions app/views/licences/view.njk
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
{% if activeTab === 'summary' %}
{% include "licences/tabs/summary.njk" %}
{% endif %}
{% if activeTab === 'returns' %}
{% include "licences/tabs/returns.njk" %}
{% endif %}
</div>
</div>
{% endblock %}
41 changes: 40 additions & 1 deletion test/controllers/licences.controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const Boom = require('@hapi/boom')

// Things we need to stub
const InitiateReturnRequirementSessionService = require('../../app/services/return-requirements/initiate-return-requirement-session.service.js')
const ViewLicenceSummaryService = require('../../app/services/licences/view-license-summary.service')
const ViewLicenceSummaryService = require('../../app/services/licences/view-licence-summary.service')
const ViewLicenceReturnsService = require('../../app/services/licences/view-licence-returns.service')

// For running our service
const { init } = require('../../app/server.js')
Expand Down Expand Up @@ -188,4 +189,42 @@ describe('Licences controller', () => {
}
}
})

describe('GET /licences/{id}/returns', () => {
beforeEach(async () => {
options = {
method: 'GET',
url: '/licences/7861814c-ca19-43f2-be11-3c612f0d744b/returns',
auth: {
strategy: 'session',
credentials: { scope: ['billing'] }
}
}
})

describe('when a request is valid and has returns', () => {
beforeEach(async () => {
Sinon.stub(ViewLicenceReturnsService, 'go').resolves(_viewLicenceReturns())
})

it('returns the page successfully', async () => {
const response = await server.inject(options)

expect(response.statusCode).to.equal(200)
expect(response.payload).to.contain('Returns')
// Check the table titles
expect(response.payload).to.contain('Return reference and dates')
expect(response.payload).to.contain('Purpose and description')
expect(response.payload).to.contain('Due date')
expect(response.payload).to.contain('Status')
})
})
})
})

function _viewLicenceReturns () {
return {
activeTab: 'returns',
returns: [{}]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ describe('View Bill Summaries presenter', () => {
})

describe("the bill 'licences' property", () => {
it('splits the licenses provided by , and places the resulting references into an array', () => {
it('splits the licences provided by , and places the resulting references into an array', () => {
const result = ViewBillSummariesPresenter.go(billSummaries)

expect(result[0].bills[0].licences).to.equal(['17/53/001/A/101', '17/53/002/B/205', '17/53/002/C/308'])
Expand Down
7 changes: 4 additions & 3 deletions test/presenters/licences/view-licence-presenter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('View Licence presenter', () => {
const result = ViewLicencePresenter.go(licence)

expect(result).to.equal({
licenceId: 'f1288f6c-8503-4dc1-b114-75c408a14bd0',
licenceName: 'Unregistered licence',
licenceRef: '01/123',
notification: null,
Expand Down Expand Up @@ -151,7 +152,7 @@ describe('View Licence presenter', () => {
it('returns the notification for PRESROC', () => {
const result = ViewLicencePresenter.go(licence)

expect(result.notification).to.equal('This license has been marked for the next supplementary bill run for the old charge scheme.')
expect(result.notification).to.equal('This licence has been marked for the next supplementary bill run for the old charge scheme.')
})
})

Expand All @@ -163,7 +164,7 @@ describe('View Licence presenter', () => {
it('returns the notification for SROC', () => {
const result = ViewLicencePresenter.go(licence)

expect(result.notification).to.equal('This license has been marked for the next supplementary bill run.')
expect(result.notification).to.equal('This licence has been marked for the next supplementary bill run.')
})
})

Expand All @@ -176,7 +177,7 @@ describe('View Licence presenter', () => {
it('returns the notification for SROC & PRESROC)', () => {
const result = ViewLicencePresenter.go(licence)

expect(result.notification).to.equal('This license has been marked for the next supplementary bill runs for the current and old charge schemes.')
expect(result.notification).to.equal('This licence has been marked for the next supplementary bill runs for the current and old charge schemes.')
})
})
})
Expand Down
Loading

0 comments on commit 16caae5

Please sign in to comment.