// payment-modal.js — ES Module für das Payment Recording Modal // Fixes: Correct CSS class 'modal', local DB payment storage // ============================================================ // State // ============================================================ let bankAccounts = []; let paymentMethods = []; let selectedInvoices = []; let dataLoaded = false; // ============================================================ // Load QBO Reference Data // ============================================================ async function loadQboData() { if (dataLoaded) return; try { const [accRes, pmRes] = await Promise.all([ fetch('/api/qbo/accounts'), fetch('/api/qbo/payment-methods') ]); if (accRes.ok) bankAccounts = await accRes.json(); if (pmRes.ok) paymentMethods = await pmRes.json(); dataLoaded = true; } catch (error) { console.error('Error loading QBO reference data:', error); } } // ============================================================ // Open / Close // ============================================================ export async function openPaymentModal(invoiceIds = []) { await loadQboData(); selectedInvoices = []; for (const id of invoiceIds) { try { const res = await fetch(`/api/invoices/${id}`); const data = await res.json(); if (data.invoice) { selectedInvoices.push(data.invoice); } } catch (e) { console.error('Error loading invoice:', id, e); } } ensureModalElement(); renderModalContent(); document.getElementById('payment-modal').classList.add('active'); } export function closePaymentModal() { const modal = document.getElementById('payment-modal'); if (modal) modal.classList.remove('active'); selectedInvoices = []; } // ============================================================ // DOM // ============================================================ function ensureModalElement() { let modal = document.getElementById('payment-modal'); if (!modal) { modal = document.createElement('div'); modal.id = 'payment-modal'; // Verwende GLEICHE Klasse wie die existierenden Modals modal.className = 'modal fixed inset-0 bg-black bg-opacity-50 z-50 justify-center items-start pt-10 overflow-y-auto'; document.body.appendChild(modal); } } function renderModalContent() { const modal = document.getElementById('payment-modal'); if (!modal) return; const accountOptions = bankAccounts.map(acc => `` ).join(''); // Zeige Check und ACH bevorzugt, aber alle als Fallback const filteredMethods = paymentMethods.filter(pm => pm.name.toLowerCase().includes('check') || pm.name.toLowerCase().includes('ach') ); const methodsToShow = filteredMethods.length > 0 ? filteredMethods : paymentMethods; const methodOptions = methodsToShow.map(pm => `` ).join(''); const today = new Date().toISOString().split('T')[0]; modal.innerHTML = `

💰 Record Payment

Total Payment: $0.00
`; renderInvoiceList(); updateTotal(); } function renderInvoiceList() { const container = document.getElementById('payment-invoice-list'); if (!container) return; if (selectedInvoices.length === 0) { container.innerHTML = `
Keine Rechnungen ausgewählt
`; return; } container.innerHTML = selectedInvoices.map(inv => `
#${inv.invoice_number || 'Draft'} ${inv.customer_name || ''}
$${parseFloat(inv.total).toFixed(2)}
`).join(''); } function updateTotal() { const totalEl = document.getElementById('payment-total'); if (!totalEl) return; const total = selectedInvoices.reduce((sum, inv) => sum + parseFloat(inv.total), 0); totalEl.textContent = `$${total.toFixed(2)}`; } function removeInvoiceFromPayment(invoiceId) { selectedInvoices = selectedInvoices.filter(inv => inv.id !== invoiceId); renderInvoiceList(); updateTotal(); } // ============================================================ // Submit // ============================================================ async function submitPayment() { if (selectedInvoices.length === 0) return; const paymentDate = document.getElementById('payment-date').value; const reference = document.getElementById('payment-reference').value; const methodSelect = document.getElementById('payment-method'); const depositSelect = document.getElementById('payment-deposit-to'); const methodId = methodSelect.value; const methodName = methodSelect.options[methodSelect.selectedIndex]?.text || ''; const depositToId = depositSelect.value; const depositToName = depositSelect.options[depositSelect.selectedIndex]?.text || ''; if (!paymentDate || !methodId || !depositToId) { alert('Bitte alle Felder ausfüllen.'); return; } const total = selectedInvoices.reduce((sum, inv) => sum + parseFloat(inv.total), 0); const invoiceNums = selectedInvoices.map(i => i.invoice_number || `ID:${i.id}`).join(', '); if (!confirm(`Payment $${total.toFixed(2)} für #${invoiceNums} an QBO senden?`)) return; const submitBtn = document.getElementById('payment-submit-btn'); submitBtn.innerHTML = '⏳ Wird gesendet...'; submitBtn.disabled = true; try { const response = await fetch('/api/qbo/record-payment', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ invoice_ids: selectedInvoices.map(inv => inv.id), payment_date: paymentDate, reference_number: reference, payment_method_id: methodId, payment_method_name: methodName, deposit_to_account_id: depositToId, deposit_to_account_name: depositToName }) }); const result = await response.json(); if (response.ok) { alert(`✅ ${result.message}`); closePaymentModal(); if (window.invoiceView) window.invoiceView.loadInvoices(); } else { alert(`❌ Fehler: ${result.error}`); } } catch (error) { console.error('Payment error:', error); alert('Netzwerkfehler beim Payment.'); } finally { submitBtn.innerHTML = '💰 Record Payment in QBO'; submitBtn.disabled = false; } } // ============================================================ // Expose // ============================================================ window.paymentModal = { open: openPaymentModal, close: closePaymentModal, submit: submitPayment, removeInvoice: removeInvoiceFromPayment };