Last active
April 22, 2024 12:36
-
-
Save gutomarzagao/ce1b5fa5df496ab26228fabe457c33a3 to your computer and use it in GitHub Desktop.
Payment Analyzer
This file contains hidden or 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
| class Base { | |
| CONSECUTIVE_PAYMENTS = 3 | |
| ALLOWED_PAYMENTS_MEAN_DIFF_PERCENTEGE = 8 | |
| PAY_CYCLE = 31 | |
| constructor(loan) { | |
| this.loan = loan | |
| } | |
| paymentsData() { | |
| // Get payments from database | |
| return this.loan.payments | |
| } | |
| } | |
| export default Base |
This file contains hidden or 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
| import { differenceInDays } from 'date-fns' | |
| import Base from './Base.js' | |
| class ConsecutivePayments extends Base { | |
| constructor(loan) { | |
| super(loan) | |
| } | |
| consecutivePayments() { | |
| if (!this._consecutivePayments) { | |
| this._consecutivePayments = this.calculateConsecutivePayments(this.paymentsData()) | |
| } | |
| return this._consecutivePayments | |
| } | |
| averageDaysConsecutiveAllotmentPayments() { | |
| const allotmentPayments = this.paymentsData().filter(e => e.source == 'Allotment') | |
| if (!this._averageDaysConsecutiveAllotmentPayments) { | |
| this._averageDaysConsecutiveAllotmentPayments = | |
| this.calculateAverageDaysAllotmentPayments(allotmentPayments) | |
| } | |
| return this._averageDaysConsecutiveAllotmentPayments | |
| } | |
| consecutiveAllotmentPayments() { | |
| const allotmentPayments = this.paymentsData().filter(e => e.source == 'Allotment') | |
| if (!this._consecutiveAllotmentPayments) { | |
| this._consecutiveAllotmentPayments = this.calculateConsecutivePayments(allotmentPayments) | |
| } | |
| return this._consecutiveAllotmentPayments | |
| } | |
| allotmentPayments() { | |
| return this.paymentsData().filter(e => e.source == 'Allotment') | |
| } | |
| calculateAverageDaysAllotmentPayments(paymentsData) { | |
| if (paymentsData.length == 0) { | |
| return [] | |
| } | |
| let averageDays = 0 | |
| let differenceDays = 0 | |
| let lastPayment = null | |
| paymentsData.forEach(paymentData => { | |
| differenceDays = this.consecutivePaymentsDiff(paymentData, lastPayment) | |
| lastPayment = paymentData | |
| if (differenceDays) { | |
| averageDays += differenceDays | |
| } | |
| }) | |
| const paymentsDataCount = paymentsData.length | |
| if (paymentsDataCount < 2) { | |
| return 0 | |
| } else { | |
| return averageDays / (paymentsDataCount - 1) | |
| } | |
| } | |
| consecutivePaymentsDiff(payment1, payment2) { | |
| if (!payment1 || !payment2) { | |
| return false | |
| } | |
| const effectiveDate1 = payment1.effectiveDate | |
| const effectiveDate2 = payment2.effectiveDate | |
| const diff = differenceInDays(effectiveDate1, effectiveDate2) | |
| return Math.abs(diff) | |
| } | |
| calculateConsecutivePayments(paymentsData) { | |
| if (paymentsData.length == 0) { | |
| return [] | |
| } | |
| let consecutivePayments = [] | |
| paymentsData.forEach(paymentData => { | |
| if (!this.isConsecutivePayments(paymentData, consecutivePayments[consecutivePayments.length - 1])) { | |
| consecutivePayments = [] | |
| } | |
| consecutivePayments.push(paymentData) | |
| }) | |
| return consecutivePayments | |
| } | |
| isConsecutivePayments(payment1, payment2) { | |
| if (!payment1 || !payment2) { | |
| return false | |
| } | |
| const effectiveDate1 = payment1.effectiveDate | |
| const effectiveDate2 = payment2.effectiveDate | |
| const diff = differenceInDays(effectiveDate1, effectiveDate2) | |
| if (Math.abs(diff) <= this.PAY_CYCLE) { | |
| return true | |
| } | |
| return false | |
| } | |
| } | |
| export default ConsecutivePayments |
This file contains hidden or 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
| import { add } from "date-fns"; | |
| import ConsecutivePayments from './ConsecutivePayments.js' | |
| class PaymentAnalyzer extends ConsecutivePayments { | |
| constructor(loan) { | |
| super(loan) | |
| } | |
| canRefinance() { | |
| if (add(this.analyzeData().lastPaymentDate, { days: this.PAY_CYCLE}) < Date.now()) { | |
| return false | |
| } | |
| if (this.cantRefinanceByRuleAverageDays()) { | |
| return false | |
| } | |
| if (this.analyzeData().paymentsCount < this.CONSECUTIVE_PAYMENTS) { | |
| return false | |
| } | |
| if (this.analyzeData().paymentsMeanDiffPercentege > this.ALLOWED_PAYMENTS_MEAN_DIFF_PERCENTEGE) { | |
| return false | |
| } | |
| return true | |
| } | |
| cantRefinanceByRuleAverageDays() { | |
| if (this.analyzeData().paymentsCount === 0) { | |
| return true | |
| } | |
| if (this.analyzeData().averageDaysConsecutiveAllotmentPaymentsCount > this.PAY_CYCLE) { | |
| return true | |
| } | |
| return false | |
| } | |
| analyzeData() { | |
| const paymentsSum = this.allotmentPaymentsSum() | |
| const paymentsMean = paymentsSum / this.allotmentPayments().length | |
| const paymentsMeanDiff = this.loan.fixedPaymentAmount - paymentsMean | |
| const paymentsMeanDiffPercentege = (paymentsMeanDiff / this.loan.fixedPaymentAmount) * 100 | |
| const consecutiveAllotmentPayments = this.consecutiveAllotmentPayments() | |
| return { | |
| averageDaysConsecutiveAllotmentPaymentsCount: this.averageDaysConsecutiveAllotmentPayments(), | |
| paymentsCount: consecutiveAllotmentPayments.length, | |
| lastPaymentDate: consecutiveAllotmentPayments[consecutiveAllotmentPayments.length -1].effectiveDate, | |
| paymentsSum: paymentsSum, | |
| paymentsMean: paymentsMean, | |
| paymentsMeanDiff: paymentsMeanDiff, | |
| paymentsMeanDiffPercentege: paymentsMeanDiffPercentege | |
| } | |
| } | |
| allotmentPaymentsSum() { | |
| return this.allotmentPayments().reduce((acc, cur) => acc + cur.amount, 0) | |
| } | |
| consecutiveAllotmentPaymentsSum() { | |
| return this.consecutiveAllotmentPayments().reduce((acc, cur) => acc + cur.amount, 0) | |
| } | |
| } | |
| export default PaymentAnalyzer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment