accounting fixes
This commit is contained in:
@@ -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 & 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 & 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>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user