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

Review an individual licence page #806

Merged
merged 36 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5f39adf
Review an individual licence page
Beckyrose200 Mar 12, 2024
2f30c8b
WIP
Beckyrose200 Mar 12, 2024
40f5580
WIP
Beckyrose200 Mar 14, 2024
060621e
Merge branch 'main' into review-licence-page
Beckyrose200 Mar 14, 2024
4d67ebd
Add return volumes
Beckyrose200 Mar 15, 2024
eee158f
Add return issues
Beckyrose200 Mar 15, 2024
ee31403
Fix reviewChargeElementModel tests
Beckyrose200 Mar 15, 2024
5c987e5
Fix reviewChargeReferenceModel tests
Beckyrose200 Mar 15, 2024
3be5bd1
Fix reviewChargeVersionModel tests
Beckyrose200 Mar 15, 2024
7995d2e
Merge branch 'main' into review-licence-page
Beckyrose200 Mar 15, 2024
eaff4fe
Update bill-runs.controller.test
Beckyrose200 Mar 15, 2024
32adda4
Remove .only
Beckyrose200 Mar 15, 2024
0744784
Make FetchBillingAccountService a shared service
Beckyrose200 Mar 15, 2024
79fa40a
Fix reviewLicenceService tests
Beckyrose200 Mar 15, 2024
ac4f208
Remove .only
Beckyrose200 Mar 15, 2024
90cb332
Refactor and fix unit tests for FetchReviewLicenceResultsService
Beckyrose200 Mar 15, 2024
55151f4
Refactor view
Beckyrose200 Mar 18, 2024
c079076
Refactor presenter
Beckyrose200 Mar 18, 2024
09d484d
Refactor presenter and fix tests
Beckyrose200 Mar 18, 2024
7737310
Merge branch 'main' into review-licence-page
Beckyrose200 Mar 18, 2024
a4001af
Linting
Beckyrose200 Mar 18, 2024
54cd531
Sonar Cloud
Beckyrose200 Mar 18, 2024
700d008
Fix Sonar Cloud
Beckyrose200 Mar 18, 2024
9f7cba8
Remove <br> tag and safe tags
Beckyrose200 Mar 25, 2024
7d40570
Refactor view and presenter
Beckyrose200 Mar 26, 2024
829eb16
Merge branch 'main' into review-licence-page
Beckyrose200 Mar 26, 2024
3d19363
Fix presenter test
Beckyrose200 Mar 26, 2024
6ef4833
Merge branch 'main' into review-licence-page
Beckyrose200 Mar 26, 2024
09dcc40
Merge branch 'main' into review-licence-page
Beckyrose200 Mar 26, 2024
0f63e52
Merge branch 'main' into review-licence-page
Beckyrose200 Mar 27, 2024
9891b81
Move fetchBillingAccountService test file
Beckyrose200 Mar 27, 2024
1c70c53
Fix line length issue
Beckyrose200 Mar 27, 2024
10a0e28
Merge branch 'main' into review-licence-page
Jozzey Mar 27, 2024
5e58d55
Minor tweaks to the view
Jozzey Mar 27, 2024
08d7f00
Fix line lengths
Beckyrose200 Mar 28, 2024
4b9f9cc
Merge branch 'main' into review-licence-page
Beckyrose200 Mar 28, 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
2 changes: 1 addition & 1 deletion app/controllers/bill-runs.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ async function reviewLicence (request, h) {
const pageData = await ReviewLicenceService.go(billRunId, licenceId)

return h.view('bill-runs/review-licence.njk', {
pageTitle: `Licence ${pageData.licenceRef}`,
pageTitle: `Licence ${pageData.licence.licenceRef}`,
activeNavBar: 'bill-runs',
...pageData
})
Expand Down
8 changes: 8 additions & 0 deletions app/models/review-charge-element.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ class ReviewChargeElementModel extends BaseModel {
},
to: 'reviewReturns.id'
}
},
chargeElement: {
relation: Model.BelongsToOneRelation,
modelClass: 'charge-element.model',
join: {
from: 'reviewChargeElements.chargeElementId',
to: 'chargeElements.id'
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions app/models/review-charge-reference.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ class ReviewChargeReferenceModel extends BaseModel {
from: 'reviewChargeReferences.id',
to: 'reviewChargeElements.reviewChargeReferenceId'
}
},
chargeReference: {
relation: Model.BelongsToOneRelation,
modelClass: 'charge-reference.model',
join: {
from: 'reviewChargeReferences.chargeReferenceId',
to: 'chargeReferences.id'
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions app/models/review-charge-version.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ class ReviewChargeVersionModel extends BaseModel {
from: 'reviewChargeVersions.id',
to: 'reviewChargeReferences.reviewChargeVersionId'
}
},
chargeVersion: {
relation: Model.BelongsToOneRelation,
modelClass: 'charge-version.model',
join: {
from: 'reviewChargeVersions.chargeVersionId',
to: 'chargeVersions.id'
}
}
}
}
Expand Down
271 changes: 269 additions & 2 deletions app/presenters/bill-runs/two-part-tariff/review-licence.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,287 @@
* @module ReviewLicencePresenter
*/

const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js')
const { formatLongDate } = require('../../base.presenter.js')

/**
* Prepares and processes bill run and review licence data for presentation
*
* @param {module:BillRunModel} billRun the data from the bill run
* @param {module:ReviewLicenceModel} licence the data from review licence
*
* @returns {Object} the prepared bill run and licence data to be passed to the review licence page
*/
function go (billRun, licence) {
return {
billRunId: billRun.id,
status: 'review',
region: billRun.region.displayName,
licenceRef: licence[0].licenceRef
licence: {
licenceId: licence[0].licenceId,
licenceRef: licence[0].licenceRef,
status: licence[0].status,
licenceHolder: licence[0].licenceHolder
},
matchedReturns: _matchedReturns(licence[0].reviewReturns),
unmatchedReturns: _unmatchedReturns(licence[0].reviewReturns),
chargeData: _prepareChargeData(licence, billRun)
}
}

function _accountName (billingAccount) {
const accountAddress = billingAccount.billingAccountAddresses[0]

if (accountAddress.company) {
return accountAddress.company.name
}

return billingAccount.company.name
}

function _addressLines (billingAccount) {
const { address } = billingAccount.billingAccountAddresses[0]

const addressParts = [
address.address1,
address.address2,
address.address3,
address.address4,
address.address5,
address.address6,
address.postcode,
address.country
]

return addressParts.filter((part) => {
return part
})
}

function _billingAccountDetails (billingAccount) {
return {
billingAccountId: billingAccount.id,
accountNumber: billingAccount.accountNumber,
accountName: _accountName(billingAccount),
contactName: _contactName(billingAccount),
addressLines: _addressLines(billingAccount)
}
}

function _chargeElementDetails (reviewChargeReference, chargePeriod) {
const { reviewChargeElements } = reviewChargeReference

const chargeElements = reviewChargeElements.map((reviewChargeElement, index) => {
const elementNumber = `Element ${index + 1} of ${reviewChargeElements.length}`
const dates = _prepareChargeElementDates(reviewChargeElement.chargeElement, chargePeriod)
const issues = reviewChargeElement.issues.length > 0 ? reviewChargeElement.issues.split(', ') : ['']
const billableReturns = `${reviewChargeElement.allocated} ML / ${reviewChargeElement.chargeElement.authorisedAnnualQuantity} ML`
const returnVolume = _prepareReturnVolume(reviewChargeElement)

return {
elementNumber,
elementStatus: reviewChargeElement.status,
elementDescription: reviewChargeElement.chargeElement.description,
dates,
issues,
billableReturns,
returnVolume

}
})

return chargeElements
}

function _chargeReferenceDetails (reviewChargeVersion, chargePeriod) {
const chargeReference = []

const { reviewChargeReferences } = reviewChargeVersion

for (const reviewChargeReference of reviewChargeReferences) {
Beckyrose200 marked this conversation as resolved.
Show resolved Hide resolved
chargeReference.push({
chargeCategory: `Charge reference ${reviewChargeReference.chargeReference.chargeCategory.reference}`,
chargeDescription: reviewChargeReference.chargeReference.chargeCategory.shortDescription,
totalBillableReturns: _totalBillableReturns(reviewChargeReference),
chargeElements: _chargeElementDetails(reviewChargeReference, chargePeriod)
})
}

return chargeReference
}

function _chargeElementCount (reviewChargeVersion) {
const { reviewChargeReferences } = reviewChargeVersion

const chargeElementCount = reviewChargeReferences.reduce((total, reviewChargeReference) => {
return total + reviewChargeReference.reviewChargeElements.length
}, 0)

return chargeElementCount
}

function _returnStatus (returnLog) {
if (returnLog.returnStatus === 'due') {
return 'overdue'
} else if (returnLog.underQuery) {
return 'query'
} else {
return returnLog.returnStatus
}
}

function _returnTotal (returnLog) {
const { returnStatus, allocated, quantity } = returnLog

if (returnStatus === 'void' || returnStatus === 'received' || returnStatus === 'due') {
return '/'
} else {
return `${allocated} ML / ${quantity} ML`
}
}

function _contactName (billingAccount) {
const contact = billingAccount.billingAccountAddresses[0].contact

if (contact) {
return contact.$name()
}

return null
}

function _financialYear (financialYearEnding) {
const startYear = financialYearEnding - 1
const endYear = financialYearEnding

return `${startYear} to ${endYear}`
}

function _matchedReturns (returnLogs) {
const matchedReturns = []

for (const returnLog of returnLogs) {
Beckyrose200 marked this conversation as resolved.
Show resolved Hide resolved
if (returnLog.reviewChargeElements.length > 0) {
matchedReturns.push(
{
returnId: returnLog.returnId,
reference: returnLog.returnReference,
dates: _prepareDate(returnLog.startDate, returnLog.endDate),
returnStatus: _returnStatus(returnLog),
description: returnLog.description,
purpose: returnLog.purposes[0].tertiary.description,
returnTotal: _returnTotal(returnLog),
issues: returnLog.issues.length > 0 ? returnLog.issues.split(', ') : ['']
}
)
}
}

return matchedReturns
}

function _prepareChargeData (licence, billRun) {
const chargeData = []

for (const reviewChargeVersion of licence[0].reviewChargeVersions) {
Beckyrose200 marked this conversation as resolved.
Show resolved Hide resolved
const chargePeriod = {
startDate: reviewChargeVersion.chargePeriodStartDate,
endDate: reviewChargeVersion.chargePeriodEndDate
}

chargeData.push({
financialYear: _financialYear(billRun.toFinancialYearEnding),
chargePeriodDate: _prepareDate(reviewChargeVersion.chargePeriodStartDate, reviewChargeVersion.chargePeriodEndDate),
Beckyrose200 marked this conversation as resolved.
Show resolved Hide resolved
licenceHolderName: licence[0].licenceHolder,
chargeElementCount: _chargeElementCount(reviewChargeVersion),
billingAccountDetails: _billingAccountDetails(reviewChargeVersion.billingAccountDetails),
chargeReferences: _chargeReferenceDetails(reviewChargeVersion, chargePeriod)
})
}

return chargeData
}

function _prepareChargeElementDates (chargeElement, chargePeriod) {
const {
abstractionPeriodStartDay,
abstractionPeriodStartMonth,
abstractionPeriodEndDay,
abstractionPeriodEndMonth
} = chargeElement

const abstractionPeriods = DetermineAbstractionPeriodService.go(
chargePeriod,
abstractionPeriodStartDay,
abstractionPeriodStartMonth,
abstractionPeriodEndDay,
abstractionPeriodEndMonth
)

const dates = []

// NOTE: There can be more than 1 abstraction period for an element, hence why we loop through them
abstractionPeriods.forEach((abstractionPeriod) => {
dates.push(_prepareDate(abstractionPeriod.startDate, abstractionPeriod.endDate))
})

return dates
}

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

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

function _prepareReturnVolume (reviewChargeElement) {
const { reviewReturns } = reviewChargeElement
const returnVolumes = []

if (reviewReturns) {
reviewReturns.forEach((reviewReturn) => {
returnVolumes.push(`${reviewReturn.quantity} ML (${reviewReturn.returnReference})`)
})
}

return returnVolumes
}

function _totalBillableReturns (reviewChargeReference) {
let totalBillableReturns = 0
let totalQuantity = 0

for (const reviewChargeElement of reviewChargeReference.reviewChargeElements) {
Beckyrose200 marked this conversation as resolved.
Show resolved Hide resolved
totalBillableReturns += reviewChargeElement.allocated
totalQuantity += reviewChargeElement.chargeElement.authorisedAnnualQuantity
}

return `${totalBillableReturns} ML / ${totalQuantity} ML`
}

function _unmatchedReturns (returnLogs) {
const unmatchedReturns = []

for (const returnLog of returnLogs) {
Beckyrose200 marked this conversation as resolved.
Show resolved Hide resolved
// If the reviewChargeElement length is less than 1 it means the return did not match to a charge element and
// therefore belongs in the unmatchedReturns section
if (returnLog.reviewChargeElements.length < 1) {
unmatchedReturns.push(
{
returnId: returnLog.returnId,
reference: returnLog.returnReference,
dates: _prepareDate(returnLog.startDate, returnLog.endDate),
returnStatus: _returnStatus(returnLog),
description: returnLog.description,
purpose: returnLog.purposes[0].tertiary.description,
returnTotal: `${returnLog.allocated} / ${returnLog.quantity} ML`,
issues: returnLog.issues.length > 0 ? returnLog.issues.split(', ') : ['']
}
)
}
}

return unmatchedReturns
}

module.exports = {
Expand Down
Loading
Loading