'use strict'; // ── Netto-Neuberechnung bei verknüpfter Bankbuchung ───────────── (function () { const form = document.getElementById('buchung_form'); if (!form || form.dataset.bankTxBrutto === undefined) return; const brutto = parseFloat(form.dataset.bankTxBrutto) || 0; let manualNetto = false; const nettoInput = document.getElementById('betrag_netto_input'); const ustSelect = document.getElementById('ust_satz_select'); // Netto aus Brutto bei USt-Wechsel neu berechnen (solange nicht manuell geändert) function recalcNetto() { if (manualNetto || !brutto) return; if (typeof getBetragModus === 'function' && getBetragModus() !== 'netto') return; const ust = parseFloat(ustSelect.value) / 100; const netto = Math.round(brutto / (1 + ust) * 100) / 100; nettoInput.value = netto.toFixed(2); if (typeof updateNettoAnzeige === 'function') updateNettoAnzeige(); } nettoInput.addEventListener('input', function () { manualNetto = true; }); ustSelect.addEventListener('change', recalcNetto); const _origAutoUst = updateAutoUst; window.updateAutoUst = function () { _origAutoUst.apply(this, arguments); recalcNetto(); }; // Zahlungskonto 1200 vorauswählen const zkSelect = document.getElementById('zahlungskonto_id'); if (zkSelect) { for (const opt of zkSelect.options) { if ((opt.dataset.search || '').startsWith('1200 ')) { opt.selected = true; zkSelect.dispatchEvent(new Event('change')); break; } } } // Meta-Formular mit Lieferant aufklappen wenn noch nicht gespeichert if (form.dataset.openMetaForm) { const metaForm = document.getElementById('beleg-meta-form'); if (metaForm) metaForm.style.display = 'block'; } })(); function filterKategorieKonten(buchungstyp) { const select = document.getElementById('kategorie_konto_id'); const groups = select.querySelectorAll('optgroup'); const zielArt = buchungstyp === 'Einnahme' ? 'Betriebseinnahme' : 'Betriebsausgabe'; groups.forEach(function(g) { const art = g.getAttribute('data-kontenart'); if (!art) return; // Privat, Verbindlichkeit und Anlagevermögen immer anzeigen, Kategorie nach Typ filtern g.style.display = (art === zielArt || art === 'Privat' || art === 'Verbindlichkeit' || art === 'Anlagevermögen') ? '' : 'none'; }); // Auswahl zurücksetzen wenn aktuell gewähltes Konto nicht mehr sichtbar if (select.selectedIndex > 0) { const selected = select.options[select.selectedIndex]; if (selected && selected.closest('optgroup') && selected.closest('optgroup').style.display === 'none') { select.selectedIndex = 0; } } updateEigenanteilState(); } function updateAutoUst() { const kategorieEl = document.getElementById('kategorie_konto_id'); const ustSatzEl = document.getElementById('ust_satz_select'); if (!kategorieEl || !ustSatzEl) return; const selectedOpt = kategorieEl.options[kategorieEl.selectedIndex]; const steuercode = selectedOpt ? (selectedOpt.getAttribute('data-steuercode') || '') : ''; const kontonummer = selectedOpt ? (selectedOpt.getAttribute('data-kontonummer') || '') : ''; const ustMap = { 'VSt19': '19', 'USt19': '19', 'VSt7': '7', 'USt7': '7' }; // 4652/4657 immer 0 % (keine Vorsteuer bei pauschalen Bewirtungskosten ohne USt-Ausweis) const autoUst = (['4652','4657'].includes(kontonummer)) ? '0' : (ustMap[steuercode] || null); const hiddenEl = document.getElementById('ust_satz_hidden'); if (autoUst !== null) { ustSatzEl.value = autoUst; if (hiddenEl) hiddenEl.value = autoUst; } ustSatzEl.disabled = false; ustSatzEl.title = ''; if (hiddenEl && autoUst === null) hiddenEl.value = ustSatzEl.value; updateSteuerartVisibility(); updateNettoAnzeige(); } function updateBewirtungsState() { const kategorieEl = document.getElementById('kategorie_konto_id'); const felder = document.getElementById('bewirtungsfelder'); if (!kategorieEl || !felder) return; const selectedOpt = kategorieEl.options[kategorieEl.selectedIndex]; const kontonummer = selectedOpt ? (selectedOpt.getAttribute('data-kontonummer') || '') : ''; const istBewirtung = ['4650','4651','4652'].includes(kontonummer); felder.style.display = istBewirtung ? '' : 'none'; const grundEl = document.getElementById('bewirtungsgrund_input'); const teilnEl = document.getElementById('teilnehmerliste_input'); if (grundEl) grundEl.required = istBewirtung; if (teilnEl) teilnEl.required = istBewirtung; } function updateEigenanteilState() { const group = document.getElementById('eigenanteil_group'); const cb = document.getElementById('eigenanteil_30_cb'); if (!group || !cb) return; const buchungstyp = document.querySelector('input[name="buchungstyp"]:checked'); const kategorieEl = document.getElementById('kategorie_konto_id'); const ustSatzEl = document.getElementById('ust_satz_select'); const istAusgabe = buchungstyp && buchungstyp.value === 'Ausgabe'; const selectedOpt = kategorieEl && kategorieEl.options[kategorieEl.selectedIndex]; const kontonummer = selectedOpt ? (selectedOpt.getAttribute('data-search') || '').split(' ')[0] : ''; const istTelInternet = kontonummer === '4920' || kontonummer === '4925'; const ist19 = ustSatzEl && ustSatzEl.value === '19'; const aktiv = istAusgabe && istTelInternet && ist19; group.style.opacity = aktiv ? '1' : '.35'; group.style.pointerEvents = aktiv ? '' : 'none'; group.style.cursor = aktiv ? 'pointer' : 'not-allowed'; cb.disabled = !aktiv; if (!aktiv) cb.checked = false; } // ── Info-Bar: Zuschneiden-Button, Metadaten-Formular ein-/ausblenden ── const _cropOpenBtn = document.getElementById('beleg-crop-open-btn'); if (_cropOpenBtn) _cropOpenBtn.addEventListener('click', function () { openCropModal(); }); const _metaToggleBtn = document.getElementById('beleg-meta-toggle-btn'); if (_metaToggleBtn) { _metaToggleBtn.addEventListener('click', function () { const metaForm = document.getElementById('beleg-meta-form'); if (metaForm) metaForm.style.display = metaForm.style.display === 'none' ? 'block' : 'none'; }); } const _metaCancelBtn = document.getElementById('beleg-meta-cancel-btn'); if (_metaCancelBtn) { _metaCancelBtn.addEventListener('click', function () { const metaForm = document.getElementById('beleg-meta-form'); if (metaForm) metaForm.style.display = 'none'; }); } // ── Inline-Handler der Buchungszeile: zentrale Listener statt onchange/onclick/oninput ── document.querySelectorAll('input[name="buchungstyp"]').forEach(function (radio) { radio.addEventListener('change', function () { filterKategorieKonten(this.value); }); }); const _ustSatzSelect = document.getElementById('ust_satz_select'); if (_ustSatzSelect) { _ustSatzSelect.addEventListener('change', function () { updateSteuerartVisibility(); updateNettoAnzeige(); const hidden = document.getElementById('ust_satz_hidden'); if (hidden) hidden.value = this.value; }); } const _kategorieKontoSelect = document.getElementById('kategorie_konto_id'); if (_kategorieKontoSelect) { _kategorieKontoSelect.addEventListener('change', function () { showKontoArt('kategorie_konto_id', 'kategorie_konto_art', this); updateEigenanteilState(); updateBewirtungsState(); updateAutoUst(); checkAnlagevermoegen(); }); } const _zahlungskontoSelect = document.getElementById('zahlungskonto_id'); if (_zahlungskontoSelect) { _zahlungskontoSelect.addEventListener('change', function () { showKontoArt('zahlungskonto_id', 'zahlungskonto_art', this); }); } const _betragModusNettoBtn = document.getElementById('betrag_modus_netto_btn'); const _betragModusBruttoBtn = document.getElementById('betrag_modus_brutto_btn'); if (_betragModusNettoBtn) _betragModusNettoBtn.addEventListener('click', function () { setBetragModus('netto'); }); if (_betragModusBruttoBtn) _betragModusBruttoBtn.addEventListener('click', function () { setBetragModus('brutto'); }); const _betragNettoInput = document.getElementById('betrag_netto_input'); if (_betragNettoInput) _betragNettoInput.addEventListener('input', updateNettoAnzeige); // Initial filtern document.addEventListener('DOMContentLoaded', function() { const checked = document.querySelector('input[name="buchungstyp"]:checked'); if (checked) filterKategorieKonten(checked.value); updateSteuerartVisibility(); updateEigenanteilState(); updateBewirtungsState(); updateAutoUst(); updateNettoAnzeige(); // Leeres Lieferantenfeld fokussieren wenn kein KI-Block aktiv const sup = document.getElementById('supplier-persistent-input'); if (sup && !document.getElementById('ki-badge')) sup.focus(); }); function updateSteuerartVisibility() { const ustSatz = document.getElementById('ust_satz_select'); const steuerartGroup = document.getElementById('steuerart_group'); const steuerartSelect = document.getElementById('steuerart_select'); if (!ustSatz || !steuerartGroup) return; if (ustSatz.value === '0') { steuerartGroup.style.display = ''; } else { steuerartGroup.style.display = 'none'; if (steuerartSelect) steuerartSelect.value = 'normal'; } updateEigenanteilState(); } // ── Netto/Brutto-Eingabemodus ────────────────────────────────── // Solange Modus "netto" ist, entspricht der Feldwert dem Nettobetrag (wie bisher). // Im Modus "brutto" wird der eingegebene Wert als Bruttobetrag interpretiert; // vor dem Absenden wird er in den tatsächlichen Nettobetrag umgerechnet (siehe Submit-Handler unten). let _betragModus = 'netto'; function getBetragModus() { return _betragModus; } function setBetragModus(modus) { if (modus === _betragModus) return; const input = document.getElementById('betrag_netto_input'); const ustEl = document.getElementById('ust_satz_select'); const ustSatz = ustEl ? (parseFloat(ustEl.value) || 0) : 0; const alt = parseFloat(input.value); if (!isNaN(alt)) { const neu = (modus === 'brutto') ? Math.round(alt * (1 + ustSatz / 100) * 100) / 100 // Netto → Brutto : Math.round(alt / (1 + ustSatz / 100) * 100) / 100; // Brutto → Netto input.value = neu.toFixed(2); } _betragModus = modus; const nettoBtn = document.getElementById('betrag_modus_netto_btn'); const bruttoBtn = document.getElementById('betrag_modus_brutto_btn'); nettoBtn.classList.toggle('active', modus === 'netto'); nettoBtn.setAttribute('aria-pressed', modus === 'netto' ? 'true' : 'false'); bruttoBtn.classList.toggle('active', modus === 'brutto'); bruttoBtn.setAttribute('aria-pressed', modus === 'brutto' ? 'true' : 'false'); updateNettoAnzeige(); } // Übernimmt einen Netto-Betrag (z.B. aus KI-Vorschlag) und schaltet dafür in den Netto-Modus zurück. function setBetragNettoWert(wert) { if (_betragModus !== 'netto') setBetragModus('netto'); const input = document.getElementById('betrag_netto_input'); input.value = wert; updateNettoAnzeige(); } function updateNettoAnzeige() { const eingabeEl = document.getElementById('betrag_netto_input'); const ustEl = document.getElementById('ust_satz_select'); const anzeige = document.getElementById('ust_brutto_anzeige'); if (!eingabeEl || !ustEl || !anzeige) return; const eingabe = parseFloat(eingabeEl.value); if (isNaN(eingabe) || eingabeEl.value === '') { anzeige.textContent = ''; return; } const ustSatz = parseFloat(ustEl.value) || 0; const fmt = v => v.toLocaleString('de-DE', {minimumFractionDigits: 2, maximumFractionDigits: 2}) + ' €'; if (_betragModus === 'brutto') { const netto = Math.round(eingabe / (1 + ustSatz / 100) * 100) / 100; const ust = Math.round((eingabe - netto) * 100) / 100; anzeige.innerHTML = 'Netto ' + fmt(netto) + '  ·  USt. ' + fmt(ust); } else { const ust = Math.round(eingabe * ustSatz / 100 * 100) / 100; const brutto = Math.round((eingabe + ust) * 100) / 100; anzeige.innerHTML = 'USt. ' + fmt(ust) + '  ·  Brutto ' + fmt(brutto); } } // Vor dem Absenden: Im Brutto-Modus enthält das Feld einen Bruttobetrag, // das Backend erwartet aber immer den Nettobetrag (Feldname betrag_netto). const _buchungFormEl = document.getElementById('buchung_form'); if (_buchungFormEl) { _buchungFormEl.addEventListener('submit', function () { if (_betragModus !== 'brutto') return; const input = document.getElementById('betrag_netto_input'); const ustEl = document.getElementById('ust_satz_select'); const ustSatz = ustEl ? (parseFloat(ustEl.value) || 0) : 0; const brutto = parseFloat(input.value); if (!isNaN(brutto)) { input.value = (Math.round(brutto / (1 + ustSatz / 100) * 100) / 100).toFixed(2); } }); }