Fixed simulation when salary = 0, stale college profile/grad date existed
This commit is contained in:
parent
0635b60792
commit
81a5592e23
@ -126,6 +126,8 @@ const {
|
|||||||
|
|
||||||
// College ----------------------------------------------------
|
// College ----------------------------------------------------
|
||||||
inCollege = false,
|
inCollege = false,
|
||||||
|
collegeEnrollmentStatus = 'none',
|
||||||
|
|
||||||
programType,
|
programType,
|
||||||
hoursCompleted: _hoursCompleted = 0,
|
hoursCompleted: _hoursCompleted = 0,
|
||||||
creditHoursPerYear: _creditHoursPerYear,
|
creditHoursPerYear: _creditHoursPerYear,
|
||||||
@ -172,6 +174,9 @@ const extraPayment = num(_extraPayment);
|
|||||||
const studentLoanAmount = num(_studentLoanAmount);
|
const studentLoanAmount = num(_studentLoanAmount);
|
||||||
const interestRate = num(_interestRate);
|
const interestRate = num(_interestRate);
|
||||||
const loanTerm = num(_loanTerm);
|
const loanTerm = num(_loanTerm);
|
||||||
|
const isProgrammeActive =
|
||||||
|
['enrolled', 'graduated'].includes(collegeEnrollmentStatus);
|
||||||
|
|
||||||
|
|
||||||
const hoursCompleted = num(_hoursCompleted);
|
const hoursCompleted = num(_hoursCompleted);
|
||||||
const creditHoursPerYear = num(_creditHoursPerYear);
|
const creditHoursPerYear = num(_creditHoursPerYear);
|
||||||
@ -360,6 +365,11 @@ function simulateDrawdown(opts){
|
|||||||
for (let monthIndex = 0; monthIndex < maxMonths; monthIndex++) {
|
for (let monthIndex = 0; monthIndex < maxMonths; monthIndex++) {
|
||||||
const currentSimDate = scenarioStartClamped.clone().add(monthIndex, 'months');
|
const currentSimDate = scenarioStartClamped.clone().add(monthIndex, 'months');
|
||||||
|
|
||||||
|
const hasGraduated =
|
||||||
|
isProgrammeActive &&
|
||||||
|
gradDate &&
|
||||||
|
currentSimDate.isSameOrAfter(moment(gradDate).startOf('month'));
|
||||||
|
|
||||||
if (!reachedRetirement && currentSimDate.isSameOrAfter(retirementStartISO)) {
|
if (!reachedRetirement && currentSimDate.isSameOrAfter(retirementStartISO)) {
|
||||||
reachedRetirement = true;
|
reachedRetirement = true;
|
||||||
firstRetirementBalance = currentRetirementSavings; // capture once
|
firstRetirementBalance = currentRetirementSavings; // capture once
|
||||||
@ -410,9 +420,19 @@ for (let monthIndex = 0; monthIndex < maxMonths; monthIndex++) {
|
|||||||
currentRetirementSavings -= withdrawal;
|
currentRetirementSavings -= withdrawal;
|
||||||
baseMonthlyIncome += withdrawal;
|
baseMonthlyIncome += withdrawal;
|
||||||
} else if (!stillInCollege) {
|
} else if (!stillInCollege) {
|
||||||
baseMonthlyIncome = (expectedSalary || currentSalary) / 12;
|
// Use expectedSalary **only** once the user has graduated
|
||||||
} else {
|
const monthlyFromJob = (
|
||||||
baseMonthlyIncome = (currentSalary / 12) + (additionalIncome / 12);
|
hasGraduated && expectedSalary > 0
|
||||||
|
? expectedSalary // kicks in the month *after* gradDate
|
||||||
|
: currentSalary
|
||||||
|
) / 12;
|
||||||
|
|
||||||
|
baseMonthlyIncome =
|
||||||
|
monthlyFromJob + (additionalIncome / 12);
|
||||||
|
|
||||||
|
} else { // stillInCollege branch
|
||||||
|
baseMonthlyIncome =
|
||||||
|
(currentSalary / 12) + (additionalIncome / 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
@ -512,9 +532,13 @@ baseMonthlyIncome += salaryAdjustThisMonth; // adjust gross BEFORE tax
|
|||||||
|
|
||||||
let leftover = netMonthlyIncome - totalMonthlyExpenses;
|
let leftover = netMonthlyIncome - totalMonthlyExpenses;
|
||||||
|
|
||||||
|
const canSaveThisMonth = leftover > 0;
|
||||||
|
|
||||||
// baseline contributions
|
// baseline contributions
|
||||||
const monthlyRetContrib = isRetiredThisMonth ? 0 : monthlyRetirementContribution;
|
const monthlyRetContrib =
|
||||||
const monthlyEmergContrib = isRetiredThisMonth ? 0 : monthlyEmergencyContribution;
|
canSaveThisMonth && !isRetiredThisMonth ? monthlyRetirementContribution : 0;
|
||||||
|
const monthlyEmergContrib =
|
||||||
|
canSaveThisMonth && !isRetiredThisMonth ? monthlyEmergencyContribution : 0;
|
||||||
const baselineContributions = monthlyRetContrib + monthlyEmergContrib;
|
const baselineContributions = monthlyRetContrib + monthlyEmergContrib;
|
||||||
let effectiveRetirementContribution = 0;
|
let effectiveRetirementContribution = 0;
|
||||||
let effectiveEmergencyContribution = 0;
|
let effectiveEmergencyContribution = 0;
|
||||||
@ -536,7 +560,7 @@ baseMonthlyIncome += salaryAdjustThisMonth; // adjust gross BEFORE tax
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Surplus => leftover
|
// Surplus => leftover
|
||||||
if (leftover > 0) {
|
if (canSaveThisMonth && leftover > 0) {
|
||||||
const totalPct = surplusEmergencyAllocation + surplusRetirementAllocation;
|
const totalPct = surplusEmergencyAllocation + surplusRetirementAllocation;
|
||||||
const emergPortion = leftover * (surplusEmergencyAllocation / totalPct);
|
const emergPortion = leftover * (surplusEmergencyAllocation / totalPct);
|
||||||
const retPortion = leftover * (surplusRetirementAllocation / totalPct);
|
const retPortion = leftover * (surplusRetirementAllocation / totalPct);
|
||||||
@ -546,7 +570,7 @@ baseMonthlyIncome += salaryAdjustThisMonth; // adjust gross BEFORE tax
|
|||||||
}
|
}
|
||||||
|
|
||||||
const monthlyReturnRate = getMonthlyInterestRate();
|
const monthlyReturnRate = getMonthlyInterestRate();
|
||||||
if (monthlyReturnRate !== 0) {
|
if (monthlyReturnRate !== 0 && leftover > 0) {
|
||||||
currentRetirementSavings *= (1 + monthlyReturnRate);
|
currentRetirementSavings *= (1 + monthlyReturnRate);
|
||||||
}
|
}
|
||||||
const netSavings = netMonthlyIncome - actualExpensesPaid;
|
const netSavings = netMonthlyIncome - actualExpensesPaid;
|
||||||
|
Loading…
Reference in New Issue
Block a user