guthaben
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user