`;
}
// ────────────────────────────────────────────────────────────────────
// 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 = `
No customer has a credit balance.
`;
return;
}
const total = credits.reduce((s, c) => s + (Number(c.credit) || 0), 0);
el.innerHTML = `
Customer
Credit
${credits.map(c => `
${escapeHtml(c.name)}
${fmtMoney(c.credit)}
`).join('')}
TOTAL (${credits.length} customer${credits.length === 1 ? '' : 's'})
${fmtMoney(total)}
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.
`;
} catch (err) {
console.error('Customer credits load failed:', err);
showError(slot, err.message || 'Failed to load customer credits');
}
}
// ────────────────────────────────────────────────────────────────────
// Register
// ────────────────────────────────────────────────────────────────────
function populateRegisterAccountDropdown(bankCardAccounts) {
const sel = document.getElementById('reg-account');
if (!sel) return;
const current = registerAccountId || sel.value;
sel.innerHTML = `` +
bankCardAccounts.map(a => ``).join('');
if (current && bankCardAccounts.find(a => a.id === current)) sel.value = current;
}
export function injectRegisterControls() {
const c = document.getElementById('accounting-register-controls');
if (!c) return;
if (!registerStartDate) registerStartDate = firstOfMonthISO();
if (!registerEndDate) registerEndDate = todayISO();
c.innerHTML = `
${makeCollapsible('Register', 'register-section-body')}
`;
}
export function selectRegisterAccount(accountId) {
registerAccountId = accountId;
const sel = document.getElementById('reg-account');
if (sel) sel.value = accountId;
loadRegister();
}
export async function loadRegister() {
const sel = document.getElementById('reg-account');
const start = document.getElementById('reg-start');
const end = document.getElementById('reg-end');
if (!sel || !sel.value) {
const slot = document.getElementById('accounting-register-table');
if (slot) slot.innerHTML = `
Select an account to view the register.
`;
return;
}
registerAccountId = sel.value;
registerStartDate = start.value;
registerEndDate = end.value;
const slot = 'accounting-register-table';
showLoading(slot, 'Loading register from QBO…');
const mySeq = ++registerLoadSeq;
try {
const result = await window.API.accounting.getRegister(registerAccountId, registerStartDate, registerEndDate);
if (mySeq !== registerLoadSeq) return;
if (result.error) return showError(slot, result.error);
renderRegisterTable(result);
} catch (err) {
if (mySeq !== registerLoadSeq) return;
console.error('Register load failed:', err);
showError(slot, err.message || 'Failed to load register');
}
}
function renderRegisterTable(result) {
const el = document.getElementById('accounting-register-table');
if (!el) return;
let rows = (result.rows || []).slice().sort((a, b) => (b.date || '').localeCompare(a.date || ''));
const meta = result.meta || {};
if (!rows.length) {
el.innerHTML = `