Created
August 30, 2019 14:29
-
-
Save LFTroya/928071ffd0c32280ab07157bb3e50a80 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ExpenseBudget } from "../models"; | |
import expenseBudget = require("../schemas/expenseBudget"); | |
const filter = require('lodash/filter'); | |
const data = [ | |
{ | |
"index": 1, | |
"year": 2019, | |
"month": 1, | |
"value": 126685 | |
}, | |
{ | |
"index": 2, | |
"year": 2019, | |
"month": 2, | |
"value": 94523 | |
}, | |
{ | |
"index": 3, | |
"year": 2019, | |
"month": 3, | |
"value": 125739 | |
}, | |
{ | |
"index": 4, | |
"year": 2019, | |
"month": 4, | |
"value": 90005 | |
}, | |
{ | |
"index": 5, | |
"year": 2019, | |
"month": 5, | |
"value": 85358 | |
}, | |
{ | |
"index": 6, | |
"year": 2019, | |
"month": 6, | |
"value": 72301 | |
}, | |
{ | |
"index": 7, | |
"year": 2019, | |
"month": 7, | |
"value": 74212 | |
}, | |
{ | |
"index": 8, | |
"year": 2019, | |
"month": 8, | |
"value": 101509 | |
}, | |
{ | |
"index": 9, | |
"year": 2019, | |
"month": 9, | |
"value": 123775 | |
}, | |
{ | |
"index": 10, | |
"year": 2019, | |
"month": 10, | |
"value": 90618 | |
}, | |
{ | |
"index": 11, | |
"year": 2019, | |
"month": 11, | |
"value": 120466 | |
}, | |
{ | |
"index": 12, | |
"year": 2019, | |
"month": 12, | |
"value": 103106 | |
}, | |
{ | |
"index": 13, | |
"year": 2020, | |
"month": 1, | |
"value": 125462 | |
}, | |
{ | |
"index": 14, | |
"year": 2020, | |
"month": 2, | |
"value": 101352 | |
}, | |
{ | |
"index": 15, | |
"year": 2020, | |
"month": 3, | |
"value": 117452 | |
}, | |
{ | |
"index": 16, | |
"year": 2020, | |
"month": 4, | |
"value": 94485 | |
}, | |
{ | |
"index": 17, | |
"year": 2020, | |
"month": 5, | |
"value": 72011 | |
}, | |
{ | |
"index": 18, | |
"year": 2020, | |
"month": 6, | |
"value": 71593 | |
}, | |
{ | |
"index": 19, | |
"year": 2020, | |
"month": 7, | |
"value": 72727 | |
}, | |
{ | |
"index": 20, | |
"year": 2020, | |
"month": 8, | |
"value": 109282 | |
}, | |
{ | |
"index": 21, | |
"year": 2020, | |
"month": 9, | |
"value": 121578 | |
}, | |
{ | |
"index": 22, | |
"year": 2020, | |
"month": 10, | |
"value": 87681 | |
}, | |
{ | |
"index": 23, | |
"year": 2020, | |
"month": 11, | |
"value": 119796 | |
}, | |
{ | |
"index": 24, | |
"year": 2020, | |
"month": 12, | |
"value": 110655 | |
}, | |
{ | |
"index": 25, | |
"year": 2021, | |
"month": 1, | |
"value": 128485 | |
}, | |
{ | |
"index": 26, | |
"year": 2021, | |
"month": 2, | |
"value": 92287 | |
}, | |
{ | |
"index": 27, | |
"year": 2021, | |
"month": 3, | |
"value": 97496 | |
}, | |
{ | |
"index": 28, | |
"year": 2021, | |
"month": 4, | |
"value": 85621 | |
}, | |
{ | |
"index": 29, | |
"year": 2021, | |
"month": 5, | |
"value": 67673 | |
}, | |
{ | |
"index": 30, | |
"year": 2021, | |
"month": 6, | |
"value": 77523 | |
}, | |
{ | |
"index": 31, | |
"year": 2021, | |
"month": 7, | |
"value": 80592 | |
}, | |
{ | |
"index": 32, | |
"year": 2021, | |
"month": 8, | |
"value": 117984 | |
}, | |
{ | |
"index": 33, | |
"year": 2021, | |
"month": 9, | |
"value": 128594 | |
}, | |
{ | |
"index": 34, | |
"year": 2021, | |
"month": 10, | |
"value": 87350 | |
}, | |
{ | |
"index": 35, | |
"year": 2021, | |
"month": 11, | |
"value": 93832 | |
}, | |
{ | |
"index": 36, | |
"year": 2021, | |
"month": 12, | |
"value": 102065 | |
} | |
]; | |
const compose = (...fns: any[]) => fns.reduce((f, g) => (...args: any[]) => f(g(...args))); | |
const pipe = (...fns: any[]) => compose.apply(compose, fns.reverse()); | |
const toNumber = (percentage: number | string): number => { | |
if (typeof percentage === "string") { | |
percentage = String(parseFloat(percentage) / 100); | |
} else { | |
percentage = String(percentage / 100); | |
} | |
return parseFloat(percentage); | |
}; | |
const fixDecimals = (number: number, decimalCount: number = 11) => parseFloat(String(number)).toFixed(decimalCount); | |
const addVariations = (entities = data) => { | |
return entities.map((entity, index) => { | |
if (index === 0) { | |
return {...entity, variation: 0}; | |
} | |
const previousEntity = entities[index - 1]; | |
const variation = (entity.value - previousEntity.value) / previousEntity.value; | |
const variationPercentage = fixDecimals(variation * 100); | |
return {...entity, variation: parseFloat(variationPercentage)} | |
}); | |
}; | |
const addAverageByMonth = (entities: any) => { | |
return entities.map((entity: any, index: number) => { | |
const month = entity.month; | |
const monthEntities = filter(entities, (entity: any) => entity.month === month && entity.variation); | |
const variationTotal = monthEntities.reduce((total: number, entity: any) => { | |
return total + parseFloat(entity.variation); | |
}, 0); | |
const average = variationTotal === 0 ? 0 : variationTotal / monthEntities.length; | |
return { | |
...entity, | |
average: average, | |
to_projection: parseFloat((String(1 + toNumber(average)))) | |
} | |
}); | |
}; | |
const addProjections = (entities: any) => { | |
const lastEntity = entities[entities.length - 1]; | |
return entities.map((entity: any, index: number) => { | |
// if (entity.month === 1) { | |
// return {...entity, projection: lastEntity.value * entity.to_projection} | |
// } | |
const toProjections = parseFloat(entities.slice(0, entity.month).reduce((total: number, entity: any) => { | |
return total * parseFloat(entity.to_projection); | |
}, 1)); | |
const projection = parseFloat(lastEntity.value) * toProjections; | |
return {...entity, projection: projection} | |
}); | |
}; | |
const addInflation = (inflationPoint: number) => { | |
return (entities: any) => entities.map((entity: any) => { | |
return {...entity, final_value: parseFloat(entity.projection) * (1 + toNumber(inflationPoint))} | |
}); | |
}; | |
const getTotalBudgetedValue = (expenseBudgets: ExpenseBudget[]) => { | |
return expenseBudgets.reduce((total, expenseBudget: ExpenseBudget) => total + (expenseBudget.final_value || 0), 0); | |
} | |
const getTotalExpenseEstimatedValue = (expenseBudgets: ExpenseBudget[]) => { | |
return expenseBudgets.reduce((total, expenseBudget: ExpenseBudget) => total + expenseBudget.value, 0); | |
} | |
const calculateRecurrentIncrementAverage = (expenseBudgets: ExpenseBudget[], annualValue: number) => { | |
const monthlyValue = annualValue / 12; | |
const totalEstimatedValue = getTotalExpenseEstimatedValue(expenseBudgets); | |
const totalBudgetedValue = getTotalBudgetedValue(expenseBudgets); | |
const monthlyRecurrentValue = getMonthlyRecurrentValue(totalEstimatedValue, monthlyValue); | |
return { | |
income_monthly_average: monthlyRecurrentValue, | |
increment_monthly_average: getIncrementByMonth(totalBudgetedValue, monthlyRecurrentValue, monthlyValue) | |
} | |
} | |
/** | |
* Calculate selling budget based on 36 months | |
* | |
* @param annualInflationPoint | |
*/ | |
const calculateFullSellingBudget = (annualInflationPoint = 3.43) => (entities: any) => { | |
const withVariations = addVariations(entities); | |
const withAverages = addAverageByMonth(withVariations); | |
const withProjections = addProjections(withAverages); | |
const withInflation = addInflation(annualInflationPoint)(withProjections); | |
return withInflation; | |
} | |
function getIncrementByMonth(totalBudgetedValue: number, monthlyRecurrentValue: number, monthlyValue: number) { | |
return ((totalBudgetedValue / monthlyRecurrentValue) - monthlyValue) / monthlyValue; | |
} | |
function getMonthlyRecurrentValue(totalExpenseEstimatedValue: number, monthlyValue: number) { | |
return totalExpenseEstimatedValue / monthlyValue; | |
} | |
/** | |
* Calculate selling budget based on expense/income monthly average and how it increments by month | |
* | |
* @param totalExpenseEstimatedValue | |
* @param totalBudgetedValue | |
* @param expenseBudgetAnnualValue | |
* @param now | |
* @param inflationPointPercentage | |
* @returns {{annual_value: *, index: *, final_value: number, monthly_value: *}[]} | |
*/ | |
const calculateSellingBudgetBasedOnIncrements = ( | |
totalExpenseEstimatedValue: number, | |
totalBudgetedValue: number, | |
expenseBudgetAnnualValue: number, | |
now: any, | |
inflationPointPercentage: number | |
) => { | |
const monthlyValue = expenseBudgetAnnualValue / 12; | |
const monthlyRecurrentValue = getMonthlyRecurrentValue(totalExpenseEstimatedValue, monthlyValue); | |
const incrementByMonth = getIncrementByMonth(totalBudgetedValue, monthlyRecurrentValue, monthlyValue); | |
return Array(6) | |
.fill(undefined) | |
.map((item, index) => { | |
const month = now.clone().add(index, 'month'); | |
return { | |
annual_value: expenseBudgetAnnualValue, | |
value: monthlyValue, | |
final_value: monthlyValue * (1 + incrementByMonth), | |
month: month.format('MM'), | |
year: month.format('YYYY'), | |
inflation_point_percentage: inflationPointPercentage | |
}; | |
}); | |
}; | |
/** | |
* Calculate selling budget based on annual inflation and percentage points | |
* | |
* @param totalBudgetedValue | |
* @param inflationPoints | |
* @param percentagePoints | |
* @param now | |
* @returns {{annual_value: *, final_value: number, monthly_value: *}[]} | |
*/ | |
const calculateSellingBudgetBasedOnInflation = ( | |
totalBudgetedValue: number, | |
inflationPoints: number, | |
percentagePoints: number, | |
now: any | |
) => { | |
const monthlyValue = totalBudgetedValue / 12; | |
return Array(6).fill(undefined).map((item, index) => { | |
const month = now.clone().add(index, 'month'); | |
return { | |
value: monthlyValue, | |
final_value: monthlyValue * (1 + toNumber(inflationPoints) + toNumber(percentagePoints)), | |
month: month.format('MM'), | |
year: month.format('YYYY'), | |
inflation_point_percentage: percentagePoints | |
} | |
}); | |
}; | |
export { | |
calculateFullSellingBudget, | |
calculateSellingBudgetBasedOnIncrements, | |
calculateSellingBudgetBasedOnInflation, | |
calculateRecurrentIncrementAverage | |
} | |
// console.log( | |
// JSON.stringify( | |
// calculateSellingBudgetBasedOnInflation( | |
// 1200000, | |
// 3.43, | |
// 4 | |
// ) | |
// ) | |
// ); | |
// console.log( | |
// JSON.stringify( | |
// calculateSellingBudgetBasedOnIncrements( | |
// 17099, | |
// 18027.4757, | |
// 1200000 | |
// ) | |
// ) | |
// ); | |
// | |
// console.log( | |
// JSON.stringify( | |
// calculateFullSellingBudget()(data).slice(0, 2) | |
// ) | |
// ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment