Skip to content

Commit

Permalink
Merge branch 'main' into check-return-details-pt1
Browse files Browse the repository at this point in the history
  • Loading branch information
Jozzey authored Jan 24, 2025
2 parents 919a1c2 + fddda68 commit 890a542
Show file tree
Hide file tree
Showing 17 changed files with 1,356 additions and 914 deletions.
5 changes: 3 additions & 2 deletions app/controllers/notifications-setup.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ async function viewReturnsPeriod(request, h) {

async function viewReview(request, h) {
const {
params: { sessionId }
params: { sessionId },
query: { page }
} = request

const pageData = await ReviewService.go(sessionId)
const pageData = await ReviewService.go(sessionId, page)

return h.view(`${basePath}/review.njk`, pageData)
}
Expand Down
8 changes: 5 additions & 3 deletions app/lib/return-periods.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ function determineReturnsPeriods(returnCycle) {
*
* The result includes the start date, end date, and due date for each period.
*
* @param {Date} determinationDate - The date to base the calculation on. Defaults to the current date.
* @param {Date} date - The date to base the calculation on. Defaults to the current date.
*
* @returns {object} An object containing calculated dates for all return periods
*/
function determineUpcomingReturnsPeriods(determinationDate = new Date()) {
function determineUpcomingReturnsPeriods(date = new Date()) {
const determinationDate = new Date(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`)

return {
allYear: {
startDate: _cycleStartDate(determinationDate, returnPeriodDates.allYear),
Expand Down Expand Up @@ -181,7 +183,7 @@ function _isDue(determinationDate, period) {

const dueDate = new Date(`${year}-${periodDueMonth}-${periodDueDay}`)

return dueDate.getTime() < determinationDate.getTime()
return dueDate < determinationDate
}

/**
Expand Down
17 changes: 15 additions & 2 deletions app/presenters/base.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,18 @@ function generateBillRunTitle(regionName, batchType, scheme, summer) {
/**
* Formats an abstraction day and month into its string variant, for example, 1 and 4 becomes '1 April'
*
* If either value is null or undefined, it returns null.
*
* @param {number} abstractionDay
* @param {number} abstractionMonth - Note: the index starts at 1, for example, 4 would be April
*
* @returns {string} The abstraction date formatted as a 'DD MMMM' string
* @returns {string|null} The abstraction date formatted as a 'DD MMMM' string or null if either value is not set
*/
function formatAbstractionDate(abstractionDay, abstractionMonth) {
if (!abstractionDay || !abstractionMonth) {
return null
}

// NOTE: Because of the unique qualities of Javascript, Year and Day are literal values, month is an index! So,
// January is actually 0, February is 1 etc. This is why we are always deducting 1 from the months.
const abstractionDate = new Date(1970, abstractionMonth - 1, abstractionDay)
Expand All @@ -53,17 +59,24 @@ function formatAbstractionDate(abstractionDay, abstractionMonth) {
/**
* Formats an abstraction period into its string variant, for example, '1 April to 31 October'
*
* If the provided abstraction data is null or undefined, it returns null.
*
* @param {number} startDay
* @param {number} startMonth
* @param {number} endDay
* @param {number} endMonth
*
* @returns {string} The abstraction period formatted as a 'DD MMMM to DD MMMM' string
* @returns {string} The abstraction period formatted as a 'DD MMMM to DD MMMM' string, unless the abstraction period
* cannot be determined, in which case it returns null
*/
function formatAbstractionPeriod(startDay, startMonth, endDay, endMonth) {
const startDate = formatAbstractionDate(startDay, startMonth)
const endDate = formatAbstractionDate(endDay, endMonth)

if (!startDate || !endDate) {
return null
}

return `${startDate} to ${endDate}`
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function _formatReturnPeriod(returnsPeriod, savedReturnsPeriod) {

function _textPrefix(returnPeriod) {
if (returnPeriod.name === 'allYear') {
return 'Winter and all year'
return 'Winter and all year annual'
} else if (returnPeriod.name === 'summer') {
return 'Summer annual'
} else {
Expand Down
35 changes: 29 additions & 6 deletions app/presenters/notifications/setup/review.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ const { titleCase } = require('../../base.presenter.js')
/**
* Formats data for the `/notifications/setup/review` page
*
* @param recipients
* @param {object[]} recipients - List of recipient objects, each containing recipient details like email or name.
* @param {number|string} page - The currently selected page
* @param {object} pagination -
*
* @returns {object} - The data formatted for the view template
*/
function go(recipients) {
function go(recipients, page, pagination) {
return {
defaultPageSize,
pageTitle: 'Send returns invitations',
recipients: _recipients(recipients),
pageTitle: _pageTitle(page, pagination),
recipients: _recipients(recipients, page),
recipientsAmount: recipients.length
}
}
Expand Down Expand Up @@ -52,8 +55,28 @@ function _licences(licences) {
return licences.split(',')
}

function _recipients(recipients) {
return recipients.map((recipient) => {
function _pageTitle(page, pagination) {
if (pagination.numberOfPages > 1) {
return `Send returns invitations (page ${page} of ${pagination.numberOfPages})`
}

return 'Send returns invitations'
}

/**
* Due to the complexity of the query to get the recipients data, we handle pagination in the presenter.
*
* @private
*/
function _pagination(recipients, page) {
const pageNumber = Number(page) * defaultPageSize
return recipients.slice(pageNumber - defaultPageSize, pageNumber)
}

function _recipients(recipients, page) {
const paginatedRecipients = _pagination(recipients, page)

return paginatedRecipients.map((recipient) => {
return {
contact: _contact(recipient),
licences: _licences(recipient.all_licences),
Expand Down
15 changes: 8 additions & 7 deletions app/presenters/return-versions/view.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @module ViewPresenter
*/

const { formatAbstractionDate } = require('../base.presenter.js')
const { formatAbstractionPeriod } = require('../base.presenter.js')
const { formatLongDate } = require('../base.presenter.js')
const { isQuarterlyReturnSubmissions } = require('../../lib/dates.lib.js')
const { returnRequirementReasons, returnRequirementFrequencies } = require('../../lib/static-lookups.lib.js')
Expand Down Expand Up @@ -39,13 +39,14 @@ function go(returnVersion) {
}

function _abstractionPeriod(requirement) {
const { abstractionPeriodStartDay, abstractionPeriodStartMonth, abstractionPeriodEndDay, abstractionPeriodEndMonth } =
requirement

const startDate = formatAbstractionDate(abstractionPeriodStartDay, abstractionPeriodStartMonth)
const endDate = formatAbstractionDate(abstractionPeriodEndDay, abstractionPeriodEndMonth)
const abstractionPeriod = formatAbstractionPeriod(
requirement.abstractionPeriodStartDay,
requirement.abstractionPeriodStartMonth,
requirement.abstractionPeriodEndDay,
requirement.abstractionPeriodEndMonth
)

return `From ${startDate} to ${endDate}`
return abstractionPeriod ?? ''
}

function _agreementsExceptions(returnRequirement) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,25 @@ const ReturnLogModel = require('../../../models/return-log.model.js')
* `returnSubmissionLines` if they exist
*/
async function go(licenceRef, billingPeriod) {
return _fetch(licenceRef, billingPeriod)
try {
return await _fetch(licenceRef, billingPeriod)
} catch (error) {
// NOTE: The try/catch was added after we found out that it is possible to set up return requirements in NALD with
// empty abstraction periods. This then causes the return log to also be missing abstraction period data. Our
// CAST() in the query then causes an error.
global.GlobalNotifier.omfg(
'Bill run process fetch return logs for licence failed',
{ licenceRef, billingPeriod },
error
)
// NOTE: We rethrow the error so that the bill run will be set to 'errored'. We know this will result in us
// having to investigate the issue, but with this additional logging we should be able to quickly see which licence
// caused the error and why.
//
// If we don't rethrow the error then the bill run will complete without the return log being picked up. This would
// result in an incorrect bill run because the submission would not have been picked up for allocation.
throw error
}
}

async function _fetch(licenceRef, billingPeriod) {
Expand Down
18 changes: 14 additions & 4 deletions app/services/notifications/setup/review.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@
* @module ReviewService
*/

const DedupeRecipientsService = require('./dedupe-recipients.service.js')
const PaginatorPresenter = require('../../../presenters/paginator.presenter.js')
const RecipientsService = require('./fetch-recipients.service.js')
const ReviewPresenter = require('../../../presenters/notifications/setup/review.presenter.js')
const SessionModel = require('../../../models/session.model.js')
const { determineUpcomingReturnPeriods } = require('../../../lib/return-periods.lib.js')
const DedupeRecipientsService = require('./dedupe-recipients.service.js')

/**
* Orchestrates fetching and presenting the data needed for the notifications setup review page
*
* @param {string} sessionId - The UUID for setup ad-hoc returns notification session record
* @param {number|string} [page=1] - The currently selected page (if paginated)
*
* @returns {object} The view data for the review page
*/
async function go(sessionId) {
async function go(sessionId, page = 1) {
const session = await SessionModel.query().findById(sessionId)

const { returnsPeriod } = session
Expand All @@ -29,11 +31,19 @@ async function go(sessionId) {

const dedupeRecipients = DedupeRecipientsService.go(recipients)

const formattedData = ReviewPresenter.go(dedupeRecipients)
const pagination = PaginatorPresenter.go(
dedupeRecipients.length,
Number(page),
`/system/notifications/setup/${sessionId}/review`
)

const formattedData = ReviewPresenter.go(dedupeRecipients, page, pagination)

return {
activeNavBar: 'manage',
...formattedData
...formattedData,
pagination,
page
}
}

Expand Down
16 changes: 12 additions & 4 deletions app/views/notifications/setup/review.njk
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
{% from "govuk/components/button/macro.njk" import govukButton %}
{% from "govuk/components/details/macro.njk" import govukDetails %}
{% from "govuk/components/pagination/macro.njk" import govukPagination %}
{% from "govuk/components/pagination/macro.njk" import govukPagination %}
{% from "govuk/components/radios/macro.njk" import govukRadios %}
{% from "govuk/components/table/macro.njk" import govukTable %}
{% from 'govuk/components/error-summary/macro.njk' import govukErrorSummary %}

{% from "macros/new-line-array-items.njk" import newLineArrayItems %}

{% block breadcrumbs %}
Expand All @@ -15,8 +17,6 @@
}) }}
{% endblock %}



{% set rows = [] %}

{%for recipient in recipients %}
Expand Down Expand Up @@ -47,7 +47,7 @@

{% block content %}
<div class="govuk-body">
<h1 class="govuk-heading-l">{{ pageTitle }}</h1>
<h1 class="govuk-heading-l"> {{ pageTitle }} </h1>

<p> Returns invitations are ready to send.</p>

Expand All @@ -63,7 +63,11 @@
}) }}
</div>

<p>Showing {{ defaultPageSize }} of {{ recipientsAmount }}</p>
{% if pagination.numberOfPages > 1 %}
<p> Showing {{ defaultPageSize }} of {{ recipientsAmount }} recipients </p>
{% else %}
<p> Showing all {{ recipientsAmount }} recipients </p>
{% endif %}

{{ govukTable({
captionClasses: "govuk-table__caption--m",
Expand All @@ -85,6 +89,10 @@
rows: rows
}) }}

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

<form method="post">
<input type="hidden" name="wrlsCrumb" value="{{ wrlsCrumb }}"/>

Expand Down
Loading

0 comments on commit 890a542

Please sign in to comment.