This commit is contained in:
2026-08-19 19:18:45 +02:00
parent f8b0d52ff7
commit b644253e0b
9 changed files with 379 additions and 20 deletions

View File

@@ -188,6 +188,62 @@ function renderAccountCard(a) {
</div>`;
}
// ────────────────────────────────────────────────────────────────────
// Customer Credits
//
// Kunden mit negativem A/R-Saldo in QBO — typischerweise Doppelzahlungen, die
// im Banking-Screen als Einzahlung auf Accounts Receivable aufgelöst wurden.
// Führend ist QBO; die App hält dazu keinen eigenen Bestand.
// ────────────────────────────────────────────────────────────────────
export async function loadCustomerCredits() {
const slot = 'accounting-credits';
showLoading(slot, 'Loading customer credits from QBO…');
try {
const credits = await window.API.accounting.getCustomerCredits();
if (credits.error) return showError(slot, credits.error);
const el = document.getElementById(slot);
if (!credits.length) {
el.innerHTML = `<div class="p-4 bg-gray-50 border border-gray-200 rounded-lg text-gray-600 text-sm">No customer has a credit balance.</div>`;
return;
}
const total = credits.reduce((s, c) => s + (Number(c.credit) || 0), 0);
el.innerHTML = `
<div class="overflow-x-auto border border-gray-200 rounded-lg bg-white">
<table class="min-w-full text-sm">
<thead class="bg-gray-50">
<tr>
<th class="px-3 py-2 text-left font-medium text-gray-700">Customer</th>
<th class="px-3 py-2 text-right font-medium text-gray-700">Credit</th>
</tr>
</thead>
<tbody>
${credits.map(c => `
<tr class="border-t">
<td class="px-3 py-2">${escapeHtml(c.name)}</td>
<td class="px-3 py-2 text-right font-semibold text-green-700">${fmtMoney(c.credit)}</td>
</tr>`).join('')}
<tr class="border-t-2 border-gray-300 bg-gray-50 font-semibold">
<td class="px-3 py-2">TOTAL (${credits.length} customer${credits.length === 1 ? '' : 's'})</td>
<td class="px-3 py-2 text-right">${fmtMoney(total)}</td>
</tr>
</tbody>
</table>
</div>
<p class="mt-2 text-xs text-gray-500">
Net A/R balance from QBO. A customer with a credit and open invoices at the same time
nets out and is not listed here. Apply a credit in QBO when receiving payment, then run
Sync payments.
</p>`;
} catch (err) {
console.error('Customer credits load failed:', err);
showError(slot, err.message || 'Failed to load customer credits');
}
}
// ────────────────────────────────────────────────────────────────────
// Register
// ────────────────────────────────────────────────────────────────────
@@ -500,11 +556,13 @@ export function renderAccountingView() {
maybeAutoSyncCaches().then(() => {
loadAccountsOverview();
loadCustomerCredits();
});
}
export function refreshAll() {
loadAccountsOverview();
loadCustomerCredits();
if (registerAccountId) loadRegister();
}
export async function editExpense(expenseJson) {
@@ -533,6 +591,7 @@ window.accountingView = {
refreshAll,
manualSync,
loadAccountsOverview,
loadCustomerCredits,
loadRegister,
loadExpenses,
openNewExpense,