Fix: Buchungsvorlagen-Modal – Gruppenunabhängiges Feldrendering und Komma als Dezimaltrenner

This commit is contained in:
fds2610-bot 2026-06-04 16:17:50 +02:00
parent 0488edba7c
commit e1c262c369
4 changed files with 89 additions and 87 deletions

View file

@ -524,17 +524,18 @@ document.addEventListener('input', function(e) {
if (!inp.matches('#vorlage-modal .vorlage-netto, #vorlage-modal .vorlage-brutto')) return; if (!inp.matches('#vorlage-modal .vorlage-netto, #vorlage-modal .vorlage-brutto')) return;
const row = inp.closest('.vorlage-ust-row'); const row = inp.closest('.vorlage-ust-row');
if (!row) return; if (!row) return;
const pDec = v => parseFloat(String(v).replace(',', '.')) || 0;
const satz = parseFloat(row.dataset.ustSatz) / 100; const satz = parseFloat(row.dataset.ustSatz) / 100;
const netto = row.querySelector('.vorlage-netto'); const netto = row.querySelector('.vorlage-netto');
const brutto = row.querySelector('.vorlage-brutto'); const brutto = row.querySelector('.vorlage-brutto');
const ust = row.querySelector('.vorlage-ust'); const ust = row.querySelector('.vorlage-ust');
const ustAnzeige = row.querySelector('.vorlage-ust-anzeige'); const ustAnzeige = row.querySelector('.vorlage-ust-anzeige');
if (inp.classList.contains('vorlage-netto')) { if (inp.classList.contains('vorlage-netto')) {
const n = parseFloat(netto.value) || 0; const n = pDec(netto.value);
brutto.value = (n * (1 + satz)).toFixed(2); brutto.value = (n * (1 + satz)).toFixed(2);
ust.value = (n * satz).toFixed(2); ust.value = (n * satz).toFixed(2);
} else { } else {
const b = parseFloat(brutto.value) || 0; const b = pDec(brutto.value);
const n = b / (1 + satz); const n = b / (1 + satz);
netto.value = n.toFixed(2); netto.value = n.toFixed(2);
ust.value = (b - n).toFixed(2); ust.value = (b - n).toFixed(2);
@ -547,7 +548,7 @@ function vorlageUpdateBruttoGesamt() {
const modal = document.getElementById('vorlage-modal'); const modal = document.getElementById('vorlage-modal');
if (!modal) return; if (!modal) return;
const bruttoFelder = modal.querySelectorAll('.vorlage-brutto'); const bruttoFelder = modal.querySelectorAll('.vorlage-brutto');
const summe = Array.from(bruttoFelder).reduce((s, el) => s + (parseFloat(el.value) || 0), 0); const summe = Array.from(bruttoFelder).reduce((s, el) => s + (parseFloat(String(el.value).replace(',', '.')) || 0), 0);
const anzeige = modal.querySelector('[data-feldname="brutto_gesamt"]'); const anzeige = modal.querySelector('[data-feldname="brutto_gesamt"]');
if (anzeige) anzeige.textContent = summe.toFixed(2).replace('.', ',') + ' €'; if (anzeige) anzeige.textContent = summe.toFixed(2).replace('.', ',') + ' €';
} }

View file

@ -58,7 +58,7 @@ class VorlageBuchungsService
continue; continue;
} }
foreach ($regel['buchungen'] as $buchung) { foreach ($regel['buchungen'] as $buchung) {
$betrag = round((float)($inputDaten[$buchung['betrag_ref']] ?? 0), 2); $betrag = round((float)str_replace(',', '.', (string)($inputDaten[$buchung['betrag_ref']] ?? 0)), 2);
if ($betrag == 0.0) { if ($betrag == 0.0) {
continue; continue;
} }

View file

@ -2,10 +2,14 @@
declare(strict_types=1); declare(strict_types=1);
$h = fn($v) => htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); $h = fn($v) => htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
// Felder nach Gruppen aufteilen // Felder nach Gruppe_nr sortiert gruppieren (dynamisch, unabhängig von festen Nummern)
$gruppe1 = array_filter($felder, fn($f) => $f['gruppe_nr'] == 1); $gruppenFelder = [];
$gruppe2 = array_filter($felder, fn($f) => $f['gruppe_nr'] == 2); foreach ($felder as $feld) {
$gruppe3 = array_filter($felder, fn($f) => $f['gruppe_nr'] == 3); $gruppenFelder[(int)$feld['gruppe_nr']][] = $feld;
}
ksort($gruppenFelder);
$gruppenLabel = [1 => 'Belegdaten', 2 => 'Beträge', 3 => 'Zahlung'];
// Vorbelegen: Vorlage-Standard-Lieferant hat Vorrang vor Beleg-Lieferant // Vorbelegen: Vorlage-Standard-Lieferant hat Vorrang vor Beleg-Lieferant
$standardLieferant = trim($vorlage['standard_lieferant'] ?? ''); $standardLieferant = trim($vorlage['standard_lieferant'] ?? '');
@ -44,19 +48,83 @@ if (!$defaultKontoId && !empty($zahlungskonten)) {
<input type="hidden" name="bank_tx_id" value="<?= $h($bankTxId) ?>"> <input type="hidden" name="bank_tx_id" value="<?= $h($bankTxId) ?>">
<?php endif; ?> <?php endif; ?>
<?php if (!empty($gruppe1)): ?> <?php foreach ($gruppenFelder as $gruppeNr => $felderInGruppe): ?>
<!-- Gruppe 1: Metadaten -->
<div style="margin-bottom:1.25rem"> <div style="margin-bottom:1.25rem">
<div style="font-weight:600;font-size:.8rem;text-transform:uppercase;letter-spacing:.05em;color:var(--color-text-muted);margin-bottom:.75rem">Belegdaten</div> <div style="font-weight:600;font-size:.8rem;text-transform:uppercase;letter-spacing:.05em;color:var(--color-text-muted);margin-bottom:.75rem">
<?php foreach ($gruppe1 as $feld): ?> <?= $h($gruppenLabel[$gruppeNr] ?? 'Abschnitt ' . $gruppeNr) ?>
<?php if ($feld['typ'] === 'readonly'): ?> </div>
<?php
$inUstTable = false;
foreach ($felderInGruppe as $feld):
$typ = $feld['typ'];
// ust_zeile braucht Tabellenkontext – öffnen/schließen bei Typwechsel
if ($typ === 'ust_zeile' && !$inUstTable):
$inUstTable = true;
?>
<table style="width:100%;border-collapse:collapse;font-size:.875rem">
<thead>
<tr style="color:var(--color-text-muted);font-size:.8rem">
<th style="text-align:left;padding:.3rem .5rem;font-weight:500">Steuer</th>
<th style="text-align:right;padding:.3rem .5rem;font-weight:500">Netto (€)</th>
<th style="text-align:right;padding:.3rem .5rem;font-weight:500">Brutto (€)</th>
<th style="text-align:right;padding:.3rem .5rem;font-weight:500;color:var(--color-text-muted)">USt (€)</th>
</tr>
</thead>
<tbody>
<?php elseif ($typ !== 'ust_zeile' && $inUstTable):
$inUstTable = false;
?>
</tbody>
</table>
<?php endif; ?>
<?php if ($typ === 'ust_zeile'):
$satz = (float)$feld['ust_satz'];
$satzInt = (int)$satz;
$nKey = $feld['feldname'];
$uKey = 'ust_' . $satzInt;
$bKey = 'brutto_' . $satzInt;
?>
<tr data-ust-satz="<?= $h($satz) ?>" class="vorlage-ust-row">
<td style="padding:.3rem .5rem"><?= $h($feld['label']) ?></td>
<td style="padding:.3rem .5rem">
<input type="text" inputmode="decimal" name="<?= $h($nKey) ?>" value=""
class="form-control form-control-sm vorlage-netto"
style="text-align:right;width:110px"
placeholder="0,00">
</td>
<td style="padding:.3rem .5rem">
<input type="text" inputmode="decimal" name="<?= $h($bKey) ?>" value=""
class="form-control form-control-sm vorlage-brutto"
style="text-align:right;width:110px"
placeholder="0,00">
</td>
<td style="padding:.3rem .5rem;text-align:right">
<span class="vorlage-ust-anzeige"
style="display:inline-block;width:90px;text-align:right;color:var(--color-text-muted);font-size:.875rem">0,00</span>
<input type="hidden" name="<?= $h($uKey) ?>" class="vorlage-ust" value="">
</td>
</tr>
<?php elseif ($typ === 'account_select'): ?>
<div class="form-group" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.6rem">
<label style="min-width:130px;margin:0;font-size:.875rem"><?= $h($feld['label']) ?></label>
<select name="zahlungskonto_id" class="form-control form-control-sm" style="flex:1;max-width:320px">
<?php foreach ($zahlungskonten as $zk): ?>
<option value="<?= $h($zk['id']) ?>"<?= (int)$zk['id'] === $defaultKontoId ? ' selected' : '' ?>>
<?= $h($zk['kontonummer']) ?> – <?= $h($zk['bezeichnung']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php elseif ($typ === 'readonly'): ?>
<div class="form-group" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.6rem"> <div class="form-group" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.6rem">
<label style="min-width:130px;margin:0;font-size:.875rem"><?= $h($feld['label']) ?></label> <label style="min-width:130px;margin:0;font-size:.875rem"><?= $h($feld['label']) ?></label>
<span id="vorlage-field-<?= $h($feld['feldname']) ?>" <span id="vorlage-field-<?= $h($feld['feldname']) ?>"
data-feldname="<?= $h($feld['feldname']) ?>" data-feldname="<?= $h($feld['feldname']) ?>"
style="font-weight:600;font-size:.95rem">0,00 €</span> style="font-weight:600;font-size:.95rem">0,00 €</span>
</div> </div>
<?php elseif ($feld['typ'] === 'date'): ?> <?php elseif ($typ === 'date'): ?>
<div class="form-group" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.6rem;flex-wrap:wrap"> <div class="form-group" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.6rem;flex-wrap:wrap">
<label style="min-width:130px;margin:0;font-size:.875rem"><?= $h($feld['label']) ?></label> <label style="min-width:130px;margin:0;font-size:.875rem"><?= $h($feld['label']) ?></label>
<input type="date" name="<?= $h($feld['feldname']) ?>" <input type="date" name="<?= $h($feld['feldname']) ?>"
@ -69,88 +137,21 @@ if (!$defaultKontoId && !empty($zahlungskonten)) {
style="width:150px" class="form-control form-control-sm"> style="width:150px" class="form-control form-control-sm">
<?php endif; ?> <?php endif; ?>
</div> </div>
<?php else: ?> <?php else: ?>
<div class="form-group" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.6rem"> <div class="form-group" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.6rem">
<label style="min-width:130px;margin:0;font-size:.875rem"><?= $h($feld['label']) ?></label> <label style="min-width:130px;margin:0;font-size:.875rem"><?= $h($feld['label']) ?></label>
<input type="text" name="<?= $h($feld['feldname']) ?>" <input type="text" name="<?= $h($feld['feldname']) ?>"
value="<?= $h($vorbelegt[$feld['feldname']] ?? '') ?>" value="<?= $h($vorbelegt[$feld['feldname']] ?? '') ?>"
style="flex:1" class="form-control form-control-sm"> style="flex:1" class="form-control form-control-sm">
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
</div> <?php if ($inUstTable): ?>
<?php endif; ?>
<?php if (!empty($gruppe2)): ?>
<!-- Gruppe 2: USt-Zeilen -->
<div style="margin-bottom:1.25rem">
<div style="font-weight:600;font-size:.8rem;text-transform:uppercase;letter-spacing:.05em;color:var(--color-text-muted);margin-bottom:.75rem">Beträge</div>
<table style="width:100%;border-collapse:collapse;font-size:.875rem">
<thead>
<tr style="color:var(--color-text-muted);font-size:.8rem">
<th style="text-align:left;padding:.3rem .5rem;font-weight:500">Steuer</th>
<th style="text-align:right;padding:.3rem .5rem;font-weight:500">Netto (€)</th>
<th style="text-align:right;padding:.3rem .5rem;font-weight:500">Brutto (€)</th>
<th style="text-align:right;padding:.3rem .5rem;font-weight:500;color:var(--color-text-muted)">USt (€)</th>
</tr>
</thead>
<tbody>
<?php foreach ($gruppe2 as $feld): ?>
<?php if ($feld['typ'] === 'ust_zeile'): ?>
<?php
$satz = (float)$feld['ust_satz'];
$satzInt = (int)$satz;
$nKey = $feld['feldname'];
$uKey = 'ust_' . $satzInt;
$bKey = 'brutto_' . $satzInt;
?>
<tr data-ust-satz="<?= $h($satz) ?>" class="vorlage-ust-row">
<td style="padding:.3rem .5rem"><?= $h($feld['label']) ?></td>
<td style="padding:.3rem .5rem">
<input type="number" name="<?= $h($nKey) ?>" step="0.01" min="0" value=""
class="form-control form-control-sm vorlage-netto"
style="text-align:right;width:110px"
placeholder="0,00">
</td>
<td style="padding:.3rem .5rem">
<input type="number" name="<?= $h($bKey) ?>" step="0.01" min="0" value=""
class="form-control form-control-sm vorlage-brutto"
style="text-align:right;width:110px"
placeholder="0,00">
</td>
<td style="padding:.3rem .5rem;text-align:right">
<span class="vorlage-ust-anzeige"
style="display:inline-block;width:90px;text-align:right;color:var(--color-text-muted);font-size:.875rem">0,00</span>
<input type="hidden" name="<?= $h($uKey) ?>" class="vorlage-ust" value="">
</td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
</tbody> </tbody>
</table> </table>
<?php endif; ?>
</div> </div>
<?php endif; ?> <?php endforeach; ?>
<?php if (!empty($gruppe3)): ?>
<!-- Gruppe 3: Zahlungskonto -->
<div style="margin-bottom:1.25rem">
<div style="font-weight:600;font-size:.8rem;text-transform:uppercase;letter-spacing:.05em;color:var(--color-text-muted);margin-bottom:.75rem">Zahlung</div>
<?php foreach ($gruppe3 as $feld): ?>
<?php if ($feld['typ'] === 'account_select'): ?>
<div class="form-group" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.6rem">
<label style="min-width:130px;margin:0;font-size:.875rem"><?= $h($feld['label']) ?></label>
<select name="zahlungskonto_id" class="form-control form-control-sm" style="flex:1;max-width:320px">
<?php foreach ($zahlungskonten as $zk): ?>
<option value="<?= $h($zk['id']) ?>"<?= (int)$zk['id'] === $defaultKontoId ? ' selected' : '' ?>>
<?= $h($zk['kontonummer']) ?> – <?= $h($zk['bezeichnung']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
</form> </form>
</div> </div>

View file

@ -1 +1 @@
1-260601 1-260604