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

Create review an individual licence for 2PT bill run #704

Merged
merged 46 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
59d3cf3
Create review an individual licence for 2PT bill run
Beckyrose200 Jan 31, 2024
5ca5d87
Adding licence.id to the presenter and fixing its tests
Beckyrose200 Jan 31, 2024
e585fa2
Add billRun id to presenter and fix tests
Beckyrose200 Jan 31, 2024
320c69d
First draft presenter, view and kick off service
Beckyrose200 Jan 31, 2024
ba21267
Adding licence status to the get request
Beckyrose200 Feb 1, 2024
35dfdbc
Adding unmatched returns on the view
Beckyrose200 Feb 1, 2024
4320aab
Adding the presenter
Beckyrose200 Feb 1, 2024
7e5f940
Updating the route to take status
Beckyrose200 Feb 1, 2024
5641695
Adding the fetch data service
Beckyrose200 Feb 1, 2024
397fae0
Preparing the licence data
Beckyrose200 Feb 1, 2024
1e34bc4
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 1, 2024
35f0e5d
Fix billRuns controller test
Beckyrose200 Feb 2, 2024
261a66e
Add comments and unit test for licence-review-bill-run-service
Beckyrose200 Feb 2, 2024
b947b87
Rename the licence review route and all its files
Beckyrose200 Feb 5, 2024
b639c5a
Remove .only
Beckyrose200 Feb 5, 2024
8e36fb8
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 5, 2024
29241c9
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 5, 2024
277364a
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 5, 2024
994fac9
Refactor and write unit tests for fetch-review-licence-results service
Beckyrose200 Feb 5, 2024
c4716a3
Remove status being passed through the request params
Beckyrose200 Feb 5, 2024
1d23b6e
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 5, 2024
11cae76
Refactor and write unit tests for prepare-review-licence-results service
Beckyrose200 Feb 5, 2024
8d0bb3b
remove console logs
Beckyrose200 Feb 5, 2024
3b2bd5e
remove redundant .distinct()
Beckyrose200 Feb 5, 2024
1f4b16e
Fix test data
Beckyrose200 Feb 5, 2024
765f829
Refactor presenter
Beckyrose200 Feb 5, 2024
f919e36
Add parentheses around parameter
Beckyrose200 Feb 5, 2024
bcd22ec
Add unit tests for review-licence presenter
Beckyrose200 Feb 6, 2024
563dc15
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 6, 2024
7efc621
Remove redundant await
Beckyrose200 Feb 6, 2024
886a8ef
Adding else clause to presenter
Beckyrose200 Feb 6, 2024
66db39d
Refactor allocated function
Beckyrose200 Feb 6, 2024
98842ea
DOH!
Beckyrose200 Feb 6, 2024
6622d59
Remove redundant await
Beckyrose200 Feb 6, 2024
06db5f4
Remove .only Doh!
Beckyrose200 Feb 6, 2024
166b257
Update comment
Beckyrose200 Feb 6, 2024
4586337
Fix comments
Beckyrose200 Feb 6, 2024
62bbeb6
Updating presenter and reordering bill controller functions
Beckyrose200 Feb 6, 2024
b913ad0
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 7, 2024
0948d9c
Add cypress acceptance test hooks
Beckyrose200 Feb 7, 2024
3a44b76
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 7, 2024
bb6afff
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 7, 2024
7dbbcbc
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 8, 2024
921f385
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 8, 2024
ad03cd8
Rename returnLogs to reviewReturnResults
Beckyrose200 Feb 8, 2024
1f2e320
Merge branch 'main' into create-individual-licence-bill-run-pages
Beckyrose200 Feb 9, 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
14 changes: 14 additions & 0 deletions app/controllers/bill-runs.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const CreateBillRunValidator = require('../validators/create-bill-run.validator.
const StartBillRunProcessService = require('../services/bill-runs/start-bill-run-process.service.js')
const ViewBillRunService = require('../services/bill-runs/view-bill-run.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')

async function create (request, h) {
const validatedData = CreateBillRunValidator.go(request.payload)
Expand Down Expand Up @@ -41,6 +42,18 @@ async function review (request, h) {
})
}

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

const pageData = await ReviewLicenceService.go(billRunId, licenceId)

return h.view('bill-runs/review-licence.njk', {
pageTitle: `Licence ${pageData.licenceRef}`,
activeNavBar: 'bill-runs',
...pageData
})
}

async function view (request, h) {
const { id } = request.params

Expand Down Expand Up @@ -69,5 +82,6 @@ function _formattedInitiateBillRunError (error) {
module.exports = {
create,
review,
reviewLicence,
view
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ function _prepareLicences (licences) {
}

preparedLicences.push({
id: licence.id,
licenceRef: licence.licenceRef,
licenceHolder: licence.licenceHolder,
status: licence.status,
Expand Down
112 changes: 112 additions & 0 deletions app/presenters/bill-runs/two-part-tariff/review-licence.presenter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
'use strict'

/**
* Formats the review licence data ready for presenting in the review licence page
* @module ReviewLicencePresenter
*/

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

/**
* Prepares and processes bill run and review licence data for presentation
*
* @param {module:ReviewReturnResultModel} matchedReturns matched return logs for an individual licence
* @param {module:ReviewReturnResultModel} unmatchedReturns unmatched return logs for an individual licence
* @param {Object[]} chargePeriods chargePeriods with start and end date properties
* @param {module:BillRunModel} billRun the data from the bill run
* @param {String} licenceRef the reference for the licence
*
* @returns {Object} the prepared bill run and licence data to be passed to the review licence page
*/
function go (matchedReturns, unmatchedReturns, chargePeriods, billRun, licenceRef) {
return {
licenceRef,
billRunId: billRun.id,
status: 'Review',
region: billRun.region.displayName,
matchedReturns: _prepareMatchedReturns(matchedReturns),
unmatchedReturns: _prepareUnmatchedReturns(unmatchedReturns),
chargePeriodDates: _prepareLicenceChargePeriods(chargePeriods)
}
}

function _prepareLicenceChargePeriods (chargePeriods) {
return chargePeriods.map((chargePeriod) => {
const { startDate, endDate } = chargePeriod

return _prepareDate(startDate, endDate)
})
}

function _prepareUnmatchedReturns (unmatchedReturns) {
return unmatchedReturns.map((unmatchedReturn) => {
const { returnReference, status, description, purposes, allocated, quantity, startDate, endDate } = unmatchedReturn.reviewReturnResults

return {
reference: returnReference,
dates: _prepareDate(startDate, endDate),
status,
description,
purpose: purposes[0].tertiary.description,
total: `${allocated} ML / ${quantity} ML`
}
})
}

function _prepareMatchedReturns (matchedReturns) {
return matchedReturns.map((matchedReturn) => {
const { returnStatus, total, allocated } = _checkStatusAndReturnTotal(matchedReturn)
const { returnReference, description, purposes, startDate, endDate } = matchedReturn.reviewReturnResults

return {
reference: returnReference,
dates: _prepareDate(startDate, endDate),
status: returnStatus,
description,
purpose: purposes[0].tertiary.description,
total,
allocated
}
})
}

function _checkStatusAndReturnTotal (returnLog) {
const { status, allocated, quantity, underQuery } = returnLog.reviewReturnResults

let allocatedStatus
let total
let returnStatus = underQuery ? 'query' : status

if (status === 'void' || status === 'received') {
total = '/'
allocatedStatus = 'Not processed'
} else if (status === 'due') {
returnStatus = 'overdue'
total = '/'
allocatedStatus = 'Not processed'
} else {
total = `${allocated} ML / ${quantity} ML`
allocatedStatus = _allocated(quantity, allocated)
}

return { returnStatus, total, allocated: allocatedStatus }
}

function _allocated (quantity, allocated) {
if (quantity > allocated) {
return 'Over abstraction'
} else {
return 'Fully allocated'
}
}

function _prepareDate (startDate, endDate) {
const preparedStartDate = formatLongDate(startDate)
const preparedEndDate = formatLongDate(endDate)

return `${preparedStartDate} to ${preparedEndDate}`
}

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 @@ -44,6 +44,19 @@ const routes = [
},
description: 'Review two-part tariff match and allocation results'
}
},
{
method: 'GET',
path: '/bill-runs/{id}/review/{licenceId}',
handler: BillRunsController.reviewLicence,
options: {
auth: {
access: {
scope: ['billing']
}
},
description: 'Review a two-part tariff licence'
}
}
]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict'

/**
* Fetches the review licence results and bill run data for a two-part tariff bill run
* @module FetchReviewLicenceResultsService
*/

const BillRunModel = require('../../../models/bill-run.model.js')
const ReviewResultModel = require('../../../models/review-result.model.js')

/**
* Fetches the review return results data for an individual licence in the bill run and the bill run data
*
* @param {String} billRunId UUID of the bill run
* @param {String} licenceId UUID of the licence
*
* @returns {Promise<Object[]>} Contains an array of bill run data and review licence data
*/
async function go (billRunId, licenceId) {
const billRun = await _fetchBillRun(billRunId)
const reviewReturnResults = await _fetchReviewReturnResults(billRunId, licenceId)

return { reviewReturnResults, billRun }
}

async function _fetchBillRun (billRunId) {
return BillRunModel.query()
.findById(billRunId)
.select([
'id',
'batchType'
])
.withGraphFetched('region')
.modifyGraph('region', (builder) => {
builder.select([
'id',
'displayName'
])
})
}

async function _fetchReviewReturnResults (billRunId, licenceId) {
return ReviewResultModel.query()
.where({ billRunId, licenceId })
.whereNotNull('reviewReturnResultId')
.select([
'reviewReturnResultId',
'reviewChargeElementResultId',
'chargeVersionId',
'chargePeriodStartDate',
'chargePeriodEndDate'])
.withGraphFetched('reviewReturnResults')
.modifyGraph('reviewReturnResults', (builder) => {
builder.select([
'id',
'returnId',
'return_reference',
'startDate',
'endDate',
'dueDate',
'receivedDate',
'status',
'underQuery',
'nilReturn',
'description',
'purposes',
'quantity',
'allocated',
'abstractionOutsidePeriod'
])
})
.withGraphFetched('licence')
.modifyGraph('licence', (builder) => {
builder.select([
'id',
'licenceRef'
])
})
}

module.exports = {
go
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'use strict'

/**
* Prepares the review return logs ready for presenting in the review page
* @module PrepareReviewLicenceResultsService
*/

/**
* Prepares the given review return logs, deduplicates them, and extracts matched and unmatched returns along with their
* corresponding charge periods for the licence being reviewed
*
* @param {module:ReviewReturnResultModel} reviewReturnResults All the review return logs associated with the licence being reviewed
*
* @returns {Object[]} matched and unmatched return logs and the charge periods for that licence
*/
function go (reviewReturnResults) {
const licenceRef = reviewReturnResults[0].licence.licenceRef
const uniqueReturnLogs = _dedupeReturnLogs(reviewReturnResults)

const { matchedReturns, unmatchedReturns } = _splitReturns(uniqueReturnLogs)

// Only matched returns have a charge version and therefore chargePeriods
const chargePeriods = _fetchChargePeriods(matchedReturns)

return { matchedReturns, unmatchedReturns, chargePeriods, licenceRef }
}

function _dedupeReturnLogs (reviewReturnResults) {
const uniqueReturnIds = new Set()
const uniqueReturnLogs = []

reviewReturnResults.forEach((returnLog) => {
const id = returnLog.reviewReturnResultId

if (!uniqueReturnIds.has(id)) {
uniqueReturnIds.add(id)
uniqueReturnLogs.push(returnLog)
}
})

return uniqueReturnLogs
}

// To generate a list of charge periods from the return logs, we need to eliminate duplicate charge versions and extract
// unique charge periods based on their start and end dates.
function _fetchChargePeriods (matchedReturns) {
const uniqueChargeVersionIds = new Set()
const chargePeriods = []

for (const returnLog of matchedReturns) {
const id = returnLog.chargeVersionId

if (!uniqueChargeVersionIds.has(id)) {
uniqueChargeVersionIds.add(id)

chargePeriods.push({
startDate: returnLog.chargePeriodStartDate,
endDate: returnLog.chargePeriodEndDate
})
}
}

return chargePeriods
}

function _splitReturns (uniqueReturnLogs) {
// Filters the return logs to only return the ones where reviewChargeElementResultId exists (ie the return log
// matches to a charge element)
const matchedReturns = uniqueReturnLogs.filter((returnLog) => {
return returnLog.reviewChargeElementResultId !== null
})

// Filters the return logs to only return the ones where reviewChargeElementResultId is null (ie the return log
// does not match to a charge element)
const unmatchedReturns = uniqueReturnLogs.filter((returnLog) => {
return returnLog.reviewChargeElementResultId === null
})

return { matchedReturns, unmatchedReturns }
}

module.exports = {
go
}
34 changes: 34 additions & 0 deletions app/services/bill-runs/two-part-tariff/review-licence.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict'

/**
* Orchestrates fetching and presenting the data needed for the licence review page
* @module ReviewLicenceService
*/

const FetchReviewLicenceResultsService = require('./fetch-review-licence-results.service.js')
const ReviewLicencePresenter = require('../../../presenters/bill-runs/two-part-tariff/review-licence.presenter.js')
const PrepareReviewLicenceResultsService = require('./prepare-review-licence-results.service.js')

/**
* Orchestrated fetching and presenting the data needed for the licence review page
*
* @param {*} billRunId The UUID for the bill run
* @param {*} licenceId The UUID of the licence that is being reviewed
* @param {*} status The current overall status of the licence
*
* @returns {Object} an object representing the 'pageData' needed to review the individual licence. It contains the
* licence matched and unmatched returns and the licence charge data
*/
async function go (billRunId, licenceId) {
const { reviewReturnResults, billRun } = await FetchReviewLicenceResultsService.go(billRunId, licenceId)

const { matchedReturns, unmatchedReturns, chargePeriods, licenceRef } = PrepareReviewLicenceResultsService.go(reviewReturnResults)

const pageData = ReviewLicencePresenter.go(matchedReturns, unmatchedReturns, chargePeriods, billRun, licenceRef)

return pageData
}

module.exports = {
go
}
Loading
Loading