app/stores/cash.ts

124 lines
3.2 KiB
TypeScript

import { defineStore } from "pinia";
export const useCashStore = defineStore("cash", () => {
// 13-week cash flow events
const cashEvents = ref([]);
// Payment queue - staged payments within policy
const paymentQueue = ref([]);
// Week that first breaches minimum cushion
const firstBreachWeek = ref(null);
// Current cash and savings balances - start empty
const currentCash = ref(0);
const currentSavings = ref(0);
// Computed weekly projections
const weeklyProjections = computed(() => {
const weeks = [];
let runningBalance = currentCash.value;
for (let week = 1; week <= 13; week++) {
const weekEvents = cashEvents.value.filter((e) => e.week === week);
const weekInflow = weekEvents
.filter((e) => e.type === "Influx")
.reduce((sum, e) => sum + e.amount, 0);
const weekOutflow = weekEvents
.filter((e) => e.type === "Outflow")
.reduce((sum, e) => sum + e.amount, 0);
const net = weekInflow - weekOutflow;
runningBalance += net;
weeks.push({
number: week,
inflow: weekInflow,
outflow: weekOutflow,
net,
balance: runningBalance,
cushion: runningBalance, // Will be calculated properly later
breachesCushion: false, // Will be calculated properly later
});
}
return weeks;
});
// Actions
function addCashEvent(event) {
cashEvents.value.push({
id: Date.now().toString(),
date: event.date,
week: event.week,
type: event.type, // Influx|Outflow
amount: event.amount,
sourceRef: event.sourceRef,
policyTag: event.policyTag, // Payroll|Tax|Vendor|SavingsSweep
...event,
});
}
function updateCashEvent(id, updates) {
const event = cashEvents.value.find((e) => e.id === id);
if (event) {
Object.assign(event, updates);
}
}
function removeCashEvent(id) {
const index = cashEvents.value.findIndex((e) => e.id === id);
if (index > -1) {
cashEvents.value.splice(index, 1);
}
}
function addToPaymentQueue(payment) {
paymentQueue.value.push({
id: Date.now().toString(),
amount: payment.amount,
recipient: payment.recipient,
scheduledWeek: payment.scheduledWeek,
priority: payment.priority,
canStage: payment.canStage !== false,
...payment,
});
}
function stagePayment(paymentId, newWeek) {
const payment = paymentQueue.value.find((p) => p.id === paymentId);
if (payment && payment.canStage) {
payment.scheduledWeek = newWeek;
}
}
function updateCurrentBalances(cash, savings) {
currentCash.value = cash;
currentSavings.value = savings;
}
return {
cashEvents: readonly(cashEvents),
paymentQueue: readonly(paymentQueue),
firstBreachWeek: readonly(firstBreachWeek),
currentCash: readonly(currentCash),
currentSavings: readonly(currentSavings),
weeklyProjections,
addCashEvent,
updateCashEvent,
removeCashEvent,
addToPaymentQueue,
stagePayment,
updateCurrentBalances,
};
}, {
persist: {
key: "urgent-tools-cash",
paths: [
"currentCash",
"currentSavings",
"cashEvents",
"paymentQueue"
],
},
});