Skip to content

Instantly share code, notes, and snippets.

@LFTroya
Created August 30, 2019 14:29
Show Gist options
  • Save LFTroya/928071ffd0c32280ab07157bb3e50a80 to your computer and use it in GitHub Desktop.
Save LFTroya/928071ffd0c32280ab07157bb3e50a80 to your computer and use it in GitHub Desktop.
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