Fix double-counting: available = total (expenses already debit accounts)
The previous Remaining Budget card subtracted approved expenses from the account balance sum — but postExpenseTransaction already posts negative-amount rows to the ledger, so the balance sum already reflects them. Replaced with: - Available Cash (= sum of account balances) - Allocated (with % progress bar) - Unallocated (cash not assigned to any project) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,12 +9,15 @@
|
||||
const spent = $derived(data.projects.reduce((s, p) => s + parseFloat(p.spent), 0));
|
||||
const total = $derived(parseFloat(data.company.totalBudget));
|
||||
const income = $derived(parseFloat(data.totalIncome ?? '0'));
|
||||
const remaining = $derived(total - spent);
|
||||
const remainingPct = $derived(total > 0 ? (remaining / total) * 100 : 0);
|
||||
// Total already reflects approved expenses (they post negative txns to the ledger),
|
||||
// so available cash IS the total. Spent stays informational.
|
||||
const available = $derived(total);
|
||||
const unallocated = $derived(total - allocated);
|
||||
const allocatedPct = $derived(total > 0 ? (allocated / total) * 100 : 0);
|
||||
const net = $derived(income - spent);
|
||||
const netPositive = $derived(net >= 0);
|
||||
|
||||
const tone = $derived(remaining < 0 ? 'red' : remainingPct < 20 ? 'amber' : 'green');
|
||||
const tone = $derived(available < 0 ? 'red' : available < Math.abs(allocated) * 0.2 ? 'amber' : 'green');
|
||||
|
||||
const toneRing: Record<string, string> = {
|
||||
green: 'border-green-300 dark:border-green-700',
|
||||
@@ -85,36 +88,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Budget KPIs (secondary) -->
|
||||
<!-- Cash KPIs (secondary) -->
|
||||
<div class="grid grid-cols-2 gap-3 lg:grid-cols-3">
|
||||
<div class="rounded-lg border {toneRing[tone]} bg-white p-4 dark:bg-gray-800">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
|
||||
Remaining Budget
|
||||
Available Cash
|
||||
</p>
|
||||
<p class="mt-1 text-2xl font-bold {toneText[tone]}">
|
||||
{formatCurrency(remaining, currency)}
|
||||
{formatCurrency(available, currency)}
|
||||
</p>
|
||||
<div class="mt-2 h-1.5 w-full overflow-hidden rounded-full bg-gray-100 dark:bg-gray-700">
|
||||
<div
|
||||
class="h-full transition-all {toneBar[tone]}"
|
||||
style="width: {Math.max(0, Math.min(remainingPct, 100))}%"
|
||||
></div>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{remainingPct.toFixed(1)}% of total
|
||||
Sum of account balances (base currency)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-700 dark:bg-gray-800">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
|
||||
Total Budget
|
||||
</p>
|
||||
<p class="mt-1 text-2xl font-bold text-gray-900 dark:text-white">
|
||||
{formatCurrency(total, currency)}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">From account balances</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-700 dark:bg-gray-800">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
|
||||
Allocated
|
||||
@@ -122,8 +109,23 @@
|
||||
<p class="mt-1 text-2xl font-bold text-gray-900 dark:text-white">
|
||||
{formatCurrency(allocated, currency)}
|
||||
</p>
|
||||
<div class="mt-2 h-1.5 w-full overflow-hidden rounded-full bg-gray-100 dark:bg-gray-700">
|
||||
<div class="h-full bg-blue-500 transition-all" style="width: {Math.min(allocatedPct, 100)}%"></div>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{total > 0 ? ((allocated / total) * 100).toFixed(1) : '0'}% of total
|
||||
{allocatedPct.toFixed(1)}% of available
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-700 dark:bg-gray-800">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-gray-400 dark:text-gray-500">
|
||||
Unallocated
|
||||
</p>
|
||||
<p class="mt-1 text-2xl font-bold {unallocated < 0 ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-white'}">
|
||||
{formatCurrency(unallocated, currency)}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
Cash not assigned to a project
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user