Custom functions used in Google Sheets for ease of use and improved functionality.
function getIncomeForMe() {
balanceToZero("currentNetIncome", "finalYearRspValue", 500, 50);
}
/**
*
* @param {String} netIncomeCell - Named range of CELL that contains net income
* @param {String} accountBalanceCell - Named range of CELL that has account balance in year after passing
* @param {Number} startingDelta - Starting amount to adjust net income if there is a balance
* @param {Number} maxDiff - Solve until the ending balance is plus/minus this value.
* @returns {Number}
*/
function balanceToZero(netIncomeCell, accountBalanceCell, startingDelta, maxDiff) {
const ss = SpreadsheetApp.getActive();
const sheet = ss.getActiveSheet();
const accountBalanceRange = sheet.getRange(accountBalanceCell);
const netIncomeRange = sheet.getRange(netIncomeCell);
const startSalary = netIncomeRange.getValue();
const endingBalance = accountBalanceRange.getValue();
let currentBalance = endingBalance;
let floorDiff = 0; // Last salary DELTA where end balance has not gone from 0 to non zero (viceversa)
let ceilinigDiff = endingBalance === 0 ? -startingDelta : startingDelta;
// Get a ballpark range of change net income - refined in following step.
while ((endingBalance === 0 && currentBalance === 0) || (endingBalance > 0 && currentBalance !== 0)) {
netIncomeRange.setValue(startSalary + ceilinigDiff);
currentBalance = accountBalanceRange.getValue();
if ((endingBalance === 0 && currentBalance === 0) || (endingBalance > 0 && currentBalance !== 0)) {
floorDiff = ceilinigDiff;
ceilinigDiff *= 2;
}
}
// The ceilingDiff is too much of a change. It should be between the floor and ceiling.
let splitDiff = (ceilinigDiff + floorDiff) / 2;
while (Math.abs(ceilinigDiff - floorDiff) > maxDiff) {
netIncomeRange.setValue(startSalary + splitDiff);
currentBalance = accountBalanceRange.getValue();
if (endingBalance === 0) {
// This means the startSalary was too high - since nothing was left.
if (currentBalance === 0) {
// The startSalary PLUS the split difference is still TOO HIGH. We
// must reduce our salary again.
floorDiff = splitDiff;
}
else {
// The was reduced too much now. We have something left in the pot.
ceilinigDiff = splitDiff;
}
}
else {
// This means the startSalary was too low - since the end balance is > 0.
if (currentBalance > 0) {
// Salary is still TOO LOW.
floorDiff = splitDiff;
}
else {
ceilinigDiff = splitDiff;
}
}
splitDiff = (ceilinigDiff + floorDiff) / 2;
}
return startSalary + splitDiff;
}