/**
* Shared financial calculation utilities
* These functions are used by both the FinancialCalculator and Monte Carlo worker
*/
export interface CashFlowConfig {
initialInvestment: number;
monthlyBenefits: number;
timelineMonths: number;
implementationMonths: number;
rampUpMonths: number;
ongoingMonthlyCosts: number;
}
/**
* Calculate Net Present Value (NPV)
* @param cashFlows Array of cash flows (negative for costs, positive for benefits)
* @param discountRate Monthly discount rate (e.g., 0.1/12 for 10% annual)
*/
export function calculateNPV(cashFlows: number[], discountRate: number): number {
return cashFlows.reduce((npv, cashFlow, period) => {
return npv + cashFlow / Math.pow(1 + discountRate, period);
}, 0);
}
/**
* Calculate NPV derivative for IRR calculation
*/
export function calculateNPVDerivative(cashFlows: number[], rate: number): number {
return cashFlows.reduce((derivative, cashFlow, period) => {
if (period === 0) return derivative;
return derivative - (period * cashFlow) / Math.pow(1 + rate, period + 1);
}, 0);
}
/**
* Calculate payback period in months
* Returns the number of months (including fractional part) to recover investment
*/
export function calculatePaybackPeriod(cashFlows: number[]): number {
let cumulativeCashFlow = 0;
for (let period = 0; period < cashFlows.length; period++) {
cumulativeCashFlow += cashFlows[period];
if (cumulativeCashFlow >= 0) {
// Linear interpolation for partial month
if (period === 0) return 0;
const previousCumulative = cumulativeCashFlow - cashFlows[period];
// Avoid division by zero - if cashFlow is 0, no interpolation needed
if (cashFlows[period] === 0) {
return period;
}
const monthFraction = -previousCumulative / cashFlows[period];
return period - 1 + monthFraction;
}
}
return cashFlows.length; // Payback not achieved within timeline
}
/**
* Generate monthly cash flows from costs and benefits
* Handles implementation period and ramp-up period
*/
export function generateCashFlows(config: CashFlowConfig): number[] {
const {
initialInvestment,
monthlyBenefits,
timelineMonths,
implementationMonths,
rampUpMonths,
ongoingMonthlyCosts
} = config;
const cashFlows: number[] = [];
// Initial investment (negative)
cashFlows.push(-initialInvestment);
for (let month = 1; month <= timelineMonths; month++) {
let monthlyFlow = -ongoingMonthlyCosts;
// Benefits start after implementation
if (month > implementationMonths) {
const monthsSinceLaunch = month - implementationMonths;
// Ramp-up period
if (rampUpMonths > 0 && monthsSinceLaunch <= rampUpMonths) {
const rampUpFactor = monthsSinceLaunch / rampUpMonths;
monthlyFlow += monthlyBenefits * rampUpFactor;
} else {
// If rampUpMonths is 0, benefits start at full capacity immediately
monthlyFlow += monthlyBenefits;
}
}
cashFlows.push(monthlyFlow);
}
return cashFlows;
}
/**
* Calculate monthly cash flow for a specific month
* Used by Monte Carlo simulations to generate individual month flows
*/
export function calculateMonthlyFlow(
month: number,
monthlyBenefits: number,
implementationMonths: number,
rampUpMonths: number,
ongoingMonthlyCosts: number
): number {
let monthlyFlow = -ongoingMonthlyCosts;
// Benefits start after implementation
if (month > implementationMonths) {
const monthsSinceLaunch = month - implementationMonths;
// Ramp-up period
if (rampUpMonths > 0 && monthsSinceLaunch <= rampUpMonths) {
const rampUpFactor = monthsSinceLaunch / rampUpMonths;
monthlyFlow += monthlyBenefits * rampUpFactor;
} else {
// If rampUpMonths is 0, benefits start at full capacity immediately
monthlyFlow += monthlyBenefits;
}
}
return monthlyFlow;
}
/**
* Calculate break-even date from start date and payback period
*/
export function calculateBreakEvenDate(
startDate: Date,
paybackPeriodMonths: number
): Date {
const breakEvenDate = new Date(startDate);
breakEvenDate.setMonth(breakEvenDate.getMonth() + Math.floor(paybackPeriodMonths));
// Add remaining days for partial month
const partialMonth = paybackPeriodMonths % 1;
if (partialMonth > 0) {
const daysInMonth = 30; // Approximation
breakEvenDate.setDate(breakEvenDate.getDate() + Math.floor(partialMonth * daysInMonth));
}
return breakEvenDate;
}
/**
* Calculate automation factor based on potential level
*/
export function getAutomationFactor(potential: 'low' | 'medium' | 'high'): number {
switch (potential) {
case 'low': return 0.2;
case 'medium': return 0.5;
case 'high': return 0.8;
}
}
/**
* Financial calculation constants
*/
export const FINANCIAL_CONSTANTS = {
DEFAULT_DISCOUNT_RATE: 0.1 / 12, // 10% annual, converted to monthly
DEFAULT_IMPLEMENTATION_MONTHS: 3,
DEFAULT_RAMP_UP_MONTHS: 3,
DEFAULT_HOURLY_RATE: 50,
DEFAULT_DEVELOPER_HOURLY_RATE: 150,
ERROR_COST_MULTIPLIER: 10, // Errors cost 10x normal transaction
SCALABILITY_PROFIT_MARGIN: 0.2, // 20% profit margin for scalability benefits
DAYS_IN_MONTH: 30, // Approximation for date calculations
FIVE_YEAR_MONTHS: 60,
IMPLEMENTATION_COST_PER_USE_CASE: 50000 // Quick assessment estimate
} as const;