M5: Sammelerfassung (Striche/Einzahlungen) tenant-nativ machen
stricheintragen.php und einzahlung.php lasen ihren Mitarbeiter-Picker bisher direkt aus der global unscoped kl_Mitarbeiter-Tabelle. Fuer jeden Mandanten ausser dem Default-Mandanten zeigte das fremde Namen und Schreiben schlug (sicher, aber unverstaendlich) am Tenant-Check in ledger_mirror_legacy_* fehl. - Picker kommt jetzt aus participants (tenant-scoped), Formularfelder nutzen participant_id statt MitarbeiterID. - Schreibpfad pro Teilnehmer: mit legacy_mitarbeiter_id (Default-Mandant) weiterhin Dual-Write nach kl_Kaffeeverbrauch/kl_Einzahlungen plus Ledger-Spiegelung; ohne Legacy-Verknuepfung (jeder andere Mandant) direkt ueber neue ledger_record_consumption()/ledger_record_payment(). - Vorderseite/Rueckseite-Filter (100-Tage-Regel) bleiben fuer den Default-Mandanten exakt auf der bisherigen Legacy-Logik; andere Mandanten nutzen die neue ledger_fetch_participants_by_window_marks() mit tenant_settings.sheet_window_days. - Nebenbei behoben: einzahlung.php verlinkte auf ?aktion=... statt ?action=..., wodurch die Vorderseite/Rueckseite-Buttons nie griffen. Preis-pro-Strich-Vorbelegung kommt jetzt aus tenant_settings statt der seit M3 nicht mehr gepflegten kl_config-Tabelle. - Live getestet: isolierter Test-Mandant, Picker zeigt nur eigene Teilnehmer, Buchungen rein Ledger-nativ mit korrektem Saldo, 10-Striche- Schwelle korrekt sortiert, Default-Mandant-Dual-Write weiterhin gruen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -564,6 +564,85 @@ function ledger_void_entry_by_legacy_id(PDO $pdo, int $tenantId, string $legacyT
|
||||
return $stmt->rowCount() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a consumption entry straight into the ledger, without any legacy
|
||||
* kl_Kaffeeverbrauch row. Used for tenants that have no legacy shadow table
|
||||
* (every tenant except the migrated default tenant).
|
||||
*/
|
||||
function ledger_record_consumption(PDO $pdo, int $tenantId, int $participantId, int $marks, int $unitPriceCents, string $source, ?int $createdByUserId = null): int
|
||||
{
|
||||
$stmt = $pdo->prepare(
|
||||
"INSERT INTO ledger_entries
|
||||
(tenant_id, participant_id, type, amount_cents, marks_count, unit_price_cents, booked_at, source, created_by_user_id)
|
||||
SELECT ?, id, 'consumption', ?, ?, ?, NOW(), ?, ?
|
||||
FROM participants
|
||||
WHERE id = ? AND tenant_id = ?"
|
||||
);
|
||||
$stmt->execute([$tenantId, -($marks * $unitPriceCents), $marks, $unitPriceCents, $source, $createdByUserId, $participantId, $tenantId]);
|
||||
|
||||
if ($stmt->rowCount() !== 1) {
|
||||
throw new RuntimeException('Der Strich-Eintrag konnte nicht gespeichert werden.');
|
||||
}
|
||||
|
||||
return (int)$pdo->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a payment entry straight into the ledger, without any legacy
|
||||
* kl_Einzahlungen row. Used for tenants that have no legacy shadow table.
|
||||
*/
|
||||
function ledger_record_payment(PDO $pdo, int $tenantId, int $participantId, int $amountCents, string $source, ?int $createdByUserId = null): int
|
||||
{
|
||||
$stmt = $pdo->prepare(
|
||||
"INSERT INTO ledger_entries
|
||||
(tenant_id, participant_id, type, amount_cents, booked_at, source, created_by_user_id)
|
||||
SELECT ?, id, 'payment', ?, NOW(), ?, ?
|
||||
FROM participants
|
||||
WHERE id = ? AND tenant_id = ?"
|
||||
);
|
||||
$stmt->execute([$tenantId, $amountCents, $source, $createdByUserId, $participantId, $tenantId]);
|
||||
|
||||
if ($stmt->rowCount() !== 1) {
|
||||
throw new RuntimeException('Die Einzahlung konnte nicht gespeichert werden.');
|
||||
}
|
||||
|
||||
return (int)$pdo->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ledger-native equivalent of the legacy "100-Tage-Liste" front/back split:
|
||||
* active participants whose summed marks within the trailing window are at
|
||||
* or above the ten-mark threshold ($atLeastTen), or below it. Used for
|
||||
* tenants without a legacy kl_Kaffeeverbrauch history to filter against.
|
||||
*
|
||||
* @return list<array{participant_id: int, tenant_id: int, legacy_mitarbeiter_id: ?int, display_name: string, email: ?string, email_norm: ?string, paypal_name: ?string, active: bool, total_payments_cents: int, total_costs_cents: int, total_marks: int, balance_cents: int, year_payments_cents: int, year_costs_cents: int, year_marks: int}>
|
||||
*/
|
||||
function ledger_fetch_participants_by_window_marks(PDO $pdo, int $tenantId, int $windowDays, bool $atLeastTen): array
|
||||
{
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT p.id
|
||||
FROM participants p
|
||||
LEFT JOIN ledger_entries le
|
||||
ON le.tenant_id = p.tenant_id
|
||||
AND le.participant_id = p.id
|
||||
AND le.type = 'consumption'
|
||||
AND le.voided_at IS NULL
|
||||
AND le.booked_at >= DATE_SUB(NOW(), INTERVAL ? DAY)
|
||||
WHERE p.tenant_id = ?
|
||||
AND p.active = 1
|
||||
GROUP BY p.id
|
||||
HAVING COALESCE(SUM(le.marks_count), 0) " . ($atLeastTen ? '>= 10' : '< 10')
|
||||
);
|
||||
$stmt->execute([$windowDays, $tenantId]);
|
||||
$ids = array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN));
|
||||
|
||||
if ($ids === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ledger_fetch_participant_summaries($pdo, $tenantId, ['participant_ids' => $ids]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Options:
|
||||
* - participant_id: int
|
||||
|
||||
Reference in New Issue
Block a user