Finanzmanager/public/static/depotbuchung.js
fds2610-bot 9d771df028 Fix #129: Stück, Kurs und Betrag in der Depotbuchung automatisch berechnen
In „Depotbuchung erfassen“ ergibt sich bei Kauf und Verkauf aus zwei der drei
Felder Betrag, Stück und Kurs das dritte (Betrag = Stück × Kurs). Der
ausgerechnete Wert ist hervorgehoben und zieht nach, wenn sich die anderen
Felder ändern. Serverseitig rechnet Depotbuchung::dritterWert() dieselbe
Regel für den Weg ohne JavaScript.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:41:29 +02:00

111 lines
3.5 KiB
JavaScript
Raw Permalink 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.

/* Stück, Kurs und Betrag in der Maske „Depotbuchung erfassen“.
*
* Bei Kauf und Verkauf gilt Betrag = Stück × Kurs: Sobald zwei der drei Felder
* eingetragen sind, ergibt sich das dritte. Der ausgerechnete Wert bleibt
* ausgerechnet – ändert man danach eines der beiden anderen Felder, wird er
* nachgezogen. Tippt man ihn selbst um, gilt er als eingetragen; leert man eines
* der beiden anderen Felder, verschwindet er wieder, weil nichts mehr dahinter
* steht.
*
* Der Server rechnet dieselbe Regel noch einmal (Depotbuchung::dritterWert) –
* für den Weg ohne JavaScript.
*/
(function () {
'use strict';
const formular = document.getElementById('depotbuchungsformular');
if (!formular || !window.FmBetrag) {
return;
}
const vorgang = document.getElementById('vorgang');
const felder = {
stueck: document.getElementById('stueck'),
kurs: document.getElementById('kurs'),
betrag: document.getElementById('betrag')
};
if (!vorgang || !felder.stueck || !felder.kurs || !felder.betrag) {
return;
}
// Welches Feld zuletzt ausgerechnet wurde – null, solange alle eingetragen sind.
let berechnet = null;
function wert(name) {
return window.FmBetrag.zahl(felder[name].value);
}
function leer(name) {
return felder[name].value.trim() === '';
}
function formatiere(name, zahl) {
if (name === 'betrag') {
return window.FmBetrag.formatiere(zahl);
}
// Stück und Kurs führt die Datenbank mit sechs Nachkommastellen.
return zahl.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 6 });
}
function setze(name, zahl) {
felder[name].value = zahl === null ? '' : formatiere(name, zahl);
felder[name].classList.toggle('berechnet', zahl !== null);
berechnet = zahl === null ? null : name;
}
function ausrechnen(name) {
const stueck = wert('stueck');
const kurs = wert('kurs');
const betrag = wert('betrag');
switch (name) {
case 'betrag':
return stueck > 0 && kurs > 0 ? Math.round(stueck * kurs * 100) / 100 : null;
case 'kurs':
return stueck > 0 && betrag > 0 ? Math.round(betrag / stueck * 1e6) / 1e6 : null;
default:
return kurs > 0 && betrag > 0 ? Math.round(betrag / kurs * 1e6) / 1e6 : null;
}
}
function rechne(geaendert) {
if (geaendert !== null && geaendert === berechnet) {
felder[geaendert].classList.remove('berechnet');
berechnet = null;
}
if (vorgang.value !== 'kauf' && vorgang.value !== 'verkauf') {
return;
}
if (geaendert !== null && leer(geaendert) && berechnet !== null) {
setze(berechnet, null);
return;
}
let ziel = berechnet;
if (ziel === null) {
const offen = Object.keys(felder).filter(leer);
if (offen.length !== 1) {
return;
}
ziel = offen[0];
}
const ergebnis = ausrechnen(ziel);
if (ergebnis !== null) {
setze(ziel, ergebnis);
} else if (ziel === berechnet) {
setze(ziel, null);
}
}
Object.keys(felder).forEach(function (name) {
felder[name].addEventListener('input', function () {
rechne(name);
});
});
vorgang.addEventListener('change', function () {
rechne(null);
});
})();