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 ----------------------------------------------------
|
||||
inCollege = false,
|
||||
collegeEnrollmentStatus = 'none',
|
||||
|
||||
programType,
|
||||
hoursCompleted: _hoursCompleted = 0,
|
||||
creditHoursPerYear: _creditHoursPerYear,
|
||||
@ -172,6 +174,9 @@ const extraPayment = num(_extraPayment);
|
||||
const studentLoanAmount = num(_studentLoanAmount);
|
||||
const interestRate = num(_interestRate);
|
||||
const loanTerm = num(_loanTerm);
|
||||
const isProgrammeActive =
|
||||
['enrolled', 'graduated'].includes(collegeEnrollmentStatus);
|
||||
|
||||
|
||||
const hoursCompleted = num(_hoursCompleted);
|
||||
const creditHoursPerYear = num(_creditHoursPerYear);
|
||||
@ -360,6 +365,11 @@ function simulateDrawdown(opts){
|
||||
for (let monthIndex = 0; monthIndex < maxMonths; monthIndex++) {
|
||||
const currentSimDate = scenarioStartClamped.clone().add(monthIndex, 'months');
|
||||
|
||||
const hasGraduated =
|
||||
isProgrammeActive &&
|
||||
gradDate &&
|
||||
currentSimDate.isSameOrAfter(moment(gradDate).startOf('month'));
|
||||
|
||||
if (!reachedRetirement && currentSimDate.isSameOrAfter(retirementStartISO)) {
|
||||
reachedRetirement = true;
|
||||
firstRetirementBalance = currentRetirementSavings; // capture once
|
||||
@ -409,11 +419,21 @@ for (let monthIndex = 0; monthIndex < maxMonths; monthIndex++) {
|
||||
const withdrawal = Math.min(retirementSpendMonthly, currentRetirementSavings);
|
||||
currentRetirementSavings -= withdrawal;
|
||||
baseMonthlyIncome += withdrawal;
|
||||
} else if (!stillInCollege) {
|
||||
baseMonthlyIncome = (expectedSalary || currentSalary) / 12;
|
||||
} else {
|
||||
baseMonthlyIncome = (currentSalary / 12) + (additionalIncome / 12);
|
||||
}
|
||||
} else if (!stillInCollege) {
|
||||
// Use expectedSalary **only** once the user has graduated
|
||||
const monthlyFromJob = (
|
||||
hasGraduated && expectedSalary > 0
|
||||
? expectedSalary // kicks in the month *after* gradDate
|
||||
: currentSalary
|
||||
) / 12;
|
||||
|
||||
baseMonthlyIncome =
|
||||
monthlyFromJob + (additionalIncome / 12);
|
||||
|
||||
} else { // stillInCollege branch
|
||||
baseMonthlyIncome =
|
||||
(currentSalary / 12) + (additionalIncome / 12);
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* 7.3 MILESTONE IMPACTS – safe number handling
|
||||
@ -512,9 +532,13 @@ baseMonthlyIncome += salaryAdjustThisMonth; // adjust gross BEFORE tax
|
||||
|
||||
let leftover = netMonthlyIncome - totalMonthlyExpenses;
|
||||
|
||||
const canSaveThisMonth = leftover > 0;
|
||||
|
||||
// baseline contributions
|
||||
const monthlyRetContrib = isRetiredThisMonth ? 0 : monthlyRetirementContribution;
|
||||
const monthlyEmergContrib = isRetiredThisMonth ? 0 : monthlyEmergencyContribution;
|
||||
const monthlyRetContrib =
|
||||
canSaveThisMonth && !isRetiredThisMonth ? monthlyRetirementContribution : 0;
|
||||
const monthlyEmergContrib =
|
||||
canSaveThisMonth && !isRetiredThisMonth ? monthlyEmergencyContribution : 0;
|
||||
const baselineContributions = monthlyRetContrib + monthlyEmergContrib;
|
||||
let effectiveRetirementContribution = 0;
|
||||
let effectiveEmergencyContribution = 0;
|
||||
@ -536,7 +560,7 @@ baseMonthlyIncome += salaryAdjustThisMonth; // adjust gross BEFORE tax
|
||||
}
|
||||
|
||||
// Surplus => leftover
|
||||
if (leftover > 0) {
|
||||
if (canSaveThisMonth && leftover > 0) {
|
||||
const totalPct = surplusEmergencyAllocation + surplusRetirementAllocation;
|
||||
const emergPortion = leftover * (surplusEmergencyAllocation / totalPct);
|
||||
const retPortion = leftover * (surplusRetirementAllocation / totalPct);
|
||||
@ -546,9 +570,9 @@ baseMonthlyIncome += salaryAdjustThisMonth; // adjust gross BEFORE tax
|
||||
}
|
||||
|
||||
const monthlyReturnRate = getMonthlyInterestRate();
|
||||
if (monthlyReturnRate !== 0) {
|
||||
currentRetirementSavings *= (1 + monthlyReturnRate);
|
||||
}
|
||||
if (monthlyReturnRate !== 0 && leftover > 0) {
|
||||
currentRetirementSavings *= (1 + monthlyReturnRate);
|
||||
}
|
||||
const netSavings = netMonthlyIncome - actualExpensesPaid;
|
||||
|
||||
// (UPDATED) add inCollege, stillInCollege, loanDeferralUntilGraduation to the result
|
||||
|
Loading…
Reference in New Issue
Block a user