Files
kaffeekasse-saas/letzteneintraege.php
T
clemensandClaude Opus 4.8 dd6e1e77b0 Bemerkung und Abzuege bei Einzahlungen
Einzahlungen koennen jetzt eine Bemerkung tragen und negativ sein, damit
Abzuege (Auszahlung bei Austritt, Erstattung) nachvollziehbar gebucht werden
koennen.

- ledger_entries.note wurde bisher nur beim Import befuellt und wird nun auch
  bei Einzahlungen geschrieben und angezeigt
- Negative Betraege verlangen zwingend eine Bemerkung, sonst ist spaeter nicht
  mehr nachvollziehbar, warum jemandem Geld abgezogen wurde
- Plausibilitaetsgrenze von 1000 EUR gegen Groessenordnungs-Tippfehler; bei
  einem Fehler in einer Zeile wird gar nichts gebucht und die Eingaben bleiben
  stehen
- Legacy-Tabelle kl_Einzahlungen bekommt eine Bemerkung-Spalte, sonst haette
  ledger_mirror_legacy_payment die Notiz beim Re-Sync wieder mit NULL
  ueberschrieben
- PayPal-Buchungen tragen jetzt Zahler, Datum und Mitteilung als Bemerkung

Ausserdem behoben: letzteneintraege.php hat Einzahlungen und Striche direkt
aus den Legacy-Tabellen gelesen, ohne nach Mandant zu filtern. Jeder
Mandanten-Admin sah damit die Buchungen aus den Legacy-Tabellen, und das
Stornieren lief ueber die nicht mandantengetrennten Legacy-IDs. Die Seite
arbeitet jetzt auf dem mandantengebundenen Journal, und ledger_void_entry
prueft Mandant und Buchungsart, bevor es storniert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 19:53:10 +02:00

161 lines
5.4 KiB
PHP

<?php
include "functions.php";
require_once __DIR__ . "/app/ledger.php";
require_once __DIR__ . "/app/audit.php";
app_require_csrf();
include "header.php";
include "headerline.php";
include "nav.php";
?>
<!-- Banner -->
<section id="banner">
<div class="content">
<?php
$pdo = app_db_pdo();
$saasUser = saas_current_user($pdo);
$tenantId = 0;
$hasAccess = false;
if ($saasUser !== null && saas_user_has_role(['owner', 'admin', 'treasurer'], $saasUser)) {
$tenantId = (int)$saasUser['tenant_id'];
$hasAccess = true;
}
if (!$hasAccess && $saasUser === null && checkKaffeelisteAdmin($conn, $mailadress)) {
$tenant = ledger_fetch_default_tenant($pdo);
if ($tenant !== null) {
$tenantId = (int)$tenant['id'];
$hasAccess = true;
}
}
if($hasAccess){
// Stornieren einer Einzahlung. Gearbeitet wird auf der Ledger-ID, weil nur die
// mandantensicher geprueft werden kann - die Legacy-IDs sind nicht nach
// Mandant getrennt. Der Eintrag wird als storniert markiert statt geloescht,
// damit die Buchungshistorie nachvollziehbar bleibt.
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["aktion"]) && $_POST["aktion"] == "loescheneinzahlung") {
$entryId = (int)($_POST["entryId"] ?? 0);
if (ledger_void_entry($pdo, $tenantId, $entryId, 'payment')) {
app_audit_log($pdo, $tenantId, $saasUser['user_id'] ?? null, 'payment.voided', 'ledger_entries', $entryId);
echo "<div class='hint-box success'><p>Einzahlung wurde storniert.</p></div>";
} else {
echo "<div class='hint-box error'><p>Die Einzahlung konnte nicht storniert werden. Vielleicht wurde sie bereits storniert.</p></div>";
}
}
$einzahlungen = ledger_fetch_recent_entries($pdo, $tenantId, ['type' => 'payment', 'limit' => 100]);
?>
<h2>Letzte 100 Einzahlungen</h2>
<p><small>Stornieren ist der richtige Weg, wenn eine Buchung <b>falsch eingetragen</b> wurde. Für einen tatsächlichen Abzug (Auszahlung, Erstattung) stattdessen unter <a href="einzahlung.php">Einzahlung eintragen</a> einen negativen Betrag mit Bemerkung buchen.</small></p>
<table border="1" class="table table-striped">
<tr>
<th>Name des Mitarbeiters</th>
<th>Betrag</th>
<th>Bemerkung</th>
<th>Datum</th>
<th>Aktion</th>
</tr>
<?php
foreach ($einzahlungen as $eintrag) {
$betrag = number_format($eintrag['amount_cents'] / 100, 2, ',', '.');
echo "<tr>";
echo "<td>" . saas_html($eintrag['display_name']) . "</td>";
echo "<td>" . saas_html($betrag) . " €</td>";
echo "<td>" . saas_html((string)($eintrag['note'] ?? '')) . "</td>";
echo "<td>" . saas_html($eintrag['booked_at']) . "</td>";
echo "<td>";
echo "<form method='post' action='letzteneintraege.php' onsubmit=\"return confirm('Diese Einzahlung wirklich stornieren?');\">";
echo "<input type='hidden' name='aktion' value='loescheneinzahlung'>";
echo "<input type='hidden' name='entryId' value='" . (int)$eintrag['id'] . "'>";
echo app_csrf_field();
echo "<button type='submit'>Stornieren</button>";
echo "</form>";
echo "</td>";
echo "</tr>";
}
if ($einzahlungen === []) {
echo "<tr><td colspan='5'>Noch keine Einzahlungen erfasst.</td></tr>";
}
?>
</table>
<br><br>
<?php
// Stornieren eines Strich-Eintrags, ebenfalls ueber die mandantensichere
// Ledger-ID.
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["aktion"]) && $_POST["aktion"] == "loeschen") {
$entryId = (int)($_POST["entryId"] ?? 0);
if (ledger_void_entry($pdo, $tenantId, $entryId, 'consumption')) {
app_audit_log($pdo, $tenantId, $saasUser['user_id'] ?? null, 'consumption.voided', 'ledger_entries', $entryId);
echo "<div class='hint-box success'><p>Strich-Eintrag wurde storniert.</p></div>";
} else {
echo "<div class='hint-box error'><p>Der Strich-Eintrag konnte nicht storniert werden. Vielleicht wurde er bereits storniert.</p></div>";
}
}
$striche = ledger_fetch_recent_entries($pdo, $tenantId, ['type' => 'consumption', 'limit' => 100]);
?>
<h2>Letzte 100 Strich-Einträge</h2>
<table border="1" class="table table-striped">
<tr>
<th>Name des Mitarbeiters</th>
<th>Anzahlstriche</th>
<th>Betrag</th>
<th>Datum</th>
<th>Aktion</th>
</tr>
<?php
foreach ($striche as $eintrag) {
// Verbrauch ist im Journal negativ hinterlegt, hier als positive Kosten zeigen.
$betrag = number_format(-$eintrag['amount_cents'] / 100, 2, ',', '.');
echo "<tr>";
echo "<td>" . saas_html($eintrag['display_name']) . "</td>";
echo "<td>" . (int)($eintrag['marks_count'] ?? 0) . "</td>";
echo "<td>" . saas_html($betrag) . " €</td>";
echo "<td>" . saas_html($eintrag['booked_at']) . "</td>";
echo "<td>";
echo "<form method='post' action='letzteneintraege.php' onsubmit=\"return confirm('Diesen Strich-Eintrag wirklich stornieren?');\">";
echo "<input type='hidden' name='aktion' value='loeschen'>";
echo "<input type='hidden' name='entryId' value='" . (int)$eintrag['id'] . "'>";
echo app_csrf_field();
echo "<button type='submit'>Stornieren</button>";
echo "</form>";
echo "</td>";
echo "</tr>";
}
if ($striche === []) {
echo "<tr><td colspan='5'>Noch keine Striche erfasst.</td></tr>";
}
?>
</table>
<?php
}else{
echo "<h2>Kein Zugriff</h2>";
}
?>
</div>
</section>
<?php include "footer.php"; ?>