-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create review an individual licence for 2PT bill run (#704)
https://eaflood.atlassian.net/browse/WATER-4191 As part of our two-part tariff bill run work, we've developed a review page displaying a summary of all licences in a bill run. This PR allows you to click on a specific licence from the review page and review its details within the bill run.
- Loading branch information
1 parent
779b151
commit d290c0e
Showing
16 changed files
with
1,124 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
app/presenters/bill-runs/two-part-tariff/review-licence.presenter.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
app/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
84 changes: 84 additions & 0 deletions
84
app/services/bill-runs/two-part-tariff/prepare-review-licence-results.service.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
34
app/services/bill-runs/two-part-tariff/review-licence.service.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.