{"version":3,"sources":["../assets/scripts/mortgagecalc.js"],"names":["MortgageCalculator","calculateMortgage","options","initOptions","mortgage","loanTermMonths","salePrice","interestRate","downPayment","extras","propertyTaxRate","homeInsurance","adjustFixedRateMonths","adjustInitialCap","adjustPeriodicCap","adjustLifetimeCap","adjustIntervalMonths","startDate","Date","calculateLoanAmount","loanAmount","downPercent","substr","indexOf","roundDecimals","num","decimals","Math","round","pow","calculateExtraPayment","loanMonth","totalExtra","i","extra","startMonth","endMonth","extraIntervalMonths","extraAmount","aprToMonthlyInterest","apr","calculatePropertyTax","monthlyPropertyTax","needsInterestReset","calculateInterestRate","armInterestRate","min","calculateMonthlyPayment","monthlyInterestRate","monthlyPayment","calculateAmortizations","previousAmortization","remainingLoanAmountInCents","monthlyPropertyTaxInCents","amortizations","loanYear","loanYearRollUpSummary","currentInterestRate","currentMonthlyPaymentInCents","rollupSummaryFields","amortization","scheduledMonthlyPayment","interest","principal","principalTotal","propertyTax","paymentTotal","paymentDate","getTime","addMonths","remainingLoanBalnce","map","field","push","totalLoanCost","additionalFieldsToProcess","length","paymentSchedule","numberOfPayments","isLeapYear","year","getDaysInMonth","month","prototype","y","this","getFullYear","getMonth","value","n","getDate","setDate","setMonth"],"mappings":"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","file":"mortgagecalc.js","sourcesContent":["/**\n * Some of the references.\n * 1. http://stackoverflow.com/questions/5645058/how-to-add-months-to-a-date-in-javascript\n * 2. http://www.hughcalc.org/formula.php\n * 3. http://homeguides.sfgate.com/calculate-five-year-arm-mortgages-9260.html\n * 4. http://stackoverflow.com/questions/2207449/financial-formula-for-calculating-an-adjustable-rate-mortgage\n * 5. http://belkcollegeofbusiness.uncc.edu/buttimer/MBAD%206160/Topic%204%20-%20Adjustable%20Rate%20Mortgages.ppt\n *\n * @type {{calculateMortgage: calculateMortgage, calculateAmortizations: calculateAmortizations}}\n */\n\nvar MortgageCalculator = {\n calculateMortgage: function(options) {\n\n Date.isLeapYear = function (year) {\n return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));\n };\n\n Date.getDaysInMonth = function (year, month) {\n return [31, (Date.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];\n };\n\n Date.prototype.isLeapYear = function () {\n var y = this.getFullYear();\n return (((y % 4 === 0) && (y % 100 !== 0)) || (y % 400 === 0));\n };\n\n Date.prototype.getDaysInMonth = function () {\n return Date.getDaysInMonth(this.getFullYear(), this.getMonth());\n };\n\n Date.prototype.addMonths = function (value) {\n var n = this.getDate();\n this.setDate(1);\n this.setMonth(this.getMonth() + value);\n this.setDate(Math.min(n, this.getDaysInMonth()));\n return this;\n };\n\n function initOptions (options) {\n var mortgage = {};\n mortgage.loanTermMonths = options.loanTermMonths || 12 * 30;\n mortgage.salePrice = options.salePrice || 500000;\n mortgage.interestRate = options.interestRate || 5.00;\n mortgage.downPayment = options.downPayment || '20%';\n mortgage.salePrice = options.salePrice || 500000;\n mortgage.extras = options.extras || [];\n mortgage.propertyTaxRate = options.propertyTaxRate || 0;\n mortgage.homeInsurance = options.homeInsurance || 0;\n mortgage.adjustFixedRateMonths = options.adjustFixedRateMonths || 0;\n mortgage.adjustInitialCap = options.adjustInitialCap || 0;\n mortgage.adjustPeriodicCap = options.adjustPeriodicCap || 0;\n mortgage.adjustLifetimeCap = options.adjustLifetimeCap || 0;\n mortgage.adjustIntervalMonths = options.adjustIntervalMonths || 12;\n mortgage.startDate = options.startDate || new Date();\n\n return mortgage;\n }\n\n function calculateLoanAmount (mortgage) {\n var loanAmount;\n if (typeof mortgage.downPayment == 'string') {\n var downPercent = mortgage.downPayment.substr(0, mortgage.downPayment.indexOf('%'));\n loanAmount = mortgage.salePrice - (mortgage.salePrice * (downPercent / 100));\n } else {\n loanAmount = mortgage.salePrice - mortgage.downPayment;\n }\n\n return loanAmount;\n }\n\n function roundDecimals (num) {\n var decimals = 2;\n return Math.round(num * Math.pow(10, decimals)) / Math.pow(10, decimals);\n }\n\n function roundAmortizationValues (amortization) {\n amortization.monthlyPayment = roundDecimals(amortization.monthlyPayment);\n amortization.interest = roundDecimals(amortization.interest);\n amortization.interestToDate = roundDecimals(amortization.interestToDate);\n amortization.interestLoanYearToDate = roundDecimals(amortization.interestLoanYearToDate);\n amortization.principal = roundDecimals(amortization.principal);\n amortization.principalLoanYearToDate = roundDecimals(amortization.principalLoanYearToDate);\n amortization.principalToDate = roundDecimals(amortization.principalToDate);\n amortization.extra = roundDecimals(amortization.extra);\n amortization.principalTotal = roundDecimals(amortization.principalTotal);\n amortization.paymentTotal = roundDecimals(amortization.paymentTotal);\n\n return amortization;\n }\n\n function calculateExtraPayment (mortgage, loanMonth) {\n var totalExtra = 0;\n if (mortgage.extras) {\n for(var i in mortgage.extras) {\n var extra = mortgage.extras[i];\n if (loanMonth >= extra.startMonth && loanMonth <= extra.endMonth) {\n if ((loanMonth - extra.startMonth) % extra.extraIntervalMonths == 0) {\n totalExtra += extra.extraAmount * 100;\n }\n }\n }\n }\n\n return totalExtra;\n }\n\n function aprToMonthlyInterest (apr) {\n return apr / (12 * 100);\n }\n\n function calculatePropertyTax(mortgage) {\n var monthlyPropertyTax;\n if (mortgage.propertyTaxRate && mortgage.propertyTaxRate > 0) {\n monthlyPropertyTax = (mortgage.salePrice * 100 * (options.propertyTaxRate / 100)) / 12;\n } else {\n monthlyPropertyTax = 0;\n }\n\n return monthlyPropertyTax;\n }\n\n /**\n * Mortgage needs reset if this mortgage is ARM and current loam month falls into\n * new interest period.\n *\n * @param mortgage\n * @param loanMonth\n */\n function needsInterestReset(mortgage, loanMonth) {\n if (mortgage.adjustFixedRateMonths <= 0 || loanMonth <= mortgage.adjustFixedRateMonths) {\n return false;\n }\n\n return (loanMonth - mortgage.adjustFixedRateMonths - 1) % mortgage.adjustIntervalMonths == 0;\n }\n\n function calculateInterestRate(mortgage, loanMonth) {\n if (mortgage.adjustFixedRateMonths <= 0 || loanMonth <= mortgage.adjustFixedRateMonths) {\n return mortgage.interestRate;\n }\n\n var armInterestRate = mortgage.interestRate + mortgage.adjustInitialCap;\n if (loanMonth > mortgage.adjustFixedRateMonths + 1) {\n for(var i = mortgage.adjustFixedRateMonths + mortgage.adjustIntervalMonths; i <= loanMonth; i += mortgage.adjustIntervalMonths) {\n armInterestRate += mortgage.adjustPeriodicCap;\n }\n }\n\n armInterestRate = Math.min(armInterestRate, mortgage.adjustLifetimeCap + mortgage.interestRate)\n\n return armInterestRate;\n }\n\n function calculateMonthlyPayment (loanAmount, loanTermMonths, interestRate) {\n var monthlyInterestRate = aprToMonthlyInterest(interestRate);\n var monthlyPayment = loanAmount * (monthlyInterestRate * Math.pow(1 + monthlyInterestRate, loanTermMonths))\n / (Math.pow(1 + monthlyInterestRate, loanTermMonths) - 1);\n return monthlyPayment;\n }\n\n function calculateAmortizations (mortgage) {\n\n //To avoid rounding errors, all dollars will be converted to cents and converted back to dollars\n //to response objects.\n var remainingLoanAmountInCents = mortgage.loanAmount * 100;\n var loanAmountInCents = mortgage.loanAmount * 100;\n var monthlyPropertyTaxInCents = calculatePropertyTax(mortgage);\n var amortizations = [];\n var previousAmortization;\n var loanMonth = 0;\n var loanYear = 1;\n var loanYearRollUpSummary = {};\n var currentInterestRate = calculateInterestRate(mortgage, 1);\n var currentMonthlyPaymentInCents = calculateMonthlyPayment(remainingLoanAmountInCents, mortgage.loanTermMonths, currentInterestRate);\n var rollupSummaryFields = ['interest', 'principal', 'extra', 'principalTotal', 'propertyTax', 'paymentTotal'];\n\n while(remainingLoanAmountInCents >= 1) {\n loanMonth++\n var amortization = {};\n\n if (needsInterestReset(mortgage, loanMonth)) {\n currentInterestRate = calculateInterestRate(mortgage, loanMonth);\n currentMonthlyPaymentInCents = calculateMonthlyPayment(remainingLoanAmountInCents, mortgage.loanTermMonths + 1 - loanMonth, currentInterestRate);\n }\n\n amortization.interestRate = currentInterestRate;\n amortization.scheduledMonthlyPayment = currentMonthlyPaymentInCents;\n amortization.interest = remainingLoanAmountInCents * aprToMonthlyInterest(amortization.interestRate);\n amortization.principal = currentMonthlyPaymentInCents - amortization.interest;\n\n if (remainingLoanAmountInCents < amortization.principal) {\n amortization.principal = remainingLoanAmountInCents;\n amortization.extra = 0;\n } else {\n amortization.extra = calculateExtraPayment(mortgage, loanMonth);\n }\n\n amortization.principalTotal = amortization.principal + amortization.extra;\n\n amortization.propertyTax = monthlyPropertyTaxInCents;\n\n amortization.paymentTotal = amortization.interest + amortization.principalTotal + monthlyPropertyTaxInCents;\n\n amortization.paymentDate = new Date(mortgage.startDate.getTime()).addMonths(loanMonth);\n\n remainingLoanAmountInCents -= amortization.principalTotal;\n\n //If remaining loan amount is less than zero, then set it to zero.\n if (remainingLoanAmountInCents < 0) {\n remainingLoanAmountInCents = 0;\n }\n amortization.remainingLoanBalnce = remainingLoanAmountInCents;\n\n amortization.loanMonth = loanMonth;\n amortization.loanYear = loanYear;\n rollupSummaryFields.map( function(field) {\n if (loanYearRollUpSummary[field]) {\n loanYearRollUpSummary[field] += amortization[field];\n } else {\n loanYearRollUpSummary[field] = amortization[field];\n }\n\n amortization[field + 'LoanYearToDate'] = loanYearRollUpSummary[field];\n });\n\n if (loanMonth % 12 === 0) {\n loanYearRollUpSummary = {};\n loanYear++;\n }\n\n rollupSummaryFields.map( function(field) {\n if (previousAmortization) {\n amortization[field + 'ToDate'] = previousAmortization[field + 'ToDate'] + amortization[field];\n } else {\n amortization[field + 'ToDate'] = amortization[field];\n }\n });\n\n previousAmortization = amortization;\n amortizations.push(amortization);\n }\n\n\n //Round all amortization values to dollars.\n mortgage.totalLoanCost = 0;\n var additionalFieldsToProcess = ['scheduledMonthlyPayment', 'remainingLoanBalnce'];\n\n for(var i = 0; i < amortizations.length; i++) {\n var amortization = amortizations[i];\n rollupSummaryFields.map( function(field) {\n amortization[field] = roundDecimals(amortization[field] / 100);\n amortization[field + 'ToDate'] = roundDecimals(amortization[field + 'ToDate'] / 100);\n amortization[field + 'LoanYearToDate'] = roundDecimals(amortization[field + 'LoanYearToDate'] / 100);\n });\n\n additionalFieldsToProcess.map( function(field) {\n amortization[field] = roundDecimals(amortization[field] / 100);\n });\n\n mortgage.totalLoanCost += amortization.interest;\n }\n\n mortgage.totalLoanCost = roundDecimals(mortgage.totalLoanCost);\n mortgage.paymentSchedule = amortizations;\n mortgage.numberOfPayments = mortgage.paymentSchedule.length;\n mortgage.monthlyPayment = mortgage.paymentSchedule[0].scheduledMonthlyPayment;\n }\n\n var mortgage = initOptions(options);\n\n mortgage.loanAmount = calculateLoanAmount(mortgage);\n calculateAmortizations(mortgage);\n return mortgage;\n }\n}\n"],"sourceRoot":"assets/scripts/"}