Legacy-Abbau Schritt 1: Dual-Write in die kl_*-Tabellen entfernt

Die Migration in participants/ledger_entries ist abgeschlossen: kein
Teilnehmer traegt noch eine legacy_mitarbeiter_id, kein Journaleintrag eine
legacy_table. Damit war der jeweils zweite Zweig ("Default-Mandant schreibt
zusaetzlich nach kl_Einzahlungen/kl_Kaffeeverbrauch/kl_Mitarbeiter") in
sechs Dateien nicht mehr erreichbar - er musste aber bei jeder Aenderung
mitgepflegt werden, zuletzt bei der Bemerkung fuer Einzahlungen.

Entfernt:
- Dual-Write beim Buchen: einzahlung.php, stricheintragen.php, index.php,
  jahresauswertung.php, app/imports.php, app/paypal-inbox.php
- Dual-Write in der Mitgliederverwaltung: ledger_create_participant,
  ledger_update_participant, ledger_set_participant_active,
  ledger_anonymize_participant
- die verwaisten Spiegelfunktionen ledger_mirror_legacy_payment,
  ledger_mirror_legacy_consumption und ledger_void_entry_by_legacy_id

Nebenbei behoben: kaffeeliste.php hat die Teilnehmer-Detailseite nur fuer
Mitglieder mit legacy_mitarbeiter_id verlinkt - die hat seit der Migration
niemand mehr, die Seite war also fuer alle unerreichbar. Verlinkt und
adressiert wird jetzt ueber participant_id; "user_id" bleibt als Alias
erhalten. Der Mandanten-Isolationstest prueft jetzt ledger_void_entry, also
den Pfad, den letzteneintraege.php tatsaechlich nutzt.

Pruefskripte unveraendert gegenueber der Baseline vor dem Umbau
(http-smoke 27/6, role-matrix 55/0); die Isolationspruefung steigt von
9 auf 11 PASS bei gleichem vorbestehendem Fehler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 20:57:49 +02:00
co-authored by Claude Opus 4.8
parent dd6e1e77b0
commit eec7a2fef2
11 changed files with 98 additions and 482 deletions
+16 -57
View File
@@ -43,34 +43,14 @@ if (!$hasAccess) {
}
/**
* Liefert die Mitarbeiter/Teilnehmerliste fuer die Vorder-/Rueckseiten- oder
* Alle-Auswahl. Siehe stricheintragen.php fuer dieselbe Logik: Default-
* Mandant nutzt die Legacy-Historie, andere Mandanten die Ledger-native
* Fensterpruefung mit dem konfigurierten Listenfenster.
* Liefert die Teilnehmerliste fuer die Vorder-/Rueckseiten- oder Alle-Auswahl.
* Siehe stricheintragen.php fuer dieselbe Logik.
*
* @return list<array>
*/
function einzahlung_fetch_participants(PDO $pdo, int $tenantId, string $action): array
{
$isDefault = ledger_is_default_tenant($pdo, $tenantId);
if ($action === 'vorderseite' || $action === 'rueckseite') {
if ($isDefault) {
$vergleich = $action === 'vorderseite' ? '>= 10' : '< 10';
$join = $action === 'vorderseite' ? 'JOIN' : 'LEFT JOIN';
$stmt = $pdo->query(
"SELECT M.MitarbeiterID
FROM kl_Mitarbeiter M
{$join} kl_Kaffeeverbrauch V ON M.MitarbeiterID = V.MitarbeiterID AND V.Datum >= DATE_SUB(NOW(), INTERVAL 100 DAY)
WHERE M.aktiv = 1
GROUP BY M.MitarbeiterID
HAVING COALESCE(SUM(V.AnzahlStriche), 0) {$vergleich}"
);
$legacyIds = array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN));
return ledger_fetch_participant_summaries($pdo, $tenantId, ['legacy_mitarbeiter_ids' => $legacyIds]);
}
$settings = saas_fetch_tenant_settings($pdo, $tenantId);
$windowDays = $settings['sheet_window_days'] ?? 100;
@@ -94,24 +74,13 @@ const EINZAHLUNG_MAX_BETRAG = 1000.00;
// Verarbeitung des Formulars, wenn es gesendet wurde
if ($_SERVER["REQUEST_METHOD"] == "POST" ) {
$hatGespeichert = true;
$datum = date("Y-m-d H:i:s"); // Das aktuelle Datum verwenden
// Legacy-Verknuepfung je Teilnehmer vorab laden, damit pro Zeile
// entschieden werden kann, ob (Default-Mandant) zusaetzlich in
// kl_Einzahlungen geschrieben oder (jeder andere Mandant) direkt ins
// Ledger gebucht wird.
$legacyMap = [];
$stmt = $pdo->prepare('SELECT id, legacy_mitarbeiter_id FROM participants WHERE tenant_id = ?');
// Teilnehmer des Mandanten: dient zugleich der Zugehoerigkeitspruefung und
// liefert die Namen fuer verstaendliche Fehlermeldungen.
$namen = [];
$stmt = $pdo->prepare('SELECT id, display_name FROM participants WHERE tenant_id = ?');
$stmt->execute([$tenantId]);
foreach ($stmt->fetchAll() as $row) {
$legacyMap[(int)$row['id']] = $row['legacy_mitarbeiter_id'] !== null ? (int)$row['legacy_mitarbeiter_id'] : null;
}
// Namen fuer verstaendliche Fehlermeldungen.
$namen = [];
$stmtNamen = $pdo->prepare('SELECT id, display_name FROM participants WHERE tenant_id = ?');
$stmtNamen->execute([$tenantId]);
foreach ($stmtNamen->fetchAll() as $row) {
$namen[(int)$row['id']] = (string)$row['display_name'];
}
@@ -121,7 +90,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" ) {
$zuBuchen = [];
foreach ($_POST["anzahlBetrag"] ?? [] as $participantId => $anzahlBetrag) {
$participantId = (int)$participantId;
if ($participantId <= 0 || !array_key_exists($participantId, $legacyMap)) {
if ($participantId <= 0 || !array_key_exists($participantId, $namen)) {
continue;
}
@@ -180,27 +149,17 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" ) {
} else {
try {
$pdo->beginTransaction();
$insertLegacy = $pdo->prepare(
"INSERT INTO kl_Einzahlungen (MitarbeiterID, Betrag, Bemerkung, Datum) VALUES (?, ?, ?, ?)"
);
foreach ($zuBuchen as $participantId => $zeile) {
$legacyMitarbeiterId = $legacyMap[$participantId];
if ($legacyMitarbeiterId !== null) {
$insertLegacy->execute([$legacyMitarbeiterId, $zeile['betrag'], $zeile['bemerkung'], $datum]);
$legacyPaymentId = (int)$pdo->lastInsertId();
ledger_mirror_legacy_payment($pdo, $tenantId, $legacyPaymentId);
} else {
ledger_record_payment(
$pdo,
$tenantId,
$participantId,
(int)round($zeile['betrag'] * 100),
'manual_bulk',
$saasUser['user_id'] ?? null,
$zeile['bemerkung']
);
}
ledger_record_payment(
$pdo,
$tenantId,
$participantId,
(int)round($zeile['betrag'] * 100),
'manual_bulk',
$saasUser['user_id'] ?? null,
$zeile['bemerkung']
);
$eingetragen++;
}