Finanzmanager/src/Views/wertpapiere/buchungen.php
fds2610-bot 4d62529e2c Wertpapiere: Depotbuchungen sammelweise löschen
Nach einem Import, der schiefging, war das Löschen Zeile für Zeile mühsam. Die
Liste der Depotbuchungen räumt jetzt so auf wie das Kontoblatt: Ankreuzfeld je
Zeile, das Feld in der Titelzeile wählt alle angezeigten, „Auswahl löschen“ in
der Aktionsleiste schickt sie an POST /wertpapiere/buchungen/loeschen. Der Knopf
nennt die Anzahl und bleibt ohne Auswahl gesperrt; die Rückfrage nennt sie
ebenfalls. Ohne JavaScript funktioniert alles weiter – dann ist der Knopf offen
und der Controller weist eine leere Auswahl ab.

Mit jeder Depotbuchung geht ihre Geldbuchung, wie beim Löschen einer einzelnen.
Am Bestand ist nichts nachzuziehen: Er wird bei jedem Aufruf aus den
Depotbuchungen gerechnet und gibt die Löschung von selbst wieder her, ebenso
realisierter Gewinn, Veräußerungen und Erträge.

Der eingestellte Filter (Depot, Wertpapier, Vorgang) hängt am Ziel des
Formulars, deshalb steht danach wieder dieselbe Ansicht da. Zusammengesetzt wird
er im Controller neu, damit kein fremdes Ziel eingeschleust werden kann. Das
gilt jetzt auch für das „Löschen“ je Zeile, das bisher zur ungefilterten Liste
zurücksprang.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:27:51 +02:00

160 lines
7.5 KiB
PHP
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.

<?php
use Finanzmanager\Models\Depotbuchung;
use Finanzmanager\View;
/**
* @var list<array<string,mixed>> $buchungen
* @var list<array<string,mixed>> $depots
* @var list<array<string,mixed>> $wertpapiere
* @var array<string,mixed> $filter
* @var string $csrfToken
*/
// Nach dem Löschen soll dieselbe Ansicht wieder erscheinen – der Filter hängt
// deshalb am Ziel der Löschformulare.
$filterPfad = static function () use ($filter): string {
$query = array_filter([
'depot' => (string)($filter['konto_id'] ?? ''),
'wertpapier' => (string)($filter['wertpapier_id'] ?? ''),
'vorgang' => (string)($filter['vorgang'] ?? ''),
], static fn(string $wert): bool => $wert !== '');
return $query === [] ? '' : '?' . http_build_query($query);
};
include __DIR__ . '/../layout/kopf.php';
?>
<div class="tableiste">
<a href="/wertpapiere" class="tab">Bestände</a>
<span class="tab aktiv">Depotbuchungen</span>
<a href="/wertpapiere/stammdaten" class="tab">Wertpapiere</a>
<a href="/wertpapiere/auswertung?art=veraeusserungen" class="tab">Veräußerungen</a>
<a href="/wertpapiere/auswertung?art=ertraege" class="tab">Erträge</a>
</div>
<div class="seitenaktionen">
<form method="get" action="/wertpapiere/buchungen" class="inline">
<select name="depot">
<option value="">Alle Depots</option>
<?php foreach ($depots as $eintrag): ?>
<option value="<?= (int)$eintrag['id'] ?>"
<?= (int)($filter['konto_id'] ?? 0) === (int)$eintrag['id'] ? 'selected' : '' ?>>
<?= View::h($eintrag['name']) ?>
</option>
<?php endforeach; ?>
</select>
<select name="wertpapier">
<option value="">Alle Wertpapiere</option>
<?php foreach ($wertpapiere as $eintrag): ?>
<option value="<?= (int)$eintrag['id'] ?>"
<?= (int)($filter['wertpapier_id'] ?? 0) === (int)$eintrag['id'] ? 'selected' : '' ?>>
<?= View::h($eintrag['name']) ?>
</option>
<?php endforeach; ?>
</select>
<select name="vorgang">
<option value="">Alle Vorgänge</option>
<?php foreach (Depotbuchung::VORGAENGE as $schluessel => $name): ?>
<option value="<?= View::h($schluessel) ?>"
<?= ($filter['vorgang'] ?? '') === $schluessel ? 'selected' : '' ?>>
<?= View::h($name) ?>
</option>
<?php endforeach; ?>
</select>
<button type="submit" class="knopf klein">Filtern</button>
</form>
<?php if ($buchungen !== []): ?>
<!-- Wie im Kontoblatt: Das Formular steht hier, seine Ankreuzfelder
stehen in der Tabelle; verbunden sind sie über das form-Attribut.
Ein Formular um die ganze Tabelle würde das Filterformular
verschachteln. -->
<form method="post" action="/wertpapiere/buchungen/loeschen<?= View::h($filterPfad()) ?>"
id="depotbuchungsauswahl" class="inline"
data-bestaetigen="Die ausgewählten Depotbuchungen wirklich löschen? Die zugehörigen Geldbuchungen werden mitgelöscht."
data-frage-eine="Die ausgewählte Depotbuchung wirklich löschen? Die zugehörige Geldbuchung wird mitgelöscht."
data-frage-mehrere="{anzahl} ausgewählte Depotbuchungen wirklich löschen? Die zugehörigen Geldbuchungen werden mitgelöscht.">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<button type="submit" class="knopf gefahr">Auswahl löschen</button>
</form>
<?php endif; ?>
<a href="/wertpapiere/buchungen/neu" class="knopf primaer">Depotbuchung erfassen</a>
</div>
<?php if ($buchungen === []): ?>
<p class="platzhalter">Keine Depotbuchungen zu diesen Angaben.</p>
<?php else: ?>
<table class="liste zahlen">
<thead>
<tr>
<th class="wahlspalte">
<input type="checkbox" class="alle-waehlen" data-waehlt="depotbuchungsauswahl"
aria-label="Alle angezeigten Depotbuchungen auswählen">
</th>
<th>Datum</th><th>Vorgang</th><th>Wertpapier</th><th>Depot</th>
<th class="rechts">Stück</th><th class="rechts">Kurs</th>
<th class="rechts">Betrag</th><th class="rechts">Kosten</th>
<th>Verrechnung</th><th class="rechts">Aktion</th>
</tr>
</thead>
<tbody>
<?php foreach ($buchungen as $buchung): ?>
<tr>
<td class="wahlspalte">
<input type="checkbox" name="buchungen[]" value="<?= (int)$buchung['id'] ?>"
form="depotbuchungsauswahl"
aria-label="Depotbuchung vom <?= View::h(View::datum($buchung['datum'])) ?> auswählen">
</td>
<td><?= View::h(View::datum($buchung['datum'])) ?></td>
<td>
<?= View::h(Depotbuchung::VORGAENGE[$buchung['vorgang']] ?? $buchung['vorgang']) ?>
<?php if ($buchung['vorgang_qif'] !== ''): ?>
<span class="nebentext"><?= View::h($buchung['vorgang_qif']) ?></span>
<?php endif; ?>
</td>
<td>
<?= View::h($buchung['wertpapier']) ?>
<?php if ($buchung['isin'] !== ''): ?>
<span class="nebentext"><?= View::h($buchung['isin']) ?></span>
<?php endif; ?>
</td>
<td><?= View::h($buchung['depot']) ?></td>
<td class="rechts">
<?= (float)$buchung['stueck'] === 0.0
? '–'
: View::h(rtrim(rtrim(number_format((float)$buchung['stueck'], 6, ',', '.'), '0'), ',')) ?>
</td>
<td class="rechts">
<?= $buchung['kurs'] === null ? '–' : View::h(number_format((float)$buchung['kurs'], 2, ',', '.')) ?>
</td>
<td class="rechts"><?= View::betrag($buchung['betrag']) ?></td>
<td class="rechts">
<?php $kosten = (float)$buchung['gebuehren'] + (float)$buchung['steuern']; ?>
<?= $kosten > 0.0 ? View::betrag($kosten) : '–' ?>
</td>
<td>
<?php if ($buchung['buchung_id'] !== null): ?>
<a href="/buchungen/<?= (int)$buchung['buchung_id'] ?>">
<?= View::h($buchung['verrechnungskonto'] ?? 'Buchung') ?>
</a>
<?php else: ?>
<span class="nebentext">–</span>
<?php endif; ?>
</td>
<td class="rechts">
<form method="post"
action="/wertpapiere/buchungen/<?= (int)$buchung['id'] ?>/loeschen<?= View::h($filterPfad()) ?>"
class="inline"
data-bestaetigen="Depotbuchung löschen? Die zugehörige Geldbuchung wird mitgelöscht.">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
<button type="submit" class="knopf klein gefahr">Löschen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<?php include __DIR__ . '/../layout/fuss.php'; ?>