/**
* refund-modal.js — Record Vendor Refund
*
* Erzeugt einen QBO Deposit gegen die ursprüngliche Expense-Kategorie.
* Für den Fall: Geld kam tatsächlich zurück aufs Bank-/Kreditkartenkonto.
*/
import '../utils/api.js';
let modalEl = null;
let onSavedCb = null;
let vendors = [];
let expenseAccounts = [];
let paymentAccounts = [];
let selectedVendorId = null;
let selectedVendorName = '';
let isSaving = false;
function todayISO() { return new Date().toISOString().split('T')[0]; }
function escapeHtml(s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&').replace(//g, '>')
.replace(/"/g, '"').replace(/'/g, ''');
}
function escapeAttr(s) {
return String(s || '')
.replace(/&/g, '&').replace(/"/g, '"')
.replace(//g, '>');
}
export async function openRefundModal({ onSaved } = {}) {
onSavedCb = onSaved || null;
selectedVendorId = null;
selectedVendorName = '';
isSaving = false;
try {
[vendors, expenseAccounts, paymentAccounts] = await Promise.all([
window.API.accounting.getVendors('', 1000),
window.API.accounting.getExpenseAccounts(),
window.API.accounting.getPaymentAccounts()
]);
for (const [name, data] of [['vendors', vendors], ['expenseAccounts', expenseAccounts], ['paymentAccounts', paymentAccounts]]) {
if (data && data.error) {
alert(`Failed to load ${name}: ${data.error}\n\nTry "Sync from QBO" first.`);
return;
}
}
} catch (err) {
alert('Failed to load refund modal data: ' + err.message);
return;
}
renderModal();
}
function closeModal() {
if (modalEl) { modalEl.remove(); modalEl = null; }
}
function renderModal() {
closeModal();
const html = `
No vendor found.
`;
} else {
html = filtered.map(v => `
${escapeHtml(v.displayName)}
${v.email ? `
${escapeHtml(v.email)}
` : ''}
`).join('');
}
dropdownEl.innerHTML = html;
dropdownEl.classList.remove('hidden');
if (!dropdownEl._outsideHandlerInstalled) {
dropdownEl._outsideHandlerInstalled = true;
document.addEventListener('click', (e) => {
if (!dropdownEl.contains(e.target) && e.target !== inputEl) {
dropdownEl.classList.add('hidden');
}
});
}
}
function selectVendor(id, name) {
selectedVendorId = id;
selectedVendorName = name;
document.getElementById('ref-vendor-search').value = name;
document.getElementById('ref-vendor-id').value = id;
document.getElementById('ref-vendor-dropdown').classList.add('hidden');
}
async function save() {
if (isSaving) return;
hideError();
if (!selectedVendorId) return showError('Please select a vendor.');
const depositAccountId = document.getElementById('ref-deposit-account').value;
if (!depositAccountId) return showError('Please select the deposit account.');
const categoryAccountId = document.getElementById('ref-category').value;
if (!categoryAccountId) return showError('Please select the original expense category.');
const txnDate = document.getElementById('ref-date').value;
if (!txnDate) return showError('Please enter a date.');
const amount = parseFloat(document.getElementById('ref-amount').value);
if (!isFinite(amount) || amount <= 0) {
return showError('Please enter a positive refund amount.');
}
const payload = {
vendorId: selectedVendorId,
depositAccountId,
categoryAccountId,
txnDate,
amount,
refNo: document.getElementById('ref-ref-no').value.trim() || null,
memo: document.getElementById('ref-memo').value.trim() || null
};
isSaving = true;
const btn = document.getElementById('ref-save-btn');
btn.disabled = true;
btn.textContent = 'Saving…';
try {
const result = await window.API.accounting.createRefund(payload);
if (result.error) {
showError(result.error);
return;
}
if (typeof onSavedCb === 'function') {
try { onSavedCb(result); } catch (e) { console.warn('onSaved cb threw:', e); }
}
closeModal();
} catch (err) {
showError(err.message || 'Save failed');
} finally {
isSaving = false;
if (btn) { btn.disabled = false; btn.textContent = 'Record Refund'; }
}
}
function showError(msg) {
const el = document.getElementById('ref-error');
if (el) { el.textContent = msg; el.classList.remove('hidden'); }
}
function hideError() {
const el = document.getElementById('ref-error');
if (el) el.classList.add('hidden');
}
window.refundModal = {
open: openRefundModal,
close: closeModal,
onVendorInput,
selectVendor,
save
};