Skip to content
This repository has been archived by the owner on Feb 7, 2025. It is now read-only.

Commit

Permalink
PAY-2318 Aggregate, map and build statement constructor object (#22)
Browse files Browse the repository at this point in the history
* PAY-2318 Aggregate, map and build statement constructor object

* Added all statement component

* Implemented all PR feedback

* Changes IRO PR round-1

* added getStatement unit

* schedule tests added

* finalised getStatement unit

* added sendStatement tests

* more updates IRO PR

* funding code fix added

* utility tests added

* moving payment constants

* using trunc in tests

* dueDate formatted to DD/MM/YYYY

* Added schema to Organisation for DWH compactibility

* Remove all logs comment

* Fixed ConnectionAcquireTimeoutError

* Reduced splice of reversedInvoiceNumber for settlement and calculation to 7 from 8 IRO DWH data

* modified for insert into schedule table

* Added Total-aggregate as fundings item

* Modify organisation schema to correspond with statement-data structure

* Modify organisation schema to correspond with statement-data structure

Co-authored-by: Marc Templeton <marcte@kainos.com>
  • Loading branch information
AbidemiAdio and marctemp authored Sep 30, 2022
1 parent 959a4f9 commit 0a22f80
Show file tree
Hide file tree
Showing 77 changed files with 1,641 additions and 152 deletions.
8 changes: 8 additions & 0 deletions app/data/models/payment-request.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const { reverseEngineerInvoiceNumber } = require('../../utility')

module.exports = (sequelize, DataTypes) => {
const paymentRequest = sequelize.define('paymentRequest', {
paymentRequestId: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
Expand All @@ -12,6 +14,12 @@ module.exports = (sequelize, DataTypes) => {
marketingYear: DataTypes.INTEGER,
received: DataTypes.DATE,
referenceId: DataTypes.UUID,
reversedInvoiceNumber: {
type: DataTypes.VIRTUAL,
get () {
return reverseEngineerInvoiceNumber(this.invoiceNumber)
}
},
schedule: DataTypes.STRING,
sourceSystem: DataTypes.STRING,
status: DataTypes.STRING,
Expand Down
4 changes: 3 additions & 1 deletion app/inbound/return/get-payment-request-by-invoice-number.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const db = require('../../data')
const { COMPLETED } = require('../../constants/statuses')

const getPaymentRequestbyInvoiceNumber = async (invoiceNumber, transaction) => {
return db.paymentRequest.findOne({
transaction,
lock: true,
where: {
invoiceNumber
invoiceNumber,
status: COMPLETED
}
})
}
Expand Down
3 changes: 2 additions & 1 deletion app/inbound/return/save-settlement.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const getPaymentRequestbyInvoiceNumber = require('./get-payment-request-by-invoi
const saveSettlement = async (settlement, transaction) => {
const matchedPaymentRequest = await getPaymentRequestbyInvoiceNumber(settlement.invoiceNumber, transaction)
settlement.paymentRequestId = (matchedPaymentRequest ? matchedPaymentRequest?.paymentRequestId : null) ?? null
await db.settlement.create(settlement, { transaction })
const savedSettlement = await db.settlement.create(settlement, { transaction })
await db.schedule.create({ settlementId: savedSettlement.settlementId }, { transaction })
}

module.exports = saveSettlement
2 changes: 1 addition & 1 deletion app/inbound/save-invoice-number.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const db = require('../data')
const reverseEngineerInvoiceNumber = require('../processing/reverse-engineer-invoice-number')
const { reverseEngineerInvoiceNumber } = require('../utility')

const saveInvoiceNumber = async (invoiceNumber, transaction) => {
await db.invoiceNumber.findOrCreate({
Expand Down
7 changes: 5 additions & 2 deletions app/processing/calculation/calculation-schema.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const Joi = require('joi')

module.exports = Joi.object({
sbi: Joi.number().integer().required(),
calculationDate: Joi.date().required()
calculationId: Joi.number().integer().required(),
calculationDate: Joi.date().required(),
invoiceNumber: Joi.string().required(),
paymentRequestId: Joi.number().integer().required(),
sbi: Joi.number().integer().required()
}).required()
20 changes: 20 additions & 0 deletions app/processing/calculation/get-calculation-by-invoice-number.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const db = require('../../data')

const getCalculationByInvoiceNumber = async (invoiceNumber, transaction) => {
return db.calculation.findOne({
transaction,
attributes: [
'calculationId',
'calculationDate',
'invoiceNumber',
'paymentRequestId',
'sbi'
],
where: {
invoiceNumber
},
raw: true
})
}

module.exports = getCalculationByInvoiceNumber
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
const db = require('../../data')

const getCalculationByPaymentRequestId = async (paymentRequestId) => {
const getCalculationByPaymentRequestId = async (paymentRequestId, transaction) => {
return db.calculation.findOne({
transaction,
attributes: [
'sbi',
'calculationDate'
'calculationId',
'calculationDate',
'invoiceNumber',
'paymentRequestId',
'sbi'
],
where: {
paymentRequestId
Expand Down
13 changes: 10 additions & 3 deletions app/processing/calculation/get-calculation.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
const schema = require('./calculation-schema')

const getCalculationByPaymentRequestId = require('./get-calculation-by-payment-request-id')
const updateCalculationPaymentRequestId = require('./update-calculation-payment-request-id')

const getCalculation = async (paymentRequest, transaction) => {
const paymentRequestId = paymentRequest.paymentRequestId
const rawCalculation = await getCalculationByPaymentRequestId(paymentRequestId, transaction)
const calculation = rawCalculation || await updateCalculationPaymentRequestId(paymentRequest.invoiceNumber, paymentRequestId, transaction)

const getCalculation = async (paymentRequestId) => {
const calculation = await getCalculationByPaymentRequestId(paymentRequestId)
const result = schema.validate(calculation, {
abortEarly: false
})
Expand All @@ -13,8 +17,11 @@ const getCalculation = async (paymentRequestId) => {
}

return {
calculationId: calculation.calculationId,
sbi: calculation.sbi,
calculated: calculation.calculationDate
calculated: calculation.calculationDate,
invoiceNumber: calculation.invoiceNumber,
paymentRequestId: calculation.paymentRequestId
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const db = require('../../data')

const { COMPLETED } = require('../../constants/statuses')

const getCompletedPaymentRequestByReversedInvoiceNumber = async (reversedInvoiceNumber, transaction) => {
return db.paymentRequest.findOne({
transaction,
where: {
reversedInvoiceNumber,
status: COMPLETED
}
})
}

module.exports = getCompletedPaymentRequestByReversedInvoiceNumber
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const db = require('../../data')
const getCalculationByInvoiceNumber = require('./get-calculation-by-invoice-number')
const { reverseEngineerInvoiceNumber } = require('../../utility')

const updateCalculationPaymentRequestId = async (invoiceNumber, paymentRequestId, transaction) => {
const reversedInvoiceNumber = reverseEngineerInvoiceNumber(invoiceNumber)
const calculation = await getCalculationByInvoiceNumber(reversedInvoiceNumber, transaction)

if (calculation) {
await db.calculation.update({ paymentRequestId }, {
transaction,
lock: true,
where: {
invoiceNumber: reversedInvoiceNumber
}
})

calculation.paymentRequestId = paymentRequestId
}

return calculation
}

module.exports = updateCalculationPaymentRequestId
7 changes: 4 additions & 3 deletions app/processing/funding/fundings-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ module.exports = Joi.array().items(
otherwise: Joi.number().required()
}
),
fundingCode: Joi.number().required(),
level: Joi.string().allow('').allow(null).default(''),
name: Joi.string().required(),
rate: Joi.when(
'name', {
is: 'Moorland',
Expand All @@ -28,8 +31,6 @@ module.exports = Joi.array().items(
),
otherwise: Joi.number().required()
}
),
name: Joi.string().required(),
level: Joi.string().allow('').allow(null).default('')
)
})
).min(1).required()
4 changes: 3 additions & 1 deletion app/processing/funding/get-fundings-by-calculation-id.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
const db = require('../../data')

const getFundingsByCalculationId = async (calculationId) => {
const getFundingsByCalculationId = async (calculationId, transaction) => {
return db.funding.findAll({
transaction,
attributes: [
'calculationId',
'areaClaimed',
'fundingCode',
'rate'
],
include: [{
Expand Down
4 changes: 2 additions & 2 deletions app/processing/funding/get-fundings.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ const mapFundings = require('./map-fundings')

const getFundingsByCalculationId = require('./get-fundings-by-calculation-id')

const getFundings = async (calculationId) => {
const rawFundings = await getFundingsByCalculationId(calculationId)
const getFundings = async (calculationId, transaction) => {
const rawFundings = await getFundingsByCalculationId(calculationId, transaction)
const fundings = await mapFundings(rawFundings)

const result = schema.validate(fundings, {
Expand Down
3 changes: 3 additions & 0 deletions app/processing/funding/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const getFundings = require('./get-fundings')

module.exports = getFundings
5 changes: 3 additions & 2 deletions app/processing/funding/map-fundings.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const mapFundings = async (rawFundings) => {
const fundings = rawFundings.map(rawFunding => ({
area: rawFunding.areaClaimed,
rate: rawFunding.rate,
fundingCode: rawFunding.fundingCode,
level: getLevel(rawFunding.fundingOptions.name),
name: getName(rawFunding.fundingOptions.name),
level: getLevel(rawFunding.fundingOptions.name)
rate: rawFunding.rate
}))

return fundings
Expand Down
12 changes: 11 additions & 1 deletion app/processing/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
const { processingConfig } = require('../config')

const schedulePendingSettlements = require('./schedule')
const { getStatement, sendStatement } = require('./statement')

const start = async () => {
try {
await schedulePendingSettlements()
const pendingStatements = await schedulePendingSettlements()
if (!pendingStatements) {
throw new Error('No statements to be generated')
}

for (const pendingStatement of pendingStatements) {
const aggregatedStatement = await getStatement(pendingStatement.settlementId)
await sendStatement(pendingStatement.scheduleId, aggregatedStatement)
}
} catch (err) {
console.error(err)
} finally {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const db = require('../../data')

const getPositiveInvoiceLineByFundingCodeAndPaymentRequestId = async (fundingCode, paymentRequestId, transaction) => {
return db.invoiceLine.findOne({
transaction,
attributes: [
'value'
],
where: {
paymentRequestId,
fundingCode,
value: { [db.Sequelize.Op.gte]: 0 }
},
raw: true
})
}

module.exports = getPositiveInvoiceLineByFundingCodeAndPaymentRequestId
34 changes: 34 additions & 0 deletions app/processing/invoice-line/get-positive-invoice-line.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const schema = require('./invoice-line-schema')

const getPositiveInvoiceLineByFundingCodeAndPaymentRequestId = require('./get-positive-invoice-line-by-funding-code-and-payment-request-id')

const QUARTER = 0.25
const MIN_PAYMENT_VALUE = 0
const DEFAULT_REDUCTION_VALUE = 0

const getPositiveInvoiceLine = async (fundingCode, paymentRequestId) => {
const invoiceLine = await getPositiveInvoiceLineByFundingCodeAndPaymentRequestId(fundingCode, paymentRequestId)
const result = schema.validate(invoiceLine, {
abortEarly: false
})

if (result.error) {
throw new Error(`Payment request with paymentRequestId: ${paymentRequestId} does not have the required invoice-line data for funding code ${fundingCode} : ${result.error.message}`)
}

const annualValue = invoiceLine.value
const quarterlyValue = annualValue > MIN_PAYMENT_VALUE ? Math.trunc(annualValue * QUARTER) : MIN_PAYMENT_VALUE
const quarterlyReduction = DEFAULT_REDUCTION_VALUE
const quarterlyPayment = quarterlyValue - quarterlyReduction
const reductions = []

return {
annualValue,
quarterlyValue,
quarterlyReduction,
quarterlyPayment,
reductions
}
}

module.exports = getPositiveInvoiceLine
3 changes: 3 additions & 0 deletions app/processing/invoice-line/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const getPositiveInvoiceLine = require('./get-positive-invoice-line')

module.exports = getPositiveInvoiceLine
5 changes: 5 additions & 0 deletions app/processing/invoice-line/invoice-line-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const Joi = require('joi')

module.exports = Joi.object({
value: Joi.number().integer().min(0).required()
}).required()
25 changes: 25 additions & 0 deletions app/processing/organisation/get-organisation-by-sbi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const db = require('../../data')

const getOrganisationBySbi = async (sbi, transaction) => {
return db.organisation.findOne({
transaction,
attributes: [
'sbi',
'addressLine1',
'addressLine2',
'addressLine3',
'city',
'county',
'emailAddress',
'frn',
'name',
'postcode'
],
where: {
sbi
},
raw: true
})
}

module.exports = getOrganisationBySbi
29 changes: 29 additions & 0 deletions app/processing/organisation/get-organisation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const schema = require('./organisation-schema')
const getOrganisationBySbi = require('./get-organisation-by-sbi')

const getOrganisation = async (sbi, transaction) => {
const organisation = await getOrganisationBySbi(sbi, transaction)

const result = schema.validate(organisation, {
abortEarly: false
})

if (result.error) {
throw new Error(`Organisation with the sbi: ${sbi} does not have the required details data: ${result.error.message}`)
}

return {
line1: organisation.addressLine1,
line2: organisation.addressLine2,
line3: organisation.addressLine3,
line4: organisation.city,
line5: organisation.county,
postcode: organisation.postcode,
businessName: organisation.name,
email: organisation.emailAddress,
frn: organisation.frn,
sbi: organisation.sbi
}
}

module.exports = getOrganisation
3 changes: 3 additions & 0 deletions app/processing/organisation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const getOrganisation = require('./get-organisation')

module.exports = getOrganisation
14 changes: 14 additions & 0 deletions app/processing/organisation/organisation-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const Joi = require('joi')

module.exports = Joi.object({
sbi: Joi.number().integer().min(105000000).max(999999999).required(),
addressLine1: Joi.string().optional(),
addressLine2: Joi.string().optional(),
addressLine3: Joi.string().optional(),
city: Joi.string().optional(),
county: Joi.string().optional(),
emailAddress: Joi.string().email().required(),
frn: Joi.number().integer().min(1000000000).max(9999999999).required(),
name: Joi.string().required(),
postcode: Joi.string().required()
}).required()
Loading

0 comments on commit 0a22f80

Please sign in to comment.