/* Buchungsmaske: Restbetrag der Splitzeilen mitrechnen und direkte Zuordnung * und Splitbuchung gegeneinander sperren. * * Solange Splitzeilen befüllt sind, aber noch ein Restbetrag zum * Buchungswert offen ist, bleibt „Speichern“ gesperrt – das Model wiese die * Buchung sonst ohnehin ab, hier spart es die Rundreise zum Server. * * Nur Komfort – die Maske kommt fertig vom Server. Ohne JavaScript bleibt alles * bedienbar: Die Splitsumme prüft ohnehin das Model. * * Eine Buchung ist entweder direkt zugeordnet (Kategorie / Gegenkonto, Klasse) * oder eine Splitbuchung. Sobald in einer Splitzeile etwas steht, sind die * beiden Felder oben gesperrt; steht oben eine Kategorie oder Klasse, sind es * die Splitzeilen. Gesperrte Felder schickt der Browser nicht mit – was dort * noch stehen mag, geht also nicht in die Buchung ein. Der Knopf * „Splitbuchungen löschen“ leert alle Splitzeilen und gibt oben wieder frei. * * Der Schalter „Bewusst ohne Kategorie“ (#134) sperrt Kategorie / Gegenkonto * und die Splitzeilen; umgekehrt lässt er sich nur setzen, solange dort nichts * steht. Die Klasse bleibt frei – sie ist keine Zuordnung. * * Kategorie und Gegenkonto stehen in einem Feld, deshalb gibt es hier nichts * mehr ein- und auszublenden; die Art bestimmt nur noch die Richtung. */ (function () { 'use strict'; const art = document.getElementById('art'); const maske = document.querySelector('.buchungsmaske'); if (!art || !maske || !window.FmBetrag) { return; } const summenfeld = document.getElementById('splitsumme'); const betragsfeld = document.getElementById('betrag'); const speichernknopf = maske.querySelector('button[type="submit"]'); function rechneSumme() { if (!summenfeld) { return; } // Der Buchungsbetrag wird positiv eingegeben; das Vorzeichen ergibt // sich aus der Art. Für den Vergleich zählt der Betrag mit Richtung. let ziel = window.FmBetrag.zahl(betragsfeld ? betragsfeld.value : '0'); if (art.value !== 'einnahme') { ziel = -ziel; } const stand = window.FmBetrag.splitsumme( Array.from(maske.querySelectorAll('.splitbetrag')), ziel ); summenfeld.textContent = stand.text; summenfeld.classList.toggle('negativ', stand.belegt && stand.rest !== 0); // Gesperrt nur, solange tatsächlich Splitzeilen mit Beträgen stehen und // deren Summe den Buchungswert verfehlt. Eine direkte Zuordnung (oder // gar keine Eingabe) deckt den ganzen Betrag stets ab. if (speichernknopf) { speichernknopf.disabled = stand.belegt && stand.rest !== 0; } } const direktfelder = ['zuordnung', 'klasse_id'] .map(function (id) { return document.getElementById(id); }) .filter(Boolean); const splitkasten = document.getElementById('splitzeilen'); const leerenknopf = document.getElementById('splitsleeren'); const ohneKategorie = document.getElementById('bewusst_ohne_kategorie'); const zuordnungsfeld = document.getElementById('zuordnung'); function splitfelder() { return splitkasten ? Array.from(splitkasten.querySelectorAll('input, select')) : []; } function belegt(felder) { return felder.some(function (feld) { return feld.value.trim() !== ''; }); } function sperrenAktualisieren() { const splits = splitfelder(); const splitBelegt = belegt(splits); // Stehen beim Öffnen beide Seiten voll (ältere Daten), gilt wie im // Model die Splitbuchung. const direktBelegt = !splitBelegt && belegt(direktfelder); direktfelder.forEach(function (feld) { feld.disabled = splitBelegt; }); splits.forEach(function (feld) { feld.disabled = direktBelegt; }); if (ohneKategorie) { const ohne = ohneKategorie.checked; if (ohne) { splits.forEach(function (feld) { feld.disabled = true; }); if (zuordnungsfeld) { zuordnungsfeld.disabled = true; } } ohneKategorie.disabled = !ohne && (splitBelegt || (zuordnungsfeld !== null && zuordnungsfeld.value !== '')); } if (leerenknopf) { leerenknopf.hidden = !splitBelegt; } } function splitsLeeren() { splitfelder().forEach(function (feld) { feld.value = ''; }); sperrenAktualisieren(); rechneSumme(); } art.addEventListener('change', rechneSumme); maske.addEventListener('input', function (ereignis) { if (ereignis.target.classList.contains('splitbetrag') || ereignis.target.id === 'betrag') { rechneSumme(); } sperrenAktualisieren(); }); maske.addEventListener('change', sperrenAktualisieren); if (leerenknopf) { leerenknopf.addEventListener('click', splitsLeeren); } sperrenAktualisieren(); rechneSumme(); })();