Finanzmanager/public/static/buchungsmaske.js
fds2610-bot dba60c64e4 Fix #77: Splitbuchung und direkte Zuordnung sperren sich gegenseitig
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>
2026-09-28 22:40:13 +02:00

104 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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();
})();