Skip to content

Commit

Permalink
Cruikshanks latest changes to the view return log (#1621)
Browse files Browse the repository at this point in the history
https://eaflood.atlassian.net/browse/WATER-4745

> See [Create Completed Monthly Return Logs page](#1484)

The following changes are included

- switch to existing status macro and remove duplicate
- set correct status in presenter
- update versions design (add 'Version x' as a line and prefix with 'Viewing ' for selected version)
- add received date to the metadata
- update all return log links to go to view page
- update Edit return to be Edit or Submit return (depending on return log status)
- update page to handle viewing _any_ return log, including 'due' and 'received' which have no submission data
  • Loading branch information
Cruikshanks authored Jan 16, 2025
1 parent 584e6f8 commit 80deedb
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 160 deletions.
2 changes: 1 addition & 1 deletion app/controllers/return-logs.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ async function view(request, h) {

const pageData = await ViewReturnLogService.go(query.id, version, auth)

return h.view('return-logs/view.njk', { activeNavBar: 'search', ...pageData })
return h.view('return-logs/view.njk', pageData)
}

module.exports = {
Expand Down
10 changes: 5 additions & 5 deletions app/presenters/bill-runs/review/base-review.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ function calculateTotalBillableReturns(reviewChargeElements) {
function determineReturnLink(reviewReturn) {
const { returnId, returnStatus } = reviewReturn

if (FeatureFlagsConfig.enableSystemReturnsView) {
return `/system/return-logs?id=${returnId}`
}

if (['due', 'received'].includes(returnStatus)) {
if (FeatureFlagsConfig.enableSystemReturnsView) {
return `/system/return-logs/setup?returnLogId=${returnId}`
} else {
return `/return/internal?returnId=${returnId}`
}
return `/return/internal?returnId=${returnId}`
}

return `/returns/return?id=${returnId}`
Expand Down
10 changes: 5 additions & 5 deletions app/presenters/licences/view-licence-returns.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ function go(returnLogs, hasRequirements, auth) {
}

function _link(status, returnLogId, canManageReturns) {
if (FeatureFlagsConfig.enableSystemReturnsView) {
return `/system/return-logs?id=${returnLogId}`
}

if (['completed', 'void'].includes(status)) {
return `/returns/return?id=${returnLogId}`
}

if (canManageReturns) {
if (FeatureFlagsConfig.enableSystemReturnsView) {
return `/system/return-logs/setup?returnLogId=${returnLogId}`
} else {
return `/return/internal?returnId=${returnLogId}`
}
return `/return/internal?returnId=${returnLogId}`
}

return null
Expand Down
58 changes: 47 additions & 11 deletions app/presenters/return-logs/base-return-logs.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,27 @@
const { formatNumber, sentenceCase } = require('../base.presenter.js')
const { returnRequirementFrequencies, returnUnits, unitNames } = require('../../lib/static-lookups.lib.js')

/**
* Formats the details of a return submission meter
*
* @param {object} meter - the meter to be formatted
*
* @returns {object|null} The formatted meter or null if the meter is null or undefined
*/
function formatMeterDetails(meter) {
if (!meter || !meter?.manufacturer) {
return null
}

const { manufacturer: make, multiplier, serialNumber } = meter

return {
make,
serialNumber,
xDisplay: multiplier === 1 ? 'No' : 'Yes'
}
}

/**
* Converts a quantity from a given unit to cubic meters and formats it
*
Expand All @@ -22,24 +43,37 @@ function formatQuantity(units, quantity) {
}

/**
* Formats the details of a return submission meter
* Formats the status for a return log, adjusting for specific conditions.
*
* @param {object} meter - the meter to be formatted
* If the return log's status is 'completed', it will be displayed as 'complete'. If the status is 'due' and the due
* date has passed, it will be displayed as 'overdue'. For all other cases, it will return the status as is.
*
* @returns {object|null} The formatted meter or null if the meter is null or undefined
* @param {module:ReturnLogModel} returnLog - The return log containing status and due date information
*
* @returns {string} The formatted status for display.
*/
function formatMeterDetails(meter) {
if (!meter || !meter?.manufacturer) {
return null
function formatStatus(returnLog) {
const { status, dueDate } = returnLog

// If the return is completed we are required to display it as 'complete'. This also takes priority over the other
// statues
if (status === 'completed') {
return 'complete'
}

const { manufacturer: make, multiplier, serialNumber } = meter
// Work out if the return is overdue (status is still 'due' and it is past the due date)
const today = new Date()

return {
make,
serialNumber,
xDisplay: multiplier === 1 ? 'No' : 'Yes'
// The due date held in the record is date-only. If we compared it against 'today' without this step any return due
// 'today' would be flagged as overdue when it is still due (just!)
today.setHours(0, 0, 0, 0)

if (status === 'due' && dueDate < today) {
return 'overdue'
}

// For all other cases we can just return the status and the return-status-tag macro will know how to display it
return status
}

/**
Expand Down Expand Up @@ -195,6 +229,8 @@ function _linkDetails(id, method, frequency, endDate, rootPath) {

module.exports = {
formatMeterDetails,
formatQuantity,
formatStatus,
generateSummaryTableHeaders,
generateSummaryTableRows
}
137 changes: 100 additions & 37 deletions app/presenters/return-logs/view-return-log.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
const { formatAbstractionPeriod, formatLongDate, formatNumber } = require('../base.presenter.js')
const {
formatMeterDetails,
formatStatus,
generateSummaryTableHeaders,
generateSummaryTableRows
} = require('./base-return-logs.presenter.js')
Expand All @@ -31,6 +32,7 @@ function go(returnLog, auth) {
periodStartDay,
periodStartMonth,
purposes,
receivedDate,
returnReference,
returnsFrequency,
returnSubmissions,
Expand All @@ -41,52 +43,76 @@ function go(returnLog, auth) {
versions
} = returnLog

const selectedReturnSubmission = returnSubmissions[0]
const selectedReturnSubmission = _selectedReturnSubmission(returnSubmissions)
const latest = _latest(versions, selectedReturnSubmission)
const editReturn = _editReturn(latest, auth, status)

const method = selectedReturnSubmission.$method()
const units = selectedReturnSubmission.$units()
const summaryTableHeaders = generateSummaryTableHeaders(method, returnsFrequency, units)
const summaryTableRows = generateSummaryTableRows(
method,
returnsFrequency,
selectedReturnSubmission.returnSubmissionLines,
selectedReturnSubmission.id
)
const method = selectedReturnSubmission?.$method()
const units = selectedReturnSubmission?.$units()

return {
abstractionPeriod: formatAbstractionPeriod(periodStartDay, periodStartMonth, periodEndDay, periodEndMonth),
actionButton: _actionButton(latest, auth, returnLog.id, status),
backLink: _backLink(returnLog.id, licence.id, latest),
displayReadings: method !== 'abstractionVolumes',
displayTable: _displayTable(selectedReturnSubmission),
displayTotal: !!selectedReturnSubmission,
displayUnits: units !== unitNames.CUBIC_METRES,
editReturn,
editReturnLink: editReturn ? `/return/internal?returnId=${returnLog.id}` : null,
latest,
licenceRef: licence.licenceRef,
meterDetails: formatMeterDetails(selectedReturnSubmission.$meter()),
meterDetails: formatMeterDetails(selectedReturnSubmission?.$meter()),
method,
nilReturn: selectedReturnSubmission.nilReturn,
nilReturn: selectedReturnSubmission ? selectedReturnSubmission.nilReturn : false,
pageTitle: 'Abstraction return',
purpose: _purpose(purposes),
receivedDate: receivedDate ? formatLongDate(receivedDate) : null,
returnReference,
returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`,
siteDescription,
startReading: selectedReturnSubmission.$meter()?.startReading,
status,
summaryTableHeaders,
summaryTableRows,
startReading: _startReading(selectedReturnSubmission),
status: formatStatus(returnLog),
summaryTableData: _summaryTableData(selectedReturnSubmission, returnsFrequency),
tableTitle: _tableTitle(returnsFrequency, method),
tariff: twoPartTariff ? 'Two-part' : 'Standard',
total: _total(selectedReturnSubmission),
versions: _versions(selectedReturnSubmission.id, versions, id)
versions: _versions(selectedReturnSubmission, versions, id)
}
}

function _actionButton(latest, auth, returnLogId, status) {
// You cannot edit a previous version
if (!latest) {
return null
}

// You cannot edit a void return
if (status === 'void') {
return null
}

// You cannot submit or edit if you do not have permission to
if (!auth.credentials.scope.includes('returns')) {
return null
}

// You can only edit a completed return
if (status === 'completed') {
return {
href: `/return/internal?returnId=${returnLogId}`,
text: 'Edit return'
}
}

// Else you have a due or received return so can only submit the first return submission
return {
href: `/system/return-logs/setup?returnLogId=${returnLogId}`,
text: 'Submit return'
}
}

function _backLink(returnId, licenceId, latest) {
if (latest) {
return {
href: `/system/licences/${licenceId}/summary`,
href: `/system/licences/${licenceId}/returns`,
text: 'Go back to summary'
}
}
Expand All @@ -97,23 +123,23 @@ function _backLink(returnId, licenceId, latest) {
}
}

function _latest(versions, selectedReturnSubmission) {
return versions[0].id === selectedReturnSubmission.id
}

function _editReturn(latest, auth, status) {
// You cannot edit a previous version
if (!latest) {
function _displayTable(selectedReturnSubmission) {
// We are dealing with a due or received return log so there are no submissions.
if (!selectedReturnSubmission) {
return false
}

// You cannot edit if you do not have permission to
if (!auth.credentials.scope.includes('returns')) {
return false
return !selectedReturnSubmission.nilReturn
}

function _latest(versions, selectedReturnSubmission) {
// We are dealing with a due or received return log so there are no submissions. We treat this as 'latest' to avoid
// displaying the warning message
if (!selectedReturnSubmission) {
return true
}

// You can only edit (add a new submission) to a completed or received return
return ['completed', 'received'].includes(status)
return versions[0].id === selectedReturnSubmission.id
}

function _purpose(purposes) {
Expand All @@ -122,6 +148,37 @@ function _purpose(purposes) {
return firstPurpose.alias ? firstPurpose.alias : firstPurpose.tertiary.description
}

function _selectedReturnSubmission(returnSubmissions) {
if (!returnSubmissions) {
return null
}

return returnSubmissions[0]
}

function _startReading(selectedReturnSubmission) {
if (!selectedReturnSubmission) {
return null
}

return selectedReturnSubmission.$meter()?.startReading
}

function _summaryTableData(selectedReturnSubmission, returnsFrequency) {
if (!selectedReturnSubmission) {
return null
}

const { id: returnSubmissionId, returnSubmissionLines } = selectedReturnSubmission
const method = selectedReturnSubmission.$method()
const units = selectedReturnSubmission.$units()

return {
headers: generateSummaryTableHeaders(method, returnsFrequency, units),
rows: generateSummaryTableRows(method, returnsFrequency, returnSubmissionLines, returnSubmissionId)
}
}

function _tableTitle(returnsFrequency, method) {
const frequency = returnRequirementFrequencies[returnsFrequency]
const postfix = method === 'abstractionVolumes' ? 'abstraction volumes' : 'meter readings'
Expand All @@ -130,7 +187,7 @@ function _tableTitle(returnsFrequency, method) {
}

function _total(selectedReturnSubmission) {
if (selectedReturnSubmission.nilReturn) {
if (!selectedReturnSubmission || selectedReturnSubmission.nilReturn) {
return 0
}

Expand All @@ -143,14 +200,20 @@ function _total(selectedReturnSubmission) {
return formatNumber(total)
}

function _versions(selectedReturnSubmissionId, versions, returnLogId) {
function _versions(selectedReturnSubmission, versions, returnLogId) {
// We are dealing with a due or received return log so there are no submissions, which means no versions to display
if (!selectedReturnSubmission) {
return null
}

return versions.map((version) => {
const { createdAt, id, userId: user, version: number } = version

return {
createdAt: `${formatLongDate(createdAt)} v${number}`,
createdAt: `${formatLongDate(createdAt)}`,
link: `/system/return-logs?id=${returnLogId}&version=${number}`,
selected: id === selectedReturnSubmissionId,
selected: id === selectedReturnSubmission.id,
version: number,
user
}
})
Expand Down
Loading

0 comments on commit 80deedb

Please sign in to comment.