58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
/**
|
|
* Calculates weighted average payout delay across revenue streams
|
|
*/
|
|
export const usePayoutExposure = () => {
|
|
const calculateWeightedAverageDelay = (
|
|
streams: Array<{ targetMonthlyAmount: number; payoutDelayDays: number }>
|
|
): number => {
|
|
const totalRevenue = streams.reduce((sum, stream) => sum + (stream.targetMonthlyAmount || 0), 0)
|
|
|
|
if (totalRevenue === 0) return 0
|
|
|
|
const weightedSum = streams.reduce((sum, stream) => {
|
|
const weight = (stream.targetMonthlyAmount || 0) / totalRevenue
|
|
return sum + (weight * (stream.payoutDelayDays || 0))
|
|
}, 0)
|
|
|
|
return weightedSum
|
|
}
|
|
|
|
const getPayoutExposureStatus = (avgDelayDays: number, minCashCushion: number): 'green' | 'yellow' | 'red' => {
|
|
// Flag if weighted average >30 days and cushion <1 month
|
|
if (avgDelayDays > 30 && minCashCushion < 8000) return 'red' // Assuming ~8k = 1 month expenses
|
|
if (avgDelayDays > 21) return 'yellow'
|
|
return 'green'
|
|
}
|
|
|
|
const getPayoutExposureMessage = (status: 'green' | 'yellow' | 'red'): string => {
|
|
switch (status) {
|
|
case 'red':
|
|
return 'Money is earned now but arrives later. Delays can create mid-month dips.'
|
|
case 'yellow':
|
|
return 'Some payout delays present. Monitor cash timing.'
|
|
case 'green':
|
|
return 'Payout timing looks manageable.'
|
|
}
|
|
}
|
|
|
|
const analyzePayoutExposure = (
|
|
streams: Array<{ targetMonthlyAmount: number; payoutDelayDays: number }>,
|
|
minCashCushion: number
|
|
) => {
|
|
const avgDelayDays = calculateWeightedAverageDelay(streams)
|
|
const status = getPayoutExposureStatus(avgDelayDays, minCashCushion)
|
|
|
|
return {
|
|
avgDelayDays: Math.round(avgDelayDays),
|
|
status,
|
|
message: getPayoutExposureMessage(status)
|
|
}
|
|
}
|
|
|
|
return {
|
|
calculateWeightedAverageDelay,
|
|
getPayoutExposureStatus,
|
|
getPayoutExposureMessage,
|
|
analyzePayoutExposure
|
|
}
|
|
}
|