diff --git a/app/controllers/check/check.controller.js b/app/controllers/check/check.controller.js index 770f9dd948..0e2f4782fa 100644 --- a/app/controllers/check/check.controller.js +++ b/app/controllers/check/check.controller.js @@ -5,18 +5,12 @@ * @module CheckController */ -const Boom = require('@hapi/boom') - const CheckTwoPartService = require('../../services/check/two-part.service.js') async function twoPart (request, h) { - try { - const result = await CheckTwoPartService.go(request.params.naldRegionId, request.params.format) + const result = await CheckTwoPartService.go(request.params.naldRegionId, request.params.format) - return h.response(result).code(200) - } catch (error) { - return Boom.badImplementation(error.message) - } + return h.response(result).code(200) } module.exports = { diff --git a/app/services/check/friendly-response.service.js b/app/services/check/friendly-response.service.js new file mode 100644 index 0000000000..faecc88a20 --- /dev/null +++ b/app/services/check/friendly-response.service.js @@ -0,0 +1,246 @@ +'use strict' + +/** + * Used to generate a 'friendly' response from TwoPartService that better matches the UI + * @module FriendlyResponseService + */ + +const { formatAbstractionPeriod, formatLongDate } = require('../../presenters/base.presenter.js') + +function go (billingPeriod, matchedChargeVersions) { + const response = { + billingPeriod: { + startDate: formatLongDate(billingPeriod.startDate), + endDate: formatLongDate(billingPeriod.endDate) + }, + licences: [] + } + + _formatFriendlyLicences(response.licences, matchedChargeVersions) + + return response +} + +function _formatFriendlyLicences (licences, matchedChargeVersions) { + matchedChargeVersions.forEach((matchedChargeVersion) => { + const { licenceId, licenceRef, chargeVersions } = matchedChargeVersion + + const friendlyLicence = { + id: licenceId, + licenceRef, + chargeInformations: [] + } + + _formatFriendlyChargeInformation(friendlyLicence.chargeInformations, chargeVersions) + + licences.push(friendlyLicence) + }) +} + +function _formatFriendlyChargeInformation (chargeInformations, chargeVersions) { + chargeVersions.forEach((chargeVersion) => { + const { chargeVersionId, status, startDate, endDate, chargeElements } = chargeVersion + const friendlyChargeInformation = { + id: chargeVersionId, + status, + startDate, + endDate, + chargeReferences: [] + } + + _formatFriendlyChargeReferences(friendlyChargeInformation.chargeReferences, chargeElements) + + chargeInformations.push(friendlyChargeInformation) + }) +} + +function _formatFriendlyChargeReferences (chargeReferences, chargeElements) { + chargeElements.forEach((chargeElement) => { + const { + additionalCharges, + adjustments, + billingChargeCategory, + chargeElementId, + chargePurposes, + description, + eiucRegion, + isRestrictedSource, + loss, + source, + volume, + waterModel + } = chargeElement + + const formattedAdditionalCharges = _formatAdditionalCharges(additionalCharges) + const formattedAdjustments = _formatAdjustments(adjustments) + + const friendlyChargeReference = { + id: chargeElementId, + chargeReference: billingChargeCategory.reference, + chargeDescription: billingChargeCategory.shortDescription, + description, + source, + loss, + volume, + waterAvailability: _formatWaterAvailability(isRestrictedSource), + waterModel, + additionalChargesApply: (Object.keys(formattedAdditionalCharges).length > 0), + adjustmentsApply: (Object.keys(formattedAdjustments).length > 0), + eiucRegion, + additionalCharges: formattedAdditionalCharges, + adjustments: formattedAdjustments, + chargeElements: [] + } + + _formatFriendlyChargeElements(friendlyChargeReference.chargeElements, chargePurposes) + + chargeReferences.push(friendlyChargeReference) + }) +} + +function _formatFriendlyChargeElements (chargeElements, chargePurposes) { + chargePurposes.forEach((chargePurpose) => { + const { + authorisedAnnualQuantity, + chargePurposeId, + description, + isSection127AgreementEnabled, + loss, + purposesUse, + returnStatus, + timeLimitedStartDate, + timeLimitedEndDate, + abstractionPeriodEndDay: endDay, + abstractionPeriodEndMonth: endMonth, + abstractionPeriodStartDay: startDay, + abstractionPeriodStartMonth: startMonth + } = chargePurpose + const friendlyChargeElement = { + id: chargePurposeId, + description, + abstractionPeriod: formatAbstractionPeriod(startDay, startMonth, endDay, endMonth), + annualQuantities: authorisedAnnualQuantity, + timeLimit: _formatTimeLimit(timeLimitedStartDate, timeLimitedEndDate), + loss + } + + if (isSection127AgreementEnabled) { + friendlyChargeElement.twoPartTariffAgreementsApply = 'Yes, two-part tariff agreements should apply to this element' + } + + friendlyChargeElement.legacyId = purposesUse.legacyId + friendlyChargeElement.returnStatuses = returnStatus + friendlyChargeElement.returns = [] + + _formatFriendlyReturns(friendlyChargeElement.returns, chargePurpose.returns) + + chargeElements.push(friendlyChargeElement) + }) +} + +function _formatFriendlyReturns (returns, matchedReturns) { + matchedReturns.forEach((matchedReturn) => { + const { returnId, endDate, metadata, startDate, status } = matchedReturn + + const { periodEndDay, periodEndMonth, periodStartDay, periodStartMonth } = metadata.nald + + const friendlyReturn = { + id: returnId, + siteDescription: _titleCaseAllWords(metadata.description), + purpose: _titleCaseAllWords(metadata.purposes[0].alias), + returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, + abstractionPeriod: formatAbstractionPeriod(periodStartDay, periodStartMonth, periodEndDay, periodEndMonth), + twoPartTariff: metadata.isTwoPartTariff, + status, + code: metadata.purposes[0].tertiary.code + } + + returns.push(friendlyReturn) + }) +} + +function _formatAdditionalCharges (additionalCharges) { + const friendlyAdditionalCharges = {} + + if (!additionalCharges) { + return friendlyAdditionalCharges + } + + if (additionalCharges.supportedSource) { + friendlyAdditionalCharges.supportedSource = true + friendlyAdditionalCharges.supportedSourceName = additionalCharges.supportedSource.name + } else { + friendlyAdditionalCharges.supportedSource = false + } + + friendlyAdditionalCharges.supplyPublicWater = !!additionalCharges.isSupplyPublicWater + + return friendlyAdditionalCharges +} + +function _formatAdjustments (adjustments) { + const friendlyAdjustments = {} + + if (!adjustments) { + return friendlyAdjustments + } + + if (adjustments.aggregate) { + friendlyAdjustments.aggregateFactor = Number(adjustments.aggregate) + } + + if (adjustments.charge) { + friendlyAdjustments.adjustmentFactor = Number(adjustments.charge) + } + + if (adjustments.winter) { + friendlyAdjustments.winter = !!adjustments.winter + } + + if (adjustments.s127) { + friendlyAdjustments.twoPartTariffAgreement = !!adjustments.s127 + } + + if (adjustments.s126) { + friendlyAdjustments.abatementAgreement = Number(adjustments.s126) + } + + if (adjustments.s130) { + friendlyAdjustments.canalAndRiverTrustAgreement = !!adjustments.s130 + } + + return friendlyAdjustments +} + +function _titleCaseAllWords (stringToBeTitleCased) { + const lowercaseWords = stringToBeTitleCased.toLowerCase().split(' ') + + const titleCaseWords = lowercaseWords.reduce((words, lowercaseWord) => { + const titleCasedWord = `${lowercaseWord[0].toUpperCase()}${lowercaseWord.slice(1)}` + words.push(titleCasedWord) + + return words + }, []) + + return titleCaseWords.join(' ') +} + +function _formatTimeLimit (startDate, endDate) { + if (!startDate) { + return 'No' + } + + return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` +} + +function _formatWaterAvailability (isRestrictedSource) { + if (isRestrictedSource) { + return 'Restricted availablity or no availability' + } + + return 'Available' +} + +module.exports = { + go +} diff --git a/app/services/check/two-part.service.js b/app/services/check/two-part.service.js index 7493b35523..5ac41fb993 100644 --- a/app/services/check/two-part.service.js +++ b/app/services/check/two-part.service.js @@ -10,6 +10,7 @@ const { ref } = require('objection') const ChargeElementModel = require('../../models/water/charge-element.model.js') const ChargeVersionModel = require('../../models/water/charge-version.model.js') const ChargeVersionWorkflow = require('../../models/water/charge-version-workflow.model.js') +const FriendlyResponseService = require('./friendly-response.service.js') const DetermineBillingPeriodsService = require('../billing/determine-billing-periods.service.js') const ReturnModel = require('../../models/returns/return.model.js') @@ -32,7 +33,7 @@ async function go (naldRegionId, format = 'friendly') { switch (format) { case 'friendly': - return _friendlyResponse(matchedChargeVersions) + return FriendlyResponseService.go(billingPeriod, matchedChargeVersions) case 'raw': return matchedChargeVersions default: @@ -139,10 +140,6 @@ function _matchChargeVersions (chargeVersions) { }) } -function _friendlyResponse (_matchedChargeVersions) { - return { hello: 'world' } -} - function _calculateAndLogTime (startTime) { const endTime = process.hrtime.bigint() const timeTakenNs = endTime - startTime