Skip to content

Instantly share code, notes, and snippets.

@gutomarzagao
Last active April 22, 2024 12:36
Show Gist options
  • Save gutomarzagao/ce1b5fa5df496ab26228fabe457c33a3 to your computer and use it in GitHub Desktop.
Save gutomarzagao/ce1b5fa5df496ab26228fabe457c33a3 to your computer and use it in GitHub Desktop.
Payment Analyzer
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
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
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