In der Buchungsmaske sperrt eine Eingabe in den Splitzeilen sofort Kategorie / Gegenkonto und Klasse, und umgekehrt sperrt eine Kategorie oder Klasse alle Splitzeilen. Der neue Knopf „Splitbuchungen löschen“ rechts über der Splittabelle leert alle Zeilen und gibt die direkten Felder wieder frei. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
104 lines
3.6 KiB
JavaScript
104 lines
3.6 KiB
JavaScript
/* Buchungsmaske: Restbetrag der Splitzeilen mitrechnen und direkte Zuordnung
|
||
* und Splitbuchung gegeneinander sperren.
|
||
*
|
||
* 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.
|
||
*
|
||
* 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');
|
||
|
||
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);
|
||
}
|
||
|
||
const direktfelder = ['zuordnung', 'klasse_id']
|
||
.map(function (id) { return document.getElementById(id); })
|
||
.filter(Boolean);
|
||
const splitkasten = document.getElementById('splitzeilen');
|
||
const leerenknopf = document.getElementById('splitsleeren');
|
||
|
||
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 (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();
|
||
})();
|