Cleanup
This commit is contained in:
parent
fc2d9ed56b
commit
983aeca2dc
32 changed files with 1570 additions and 27266 deletions
101
stores/budget.ts
101
stores/budget.ts
|
|
@ -314,6 +314,67 @@ export const useBudgetStore = defineStore(
|
|||
}
|
||||
}
|
||||
|
||||
// Refresh payroll in budget when policy or operating mode changes
|
||||
function refreshPayrollInBudget() {
|
||||
if (!isInitialized.value) return;
|
||||
|
||||
const coopStore = useCoopBuilderStore();
|
||||
const payrollIndex = budgetWorksheet.value.expenses.findIndex(item => item.id === "expense-payroll");
|
||||
|
||||
if (payrollIndex === -1) return; // No existing payroll entry
|
||||
|
||||
const totalHours = coopStore.members.reduce((sum, m) => sum + (m.hoursPerMonth || 0), 0);
|
||||
const hourlyWage = coopStore.equalHourlyWage || 0;
|
||||
const oncostPct = coopStore.payrollOncostPct || 0;
|
||||
const basePayrollBudget = totalHours * hourlyWage;
|
||||
|
||||
if (basePayrollBudget > 0 && coopStore.members.length > 0) {
|
||||
// Use policy-driven allocation
|
||||
const payPolicy = {
|
||||
relationship: coopStore.policy.relationship,
|
||||
roleBands: coopStore.policy.roleBands
|
||||
};
|
||||
|
||||
const membersForAllocation = coopStore.members.map(m => ({
|
||||
...m,
|
||||
displayName: m.name,
|
||||
monthlyPayPlanned: m.monthlyPayPlanned || 0,
|
||||
minMonthlyNeeds: m.minMonthlyNeeds || 0,
|
||||
targetMonthlyPay: m.targetMonthlyPay || 0,
|
||||
role: m.role || '',
|
||||
hoursPerMonth: m.hoursPerMonth || 0
|
||||
}));
|
||||
|
||||
const allocatedMembers = allocatePayroll(membersForAllocation, payPolicy, basePayrollBudget);
|
||||
|
||||
// Sum with operating mode consideration
|
||||
const totalAllocatedPayroll = allocatedMembers.reduce((sum, m) => {
|
||||
const planned = m.monthlyPayPlanned || 0;
|
||||
if (coopStore.operatingMode === 'min' && m.minMonthlyNeeds) {
|
||||
return sum + Math.min(planned, m.minMonthlyNeeds);
|
||||
}
|
||||
return sum + planned;
|
||||
}, 0);
|
||||
|
||||
const monthlyPayroll = totalAllocatedPayroll * (1 + oncostPct / 100);
|
||||
|
||||
// Update monthly values
|
||||
const today = new Date();
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const date = new Date(today.getFullYear(), today.getMonth() + i, 1);
|
||||
const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
|
||||
budgetWorksheet.value.expenses[payrollIndex].monthlyValues[monthKey] = monthlyPayroll;
|
||||
}
|
||||
|
||||
// Update annual values
|
||||
budgetWorksheet.value.expenses[payrollIndex].values = {
|
||||
year1: { best: monthlyPayroll * 12, worst: monthlyPayroll * 8, mostLikely: monthlyPayroll * 12 },
|
||||
year2: { best: monthlyPayroll * 14, worst: monthlyPayroll * 10, mostLikely: monthlyPayroll * 13 },
|
||||
year3: { best: monthlyPayroll * 16, worst: monthlyPayroll * 12, mostLikely: monthlyPayroll * 15 }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize worksheet from wizard data
|
||||
async function initializeFromWizardData() {
|
||||
if (isInitialized.value && budgetWorksheet.value.revenue.length > 0) {
|
||||
|
|
@ -404,17 +465,48 @@ export const useBudgetStore = defineStore(
|
|||
});
|
||||
});
|
||||
|
||||
// Add payroll from wizard data using the allocatePayroll function
|
||||
// Add payroll from wizard data using the policy-driven allocation system
|
||||
const totalHours = coopStore.members.reduce((sum, m) => sum + (m.hoursPerMonth || 0), 0);
|
||||
const hourlyWage = coopStore.equalHourlyWage || 0;
|
||||
const oncostPct = coopStore.payrollOncostPct || 0;
|
||||
|
||||
// Calculate total payroll budget (before oncosts)
|
||||
// Calculate total payroll budget using policy allocation
|
||||
const basePayrollBudget = totalHours * hourlyWage;
|
||||
|
||||
if (basePayrollBudget > 0 && coopStore.members.length > 0) {
|
||||
// Calculate total with oncosts
|
||||
const monthlyPayroll = basePayrollBudget * (1 + oncostPct / 100);
|
||||
// Use policy-driven allocation to get actual member pay amounts
|
||||
const payPolicy = {
|
||||
relationship: coopStore.policy.relationship,
|
||||
roleBands: coopStore.policy.roleBands
|
||||
};
|
||||
|
||||
// Convert coopStore members to the format expected by allocatePayroll
|
||||
const membersForAllocation = coopStore.members.map(m => ({
|
||||
...m,
|
||||
displayName: m.name,
|
||||
// Ensure all required fields exist
|
||||
monthlyPayPlanned: m.monthlyPayPlanned || 0,
|
||||
minMonthlyNeeds: m.minMonthlyNeeds || 0,
|
||||
targetMonthlyPay: m.targetMonthlyPay || 0,
|
||||
role: m.role || '',
|
||||
hoursPerMonth: m.hoursPerMonth || 0
|
||||
}));
|
||||
|
||||
// Allocate payroll based on policy
|
||||
const allocatedMembers = allocatePayroll(membersForAllocation, payPolicy, basePayrollBudget);
|
||||
|
||||
// Sum the allocated amounts for total payroll, respecting operating mode
|
||||
const totalAllocatedPayroll = allocatedMembers.reduce((sum, m) => {
|
||||
const planned = m.monthlyPayPlanned || 0;
|
||||
// In "minimum" mode, cap at min needs to show a lean runway scenario
|
||||
if (coopStore.operatingMode === 'min' && m.minMonthlyNeeds) {
|
||||
return sum + Math.min(planned, m.minMonthlyNeeds);
|
||||
}
|
||||
return sum + planned;
|
||||
}, 0);
|
||||
|
||||
// Apply oncosts to the policy-allocated total
|
||||
const monthlyPayroll = totalAllocatedPayroll * (1 + oncostPct / 100);
|
||||
|
||||
// Create monthly values for payroll
|
||||
const monthlyValues: Record<string, number> = {};
|
||||
|
|
@ -764,6 +856,7 @@ export const useBudgetStore = defineStore(
|
|||
groupedExpenses,
|
||||
isInitialized,
|
||||
initializeFromWizardData,
|
||||
refreshPayrollInBudget,
|
||||
updateBudgetValue,
|
||||
updateMonthlyValue,
|
||||
addBudgetItem,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue