251 lines
10 KiB
JavaScript
251 lines
10 KiB
JavaScript
'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;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
});
|
|
}
|