support other interest compounding types (#24)

Co-authored-by: Chris Weiss <chrwei@users.noreply.github.com>
This commit is contained in:
Robert Dyer
2025-05-08 14:14:23 -04:00
committed by GitHub
parent 226c8cb5bd
commit e9922e30c1
2 changed files with 32 additions and 5 deletions
+5
View File
@@ -165,6 +165,11 @@ As an example, if your loan is at 4.5% interest and you want to insert an
interest transaction on the 28th of the month, set the account note to interest transaction on the 28th of the month, set the account note to
`interestRate:0.045 interestDay:28`. `interestRate:0.045 interestDay:28`.
By default, interest is calculated using the 30/360 method where interest is
computed monthly using 30/360 (or 1/12) of the interest rate. If you need to
compute interest using the ACTUAL/ACTUAL method, set `interest:actual` in the
note. If you need to compute interest daily, set `interest:daily`.
You can optionally change the payee used for the interest transactions by You can optionally change the payee used for the interest transactions by
setting `INTEREST_PAYEE_NAME` in the `.env` file. setting `INTEREST_PAYEE_NAME` in the `.env` file.
+27 -5
View File
@@ -2,6 +2,11 @@ const api = require('@actual-app/api');
const { closeBudget, ensurePayee, getAccountBalance, getAccountNote, getLastTransactionDate, getTagValue, openBudget, showPercent } = require('./utils'); const { closeBudget, ensurePayee, getAccountBalance, getAccountNote, getLastTransactionDate, getTagValue, openBudget, showPercent } = require('./utils');
require("dotenv").config(); require("dotenv").config();
function daysInYear(year) {
// Check if the year is a leap year
return ((year % 4 === 0 && year % 100 > 0) || year %400 == 0) ? 366 : 365;
}
(async () => { (async () => {
await openBudget(); await openBudget();
@@ -16,9 +21,12 @@ require("dotenv").config();
const note = await getAccountNote(account); const note = await getAccountNote(account);
if (note) { if (note) {
if (note.indexOf('interestRate:') > -1 && note.indexOf('interestDay:') > -1) { let interestRate = parseFloat(getTagValue(note, 'interestRate', 0.0));
let interestRate = parseFloat(getTagValue(note, 'interestRate')); const interestDay = parseInt(getTagValue(note, 'interestDay', 0));
const interestDay = parseInt(getTagValue(note, 'interestDay'));
if (interestRate && interestDay) {
const kind = getTagValue(note, 'interest', 'monthly');
const isDaily = kind == 'daily';
const interestTransactionDate = new Date(); const interestTransactionDate = new Date();
if (interestTransactionDate.getDate() < interestDay) { if (interestTransactionDate.getDate() < interestDay) {
@@ -35,8 +43,22 @@ require("dotenv").config();
if (!lastDate) continue; if (!lastDate) continue;
const daysPassed = Math.floor((interestTransactionDate - new Date(lastDate)) / 86400000); const daysPassed = Math.floor((interestTransactionDate - new Date(lastDate)) / 86400000);
let period = 12;
let numPeriods = 1
switch (kind) {
case 'daily':
period = daysInYear(interestTransactionDate.getFullYear());
numPeriods = daysPassed;
break;
case 'actual':
period = daysInYear(interestTransactionDate.getFullYear()) / daysPassed;
break;
default:
break;
}
const balance = await getAccountBalance(account, interestTransactionDate); const balance = await getAccountBalance(account, interestTransactionDate);
const compoundedInterest = Math.round(balance * (Math.pow(1 + interestRate / 12, 1) - 1)); const compoundedInterest = Math.round(balance * (Math.pow(1 + interestRate / period, numPeriods) - 1));
interestRate = showPercent(interestRate); interestRate = showPercent(interestRate);
@@ -52,7 +74,7 @@ require("dotenv").config();
payee: payeeId, payee: payeeId,
amount: compoundedInterest, amount: compoundedInterest,
cleared: true, cleared: true,
notes: `Interest for 1 month at ${interestRate}`, notes: `Interest for ${daysPassed} days, ${balance / 100.0} at ${interestRate} (${isDaily ? "daily" : "monthly"})`,
}]); }]);
} }
} }