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>
161 lines
5.4 KiB
PHP
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"; ?>
|