Files
RetirementCalculator/src/util/calculations.js
T
2025-05-22 13:09:26 -07:00

174 lines
6.9 KiB
JavaScript

const ObjectId = require('mongodb').ObjectId;
async function calculatePlanProgress(plans, assets, userId) {
if (!plans || typeof plans.retirementAssets === 'undefined') {
console.error("Invalid plan document provided to calculatePlanProgress:", plans);
return 0;
}
if (!assets || typeof assets.find !== 'function') {
console.error("Invalid assetsCollection provided to calculatePlanProgress");
return 0;
}
try {
const userAssets = await assets.find({ userId: new ObjectId(userId) }).toArray();
const totalUserAssetValue = await calculateTotalAssetValue(userAssets);
let percentage = 0;
if (plans.retirementAssets > 0) {
percentage = (totalUserAssetValue / plans.retirementAssets) * 100;
}
return percentage;
} catch (err) {
console.error("Error in calculatePlanProgress:", err);
return 0;
}
}
async function updatePlanProgressInDB(planId, percentage, plans) {
if (!plans || typeof plans.updateOne !== 'function') {
console.error("Error with the plans collection");
return;
}
if (typeof percentage !== 'number' || isNaN(percentage)) {
console.error(`Error with the percentage: ${percentage}`);
return;
}
try {
await plans.updateOne({ _id: new ObjectId(planId) }, { $set: { progress: parseFloat(percentage.toFixed(2)) } });
} catch (err) {
console.error("Error in updatePlanProgressInDB:", err);
}
}
async function calculateTotalAssetValue(assets) {
if (!assets || typeof assets.find !== 'function') {
console.error("Error with the assets collection");
return 0;
}
try {
let totalAssetValue = 0;
const today = new Date();
for (const asset of assets) {
if (asset.icon === "Motorcycle" || asset.icon === "Car") {
if (asset.value < 1000) {
totalAssetValue += asset.value;
} else {
const assetYear = asset.year;
const age = today.getFullYear() - assetYear;
let depreciatedValue;
if (age < 1){
depreciatedValue = asset.value * 0.9;
}else{
depreciatedValue = asset.value * Math.pow(0.90, age);
}
if (depreciatedValue < 1000) {
totalAssetValue += 1000;
} else {
totalAssetValue += depreciatedValue;
}
}
} else {
totalAssetValue += asset.value;
}
}
return totalAssetValue;
} catch (err) {
console.error("Error in calculateTotalAssetValue:", err);
return 0;
}
}
async function calculateProgress(plan, assets, users, userId) {
if (!plan || typeof plan !== 'object') {
console.error("Error with the plan");
return;
}
if (!assets || typeof assets.find !== 'function') {
console.error("Error with the assets collection");
return;
}
if (!users || typeof users.findOne !== 'function') {
console.error("Error with the users collection");
return;
}
if (!userId) {
console.error("No user ID provided");
return;
}
try {
const userAssets = await assets.find({ userId: new ObjectId(userId) }).toArray();
const totalUserAssetValue = await calculateTotalAssetValue(userAssets);
const totalUserPlanValue = plan.retirementAssets;
const userDoc = await users.findOne({ _id: new ObjectId(userId) });
if (!userDoc || !userDoc.dob) {
console.error("[calculateProgress] User document or DOB not found for userId:", userId);
// Ensure a structured return even on error to avoid undefined.progress issues
return { monthlyInvestment: NaN, totalCostOfRetirement: NaN, monthsUntilRetirement: NaN, yearsRetired: NaN, yearsUntilRetirement: NaN, percentage: NaN };
}
const userDob = new Date(userDoc.dob);
if (isNaN(userDob.getTime())) {
console.error("[calculateProgress] userDob is an invalid date. Aborting calculation.");
return { monthlyInvestment: NaN, totalCostOfRetirement: NaN, monthsUntilRetirement: NaN, yearsRetired: NaN, yearsUntilRetirement: NaN, percentage: NaN };
}
const today = new Date();
const userUnalivedBy = new Date(userDob);
userUnalivedBy.setFullYear(userUnalivedBy.getFullYear() + 90);
const yearOfRetirement = userDob.getFullYear() + plan.retirementAge;
const monthsUntilRetirement = (yearOfRetirement - today.getFullYear()) * 12;
const yearsRetired = userUnalivedBy.getFullYear() - yearOfRetirement;
const totalCostOfRetirement = ((plan.retirementExpenses + plan.retirementLiabilities) * 12) * yearsRetired;
const monthlyInvestment = (totalUserPlanValue - totalUserAssetValue + totalCostOfRetirement) / monthsUntilRetirement;
const percentageCalculated = (totalUserAssetValue / (totalUserPlanValue + totalCostOfRetirement)) * 100;
if (monthsUntilRetirement <= 0) {
return { monthlyInvestment: 0, totalCostOfRetirement: totalCostOfRetirement, monthsUntilRetirement: 0, yearsRetired: yearsRetired, yearsUntilRetirement: 0, percentage: 0 };
}
const progress = {};
progress.monthlyInvestment = Math.round(monthlyInvestment);
progress.totalCostOfRetirement = totalCostOfRetirement;
progress.monthsUntilRetirement = monthsUntilRetirement;
progress.yearsRetired = yearsRetired;
progress.yearsUntilRetirement = (yearOfRetirement - today.getFullYear());
progress.percentage = percentageCalculated;
return progress;
} catch (err) {
console.error("Error in calculateProgress:", err);
// Ensure a structured return even on error to avoid undefined.progress issues
return { monthlyInvestment: NaN, totalCostOfRetirement: NaN, monthsUntilRetirement: NaN, yearsRetired: NaN, yearsUntilRetirement: NaN, percentage: NaN };
}
}
async function updateProgress(plans, assets, users, userId) {
const userPlansFromDB = await plans.find({ userId: new ObjectId(userId) }).toArray();
for (const plan of userPlansFromDB) {
const progress = await calculateProgress(plan, assets, users, userId);
await updatePlanProgressInDB(plan._id, progress.percentage, plans);
}
const updatedUserPlans = await plans.find({ userId: new ObjectId(userId) }).toArray();
return updatedUserPlans;
}
module.exports = { calculatePlanProgress, updatePlanProgressInDB, calculateTotalAssetValue, calculateProgress, updateProgress};