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

Add View License Returns page #967

Merged
merged 40 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6a7e06a
Add View License Returns page
jonathangoulding May 1, 2024
da60d31
test: remove .only
jonathangoulding May 1, 2024
a324ad3
feat: add initial structure to view and presenter
jonathangoulding May 1, 2024
4d426df
Merge branch 'main' into view-licence-returns-page
jonathangoulding May 1, 2024
4ed39e2
feat: add license return fetch service
jonathangoulding May 2, 2024
1215af8
chore: fix lint issue
jonathangoulding May 2, 2024
973b186
feat: add start to end date text
jonathangoulding May 2, 2024
aedd94a
feat: add pagination
jonathangoulding May 2, 2024
76aa575
feat: add pagination and update tests
jonathangoulding May 3, 2024
0c3eba2
Merge branch 'main' into view-licence-returns-page
jonathangoulding May 3, 2024
e221443
Merge branch 'main' into view-licence-returns-page
jonathangoulding May 3, 2024
60cbb6d
fix: route guard
jonathangoulding May 3, 2024
5eaca75
feat: add no returns and returns not needed to view and controller
jonathangoulding May 3, 2024
f6061c6
feat: update href for no returns link
jonathangoulding May 3, 2024
0f55f59
fix: remove only text
jonathangoulding May 3, 2024
eb90d68
fix: remove only text
jonathangoulding May 3, 2024
9aa09f1
fix: remove requirement no longer needed
jonathangoulding May 3, 2024
9d9763d
fix: remove additional title
jonathangoulding May 3, 2024
473820c
Merge remote-tracking branch 'origin/main' into view-licence-returns-…
jonathangoulding May 3, 2024
19c1567
fix: rename licence spelling
jonathangoulding May 3, 2024
39637ac
fix: clean up dead code
jonathangoulding May 3, 2024
cda3e80
fix: spelling test issues
jonathangoulding May 3, 2024
4835239
fix: test
jonathangoulding May 3, 2024
e9aa37b
test: fetch returns
jonathangoulding May 3, 2024
4750d1d
test: fetch returns with multiple returns
jonathangoulding May 3, 2024
2327a0b
test: fetch returns with multiple returns
jonathangoulding May 3, 2024
5513d07
Merge branch 'main' into view-licence-returns-page
jonathangoulding May 3, 2024
aa2092c
fix: pr
jonathangoulding May 3, 2024
b895c74
fix: hard code returns url in the njk
jonathangoulding May 3, 2024
14e837a
fix: pr
jonathangoulding May 3, 2024
e12cb22
fix: pr
jonathangoulding May 3, 2024
467dbf5
fix: reorder license presenter functions alpha
jonathangoulding May 3, 2024
ad944d2
Merge remote-tracking branch 'origin/view-licence-returns-page' into …
jonathangoulding May 3, 2024
d36ca6a
fix: reorder license service test functions alpha
jonathangoulding May 3, 2024
156c73a
fix: test helper function outside of describe
jonathangoulding May 3, 2024
9bfd3d0
fix: pr
jonathangoulding May 3, 2024
47661e3
fix: sonar return blocks
jonathangoulding May 3, 2024
b1fb0cc
Merge branch 'main' into view-licence-returns-page
jonathangoulding May 3, 2024
f55d8de
fix: fetch licence test service
jonathangoulding May 3, 2024
b075208
fix: reorder
jonathangoulding May 3, 2024
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
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')

/**
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved
* 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
Loading