Skip to content

Commit

Permalink
Migrate view bill runs page from legacy UI (#925)
Browse files Browse the repository at this point in the history
https://eaflood.atlassian.net/browse/WATER-4445

> Part of a series of changes to migrate the legacy view bill runs page into this project

This is the final step in migrating the legacy view bill runs page to this project. We dealt with the support services we need in previous changes. Now we need to add

- the route
- the controller handler
- the orchestration service
- the view template

We also update the menu to point to it and not the legacy `/billing/batch/list`. Worth noting (because this is the first) we use the convention of naming the handler and subsequent files `index` to reflect they deal with displaying an index of bill runs, not a single one.
  • Loading branch information
Cruikshanks authored Apr 23, 2024
1 parent e8ea57e commit 0e64948
Show file tree
Hide file tree
Showing 17 changed files with 630 additions and 18 deletions.
2 changes: 1 addition & 1 deletion app/controllers/bill-runs-setup.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ async function create (request, h) {
try {
await CreateService.go(request.auth.credentials.user, results)

return h.redirect('/billing/batch/list')
return h.redirect('/system/bill-runs')
} catch (error) {
return Boom.badImplementation(error.message)
}
Expand Down
15 changes: 14 additions & 1 deletion app/controllers/bill-runs.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const Boom = require('@hapi/boom')

const CancelBillRunService = require('../services/bill-runs/cancel-bill-run.service.js')
const CreateBillRunValidator = require('../validators/create-bill-run.validator.js')
const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.service.js')
const MatchDetailsService = require('../services/bill-runs/two-part-tariff/match-details.service.js')
const ReviewBillRunService = require('../services/bill-runs/two-part-tariff/review-bill-run.service.js')
const ReviewLicenceService = require('../services/bill-runs/two-part-tariff/review-licence.service.js')
Expand Down Expand Up @@ -47,6 +48,17 @@ async function create (request, h) {
}
}

async function index (request, h) {
const { page } = request.query

const pageData = await IndexBillRunsService.go(page)

return h.view('bill-runs/index.njk', {
activeNavBar: 'bill-runs',
...pageData
})
}

async function matchDetails (request, h) {
const { id: billRunId, licenceId, reviewChargeElementId } = request.params

Expand Down Expand Up @@ -102,7 +114,7 @@ async function submitCancel (request, h) {
// `cancel'.
await SubmitCancelBillRunService.go(id)

return h.redirect('/billing/batch/list')
return h.redirect('/system/bill-runs')
} catch (error) {
return Boom.badImplementation(error.message)
}
Expand Down Expand Up @@ -137,6 +149,7 @@ async function view (request, h) {
module.exports = {
cancel,
create,
index,
matchDetails,
review,
reviewLicence,
Expand Down
66 changes: 66 additions & 0 deletions app/presenters/bill-runs/index-bill-runs.presenter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'use strict'

/**
* Formats the summary data for each bill run for use in the /bill-runs page
* @module IndexBillRunsPresenter
*/

const {
capitalize,
formatBillRunType,
formatLongDate,
formatMoney
} = require('../base.presenter.js')

/**
* Formats the summary data for each bill run for use in the /bill-runs page
*
* @param {module:BillRunModel[]} billRuns - The bill runs containing the data to be summarised for the view
*
* @returns {Object[]} Each bill run summary formatted for use in the `index.njk` template for `/bill-runs`
*/
function go (billRuns) {
return billRuns.map((billRun) => {
const {
batchType,
billRunNumber,
createdAt,
id,
netTotal,
numberOfBills,
region,
scheme,
summer,
status
} = billRun

return {
id,
createdAt: formatLongDate(createdAt),
link: _link(id, status),
number: billRunNumber,
numberOfBills,
region: capitalize(region),
scheme,
status,
total: formatMoney(netTotal, true),
type: formatBillRunType(batchType, scheme, summer)
}
})
}

function _link (billRunId, status) {
if (status === 'cancel') {
return null
}

if (status === 'review') {
return `/system/bill-runs/${billRunId}/review`
}

return `/system/bill-runs/${billRunId}`
}

module.exports = {
go
}
13 changes: 13 additions & 0 deletions app/routes/bill-runs.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
const BillRunsController = require('../controllers/bill-runs.controller.js')

const routes = [
{
method: 'GET',
path: '/bill-runs',
handler: BillRunsController.index,
options: {
auth: {
access: {
scope: ['billing']
}
},
description: 'List all bill runs'
}
},
{
method: 'POST',
path: '/bill-runs',
Expand Down
64 changes: 64 additions & 0 deletions app/services/bill-runs/index-bill-runs.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use strict'

/**
* Orchestrates fetching and presenting the data needed for the /bill-runs page
* @module IndexBillRunsService
*/

const CheckBusyBillRunsService = require('./check-busy-bill-runs.service.js')
const FetchBillRunsService = require('./fetch-bill-runs.service.js')
const IndexBillRunsPresenter = require('../../presenters/bill-runs/index-bill-runs.presenter.js')
const PaginatorPresenter = require('../../presenters/paginator.presenter.js')

/**
* Orchestrates fetching and presenting the data needed for the /bill-runs page
*
* @param {string} page - the page number of bill runs to be viewed
*
* @returns {Promise<Object>} an object representing the `pageData` needed by the index bill run template. It contains
* summary details for each bill run for the page selected, the template's pagination control, the title and the
* status of any busy bill runs
*/
async function go (page) {
const selectedPageNumber = _selectedPageNumber(page)

// We expect the FetchBillRunsService to take longer to complete than CheckBusyBillRunsService. But running them
// together means we are only waiting as long as it takes FetchBillRunsService to complete rather than their combined
// time
const [fetchedBillRunResult, busyResult] = await Promise.all([
FetchBillRunsService.go(selectedPageNumber),
CheckBusyBillRunsService.go()
])

const billRuns = IndexBillRunsPresenter.go(fetchedBillRunResult.results)
const pagination = PaginatorPresenter.go(fetchedBillRunResult.total, selectedPageNumber, '/system/bill-runs')

const pageTitle = _pageTitle(pagination.numberOfPages, selectedPageNumber)

return {
billRuns,
busy: busyResult,
pageTitle,
pagination
}
}

function _pageTitle (numberOfPages, selectedPageNumber) {
if (numberOfPages === 1) {
return 'Bill runs'
}

return `Bill runs (page ${selectedPageNumber} of ${numberOfPages})`
}

function _selectedPageNumber (page) {
if (!page) {
return 1
}

return Number(page)
}

module.exports = {
go
}
2 changes: 1 addition & 1 deletion app/views/bill-runs/empty.njk
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{{
govukBackLink({
text: 'Go back to bill runs',
href: '/billing/batch/list'
href: '/system/bill-runs'
})
}}
{% endblock %}
Expand Down
2 changes: 1 addition & 1 deletion app/views/bill-runs/errored.njk
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{{
govukBackLink({
text: 'Go back to bill runs',
href: '/billing/batch/list'
href: '/system/bill-runs'
})
}}
{% endblock %}
Expand Down
138 changes: 138 additions & 0 deletions app/views/bill-runs/index.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
{% extends 'layout.njk' %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %}
{% from "govuk/components/pagination/macro.njk" import govukPagination %}
{% from "govuk/components/table/macro.njk" import govukTable %}

{% from "macros/bill-run-status-tag.njk" import statusTag %}

{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-full">
{# Bill runs busy banner #}
{% if busy == 'both' %}
{{ govukNotificationBanner({
html: '<p class="govuk-notification-banner__heading">Bill runs are currently busy building and cancelling.</p>
<p class="govuk-body">Please wait for these bill runs to finish before creating another one.</p>'
}) }}
{% elif busy == 'building' %}
{{ govukNotificationBanner({
html: '<p class="govuk-notification-banner__heading">A bill run is currently building.</p>
<p class="govuk-body">Please wait for this bill run to finish building before creating another one.</p>'
}) }}
{% elif busy == 'cancelling' %}
{{ govukNotificationBanner({
html: '<p class="govuk-notification-banner__heading">A bill run is currently cancelling.</p>
<p class="govuk-body">Please wait for this bill run to finish cancelling before creating another one.</p>'
}) }}
{% endif %}

<h1 class="govuk-heading-xl">Bill runs</h1>

<p class="govuk-body">Create a supplementary, annual or two-part tariff bill run.</p>

{{ govukButton({
text: "Create a bill run",
href: "/system/bill-runs/setup"
}) }}

<hr class="govuk-section-break govuk-section-break--m govuk-section-break--visible">

</div>
</div>

<div class="govuk-grid-row govuk-!-margin-bottom-9">
<div class="govuk-grid-column-full">
{# Results #}
{% if billRuns|length == 0 %}
<p>No bill runs found.</p>
{% else %}
<h2 class="govuk-heading-l govuk-!-margin-top-6">View a bill run</h2>

<p class="govuk-body">Select date to see the details of a bill run.</p>

{% set tableRows = [] %}
{% for billRun in billRuns %}
{# Set an easier to use index #}
{% set rowIndex = loop.index0 %}


{# Link to view the bill run #}
{% set viewLink %}
{# If the link is null it is because the bill run is cancelling so we do not want to display a link #}
{% if billRun.link %}
<a class="govuk-link" href="{{ billRun.link }}">{{ billRun.createdAt }} <span class="govuk-visually-hidden">View bill run {{ billRun.number }}</span></a>
{% else %}
{{ billRun.createdAt }}
{% endif %}

{% if billRun.scheme == 'alcs' %}
<div class="govuk-body-s govuk-!-margin-0">Old charge scheme</div>
{% endif %}
{% endset %}

{% set billRunStatusTag %}
{{ statusTag(billRun.status, true) }}
{% endset %}

{% set tableRow = [
{
html: viewLink,
attributes: { 'data-test': 'date-created-' + rowIndex }
},
{
text: billRun.region,
attributes: { 'data-test': 'region-' + rowIndex }
},
{
text: billRun.type,
attributes: { 'data-test': 'bill-run-type-' + rowIndex }
},
{
text: billRun.number,
attributes: { 'data-test': 'bill-run-number-' + rowIndex },
format: 'numeric'
},
{
text: billRun.numberOfBills,
attributes: { 'data-test': 'number-of-bills-' + rowIndex },
format: 'numeric'
},
{
text: billRun.total,
attributes: { 'data-test': 'bill-run-total-' + rowIndex },
format: 'numeric'
},
{
html: billRunStatusTag,
attributes: { 'data-test': 'bill-run-status-' + rowIndex },
format: 'numeric'
}
] %}

{# Push our row into the table rows array #}
{% set tableRows = (tableRows.push(tableRow), tableRows) %}
{% endfor %}

{{ govukTable({
firstCellIsHeader: false,
attributes: { 'data-test': 'bill-runs'},
head: [
{ text: 'Date' },
{ text: 'Region' },
{ text: 'Run type' },
{ text: 'Number', format: 'numeric' },
{ text: 'Bills', format: 'numeric' },
{ text: 'Values', format: 'numeric' },
{ text: 'Status', format: 'numeric' }
],
rows: tableRows
}) }}

{% if pagination.numberOfPages > 1 %}
{{ govukPagination(pagination.component) }}
{% endif %}
{% endif %}
</div>
</div>
{% endblock %}
2 changes: 1 addition & 1 deletion app/views/bill-runs/review.njk
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
{# Back link #}
{{ govukBackLink({
text: 'Go back to bill runs',
href: '/billing/batch/list'
href: '/system/bill-runs'
}) }}
{% endblock %}

Expand Down
2 changes: 1 addition & 1 deletion app/views/bill-runs/setup/type.njk
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{{
govukBackLink({
text: 'Go back to bill runs',
href: '/billing/batch/list'
href: '/system/bill-runs'
})
}}
{% endblock %}
Expand Down
2 changes: 1 addition & 1 deletion app/views/bill-runs/view.njk
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{{
govukBackLink({
text: 'Go back to bill runs',
href: '/billing/batch/list'
href: '/system/bill-runs'
})
}}
{% endblock %}
Expand Down
2 changes: 1 addition & 1 deletion app/views/includes/nav-bar.njk
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</li>
{% if auth.permission.billRuns %}
<li class="navbar__item">
<a class="navbar__link govuk-link--no-visited-state {{ 'navbar__link--active' if activeNavBar === 'bill-runs' }}" href="/billing/batch/list" id="nav-bill-runs">
<a class="navbar__link govuk-link--no-visited-state {{ 'navbar__link--active' if activeNavBar === 'bill-runs' }}" href="/system/bill-runs" id="nav-bill-runs">
Bill runs
</a>
</li>
Expand Down
Loading

0 comments on commit 0e64948

Please sign in to comment.