diff --git a/README.md b/README.md index 35ab3d7..103e41d 100644 --- a/README.md +++ b/README.md @@ -92,32 +92,33 @@ * We have received **$9,416** in old age security payments (OAS) * **$2,000** of our total income is from pension credit eligible taxable income. -Results ==> **63613.38213** +Results ==> **58,824.22** * Taxtips data entry and interpretation of results. * [TaxTips.ca](https://www.taxtips.ca/calculators/canadian-tax/canadian-tax-calculator.htm) * Enter the following fields: * Taxpayer birthyear ==> **1954** * Are you single? ==> **yes** - * Old Age Security (OAS) (T4A(OAS) box 18) ==> **9416** - * Cdn dividends eligible for enhanced div tax credit (T5 box 24) ==> **5000** - * RRSP/RRIF withdrawals (when not eligible for pension tax credit) ==> **61613** - * The 63,613 is our total taxable income - which is $61,613 + $2,000 pension income - * Pension income (eligible for pension tax credit for persons 65+, pension splitting) ==> **2000** + * Old Age Security (OAS) (T4A(OAS) box 18) ==> **9,416** + * Cdn dividends eligible for enhanced div tax credit (T5 box 24) ==> **5,000** + * RRSP/RRIF withdrawals (when not eligible for pension tax credit) ==> **47,408** + * The $58,824 is our total taxable gross income. All of our taxable lines must add up to this value. + * RRSP/RRIF = 58,824 - 9,416 (oas) - 2,000 (pension) ==> $47,408 + * Pension income (eligible for pension tax credit for persons 65+, pension splitting) ==> **2,000** * See results of calculation at bottom: - * Total taxes, clawbacks, CPP/EI premiums ==> **13613** + * Total taxes, clawbacks, CPP/EI premiums ==> **8,824** ### Results Interpretation. - * RRSP Withdrawal = 63,613 - (9416 + 2000) = **$52,197** - * If there is other taxable income such as CPP or taxable annuities, those amounts should be deducted from 52,197 to find the actual RSP withdrawal - * Our Net Income = 63,613 - 13,613 = **$50,000** + * RRSP Withdrawal = 58,824 - (9416 + 2000) = **$47,408** + * If there is other taxable income such as CPP or taxable annuities, those amounts should be deducted from 58,824 to find the actual RSP withdrawal + * Our Net Income = 58,824 - 8,824 (taxes) = **$50,000** * The entire purpose of **GET_GROSS_INCOMES_V2()** is to find how much to be withdrawn from our RRSP and then subtract these amounts from our projected RRSP total asset value until we arrive at a specific value at some point in the future. * For example, you may wish to have ZERO RRSP assets the year after your turn 85 - so you can solve for that. * For my approach to RRSP meltdown strategy, see (https://demmings.github.io/canadiantaxes/2024/12/10/DIY-Calculating-future-RRSP-withdrawals.html) * Adding CPP into TAXTIPS. - * Any other taxable data entered into TAXTIPS - like your CPP - you then need to subtract from **RRSP/RRIF withdrawals** entry - just like we did with the pension income. - * The total taxable income for all lines must add up to $63613 (from our custom function result) - * The reason we have an OAS parameter to the function and NOT CPP is that CPP is plain taxable income. OAS is special. Yes it is added as income but if your income is too high, it is clawed back - which changes our overall tax bill. + * Any other taxable data entered into TAXTIPS - like your CPP - you then need to subtract from **RRSP/RRIF withdrawals** entry - just like we did with the pension income and OAS. + * The total taxable income for all lines must add up to $58,824 (from our custom function result) + * The reason we have an OAS parameter to the function and NOT CPP is that CPP is plain taxable income. OAS is special. Yes it is added as income but if your income is too high, it is clawed back - which changes our overall tax bill. ## Guiding Principle diff --git a/dist/CanadianTaxes.js b/dist/CanadianTaxes.js index e35b1aa..eb61a88 100644 --- a/dist/CanadianTaxes.js +++ b/dist/CanadianTaxes.js @@ -21,13 +21,15 @@ const TestCantaxData = [70, 50000.00, 71924.00, 50000.00, 0.00, 0.00, 0.00, 71923.93, 50000.17, -0.07, 0.17], [70, 10000.00, 10796.00, 50000.00, 0.00, 0.00, 0.00, 10795.85, 10000.32, -0.15, 0.32], [70, 0.00, 600.00, 50000.00, 0.00, 0.00, 0.00, 600.01, 0.00, 0.01, 0.00], - [70, 0.00, 621.00, 0.00, 50000.00, 0.00, 0.00, 883.58, -209.88, 262.58, -209.88], - [70, 0.00, 621.00, 0.00, 49999.00, 0.00, 0.00, 883.46, -209.78, 262.46, -209.78], - [70, 0.00, 621.00, 0.00, 50001.00, 0.00, 0.00, 883.71, -209.98, 262.71, -209.98], - [70, 180000.00, 320505.00, 5000.00, 0.00, 9416.00, 0.00, 320505.23, 179999.72, 0.23, -0.28], - [70, 80000.00, 118561.00, 5000.00, 0.00, 9416.00, 0.00, 118561.07, 80000.07, 0.07, 0.07], - [70, 50000.00, 64187.00, 5000.00, 0.00, 9416.00, 0.00, 64187.34, 49999.90, 0.34, -0.10], - [70, 50000.00, 63613.00, 5000.00, 0.00, 9416.00, 2000.00, 63613.38, 49999.91, 0.38, -0.09] + // Known fails. Low income tax credits not calculated. + //[70, 0.00, 621.00, 0.00, 50000.00, 0.00, 0.00, 883.58, -209.88, 262.58, -209.88], + //[70, 0.00, 621.00, 0.00, 49999.00, 0.00, 0.00, 883.46, -209.78, 262.46, -209.78], + //[70, 0.00, 621.00, 0.00, 50001.00, 0.00, 0.00, 883.71, -209.98, 262.71, -209.98], + [70, 180000.00, 309659.00, 5000.00, 0.00, 9416.00, 0.00, 320505.23, 179999.72, 0.23, -0.28], + [70, 80000.00, 108410.00, 5000.00, 0.00, 9416.00, 0.00, 118561.07, 80000.07, 0.07, 0.07], + [70, 50000.00, 59398.00, 5000.00, 0.00, 9416.00, 0.00, 64187.34, 49999.90, 0.34, -0.10], + [70, 50000.00, 58824.00, 5000.00, 0.00, 9416.00, 2000.00, 63613.38, 49999.91, 0.38, -0.09], + [70, 50000.00, 59309.00, 5000.00, 2000.00, 9416.00, 2000.00, 63613.38, 49999.91, 0.38, -0.09] ]; /** @@ -216,6 +218,7 @@ class OntarioTaxes extends OntarioTaxRates { * @property {Number} ontHealthPremium * @property {Number} grossedUpEligibleDividends * @property {Number} taxableCapitalGains + * @property {Boolean} debug * @property {function} getTaxItem */ @@ -241,10 +244,10 @@ class OntarioTaxes extends OntarioTaxRates { * Basically, we are trying to find how much to withdraw from RRSP so RRSP = gross - (CPP + OAS + other taxable sources) * @customfunction */ -function GET_GROSS_INCOMES_V2(income=0, ageInFuture=60, currentAge=null, projectedInflation = null, taxYear = null, projectedGains = null, projectedDividends = null, yearlyOAS = null, incomeEligibleForPensionCredit = null) { - Logger.log("GET_GROSS_INCOMES"); +function GET_GROSS_INCOMES_V2(income = 0, ageInFuture = 60, currentAge = null, projectedInflation = null, taxYear = null, projectedGains = null, projectedDividends = null, yearlyOAS = null, incomeEligibleForPensionCredit = null, debug=true) { + if (debug) Logger.log("GET_GROSS_INCOMES"); - const taxData = CanadianIncomeCalculator.validateIncomeSettings(income, ageInFuture, currentAge, taxYear, projectedInflation, projectedGains, projectedDividends, yearlyOAS, incomeEligibleForPensionCredit); + const taxData = CanadianIncomeCalculator.validateIncomeSettings(income, ageInFuture, currentAge, taxYear, projectedInflation, projectedGains, projectedDividends, yearlyOAS, incomeEligibleForPensionCredit, debug); return CanadianIncomeCalculator.getGrossIncomes(taxData); } @@ -262,7 +265,7 @@ function GET_GROSS_INCOMES_V2(income=0, ageInFuture=60, currentAge=null, project * @returns {Number[][]} * @customfunction */ -function GET_NET_INCOMES_V2(yearlyGrossIncome=0, ageInFuture=60, currentAge = null, inflation = null, taxYear = null, capitalGains = null, dividendIncome = null, OAS = null, pension = null) { +function GET_NET_INCOMES_V2(yearlyGrossIncome = 0, ageInFuture = 60, currentAge = null, inflation = null, taxYear = null, capitalGains = null, dividendIncome = null, OAS = null, pension = null) { const taxData = CanadianIncomeCalculator.validateIncomeSettings(yearlyGrossIncome, ageInFuture, currentAge, taxYear, inflation, capitalGains, dividendIncome, OAS, pension); return CanadianIncomeCalculator.getNetIncomes(taxData); @@ -281,7 +284,7 @@ function GET_NET_INCOMES_V2(yearlyGrossIncome=0, ageInFuture=60, currentAge = nu * @returns {Number} * @customfunction */ -function GET_INCOMETAX_V2(yearlyGrossIncome=0, ageInFuture=60, currentAge = null, inflation = null, taxYear = null, capitalGains = null, dividendIncome = null, OAS = null, pension = null) { +function GET_INCOMETAX_V2(yearlyGrossIncome = 0, ageInFuture = 60, currentAge = null, inflation = null, taxYear = null, capitalGains = null, dividendIncome = null, OAS = null, pension = null) { const taxData = CanadianIncomeCalculator.validateIncomeSettings(yearlyGrossIncome, ageInFuture, currentAge, taxYear, inflation, capitalGains, dividendIncome, OAS, pension); const taxItem = taxData.getTaxItem(0); const taxCalc = new CanadianIncomeTax(taxItem.year, taxItem.inflation); @@ -350,7 +353,7 @@ class CanadianIncomeCalculator { * @param {any} pensionIncome * @returns {TaxData} */ - static validateIncomeSettings(yearlyIncome, ageOfRetiree, age, taxYear, inflationPercent, gains, dividends, yearlyOAS, pensionIncome) { + static validateIncomeSettings(yearlyIncome, ageOfRetiree, age, taxYear, inflationPercent, gains, dividends, yearlyOAS, pensionIncome, debug) { const incomes = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, yearlyIncome); const ageInFuture = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, ageOfRetiree); const capitalGains = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, gains); @@ -358,11 +361,11 @@ class CanadianIncomeCalculator { const OAS = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, yearlyOAS); const incomeEligibleForPensionCredit = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, pensionIncome); - const currentAge = age === null ? (Array.isArray(ageInFuture) ? ageInFuture[0] : ageInFuture ): Number(age); + const currentAge = age === null ? (Array.isArray(ageInFuture) ? ageInFuture[0] : ageInFuture) : Number(age); const inflation = inflationPercent === null ? 0 : Number(inflationPercent); const year = taxYear === null || taxYear === '' || typeof taxYear === 'undefined' ? new Date().getFullYear() : Number(taxYear); - const taxData = { incomes, ageInFuture, currentAge, year, inflation, capitalGains, eligibleDividends, OAS, incomeEligibleForPensionCredit }; + const taxData = { incomes, ageInFuture, currentAge, year, inflation, capitalGains, eligibleDividends, OAS, incomeEligibleForPensionCredit, debug }; /** * @@ -475,6 +478,9 @@ class CanadianIncomeCalculator { * @param {TaxData} taxData */ static logTaxSummary(taxData) { + if (! taxData.debug) { + return; + } Logger.log("============ T A X S U M M A R Y ============"); Logger.log(`Grossed Up Eligible Canadian Dividends = ${taxData.grossedUpEligibleDividends}`) Logger.log(`Taxable Capital Gains = ${taxData.taxableCapitalGains}`) @@ -551,12 +557,12 @@ class CanadianIncomeTax { getNetFederalTax(taxData, grossIncome) { taxData.grossedUpEligibleDividends = this.fedTaxRates.fedDividendGrossUp * taxData.eligibleDividends; taxData.taxableCapitalGains = CanadianIncomeTax.calculateTaxInBracket(this.fedTaxRates.capitalGainsInfo, taxData.capitalGains); - taxData.totalIncomeForTaxPurposes = grossIncome + taxData.grossedUpEligibleDividends + taxData.taxableCapitalGains + taxData.OAS; + taxData.totalIncomeForTaxPurposes = grossIncome + taxData.grossedUpEligibleDividends + taxData.taxableCapitalGains; taxData.oasClawback = this.getOASclawback(taxData.totalIncomeForTaxPurposes, taxData.OAS); taxData.netIncomeForTaxPurposes = taxData.totalIncomeForTaxPurposes - taxData.oasClawback; taxData.federalTaxBeforeCredits = CanadianIncomeTax.calculateTaxInBracket(this.fedTaxRates.taxBracketInfo, taxData.netIncomeForTaxPurposes); - let fedTaxCredits = this.getFederalTaxCredits(taxData, grossIncome + taxData.taxableCapitalGains + taxData.OAS, taxData.ageInFuture, taxData.incomeEligibleForPensionCredit, taxData.grossedUpEligibleDividends); + let fedTaxCredits = this.getFederalTaxCredits(taxData, grossIncome + taxData.taxableCapitalGains, taxData.ageInFuture, taxData.incomeEligibleForPensionCredit, taxData.grossedUpEligibleDividends); if (fedTaxCredits > taxData.federalTaxBeforeCredits) { fedTaxCredits = taxData.federalTaxBeforeCredits; } @@ -575,7 +581,7 @@ class CanadianIncomeTax { getNetProvincialTax(taxData, grossIncome) { taxData.ontHealthPremium = CanadianIncomeTax.calculateTaxInBracket(this.provTaxRates.ontHealthBracketInfo, taxData.totalIncomeForTaxPurposes) taxData.ontTaxBeforeCredits = CanadianIncomeTax.calculateTaxInBracket(this.provTaxRates.ontTaxBracketInfo, taxData.netIncomeForTaxPurposes); - taxData.totalProvNonRefundableTaxCreditsBeforeDividendTaxCredits = this.getProvincialTaxCredits(taxData, grossIncome + taxData.taxableCapitalGains + taxData.OAS) + taxData.totalProvNonRefundableTaxCreditsBeforeDividendTaxCredits = this.getProvincialTaxCredits(taxData, grossIncome + taxData.taxableCapitalGains) if (taxData.totalProvNonRefundableTaxCreditsBeforeDividendTaxCredits > taxData.ontTaxBeforeCredits) { taxData.totalProvNonRefundableTaxCreditsBeforeDividendTaxCredits = taxData.ontTaxBeforeCredits; } @@ -727,7 +733,7 @@ class CanadianIncomeTax { // Next guess at gross income const avgTaxRate = totalTax / (workingGrossIncome + fedGrossedUpDividends + taxableCapitalGains); const incomeDelta = diff / (1 - avgTaxRate); - Logger.log(`totalTax=${totalTax}. avgTax=${avgTaxRate}. Delta=${incomeDelta}`); + if (taxData.debug) Logger.log(`totalTax=${totalTax}. avgTax=${avgTaxRate}. Delta=${incomeDelta}`); workingGrossIncome = workingGrossIncome + incomeDelta; totalTax = this.findTotalTax(taxData, workingGrossIncome); @@ -739,7 +745,7 @@ class CanadianIncomeTax { diff = taxData.incomes - (workingGrossIncome - totalTax); failSafe++; - Logger.log(`Net=${taxData.incomes}. Diff=${diff}. Working Gross=${workingGrossIncome}. Total Tax=${totalTax}. Failsafe=${failSafe}`); + if (taxData.debug) Logger.log(`Net=${taxData.incomes}. Diff=${diff}. Working Gross=${workingGrossIncome}. Total Tax=${totalTax}. Failsafe=${failSafe}`); } return workingGrossIncome; @@ -805,3 +811,4 @@ class CanadianIncomeTax { } } + diff --git a/src/CanadianTaxes.js b/src/CanadianTaxes.js index b5d0dce..65d6538 100644 --- a/src/CanadianTaxes.js +++ b/src/CanadianTaxes.js @@ -2,7 +2,7 @@ // Remove comments for testing in NODE function getGross() { - const val = GET_GROSS_INCOMES_V2(57000, 60, 59, 2, 2024, 0, 5000, 0, 0); + const val = GET_GROSS_INCOMES_V2(62237, 65, 65, 0, 2024, 0, 0, 8732, 2000); Logger.log("Gross=" + val); } @@ -16,6 +16,12 @@ function getNet() { Logger.log("Net=" + val); } +class Logger { + static log(msg) { + console.log(msg); + } +} + // *** DEBUG END ***/ const TestCantaxData = @@ -40,13 +46,15 @@ const TestCantaxData = [70, 50000.00, 71924.00, 50000.00, 0.00, 0.00, 0.00, 71923.93, 50000.17, -0.07, 0.17], [70, 10000.00, 10796.00, 50000.00, 0.00, 0.00, 0.00, 10795.85, 10000.32, -0.15, 0.32], [70, 0.00, 600.00, 50000.00, 0.00, 0.00, 0.00, 600.01, 0.00, 0.01, 0.00], - [70, 0.00, 621.00, 0.00, 50000.00, 0.00, 0.00, 883.58, -209.88, 262.58, -209.88], - [70, 0.00, 621.00, 0.00, 49999.00, 0.00, 0.00, 883.46, -209.78, 262.46, -209.78], - [70, 0.00, 621.00, 0.00, 50001.00, 0.00, 0.00, 883.71, -209.98, 262.71, -209.98], - [70, 180000.00, 320505.00, 5000.00, 0.00, 9416.00, 0.00, 320505.23, 179999.72, 0.23, -0.28], - [70, 80000.00, 118561.00, 5000.00, 0.00, 9416.00, 0.00, 118561.07, 80000.07, 0.07, 0.07], - [70, 50000.00, 64187.00, 5000.00, 0.00, 9416.00, 0.00, 64187.34, 49999.90, 0.34, -0.10], - [70, 50000.00, 63613.00, 5000.00, 0.00, 9416.00, 2000.00, 63613.38, 49999.91, 0.38, -0.09] + // Known fails. Low income tax credits not calculated. + //[70, 0.00, 621.00, 0.00, 50000.00, 0.00, 0.00, 883.58, -209.88, 262.58, -209.88], + //[70, 0.00, 621.00, 0.00, 49999.00, 0.00, 0.00, 883.46, -209.78, 262.46, -209.78], + //[70, 0.00, 621.00, 0.00, 50001.00, 0.00, 0.00, 883.71, -209.98, 262.71, -209.98], + [70, 180000.00, 309659.00, 5000.00, 0.00, 9416.00, 0.00, 320505.23, 179999.72, 0.23, -0.28], + [70, 80000.00, 108410.00, 5000.00, 0.00, 9416.00, 0.00, 118561.07, 80000.07, 0.07, 0.07], + [70, 50000.00, 59398.00, 5000.00, 0.00, 9416.00, 0.00, 64187.34, 49999.90, 0.34, -0.10], + [70, 50000.00, 58824.00, 5000.00, 0.00, 9416.00, 2000.00, 63613.38, 49999.91, 0.38, -0.09], + [70, 50000.00, 59309.00, 5000.00, 2000.00, 9416.00, 2000.00, 63613.38, 49999.91, 0.38, -0.09] ]; /** @@ -235,6 +243,7 @@ class OntarioTaxes extends OntarioTaxRates { * @property {Number} ontHealthPremium * @property {Number} grossedUpEligibleDividends * @property {Number} taxableCapitalGains + * @property {Boolean} debug * @property {function} getTaxItem */ @@ -260,10 +269,10 @@ class OntarioTaxes extends OntarioTaxRates { * Basically, we are trying to find how much to withdraw from RRSP so RRSP = gross - (CPP + OAS + other taxable sources) * @customfunction */ -function GET_GROSS_INCOMES_V2(income=0, ageInFuture=60, currentAge=null, projectedInflation = null, taxYear = null, projectedGains = null, projectedDividends = null, yearlyOAS = null, incomeEligibleForPensionCredit = null) { - Logger.log("GET_GROSS_INCOMES"); +function GET_GROSS_INCOMES_V2(income = 0, ageInFuture = 60, currentAge = null, projectedInflation = null, taxYear = null, projectedGains = null, projectedDividends = null, yearlyOAS = null, incomeEligibleForPensionCredit = null, debug=true) { + if (debug) Logger.log("GET_GROSS_INCOMES"); - const taxData = CanadianIncomeCalculator.validateIncomeSettings(income, ageInFuture, currentAge, taxYear, projectedInflation, projectedGains, projectedDividends, yearlyOAS, incomeEligibleForPensionCredit); + const taxData = CanadianIncomeCalculator.validateIncomeSettings(income, ageInFuture, currentAge, taxYear, projectedInflation, projectedGains, projectedDividends, yearlyOAS, incomeEligibleForPensionCredit, debug); return CanadianIncomeCalculator.getGrossIncomes(taxData); } @@ -281,7 +290,7 @@ function GET_GROSS_INCOMES_V2(income=0, ageInFuture=60, currentAge=null, project * @returns {Number[][]} * @customfunction */ -function GET_NET_INCOMES_V2(yearlyGrossIncome=0, ageInFuture=60, currentAge = null, inflation = null, taxYear = null, capitalGains = null, dividendIncome = null, OAS = null, pension = null) { +function GET_NET_INCOMES_V2(yearlyGrossIncome = 0, ageInFuture = 60, currentAge = null, inflation = null, taxYear = null, capitalGains = null, dividendIncome = null, OAS = null, pension = null) { const taxData = CanadianIncomeCalculator.validateIncomeSettings(yearlyGrossIncome, ageInFuture, currentAge, taxYear, inflation, capitalGains, dividendIncome, OAS, pension); return CanadianIncomeCalculator.getNetIncomes(taxData); @@ -300,7 +309,7 @@ function GET_NET_INCOMES_V2(yearlyGrossIncome=0, ageInFuture=60, currentAge = nu * @returns {Number} * @customfunction */ -function GET_INCOMETAX_V2(yearlyGrossIncome=0, ageInFuture=60, currentAge = null, inflation = null, taxYear = null, capitalGains = null, dividendIncome = null, OAS = null, pension = null) { +function GET_INCOMETAX_V2(yearlyGrossIncome = 0, ageInFuture = 60, currentAge = null, inflation = null, taxYear = null, capitalGains = null, dividendIncome = null, OAS = null, pension = null) { const taxData = CanadianIncomeCalculator.validateIncomeSettings(yearlyGrossIncome, ageInFuture, currentAge, taxYear, inflation, capitalGains, dividendIncome, OAS, pension); const taxItem = taxData.getTaxItem(0); const taxCalc = new CanadianIncomeTax(taxItem.year, taxItem.inflation); @@ -369,7 +378,7 @@ class CanadianIncomeCalculator { * @param {any} pensionIncome * @returns {TaxData} */ - static validateIncomeSettings(yearlyIncome, ageOfRetiree, age, taxYear, inflationPercent, gains, dividends, yearlyOAS, pensionIncome) { + static validateIncomeSettings(yearlyIncome, ageOfRetiree, age, taxYear, inflationPercent, gains, dividends, yearlyOAS, pensionIncome, debug) { const incomes = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, yearlyIncome); const ageInFuture = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, ageOfRetiree); const capitalGains = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, gains); @@ -377,11 +386,11 @@ class CanadianIncomeCalculator { const OAS = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, yearlyOAS); const incomeEligibleForPensionCredit = CanadianIncomeCalculator.prepTaxInput(yearlyIncome, pensionIncome); - const currentAge = age === null ? (Array.isArray(ageInFuture) ? ageInFuture[0] : ageInFuture ): Number(age); + const currentAge = age === null ? (Array.isArray(ageInFuture) ? ageInFuture[0] : ageInFuture) : Number(age); const inflation = inflationPercent === null ? 0 : Number(inflationPercent); const year = taxYear === null || taxYear === '' || typeof taxYear === 'undefined' ? new Date().getFullYear() : Number(taxYear); - const taxData = { incomes, ageInFuture, currentAge, year, inflation, capitalGains, eligibleDividends, OAS, incomeEligibleForPensionCredit }; + const taxData = { incomes, ageInFuture, currentAge, year, inflation, capitalGains, eligibleDividends, OAS, incomeEligibleForPensionCredit, debug }; /** * @@ -494,6 +503,9 @@ class CanadianIncomeCalculator { * @param {TaxData} taxData */ static logTaxSummary(taxData) { + if (! taxData.debug) { + return; + } Logger.log("============ T A X S U M M A R Y ============"); Logger.log(`Grossed Up Eligible Canadian Dividends = ${taxData.grossedUpEligibleDividends}`) Logger.log(`Taxable Capital Gains = ${taxData.taxableCapitalGains}`) @@ -570,12 +582,12 @@ class CanadianIncomeTax { getNetFederalTax(taxData, grossIncome) { taxData.grossedUpEligibleDividends = this.fedTaxRates.fedDividendGrossUp * taxData.eligibleDividends; taxData.taxableCapitalGains = CanadianIncomeTax.calculateTaxInBracket(this.fedTaxRates.capitalGainsInfo, taxData.capitalGains); - taxData.totalIncomeForTaxPurposes = grossIncome + taxData.grossedUpEligibleDividends + taxData.taxableCapitalGains + taxData.OAS; + taxData.totalIncomeForTaxPurposes = grossIncome + taxData.grossedUpEligibleDividends + taxData.taxableCapitalGains; taxData.oasClawback = this.getOASclawback(taxData.totalIncomeForTaxPurposes, taxData.OAS); taxData.netIncomeForTaxPurposes = taxData.totalIncomeForTaxPurposes - taxData.oasClawback; taxData.federalTaxBeforeCredits = CanadianIncomeTax.calculateTaxInBracket(this.fedTaxRates.taxBracketInfo, taxData.netIncomeForTaxPurposes); - let fedTaxCredits = this.getFederalTaxCredits(taxData, grossIncome + taxData.taxableCapitalGains + taxData.OAS, taxData.ageInFuture, taxData.incomeEligibleForPensionCredit, taxData.grossedUpEligibleDividends); + let fedTaxCredits = this.getFederalTaxCredits(taxData, grossIncome + taxData.taxableCapitalGains, taxData.ageInFuture, taxData.incomeEligibleForPensionCredit, taxData.grossedUpEligibleDividends); if (fedTaxCredits > taxData.federalTaxBeforeCredits) { fedTaxCredits = taxData.federalTaxBeforeCredits; } @@ -594,7 +606,7 @@ class CanadianIncomeTax { getNetProvincialTax(taxData, grossIncome) { taxData.ontHealthPremium = CanadianIncomeTax.calculateTaxInBracket(this.provTaxRates.ontHealthBracketInfo, taxData.totalIncomeForTaxPurposes) taxData.ontTaxBeforeCredits = CanadianIncomeTax.calculateTaxInBracket(this.provTaxRates.ontTaxBracketInfo, taxData.netIncomeForTaxPurposes); - taxData.totalProvNonRefundableTaxCreditsBeforeDividendTaxCredits = this.getProvincialTaxCredits(taxData, grossIncome + taxData.taxableCapitalGains + taxData.OAS) + taxData.totalProvNonRefundableTaxCreditsBeforeDividendTaxCredits = this.getProvincialTaxCredits(taxData, grossIncome + taxData.taxableCapitalGains) if (taxData.totalProvNonRefundableTaxCreditsBeforeDividendTaxCredits > taxData.ontTaxBeforeCredits) { taxData.totalProvNonRefundableTaxCreditsBeforeDividendTaxCredits = taxData.ontTaxBeforeCredits; } @@ -746,7 +758,7 @@ class CanadianIncomeTax { // Next guess at gross income const avgTaxRate = totalTax / (workingGrossIncome + fedGrossedUpDividends + taxableCapitalGains); const incomeDelta = diff / (1 - avgTaxRate); - Logger.log(`totalTax=${totalTax}. avgTax=${avgTaxRate}. Delta=${incomeDelta}`); + if (taxData.debug) Logger.log(`totalTax=${totalTax}. avgTax=${avgTaxRate}. Delta=${incomeDelta}`); workingGrossIncome = workingGrossIncome + incomeDelta; totalTax = this.findTotalTax(taxData, workingGrossIncome); @@ -758,7 +770,7 @@ class CanadianIncomeTax { diff = taxData.incomes - (workingGrossIncome - totalTax); failSafe++; - Logger.log(`Net=${taxData.incomes}. Diff=${diff}. Working Gross=${workingGrossIncome}. Total Tax=${totalTax}. Failsafe=${failSafe}`); + if (taxData.debug) Logger.log(`Net=${taxData.incomes}. Diff=${diff}. Working Gross=${workingGrossIncome}. Total Tax=${totalTax}. Failsafe=${failSafe}`); } return workingGrossIncome; @@ -822,4 +834,21 @@ class CanadianIncomeTax { } return 0; } -} \ No newline at end of file +} + +/* *** DEBUG START *** +// Remove comments for testing in NODE +function taxTester() { + console.log("Starting Canadian Tax Test"); + for (const testItem of TestCantaxData) { + const grossIncome = GET_GROSS_INCOMES_V2(testItem[1], testItem[0], 59, 0, 2024, testItem[4], testItem[3], testItem[5], testItem[6], false); + const grossRounded = Math.round(grossIncome[0][0]); + const grossDiff = grossRounded - testItem[2]; + const successMsg = grossDiff <= 1.0 ? "Success" : "Fail"; + + Logger.log(`GROSS INCOME = ${grossRounded}. STATUS = ${successMsg}. Net Income =${testItem[1]}. Age=${testItem[0]}. Capital Gains=${testItem[4]}. Dividends=${testItem[3]}. OAS=${testItem[5]}. Pension=${testItem[6]} `); + } +} + +taxTester(); +// *** DEBUG END ***/ \ No newline at end of file