moneyfunx 0.0.38 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.ts +2 -2
- package/build/lib/paymentTypes.d.ts +4 -7
- package/build/lib/payments.d.ts +4 -4
- package/build/lib/payments.js +20 -10
- package/build/lib/sorting.d.ts +2 -2
- package/package.json +1 -1
- package/src/index.ts +4 -4
- package/src/lib/paymentTypes.ts +4 -7
- package/src/lib/payments.ts +48 -26
- package/src/lib/sorting.ts +2 -2
package/build/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { PaymentTooLowError } from "./lib/errors";
|
|
2
2
|
export { calculateMinPayment, numPaymentsToZero, principalRemaining, interestPaid, } from "./lib/helperFunctions";
|
|
3
|
-
export { ILoan, Loan } from "./lib/loan";
|
|
3
|
+
export { type ILoan, Loan } from "./lib/loan";
|
|
4
4
|
export { determineExtraPayment, amortizePayments, payLoans, } from "./lib/payments";
|
|
5
|
-
export { AmortizationRecord, LoansPaymentSummary, PaymentSummary, } from "./lib/paymentTypes";
|
|
5
|
+
export { type AmortizationRecord, type LoansPaymentSummary, type PaymentSummary, } from "./lib/paymentTypes";
|
|
6
6
|
export { snowball, avalanche, sortLoans } from "./lib/sorting";
|
|
@@ -6,11 +6,8 @@ export interface AmortizationRecord {
|
|
|
6
6
|
}
|
|
7
7
|
export interface PaymentSummary {
|
|
8
8
|
lifetimeInterest: number;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export interface LoansPaymentSummary {
|
|
12
|
-
[id: string]: PaymentSummary;
|
|
13
|
-
}
|
|
14
|
-
export interface LoanPrincipals {
|
|
15
|
-
[id: string]: number;
|
|
9
|
+
lifetimePrincipal: number;
|
|
10
|
+
amortizationSchedule: AmortizationRecord[];
|
|
16
11
|
}
|
|
12
|
+
export type LoansPaymentSummary = Record<string, PaymentSummary>;
|
|
13
|
+
export type LoanPrincipals = Record<string, number>;
|
package/build/lib/payments.d.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* This file contains functions for computing detailed information on paying loans
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
import { ILoan, Loan } from "./loan";
|
|
7
|
-
import { AmortizationRecord, LoansPaymentSummary } from "./paymentTypes";
|
|
6
|
+
import type { ILoan, Loan } from "./loan";
|
|
7
|
+
import type { AmortizationRecord, LoansPaymentSummary } from "./paymentTypes";
|
|
8
8
|
/**
|
|
9
9
|
*
|
|
10
10
|
* Calculates the extra amount in a payment after all loans' minimum payments are met
|
|
@@ -14,7 +14,7 @@ import { AmortizationRecord, LoansPaymentSummary } from "./paymentTypes";
|
|
|
14
14
|
* @param {number} payment The amount to pay across all loans
|
|
15
15
|
* @returns {number} The extra amount of payment
|
|
16
16
|
*/
|
|
17
|
-
export declare function determineExtraPayment(loans:
|
|
17
|
+
export declare function determineExtraPayment(loans: ILoan[], payment: number): number;
|
|
18
18
|
/**
|
|
19
19
|
*
|
|
20
20
|
* Calculates the amortization schedule for a loan paid with a payment
|
|
@@ -25,7 +25,7 @@ export declare function determineExtraPayment(loans: Array<ILoan>, payment: numb
|
|
|
25
25
|
* @param {number} startPeriod An initial offset of periods to "fast-forward" the state of the loan to prior to calculation of each period
|
|
26
26
|
* @returns {Array<AmortizationRecord>} The amortization schdule for the number of payments of payment made to the loan from the provided start period
|
|
27
27
|
*/
|
|
28
|
-
export declare function amortizePayments(loan: Loan, principal: number, payment: number, numPayments: number, startPeriod?: number, carryover?: number):
|
|
28
|
+
export declare function amortizePayments(loan: Loan, principal: number, payment: number, numPayments: number, startPeriod?: number, carryover?: number): AmortizationRecord[];
|
|
29
29
|
/**
|
|
30
30
|
*
|
|
31
31
|
* Calculates a wealth of information about paying of a set of loans with a total payment amount
|
package/build/lib/payments.js
CHANGED
|
@@ -40,16 +40,18 @@ export function amortizePayments(loan, principal, payment, numPayments, startPer
|
|
|
40
40
|
numPayments = loan.numPaymentsToZero(payment);
|
|
41
41
|
}
|
|
42
42
|
let principalRemaining = principal;
|
|
43
|
-
|
|
43
|
+
const amortizationSchedule = [];
|
|
44
44
|
for (let period = 0; period < numPayments; period++) {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
const interestThisPeriod = loan.accrueInterest(principalRemaining);
|
|
46
|
+
const principalThisPeriod = Math.min((period === numPayments - 1
|
|
47
|
+
? payment + carryover
|
|
48
|
+
: payment) - interestThisPeriod, principalRemaining);
|
|
47
49
|
principalRemaining -= principalThisPeriod;
|
|
48
50
|
amortizationSchedule.push({
|
|
49
51
|
period: startPeriod + period + 1,
|
|
50
52
|
principal: principalThisPeriod,
|
|
51
53
|
interest: interestThisPeriod,
|
|
52
|
-
principalRemaining
|
|
54
|
+
principalRemaining,
|
|
53
55
|
});
|
|
54
56
|
}
|
|
55
57
|
return amortizationSchedule;
|
|
@@ -68,13 +70,18 @@ export function payLoans(loans, payment, reduceMinimum = false) {
|
|
|
68
70
|
let monthlyPayment = payment;
|
|
69
71
|
const paymentData = {};
|
|
70
72
|
const loanPrincipalsRemaining = {};
|
|
71
|
-
loans.
|
|
72
|
-
paymentData[loan.id] = {
|
|
73
|
+
loans.forEach((loan) => {
|
|
74
|
+
paymentData[loan.id] = {
|
|
75
|
+
lifetimeInterest: 0,
|
|
76
|
+
lifetimePrincipal: loan.principal,
|
|
77
|
+
amortizationSchedule: []
|
|
78
|
+
};
|
|
73
79
|
loanPrincipalsRemaining[loan.id] = loan.principal;
|
|
74
80
|
});
|
|
75
81
|
let periodsElapsed = 0;
|
|
76
82
|
let paidLoans = 0;
|
|
77
83
|
let totalLifetimeInterest = 0;
|
|
84
|
+
let totalLifetimePrincipal = 0;
|
|
78
85
|
let totalAmortizationSchedule = [];
|
|
79
86
|
while (paidLoans < loans.length) {
|
|
80
87
|
const firstLoan = loans.slice(paidLoans)[0];
|
|
@@ -83,7 +90,7 @@ export function payLoans(loans, payment, reduceMinimum = false) {
|
|
|
83
90
|
const firstLoanPrincipalRemaining = loanPrincipalsRemaining[firstLoan.id];
|
|
84
91
|
const periodsToPay = helpers.numPaymentsToZero(firstLoanPrincipalRemaining, firstLoanPayment, firstLoan.periodicRate);
|
|
85
92
|
const firstLoanPaidPeriods = amortizePayments(firstLoan, firstLoanPrincipalRemaining, firstLoanPayment, periodsToPay, periodsElapsed);
|
|
86
|
-
const firstLoanCarryover = firstLoanPayment - firstLoan.principalRemaining(periodsToPay - 1, firstLoanPayment, firstLoanPrincipalRemaining);
|
|
93
|
+
const firstLoanCarryover = firstLoanPayment - (firstLoan.principalRemaining(periodsToPay - 1, firstLoanPayment, firstLoanPrincipalRemaining) + firstLoan.accrueInterest(firstLoan.principalRemaining(periodsToPay - 1, firstLoanPayment, firstLoanPrincipalRemaining)));
|
|
87
94
|
paymentData[firstLoan.id].amortizationSchedule = [
|
|
88
95
|
...paymentData[firstLoan.id].amortizationSchedule,
|
|
89
96
|
...firstLoanPaidPeriods
|
|
@@ -104,7 +111,7 @@ export function payLoans(loans, payment, reduceMinimum = false) {
|
|
|
104
111
|
loanPrincipalsRemaining[loan.id] = paymentData[loan.id].amortizationSchedule[paymentData[loan.id].amortizationSchedule.length - 1].principalRemaining;
|
|
105
112
|
totalAmortizationSchedule = totalAmortizationSchedule.map((element) => {
|
|
106
113
|
const matchedInnerElement = paidPeriods.find((innerElement) => innerElement.period === element.period);
|
|
107
|
-
return matchedInnerElement
|
|
114
|
+
return (matchedInnerElement != null)
|
|
108
115
|
? {
|
|
109
116
|
period: element.period,
|
|
110
117
|
principal: element.principal + matchedInnerElement.principal,
|
|
@@ -121,12 +128,15 @@ export function payLoans(loans, payment, reduceMinimum = false) {
|
|
|
121
128
|
periodsElapsed += periodsToPay;
|
|
122
129
|
}
|
|
123
130
|
for (const loan of loans) {
|
|
124
|
-
const loanLifetimeInterest = paymentData[loan.id].amortizationSchedule.reduce((acc, curval) => acc + curval.interest, 0);
|
|
131
|
+
const loanLifetimeInterest = (paymentData[loan.id].amortizationSchedule.reduce((acc, curval) => acc + curval.interest, 0));
|
|
125
132
|
paymentData[loan.id].lifetimeInterest = loanLifetimeInterest;
|
|
133
|
+
paymentData[loan.id].lifetimePrincipal = loan.principal;
|
|
126
134
|
totalLifetimeInterest += loanLifetimeInterest;
|
|
135
|
+
totalLifetimePrincipal += loan.principal;
|
|
127
136
|
}
|
|
128
|
-
paymentData
|
|
137
|
+
paymentData.totals = {
|
|
129
138
|
lifetimeInterest: totalLifetimeInterest,
|
|
139
|
+
lifetimePrincipal: totalLifetimePrincipal,
|
|
130
140
|
amortizationSchedule: totalAmortizationSchedule
|
|
131
141
|
};
|
|
132
142
|
return paymentData;
|
package/build/lib/sorting.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* This file contains functions for sorting Arrays of Loans on certain attributes
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
import { ILoan } from "./loan";
|
|
6
|
+
import { type ILoan } from "./loan";
|
|
7
7
|
type avalanche = (loan1: ILoan, loan2: ILoan) => number;
|
|
8
8
|
type snowball = (loan1: ILoan, loan2: ILoan) => number;
|
|
9
9
|
type sortFunction = avalanche | snowball;
|
|
@@ -27,5 +27,5 @@ export declare function snowball(loan1: ILoan, loan2: ILoan): number;
|
|
|
27
27
|
* @param {function} sortFunc The algorithm to sort the loans with
|
|
28
28
|
* @returns The sorted array loans
|
|
29
29
|
*/
|
|
30
|
-
export declare function sortLoans(loans:
|
|
30
|
+
export declare function sortLoans(loans: ILoan[], sortFunction: sortFunction): ILoan[];
|
|
31
31
|
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moneyfunx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.40",
|
|
5
5
|
"description": "MoneyFunx is a small library of functions for financial computations, with a focus on personal finance",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"types": "build/index.d.ts",
|
package/src/index.ts
CHANGED
|
@@ -5,15 +5,15 @@ export {
|
|
|
5
5
|
principalRemaining,
|
|
6
6
|
interestPaid,
|
|
7
7
|
} from "./lib/helperFunctions";
|
|
8
|
-
export { ILoan, Loan } from "./lib/loan";
|
|
8
|
+
export { type ILoan, Loan } from "./lib/loan";
|
|
9
9
|
export {
|
|
10
10
|
determineExtraPayment,
|
|
11
11
|
amortizePayments,
|
|
12
12
|
payLoans,
|
|
13
13
|
} from "./lib/payments";
|
|
14
14
|
export {
|
|
15
|
-
AmortizationRecord,
|
|
16
|
-
LoansPaymentSummary,
|
|
17
|
-
PaymentSummary,
|
|
15
|
+
type AmortizationRecord,
|
|
16
|
+
type LoansPaymentSummary,
|
|
17
|
+
type PaymentSummary,
|
|
18
18
|
} from "./lib/paymentTypes";
|
|
19
19
|
export { snowball, avalanche, sortLoans } from "./lib/sorting";
|
package/src/lib/paymentTypes.ts
CHANGED
|
@@ -7,13 +7,10 @@ export interface AmortizationRecord {
|
|
|
7
7
|
|
|
8
8
|
export interface PaymentSummary {
|
|
9
9
|
lifetimeInterest: number;
|
|
10
|
-
|
|
10
|
+
lifetimePrincipal: number;
|
|
11
|
+
amortizationSchedule: AmortizationRecord[];
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
export
|
|
14
|
-
[id: string]: PaymentSummary;
|
|
15
|
-
}
|
|
14
|
+
export type LoansPaymentSummary = Record<string, PaymentSummary>;
|
|
16
15
|
|
|
17
|
-
export
|
|
18
|
-
[id: string]: number;
|
|
19
|
-
}
|
|
16
|
+
export type LoanPrincipals = Record<string, number>;
|
package/src/lib/payments.ts
CHANGED
|
@@ -6,12 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
import * as errors from "./errors";
|
|
8
8
|
import * as helpers from "./helperFunctions";
|
|
9
|
-
import { ILoan, Loan } from "./loan";
|
|
10
|
-
import {
|
|
9
|
+
import type { ILoan, Loan } from "./loan";
|
|
10
|
+
import type {
|
|
11
11
|
AmortizationRecord,
|
|
12
12
|
LoanPrincipals,
|
|
13
13
|
LoansPaymentSummary,
|
|
14
|
-
PaymentSummary,
|
|
15
14
|
} from "./paymentTypes";
|
|
16
15
|
|
|
17
16
|
/**
|
|
@@ -24,7 +23,7 @@ import {
|
|
|
24
23
|
* @returns {number} The extra amount of payment
|
|
25
24
|
*/
|
|
26
25
|
export function determineExtraPayment(
|
|
27
|
-
loans:
|
|
26
|
+
loans: ILoan[],
|
|
28
27
|
payment: number
|
|
29
28
|
): number {
|
|
30
29
|
const totalMinPayment = loans.reduce(
|
|
@@ -56,7 +55,7 @@ export function amortizePayments(
|
|
|
56
55
|
numPayments: number,
|
|
57
56
|
startPeriod: number = 0,
|
|
58
57
|
carryover: number = 0
|
|
59
|
-
):
|
|
58
|
+
): AmortizationRecord[] {
|
|
60
59
|
if (payment === null) {
|
|
61
60
|
payment = loan.minPayment;
|
|
62
61
|
}
|
|
@@ -68,11 +67,13 @@ export function amortizePayments(
|
|
|
68
67
|
|
|
69
68
|
let principalRemaining = principal;
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
const amortizationSchedule: AmortizationRecord[] = [];
|
|
72
71
|
for (let period = 0; period < numPayments; period++) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
(period === numPayments - 1
|
|
72
|
+
const interestThisPeriod = loan.accrueInterest(principalRemaining);
|
|
73
|
+
const principalThisPeriod = Math.min(
|
|
74
|
+
(period === numPayments - 1
|
|
75
|
+
? payment + carryover
|
|
76
|
+
: payment) - interestThisPeriod,
|
|
76
77
|
principalRemaining
|
|
77
78
|
);
|
|
78
79
|
principalRemaining -= principalThisPeriod;
|
|
@@ -80,7 +81,7 @@ export function amortizePayments(
|
|
|
80
81
|
period: startPeriod + period + 1,
|
|
81
82
|
principal: principalThisPeriod,
|
|
82
83
|
interest: interestThisPeriod,
|
|
83
|
-
principalRemaining
|
|
84
|
+
principalRemaining,
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
87
|
return amortizationSchedule;
|
|
@@ -104,14 +105,19 @@ export function payLoans(
|
|
|
104
105
|
let monthlyPayment = payment;
|
|
105
106
|
const paymentData: LoansPaymentSummary = {};
|
|
106
107
|
const loanPrincipalsRemaining: LoanPrincipals = {};
|
|
107
|
-
loans.
|
|
108
|
-
paymentData[loan.id] = {
|
|
108
|
+
loans.forEach((loan) => {
|
|
109
|
+
paymentData[loan.id] = {
|
|
110
|
+
lifetimeInterest: 0,
|
|
111
|
+
lifetimePrincipal: loan.principal,
|
|
112
|
+
amortizationSchedule: []
|
|
113
|
+
};
|
|
109
114
|
loanPrincipalsRemaining[loan.id] = loan.principal;
|
|
110
115
|
});
|
|
111
116
|
|
|
112
117
|
let periodsElapsed = 0;
|
|
113
118
|
let paidLoans = 0;
|
|
114
119
|
let totalLifetimeInterest = 0;
|
|
120
|
+
let totalLifetimePrincipal = 0;
|
|
115
121
|
let totalAmortizationSchedule: AmortizationRecord[] = [];
|
|
116
122
|
|
|
117
123
|
while (paidLoans < loans.length) {
|
|
@@ -132,10 +138,18 @@ export function payLoans(
|
|
|
132
138
|
periodsToPay,
|
|
133
139
|
periodsElapsed
|
|
134
140
|
);
|
|
135
|
-
const firstLoanCarryover = firstLoanPayment -
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
const firstLoanCarryover = firstLoanPayment - (
|
|
142
|
+
firstLoan.principalRemaining(
|
|
143
|
+
periodsToPay - 1,
|
|
144
|
+
firstLoanPayment,
|
|
145
|
+
firstLoanPrincipalRemaining
|
|
146
|
+
) + firstLoan.accrueInterest(
|
|
147
|
+
firstLoan.principalRemaining(
|
|
148
|
+
periodsToPay - 1,
|
|
149
|
+
firstLoanPayment,
|
|
150
|
+
firstLoanPrincipalRemaining
|
|
151
|
+
)
|
|
152
|
+
)
|
|
139
153
|
);
|
|
140
154
|
paymentData[firstLoan.id].amortizationSchedule = [
|
|
141
155
|
...paymentData[firstLoan.id].amortizationSchedule,
|
|
@@ -172,15 +186,15 @@ export function payLoans(
|
|
|
172
186
|
const matchedInnerElement = paidPeriods.find(
|
|
173
187
|
(innerElement) => innerElement.period === element.period
|
|
174
188
|
);
|
|
175
|
-
return matchedInnerElement
|
|
189
|
+
return (matchedInnerElement != null)
|
|
176
190
|
? {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
191
|
+
period: element.period,
|
|
192
|
+
principal: element.principal + matchedInnerElement.principal,
|
|
193
|
+
interest: element.interest + matchedInnerElement.interest,
|
|
194
|
+
principalRemaining:
|
|
195
|
+
element.principalRemaining +
|
|
196
|
+
matchedInnerElement.principalRemaining
|
|
197
|
+
}
|
|
184
198
|
: element;
|
|
185
199
|
});
|
|
186
200
|
});
|
|
@@ -192,13 +206,21 @@ export function payLoans(
|
|
|
192
206
|
}
|
|
193
207
|
|
|
194
208
|
for (const loan of loans) {
|
|
195
|
-
const loanLifetimeInterest =
|
|
209
|
+
const loanLifetimeInterest = (
|
|
210
|
+
paymentData[loan.id].amortizationSchedule.reduce(
|
|
211
|
+
(acc, curval) => acc + curval.interest,
|
|
212
|
+
0
|
|
213
|
+
)
|
|
214
|
+
);
|
|
196
215
|
paymentData[loan.id].lifetimeInterest = loanLifetimeInterest;
|
|
216
|
+
paymentData[loan.id].lifetimePrincipal = loan.principal;
|
|
197
217
|
totalLifetimeInterest += loanLifetimeInterest;
|
|
218
|
+
totalLifetimePrincipal += loan.principal;
|
|
198
219
|
}
|
|
199
220
|
|
|
200
|
-
paymentData
|
|
221
|
+
paymentData.totals = {
|
|
201
222
|
lifetimeInterest: totalLifetimeInterest,
|
|
223
|
+
lifetimePrincipal: totalLifetimePrincipal,
|
|
202
224
|
amortizationSchedule: totalAmortizationSchedule
|
|
203
225
|
};
|
|
204
226
|
|
package/src/lib/sorting.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { ILoan } from "./loan";
|
|
7
|
+
import { type ILoan } from "./loan";
|
|
8
8
|
|
|
9
9
|
type avalanche = (loan1: ILoan, loan2: ILoan) => number;
|
|
10
10
|
type snowball = (loan1: ILoan, loan2: ILoan) => number;
|
|
@@ -36,6 +36,6 @@ export function snowball(loan1: ILoan, loan2: ILoan) {
|
|
|
36
36
|
* @param {function} sortFunc The algorithm to sort the loans with
|
|
37
37
|
* @returns The sorted array loans
|
|
38
38
|
*/
|
|
39
|
-
export function sortLoans(loans:
|
|
39
|
+
export function sortLoans(loans: ILoan[], sortFunction: sortFunction) {
|
|
40
40
|
return loans.sort(sortFunction);
|
|
41
41
|
}
|