feat: add initial application structure with configuration, UI components, and state management
This commit is contained in:
parent
fadf94002c
commit
0af6b17792
56 changed files with 6137 additions and 129 deletions
58
composables/usePayoutExposure.ts
Normal file
58
composables/usePayoutExposure.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue