accounting fixes

This commit is contained in:
2026-05-20 13:45:43 -05:00
parent 82bc055c4c
commit b4661bb3b6

View File

@@ -84,7 +84,25 @@ function showLoading(slotId, message = 'Loading…') {
<span>${escapeHtml(message)}</span> <span>${escapeHtml(message)}</span>
</div>`; </div>`;
} }
function makeCollapsible(headerText, contentId, startCollapsed = false) {
return `
<div class="flex items-center gap-2 cursor-pointer select-none mb-2"
onclick="window.accountingView.toggleSection('${contentId}', this)">
<svg class="w-4 h-4 text-gray-500 transition-transform ${startCollapsed ? '' : 'rotate-90'}"
fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<h3 class="text-base font-semibold text-gray-800">${escapeHtml(headerText)}</h3>
</div>`;
}
export function toggleSection(contentId, headerEl) {
const content = document.getElementById(contentId);
if (!content) return;
const isHidden = content.classList.toggle('hidden');
const arrow = headerEl.querySelector('svg');
if (arrow) arrow.classList.toggle('rotate-90', !isHidden);
}
// ──────────────────────────────────────────────────────────────────── // ────────────────────────────────────────────────────────────────────
// Toolbar // Toolbar
// ──────────────────────────────────────────────────────────────────── // ────────────────────────────────────────────────────────────────────
@@ -243,27 +261,30 @@ export function injectRegisterControls() {
if (!registerEndDate) registerEndDate = todayISO(); if (!registerEndDate) registerEndDate = todayISO();
c.innerHTML = ` c.innerHTML = `
<div class="flex flex-wrap items-end gap-3 mb-3 p-4 bg-white rounded-lg shadow-sm border border-gray-200"> ${makeCollapsible('Register', 'register-section-body')}
<div> <div id="register-section-body">
<label class="block text-xs font-medium text-gray-700 mb-1">Account</label> <div class="flex flex-wrap items-end gap-3 mb-3 p-4 bg-white rounded-lg shadow-sm border border-gray-200">
<select id="reg-account" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm w-72"> <div>
<option value="">— Loading accounts —</option> <label class="block text-xs font-medium text-gray-700 mb-1">Account</label>
</select> <select id="reg-account" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm w-72">
<option value="">— Loading accounts —</option>
</select>
</div>
<div>
<label class="block text-xs font-medium text-gray-700 mb-1">Start Date</label>
<input type="date" id="reg-start" value="${registerStartDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-700 mb-1">End Date</label>
<input type="date" id="reg-end" value="${registerEndDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm">
</div>
<button onclick="window.accountingView.loadRegister()"
class="px-4 py-1.5 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700">
Load Register
</button>
</div> </div>
<div> <div id="accounting-register-table"></div>
<label class="block text-xs font-medium text-gray-700 mb-1">Start Date</label> </div>`;
<input type="date" id="reg-start" value="${registerStartDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-700 mb-1">End Date</label>
<input type="date" id="reg-end" value="${registerEndDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm">
</div>
<button onclick="window.accountingView.loadRegister()"
class="px-4 py-1.5 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700">
Load Register
</button>
</div>
<div id="accounting-register-table"></div>`;
} }
export function selectRegisterAccount(accountId) { export function selectRegisterAccount(accountId) {
@@ -366,7 +387,16 @@ function renderRegisterRow(r) {
} }
function renderSplitCell(r) { function renderSplitCell(r) {
if (!r.splits || !r.splits.length) return `<span class="text-gray-500 italic">-Split-</span>`; if (!r.splits || !r.splits.length) {
const type = (r.type || '').toLowerCase();
if (type.includes('tax payment')) {
return `<span class="text-gray-500 italic" title="Sales Tax remittance — see Memo for period">-Split- (Sales Tax)</span>`;
}
if (type.includes('paycheck') || type.includes('payroll')) {
return `<span class="text-gray-500 italic" title="Payroll transaction">-Split- (Payroll)</span>`;
}
return `<span class="text-gray-500 italic">-Split-</span>`;
}
const lines = r.splits.map(s => ` const lines = r.splits.map(s => `
<div class="flex justify-between gap-3 text-xs"> <div class="flex justify-between gap-3 text-xs">
<span class="text-gray-700">${escapeHtml(s.account || '?')}</span> <span class="text-gray-700">${escapeHtml(s.account || '?')}</span>
@@ -387,39 +417,42 @@ export function injectReportsControls() {
if (!bsAsOfDate) bsAsOfDate = todayISO(); if (!bsAsOfDate) bsAsOfDate = todayISO();
c.innerHTML = ` c.innerHTML = `
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4"> ${makeCollapsible('Reports', 'reports-section-body')}
<div class="bg-white rounded-lg shadow-sm border border-gray-200"> <div id="reports-section-body">
<div class="px-4 py-3 border-b bg-gray-50"><h3 class="font-semibold text-gray-800">Profit &amp; Loss</h3></div> <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
<div class="p-4"> <div class="bg-white rounded-lg shadow-sm border border-gray-200">
<div class="flex flex-wrap items-end gap-3 mb-3"> <div class="px-4 py-3 border-b bg-gray-50"><h3 class="font-semibold text-gray-800">Profit &amp; Loss</h3></div>
<div><label class="block text-xs font-medium text-gray-700 mb-1">Start</label> <div class="p-4">
<input type="date" id="pl-start" value="${plStartDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"></div> <div class="flex flex-wrap items-end gap-3 mb-3">
<div><label class="block text-xs font-medium text-gray-700 mb-1">End</label> <div><label class="block text-xs font-medium text-gray-700 mb-1">Start</label>
<input type="date" id="pl-end" value="${plEndDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"></div> <input type="date" id="pl-start" value="${plStartDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"></div>
<div><label class="block text-xs font-medium text-gray-700 mb-1">Method</label> <div><label class="block text-xs font-medium text-gray-700 mb-1">End</label>
<select id="pl-method" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"> <input type="date" id="pl-end" value="${plEndDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"></div>
<option value="Accrual" ${plAccountingMethod === 'Accrual' ? 'selected' : ''}>Accrual</option> <div><label class="block text-xs font-medium text-gray-700 mb-1">Method</label>
<option value="Cash" ${plAccountingMethod === 'Cash' ? 'selected' : ''}>Cash</option> <select id="pl-method" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm">
</select></div> <option value="Accrual" ${plAccountingMethod === 'Accrual' ? 'selected' : ''}>Accrual</option>
<button onclick="window.accountingView.loadProfitLoss()" class="px-3 py-1.5 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700">Run</button> <option value="Cash" ${plAccountingMethod === 'Cash' ? 'selected' : ''}>Cash</option>
</select></div>
<button onclick="window.accountingView.loadProfitLoss()" class="px-3 py-1.5 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700">Run</button>
</div>
<div id="pl-result"></div>
</div> </div>
<div id="pl-result"></div>
</div> </div>
</div> <div class="bg-white rounded-lg shadow-sm border border-gray-200">
<div class="bg-white rounded-lg shadow-sm border border-gray-200"> <div class="px-4 py-3 border-b bg-gray-50"><h3 class="font-semibold text-gray-800">Balance Sheet</h3></div>
<div class="px-4 py-3 border-b bg-gray-50"><h3 class="font-semibold text-gray-800">Balance Sheet</h3></div> <div class="p-4">
<div class="p-4"> <div class="flex flex-wrap items-end gap-3 mb-3">
<div class="flex flex-wrap items-end gap-3 mb-3"> <div><label class="block text-xs font-medium text-gray-700 mb-1">As of</label>
<div><label class="block text-xs font-medium text-gray-700 mb-1">As of</label> <input type="date" id="bs-asof" value="${bsAsOfDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"></div>
<input type="date" id="bs-asof" value="${bsAsOfDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"></div> <div><label class="block text-xs font-medium text-gray-700 mb-1">Method</label>
<div><label class="block text-xs font-medium text-gray-700 mb-1">Method</label> <select id="bs-method" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm">
<select id="bs-method" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"> <option value="Accrual" ${bsAccountingMethod === 'Accrual' ? 'selected' : ''}>Accrual</option>
<option value="Accrual" ${bsAccountingMethod === 'Accrual' ? 'selected' : ''}>Accrual</option> <option value="Cash" ${bsAccountingMethod === 'Cash' ? 'selected' : ''}>Cash</option>
<option value="Cash" ${bsAccountingMethod === 'Cash' ? 'selected' : ''}>Cash</option> </select></div>
</select></div> <button onclick="window.accountingView.loadBalanceSheet()" class="px-3 py-1.5 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700">Run</button>
<button onclick="window.accountingView.loadBalanceSheet()" class="px-3 py-1.5 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700">Run</button> </div>
<div id="bs-result"></div>
</div> </div>
<div id="bs-result"></div>
</div> </div>
</div> </div>
</div>`; </div>`;
@@ -514,33 +547,36 @@ export function injectExpensesSection() {
if (!expEndDate) expEndDate = todayISO(); if (!expEndDate) expEndDate = todayISO();
c.innerHTML = ` c.innerHTML = `
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden"> ${makeCollapsible('Expenses', 'expenses-section-body')}
<div class="px-4 py-3 border-b bg-gray-50 flex flex-wrap items-end gap-3"> <div id="expenses-section-body">
<div> <div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
<label class="block text-xs font-medium text-gray-700 mb-1">Start</label> <div class="px-4 py-3 border-b bg-gray-50 flex flex-wrap items-end gap-3">
<input type="date" id="exp-start" value="${expStartDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"> <div>
</div> <label class="block text-xs font-medium text-gray-700 mb-1">Start</label>
<div> <input type="date" id="exp-start" value="${expStartDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm">
<label class="block text-xs font-medium text-gray-700 mb-1">End</label> </div>
<input type="date" id="exp-end" value="${expEndDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm"> <div>
</div> <label class="block text-xs font-medium text-gray-700 mb-1">End</label>
<div class="flex items-center gap-2 pt-5"> <input type="date" id="exp-end" value="${expEndDate}" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm">
<input type="checkbox" id="exp-only-mine" ${expOnlyMine ? 'checked' : ''} </div>
class="h-4 w-4 text-blue-600 border-gray-300 rounded"> <div class="flex items-center gap-2 pt-5">
<label for="exp-only-mine" class="text-sm text-gray-700" title="Only show expenses created from this app">Only mine</label> <input type="checkbox" id="exp-only-mine" ${expOnlyMine ? 'checked' : ''}
</div> class="h-4 w-4 text-blue-600 border-gray-300 rounded">
<button onclick="window.accountingView.loadExpenses()" <label for="exp-only-mine" class="text-sm text-gray-700" title="Only show expenses created from this app">Only mine</label>
class="px-3 py-1.5 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700"> </div>
Load <button onclick="window.accountingView.loadExpenses()"
</button> class="px-3 py-1.5 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700">
<div class="ml-auto"> Load
<button onclick="window.accountingView.openNewExpense()"
class="px-4 py-1.5 bg-green-600 text-white rounded-md text-sm font-semibold hover:bg-green-700">
+ New Expense
</button> </button>
<div class="ml-auto">
<button onclick="window.accountingView.openNewExpense()"
class="px-4 py-1.5 bg-green-600 text-white rounded-md text-sm font-semibold hover:bg-green-700">
+ New Expense
</button>
</div>
</div> </div>
<div id="accounting-expenses-table"></div>
</div> </div>
<div id="accounting-expenses-table"></div>
</div>`; </div>`;
} }