Feature: Anlagevermögen-Modal beim Buchen auf AV-Konto
This commit is contained in:
parent
f77b228fdb
commit
05a964edbb
2 changed files with 186 additions and 1 deletions
|
|
@ -7,6 +7,7 @@ namespace Steuerkram\Controllers;
|
|||
use Steuerkram\Models\Beleg;
|
||||
use Steuerkram\Models\Booking;
|
||||
use Steuerkram\Models\Account;
|
||||
use Steuerkram\Models\Asset;
|
||||
use Steuerkram\Models\Supplier;
|
||||
use Steuerkram\Config;
|
||||
use Steuerkram\View;
|
||||
|
|
@ -198,6 +199,7 @@ class BelegController
|
|||
$integrity = Beleg::verifyIntegrity((int)$params['id']);
|
||||
$accounts = Account::all(['aktiv' => 1]);
|
||||
$suppliers = Supplier::all();
|
||||
$assets = Asset::all();
|
||||
|
||||
$svc = new KontierungsvorschlagService();
|
||||
$kiAktiv = $svc->isEnabled();
|
||||
|
|
@ -214,6 +216,7 @@ class BelegController
|
|||
'bookings' => $bookings,
|
||||
'integrity' => $integrity,
|
||||
'accounts' => $accounts,
|
||||
'assets' => $assets,
|
||||
'kiAktiv' => $kiAktiv,
|
||||
'kiVorschlag' => $kiVorschlag,
|
||||
]),
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ $suppliers = $suppliers ?? [];
|
|||
data-target="kategorie_konto_id" autocomplete="off" style="margin-bottom:.3rem"
|
||||
value="<?= $h($formData['kategorie_kontonummer'] ?? '') ?>">
|
||||
<select id="kategorie_konto_id" name="kategorie_konto_id" size="6"
|
||||
onchange="showKontoArt('kategorie_konto_id','kategorie_konto_art',this);updateEigenanteilState();updateBewirtungsState();updateAutoUst()">
|
||||
onchange="showKontoArt('kategorie_konto_id','kategorie_konto_art',this);updateEigenanteilState();updateBewirtungsState();updateAutoUst();checkAnlagevermoegen()">
|
||||
<option value="">– Konto wählen –</option>
|
||||
<?php foreach (['Betriebsausgabe', 'Betriebseinnahme', 'Anlagevermögen', 'Privat', 'Verbindlichkeit'] as $art): ?>
|
||||
<?php if (empty($kontenGruppen[$art])) continue; ?>
|
||||
|
|
@ -477,6 +477,9 @@ $suppliers = $suppliers ?? [];
|
|||
</label>
|
||||
</div>
|
||||
|
||||
<!-- hidden: wird bei Auswahl eines bestehenden Anlageguts gesetzt -->
|
||||
<input type="hidden" name="asset_id" id="asset_id_hidden" value="">
|
||||
|
||||
<button type="submit" class="btn btn-primary">Buchung erfassen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -488,6 +491,185 @@ $suppliers = $suppliers ?? [];
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Modal: Anlagevermögen ──────────────────────────────────── -->
|
||||
<div id="modal-anlagevermoegen" class="modal-overlay" role="dialog" aria-modal="true">
|
||||
<div class="modal" style="max-width:640px;width:100%">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Anlagevermögen buchen</h3>
|
||||
<button type="button" class="modal-close" data-modal-close aria-label="Schließen">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p style="margin-bottom:1rem">Das gewählte Konto gehört zum Anlagevermögen. Soll ein neues Anlagegut angelegt oder ein bestehendes ausgewählt werden?</p>
|
||||
|
||||
<div style="display:flex;flex-direction:column;gap:.6rem;margin-bottom:1.25rem">
|
||||
<label style="display:flex;align-items:center;gap:.6rem;cursor:pointer">
|
||||
<input type="radio" name="anlage_wahl" id="anlage_radio_neu" value="neu" checked>
|
||||
<span>Neues Anlagegut anlegen</span>
|
||||
</label>
|
||||
<label style="display:flex;align-items:center;gap:.6rem;cursor:pointer">
|
||||
<input type="radio" name="anlage_wahl" id="anlage_radio_vorhanden" value="vorhanden">
|
||||
<span>Bestehendes Anlagegut auswählen</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Liste bestehender Anlagegüter (nur bei "vorhanden") -->
|
||||
<div id="anlage_liste_wrap" style="display:none">
|
||||
<p id="anlage_liste_leer" class="text-muted text-sm" style="display:none">
|
||||
Für dieses Konto sind noch keine Anlagegüter vorhanden.
|
||||
</p>
|
||||
<div class="table-wrap" id="anlage_liste_table_wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:3rem">Nr.</th>
|
||||
<th>Wirtschaftsgut</th>
|
||||
<th>Anschaffungsdatum</th>
|
||||
<th class="td-num">Anschaffungskosten</th>
|
||||
<th style="width:2.5rem"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="anlage_liste_tbody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer" style="display:flex;justify-content:flex-end;gap:.75rem;padding:1rem 1.5rem;border-top:1px solid var(--color-border)">
|
||||
<button type="button" class="btn btn-secondary" data-modal-close>Abbrechen</button>
|
||||
<button type="button" class="btn btn-primary" id="anlage_modal_ok">Weiter</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Assets als JSON für JS vorbereiten
|
||||
$assetsJson = json_encode(array_map(fn($a) => [
|
||||
'id' => (int)$a['id'],
|
||||
'lfd_nr' => (int)$a['lfd_nr'],
|
||||
'bezeichnung' => $a['bezeichnung'],
|
||||
'anschaffungsdatum' => $a['anschaffungsdatum'],
|
||||
'anschaffungskosten' => (float)$a['anschaffungskosten'],
|
||||
'account_id' => $a['account_id'] !== null ? (int)$a['account_id'] : null,
|
||||
], $assets ?? []), JSON_HEX_TAG);
|
||||
?>
|
||||
|
||||
<script>
|
||||
const _assets = <?= $assetsJson ?>;
|
||||
|
||||
// Formatierung Datum de-DE
|
||||
function _fmtDate(str) {
|
||||
if (!str) return '–';
|
||||
const [y, m, d] = str.split('-');
|
||||
return d + '.' + m + '.' + y;
|
||||
}
|
||||
function _fmtEur(n) {
|
||||
return n.toLocaleString('de-DE', {minimumFractionDigits:2, maximumFractionDigits:2}) + ' €';
|
||||
}
|
||||
|
||||
// Wird aufgerufen wenn Kategorie-Konto geändert wird
|
||||
function checkAnlagevermoegen() {
|
||||
const sel = document.getElementById('kategorie_konto_id');
|
||||
if (!sel) return;
|
||||
const opt = sel.options[sel.selectedIndex];
|
||||
if (!opt || opt.value === '') return;
|
||||
|
||||
const art = opt.getAttribute('data-art') || '';
|
||||
if (art !== 'Anlagevermögen') {
|
||||
// Kein AV-Konto – Asset-Auswahl zurücksetzen
|
||||
document.getElementById('asset_id_hidden').value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// AV-Konto gewählt → Modal öffnen
|
||||
const accountId = parseInt(opt.value, 10);
|
||||
_openAnlageModal(accountId);
|
||||
}
|
||||
|
||||
function _openAnlageModal(accountId) {
|
||||
// Radio auf "neu" zurücksetzen
|
||||
document.getElementById('anlage_radio_neu').checked = true;
|
||||
document.getElementById('anlage_liste_wrap').style.display = 'none';
|
||||
document.getElementById('asset_id_hidden').value = '';
|
||||
|
||||
// Liste für dieses Konto befüllen
|
||||
const passend = _assets.filter(a => a.account_id === accountId);
|
||||
_renderAnlageListe(passend);
|
||||
|
||||
document.getElementById('modal-anlagevermoegen').classList.add('open');
|
||||
}
|
||||
|
||||
function _renderAnlageListe(list) {
|
||||
const tbody = document.getElementById('anlage_liste_tbody');
|
||||
const leer = document.getElementById('anlage_liste_leer');
|
||||
const table = document.getElementById('anlage_liste_table_wrap');
|
||||
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if (list.length === 0) {
|
||||
leer.style.display = '';
|
||||
table.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
leer.style.display = 'none';
|
||||
table.style.display = '';
|
||||
|
||||
list.forEach(a => {
|
||||
const tr = document.createElement('tr');
|
||||
tr.style.cursor = 'pointer';
|
||||
tr.dataset.assetId = a.id;
|
||||
tr.innerHTML =
|
||||
'<td class="td-mono text-sm">' + a.lfd_nr + '</td>' +
|
||||
'<td>' + _esc(a.bezeichnung) + '</td>' +
|
||||
'<td class="td-muted text-sm">' + _fmtDate(a.anschaffungsdatum) + '</td>' +
|
||||
'<td class="td-num">' + _fmtEur(a.anschaffungskosten) + '</td>' +
|
||||
'<td><input type="radio" name="anlage_auswahl" value="' + a.id + '"></td>';
|
||||
tbody.appendChild(tr);
|
||||
|
||||
// Klick auf Zeile wählt Radio
|
||||
tr.addEventListener('click', () => {
|
||||
const radio = tr.querySelector('input[type="radio"]');
|
||||
if (radio) radio.checked = true;
|
||||
tbody.querySelectorAll('tr').forEach(r => r.classList.remove('row-selected'));
|
||||
tr.classList.add('row-selected');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _esc(s) {
|
||||
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
|
||||
// Radio-Wahl: neu / vorhanden
|
||||
document.addEventListener('change', e => {
|
||||
if (e.target.name !== 'anlage_wahl') return;
|
||||
const wrap = document.getElementById('anlage_liste_wrap');
|
||||
wrap.style.display = e.target.value === 'vorhanden' ? '' : 'none';
|
||||
if (e.target.value === 'neu') {
|
||||
document.getElementById('asset_id_hidden').value = '';
|
||||
document.querySelectorAll('input[name="anlage_auswahl"]').forEach(r => r.checked = false);
|
||||
document.querySelectorAll('#anlage_liste_tbody tr').forEach(r => r.classList.remove('row-selected'));
|
||||
}
|
||||
});
|
||||
|
||||
// OK-Button
|
||||
document.getElementById('anlage_modal_ok').addEventListener('click', () => {
|
||||
const wahl = document.querySelector('input[name="anlage_wahl"]:checked')?.value;
|
||||
|
||||
if (wahl === 'vorhanden') {
|
||||
const gewählt = document.querySelector('input[name="anlage_auswahl"]:checked');
|
||||
if (!gewählt) {
|
||||
alert('Bitte ein Anlagegut aus der Liste auswählen.');
|
||||
return;
|
||||
}
|
||||
document.getElementById('asset_id_hidden').value = gewählt.value;
|
||||
} else {
|
||||
// "neu" – asset_id bleibt leer, Backend legt neues Gut an
|
||||
document.getElementById('asset_id_hidden').value = '';
|
||||
}
|
||||
|
||||
document.getElementById('modal-anlagevermoegen').classList.remove('open');
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function filterKategorieKonten(buchungstyp) {
|
||||
const select = document.getElementById('kategorie_konto_id');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue