162 lines
7.2 KiB
JavaScript
162 lines
7.2 KiB
JavaScript
'use strict';
|
||
|
||
const _kiBadgeEl = document.getElementById('ki-badge');
|
||
const _belegId = parseInt(_kiBadgeEl.dataset.belegId, 10);
|
||
const _kiAktiv = JSON.parse(_kiBadgeEl.dataset.kiAktiv);
|
||
const _kiVorschlag = JSON.parse(_kiBadgeEl.dataset.kiVorschlag);
|
||
|
||
function _selectById(selectEl, id) {
|
||
if (!selectEl) return;
|
||
const str = String(id);
|
||
for (const opt of selectEl.options) {
|
||
opt.selected = (opt.value === str);
|
||
}
|
||
}
|
||
|
||
function _applyKiVorschlag(v) {
|
||
const btRadio = document.querySelector('input[name="buchungstyp"][value="' + v.buchungstyp + '"]');
|
||
if (btRadio) { btRadio.checked = true; filterKategorieKonten(v.buchungstyp); }
|
||
const ustEl = document.getElementById('ust_satz_select');
|
||
if (ustEl) { ustEl.value = String(v.ust_satz); updateSteuerartVisibility(); }
|
||
const katEl2 = document.getElementById('kategorie_konto_id');
|
||
_selectById(katEl2, v.kategorie_konto_id);
|
||
if (katEl2) transferKontoNr(katEl2);
|
||
updateEigenanteilState();
|
||
const zhlEl2 = document.getElementById('zahlungskonto_id');
|
||
_selectById(zhlEl2, v.zahlungskonto_id);
|
||
if (zhlEl2) transferKontoNr(zhlEl2);
|
||
if (v.betrag_netto) setBetragNettoWert(v.betrag_netto);
|
||
const txtEl = document.querySelector('input[name="buchungstext"]');
|
||
if (txtEl && v.buchungstext) txtEl.value = v.buchungstext;
|
||
|
||
// Lieferant aus KI-Vorschlag übernehmen
|
||
if (v.supplier_name) {
|
||
const bar = document.querySelector('[data-beleg-id]');
|
||
const persistentInput = document.getElementById('supplier-persistent-input');
|
||
const trigger = document.getElementById('supplier-inline-trigger');
|
||
if (persistentInput) {
|
||
persistentInput.value = v.supplier_name;
|
||
if (bar) bar.dataset.supplierName = v.supplier_name;
|
||
if (v.supplier_found === false) persistentInput.focus();
|
||
} else if (trigger) {
|
||
trigger.dataset.raw = v.supplier_name;
|
||
if (bar) bar.dataset.supplierName = v.supplier_name;
|
||
trigger.textContent = v.supplier_name;
|
||
if (v.supplier_found === false && !trigger.querySelector('input')) {
|
||
trigger.click();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
function _showKiBadgeDone(arr) {
|
||
// arr ist immer ein Array (bereits normalisiert)
|
||
const v = arr[0];
|
||
const katEl = document.getElementById('kategorie_konto_id');
|
||
const zhlEl = document.getElementById('zahlungskonto_id');
|
||
const katOpt = katEl ? katEl.querySelector('option[value="' + v.kategorie_konto_id + '"]') : null;
|
||
const zhlOpt = zhlEl ? zhlEl.querySelector('option[value="' + v.zahlungskonto_id + '"]') : null;
|
||
const katTxt = katOpt ? katOpt.text : v.kategorie_konto_id;
|
||
const zhlTxt = zhlOpt ? zhlOpt.text : v.zahlungskonto_id;
|
||
const supTxt = v.supplier_name
|
||
? ' · Lieferant: ' + _esc(v.supplier_name) + (v.supplier_found === false ? ' <span style="color:var(--color-warning);font-weight:600">(neu – bitte prüfen)</span>' : '')
|
||
: '';
|
||
|
||
// Erste Zeile (bereits ins Formular übertragen)
|
||
let details =
|
||
(v.buchungstyp ? v.buchungstyp + ' · ' : '') +
|
||
'Kategorie: ' + katTxt + ' · ' +
|
||
'Zahlung: ' + zhlTxt + supTxt;
|
||
|
||
// Alle Buchungszeilen mit Beträgen anzeigen
|
||
const fmt = n => parseFloat(n).toLocaleString('de-DE', {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||
let zeilen = '';
|
||
arr.forEach((z, i) => {
|
||
const netto = parseFloat(z.betrag_netto) || 0;
|
||
const ust = Math.round(netto * z.ust_satz / 100 * 100) / 100;
|
||
const brutto = Math.round((netto + ust) * 100) / 100;
|
||
const hinweis = (i > 0) ? ' <span style="color:var(--color-muted);font-style:italic">(bitte als weitere Buchung erfassen)</span>' : '';
|
||
zeilen += '<br><span style="font-size:.85em">Zeile ' + (i + 1) + ': '
|
||
+ 'Netto ' + fmt(netto) + ' € | USt ' + z.ust_satz + '% ' + fmt(ust) + ' € | Brutto ' + fmt(brutto) + ' €'
|
||
+ hinweis + '</span>';
|
||
});
|
||
|
||
const neuBtn = _kiAktiv
|
||
? '<button class="btn btn-secondary btn-sm" style="flex-shrink:0;margin-top:.1rem" onclick="_startKiAnalyse()">Neu generieren</button>'
|
||
: '';
|
||
document.getElementById('ki-badge').innerHTML =
|
||
'<div class="flash flash-info" style="display:flex;justify-content:space-between;align-items:flex-start;gap:1rem">' +
|
||
'<div><strong>KI-Vorschlag:</strong> <span style="font-size:.9em">' + details + '</span>' + zeilen + '</div>' +
|
||
neuBtn +
|
||
'</div>';
|
||
}
|
||
|
||
function _showKiBadgeNoResult() {
|
||
const neuBtn = _kiAktiv
|
||
? ' <button class="btn btn-secondary btn-sm" onclick="_startKiAnalyse()">Erneut versuchen</button>'
|
||
: '';
|
||
document.getElementById('ki-badge').innerHTML =
|
||
'<div class="flash flash-warning">Kein Kontierungsvorschlag generiert.' + neuBtn + '</div>';
|
||
}
|
||
|
||
function _showKiBadgeLoading() {
|
||
document.getElementById('ki-badge').innerHTML =
|
||
'<div class="flash flash-info" style="opacity:.65">Analysiere Beleg … bitte warten.</div>';
|
||
}
|
||
|
||
function _showKiBadgeError() {
|
||
document.getElementById('ki-badge').innerHTML =
|
||
'<div class="flash flash-warning">Fehler bei der KI-Analyse. ' +
|
||
'<button class="btn btn-secondary btn-sm" onclick="_startKiAnalyse()">Erneut versuchen</button></div>';
|
||
}
|
||
|
||
function _showKiBadgeConnectionError() {
|
||
const neuBtn = _kiAktiv
|
||
? ' <button class="btn btn-secondary btn-sm" onclick="_startKiAnalyse()">Erneut versuchen</button>'
|
||
: '';
|
||
document.getElementById('ki-badge').innerHTML =
|
||
'<div class="flash flash-warning">Ollama nicht erreichbar.' + neuBtn +
|
||
' <a href="/settings" style="color:inherit;text-decoration:underline">Einstellungen / Verbindung testen</a>' +
|
||
'</div>';
|
||
}
|
||
|
||
// Normalisiert _kiVorschlag zu einem Array (Objekt oder Array aus DB möglich).
|
||
// Gibt null zurück wenn kein Ergebnis vorhanden.
|
||
// Gibt leeres Array [] zurück wenn verarbeitet aber kein Ergebnis erzeugt.
|
||
function _normalizeKiArr(raw) {
|
||
if (raw === null || raw === undefined) return null;
|
||
const arr = Array.isArray(raw) ? raw : [raw];
|
||
// Leeres Array = "verarbeitet, kein Ergebnis"
|
||
if (arr.length === 0) return [];
|
||
// Mindestens erstes Element muss gültig sein
|
||
return (arr[0] && arr[0].kategorie_konto_id) ? arr : [];
|
||
}
|
||
|
||
async function _startKiAnalyse() {
|
||
await fetch('/belege/' + _belegId + '/vorschlag/reset', {method: 'POST'});
|
||
_showKiBadgeLoading();
|
||
try {
|
||
const r = await fetch('/belege/' + _belegId + '/vorschlag/generate', {method: 'POST'});
|
||
const raw = await r.json();
|
||
if (raw && raw.connection_error) { _showKiBadgeConnectionError(); return; }
|
||
const arr = _normalizeKiArr(raw);
|
||
if (arr && arr.length > 0) { _applyKiVorschlag(arr[0]); _showKiBadgeDone(arr); }
|
||
else _showKiBadgeNoResult();
|
||
} catch (e) {
|
||
_showKiBadgeError();
|
||
}
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
const arr = _normalizeKiArr(_kiVorschlag);
|
||
if (arr === null) {
|
||
if (_kiAktiv) { _startKiAnalyse(); }
|
||
} else if (arr.length === 0) {
|
||
// Verarbeitet, aber kein Ergebnis
|
||
_showKiBadgeNoResult();
|
||
} else {
|
||
// Vorschlag vorhanden → ins Formular übernehmen und anzeigen
|
||
_applyKiVorschlag(arr[0]);
|
||
_showKiBadgeDone(arr);
|
||
}
|
||
});
|