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
89
composables/useDeferredMetrics.ts
Normal file
89
composables/useDeferredMetrics.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* Calculates deferred balance and ratio vs monthly payroll
|
||||
* Formula: total deferred wage liability ÷ one month of payroll
|
||||
*/
|
||||
export const useDeferredMetrics = () => {
|
||||
const calculateDeferredBalance = (
|
||||
members: Array<{ deferredHours: number }>,
|
||||
hourlyWage: number
|
||||
): number => {
|
||||
const totalDeferredHours = members.reduce((sum, member) => sum + (member.deferredHours || 0), 0)
|
||||
return totalDeferredHours * hourlyWage
|
||||
}
|
||||
|
||||
const calculateMonthlyPayroll = (
|
||||
members: Array<{ targetHours: number }>,
|
||||
hourlyWage: number,
|
||||
oncostPct: number
|
||||
): number => {
|
||||
const totalTargetHours = members.reduce((sum, member) => sum + (member.targetHours || 0), 0)
|
||||
const grossPayroll = totalTargetHours * hourlyWage
|
||||
return grossPayroll * (1 + oncostPct / 100)
|
||||
}
|
||||
|
||||
const calculateDeferredRatio = (
|
||||
deferredBalance: number,
|
||||
monthlyPayroll: number
|
||||
): number => {
|
||||
if (monthlyPayroll <= 0) return 0
|
||||
return deferredBalance / monthlyPayroll
|
||||
}
|
||||
|
||||
const getDeferredRatioStatus = (ratio: number): 'green' | 'yellow' | 'red' => {
|
||||
if (ratio > 1.5) return 'red' // Flag red if >1.5× monthly payroll
|
||||
if (ratio > 1.0) return 'yellow'
|
||||
return 'green'
|
||||
}
|
||||
|
||||
const getDeferredRatioMessage = (status: 'green' | 'yellow' | 'red'): string => {
|
||||
switch (status) {
|
||||
case 'red':
|
||||
return 'Deferred balance is high. Consider repaying or reducing scope.'
|
||||
case 'yellow':
|
||||
return 'Deferred balance is building up. Monitor closely.'
|
||||
case 'green':
|
||||
return 'Deferred balance is manageable.'
|
||||
}
|
||||
}
|
||||
|
||||
const checkDeferredCap = (
|
||||
memberHours: number,
|
||||
capHoursPerQtr: number,
|
||||
quarterProgress: number
|
||||
): { withinCap: boolean; remainingHours: number } => {
|
||||
const quarterlyLimit = capHoursPerQtr * quarterProgress
|
||||
const withinCap = memberHours <= quarterlyLimit
|
||||
const remainingHours = Math.max(0, quarterlyLimit - memberHours)
|
||||
|
||||
return { withinCap, remainingHours }
|
||||
}
|
||||
|
||||
const analyzeDeferredMetrics = (
|
||||
members: Array<{ deferredHours?: number; targetHours?: number }>,
|
||||
hourlyWage: number,
|
||||
oncostPct: number
|
||||
) => {
|
||||
const deferredBalance = calculateDeferredBalance(members, hourlyWage)
|
||||
const monthlyPayroll = calculateMonthlyPayroll(members, hourlyWage, oncostPct)
|
||||
const ratio = calculateDeferredRatio(deferredBalance, monthlyPayroll)
|
||||
const status = getDeferredRatioStatus(ratio)
|
||||
|
||||
return {
|
||||
deferredBalance,
|
||||
monthlyPayroll,
|
||||
ratio: Number(ratio.toFixed(2)),
|
||||
status,
|
||||
message: getDeferredRatioMessage(status)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
calculateDeferredBalance,
|
||||
calculateMonthlyPayroll,
|
||||
calculateDeferredRatio,
|
||||
getDeferredRatioStatus,
|
||||
getDeferredRatioMessage,
|
||||
checkDeferredCap,
|
||||
analyzeDeferredMetrics
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue