Die Zugriffspruefung lief bisher in 19 Dateien auf einen Fallback gegen die Legacy-Tabelle kl_Mitarbeiter (checkKaffeelisteAdmin/-Access). Der Zugang haengt jetzt ausschliesslich an der SaaS-Anmeldung. - Fallback-Bloecke in allen 19 Dateien entfernt, ebenso getUserName/getUserId - functions.php besteht nur noch aus der SaaS-Anmeldung; die per String zusammengebaute Abfrage "WHERE Email like '<eingabe>'" ist damit weg - config.php baut keine sqlsrv-Verbindung mehr auf, der Kompatibilitaetslayer lib/sqlsrv_mysql_compat.php ist verwaist und entfaellt - Auto-Login per DEV_AUTH_EMAIL gibt es nicht mehr: er meldete jeden Besucher an und machte damit den Login-Schutz unpruefbar. Angemeldet wird auch lokal ueber login.php; die Variable dient nur noch scripts/init-mysql-dev.php http-smoke war an die Golden-Master-Daten des Default-Mandanten gebunden und hatte deshalb sechs dauerhaft rote Pruefungen. Der Test legt sich jetzt einen eigenen Mandanten mit bekannten Salden an, meldet sich per HTTP an und raeumt danach auf. Geschuetzte Seiten werden nicht mehr ueber das Wort "Login" im Text geprueft, sondern ueber die tatsaechliche 302-Umleitung. http-smoke 27 PASS / 6 FAIL -> 33 PASS / 0 FAIL role-matrix 55 PASS / 0 FAIL -> unveraendert tenant-isolation 9 PASS / 1 FAIL -> 11 PASS / 1 FAIL (Altfehler) Ausserdem "keine Zugang" -> "keinen Zugang" in zwei Fehlermeldungen; der Rollentest erkannte die Ablehnung an genau diesem Tippfehler und wurde mitgezogen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
153 lines
5.2 KiB
PHP
153 lines
5.2 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){
|
|
|
|
// 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"; ?>
|