pdf erstellung aufhrbung der 50 Personen Grenze

This commit is contained in:
2026-07-19 23:24:36 +02:00
parent f0869d8e33
commit 0551b13a86
4 changed files with 49 additions and 20 deletions
+12 -4
View File
@@ -275,7 +275,8 @@ function saas_fetch_tenant_settings(PDO $pdo, int $tenantId): ?array
ts.sheet_window_days, ts.sheet_window_days,
ts.negative_warning_cents, ts.negative_warning_cents,
ts.pdf_show_empty_rows, ts.pdf_show_empty_rows,
ts.pdf_split_mode ts.pdf_split_mode,
ts.pdf_row_height_px
FROM tenants t FROM tenants t
LEFT JOIN tenant_settings ts ON ts.tenant_id = t.id LEFT JOIN tenant_settings ts ON ts.tenant_id = t.id
WHERE t.id = ? WHERE t.id = ?
@@ -310,6 +311,7 @@ function saas_fetch_tenant_settings(PDO $pdo, int $tenantId): ?array
'negative_warning_cents' => (int)$settings['negative_warning_cents'], 'negative_warning_cents' => (int)$settings['negative_warning_cents'],
'pdf_show_empty_rows' => (int)$settings['pdf_show_empty_rows'], 'pdf_show_empty_rows' => (int)$settings['pdf_show_empty_rows'],
'pdf_split_mode' => (string)$settings['pdf_split_mode'], 'pdf_split_mode' => (string)$settings['pdf_split_mode'],
'pdf_row_height_px' => (int)$settings['pdf_row_height_px'],
]; ];
} }
@@ -324,6 +326,7 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
$negativeWarningCents = saas_parse_money_cents($input['negative_warning'] ?? ''); $negativeWarningCents = saas_parse_money_cents($input['negative_warning'] ?? '');
$paypalUrlTemplate = trim((string)($input['paypal_url_template'] ?? '')); $paypalUrlTemplate = trim((string)($input['paypal_url_template'] ?? ''));
$pdfSplitMode = trim((string)($input['pdf_split_mode'] ?? 'drinking_behavior')); $pdfSplitMode = trim((string)($input['pdf_split_mode'] ?? 'drinking_behavior'));
$pdfRowHeightPx = filter_var($input['pdf_row_height_px'] ?? null, FILTER_VALIDATE_INT);
$errors = []; $errors = [];
if (strlen($tenantName) < 3 || strlen($tenantName) > 255) { if (strlen($tenantName) < 3 || strlen($tenantName) > 255) {
@@ -353,6 +356,9 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
if (!in_array($pdfSplitMode, ['drinking_behavior', 'alphabetical'], true)) { if (!in_array($pdfSplitMode, ['drinking_behavior', 'alphabetical'], true)) {
$errors[] = 'Die Sortierung für den Ausdruck ist ungültig.'; $errors[] = 'Die Sortierung für den Ausdruck ist ungültig.';
} }
if ($pdfRowHeightPx === false || $pdfRowHeightPx < 10 || $pdfRowHeightPx > 60) {
$errors[] = 'Die Zeilenhöhe im Ausdruck muss zwischen 10 und 60 Pixel liegen.';
}
if ($errors !== []) { if ($errors !== []) {
return ['ok' => false, 'errors' => $errors]; return ['ok' => false, 'errors' => $errors];
@@ -376,8 +382,8 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
'INSERT INTO tenant_settings 'INSERT INTO tenant_settings
(tenant_id, mark_price_cents, self_entry_enabled, paypal_enabled, (tenant_id, mark_price_cents, self_entry_enabled, paypal_enabled,
paypal_url_template, sheet_window_days, negative_warning_cents, paypal_url_template, sheet_window_days, negative_warning_cents,
pdf_show_empty_rows, pdf_split_mode) pdf_show_empty_rows, pdf_split_mode, pdf_row_height_px)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE
mark_price_cents = VALUES(mark_price_cents), mark_price_cents = VALUES(mark_price_cents),
self_entry_enabled = VALUES(self_entry_enabled), self_entry_enabled = VALUES(self_entry_enabled),
@@ -386,7 +392,8 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
sheet_window_days = VALUES(sheet_window_days), sheet_window_days = VALUES(sheet_window_days),
negative_warning_cents = VALUES(negative_warning_cents), negative_warning_cents = VALUES(negative_warning_cents),
pdf_show_empty_rows = VALUES(pdf_show_empty_rows), pdf_show_empty_rows = VALUES(pdf_show_empty_rows),
pdf_split_mode = VALUES(pdf_split_mode)' pdf_split_mode = VALUES(pdf_split_mode),
pdf_row_height_px = VALUES(pdf_row_height_px)'
); );
$stmt->execute([ $stmt->execute([
$tenantId, $tenantId,
@@ -398,6 +405,7 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
-abs($negativeWarningCents), -abs($negativeWarningCents),
$pdfShowEmptyRows, $pdfShowEmptyRows,
$pdfSplitMode, $pdfSplitMode,
(int)$pdfRowHeightPx,
]); ]);
$pdo->commit(); $pdo->commit();
@@ -0,0 +1,2 @@
ALTER TABLE tenant_settings
ADD COLUMN pdf_row_height_px SMALLINT NOT NULL DEFAULT 16 AFTER pdf_split_mode;
+30 -16
View File
@@ -31,6 +31,7 @@ $windowDays = $settings['sheet_window_days'] ?? 100;
$markPrice = number_format(($settings['mark_price_cents'] ?? 20) / 100, 2, ',', '.'); $markPrice = number_format(($settings['mark_price_cents'] ?? 20) / 100, 2, ',', '.');
$showEmptyRows = (int)($settings['pdf_show_empty_rows'] ?? 1) === 1; $showEmptyRows = (int)($settings['pdf_show_empty_rows'] ?? 1) === 1;
$splitMode = (string)($settings['pdf_split_mode'] ?? 'drinking_behavior'); $splitMode = (string)($settings['pdf_split_mode'] ?? 'drinking_behavior');
$adminRowHeightPx = (int)($settings['pdf_row_height_px'] ?? 16);
// Ab dieser Mitgliederzahl wird auf zwei Seiten (Vorder-/Rueckseite) statt // Ab dieser Mitgliederzahl wird auf zwei Seiten (Vorder-/Rueckseite) statt
// einer einzelnen Seite gedruckt. // einer einzelnen Seite gedruckt.
@@ -38,33 +39,46 @@ define('EXPORT_MULTI_PAGE_THRESHOLD', 50);
// Platzbudget in TCPDF-HTML-"px" fuer die Datenzeilen einer Seite, kalibriert // Platzbudget in TCPDF-HTML-"px" fuer die Datenzeilen einer Seite, kalibriert
// an der bisherigen Ausgabe (63 Zeilen a 16px auf einer vollen A4-Seite). // an der bisherigen Ausgabe (63 Zeilen a 16px auf einer vollen A4-Seite).
define('EXPORT_PAGE_ROW_BUDGET_PX', 63 * 16); define('EXPORT_PAGE_ROW_BUDGET_PX', 63 * 16);
define('EXPORT_MIN_ROW_HEIGHT_PX', 16); // Technischer Mindestwert, nur als letzte Bremse gegen 0/negative Hoehen bei
define('EXPORT_MAX_ROW_HEIGHT_PX', 40); // absurd hohen Teilnehmerzahlen - kein gestalterisches Minimum.
// Ziel-Zeilenzahl je Seite im Zweiseiten-Modus, wenn freie Zeilen erwuenscht define('EXPORT_HARD_MIN_ROW_HEIGHT_PX', 6);
// sind - identisch zur bisherigen, getesteten Dichte (63 Zeilen a 16px).
define('EXPORT_MULTI_PAGE_FILL_ROWS', 63);
$allActive = ledger_fetch_participant_summaries($pdo, $tenantId, ['active_only' => true]); $allActive = ledger_fetch_participant_summaries($pdo, $tenantId, ['active_only' => true]);
$memberCount = count($allActive); $memberCount = count($allActive);
$isMultiPage = $memberCount >= EXPORT_MULTI_PAGE_THRESHOLD; $isMultiPage = $memberCount >= EXPORT_MULTI_PAGE_THRESHOLD;
function export_row_height_px(int $targetRows): float /**
* Ermittelt Zeilenanzahl und -hoehe fuer eine Seite: Ausgangspunkt ist die
* vom Admin gewuenschte Zeilenhoehe. Sind Fuellzeilen erwuenscht, wird die
* Seite bis zu dieser Hoehe komplett aufgefuellt (weniger Mitglieder ->
* groessere, statt immer gleich viele Zeilen). Passt die Mitgliederzahl bei
* der gewuenschten Hoehe nicht auf eine Seite, wird bei jeder Generierung
* automatisch so weit verkleinert, dass garantiert alle Teilnehmer passen.
*
* @return array{0: int, 1: float} [targetRows, rowHeightPx]
*/
function export_compute_layout(int $memberCount, bool $showEmptyRows, int $adminRowHeightPx): array
{ {
$height = EXPORT_PAGE_ROW_BUDGET_PX / max(1, $targetRows); $adminRowHeightPx = max(1, $adminRowHeightPx);
$capacityAtAdminHeight = (int)floor(EXPORT_PAGE_ROW_BUDGET_PX / $adminRowHeightPx);
return max(EXPORT_MIN_ROW_HEIGHT_PX, min(EXPORT_MAX_ROW_HEIGHT_PX, $height)); $targetRows = $showEmptyRows ? max($memberCount, $capacityAtAdminHeight) : $memberCount;
$targetRows = max(1, $targetRows);
$rowHeight = min((float)$adminRowHeightPx, EXPORT_PAGE_ROW_BUDGET_PX / $targetRows);
$rowHeight = max(EXPORT_HARD_MIN_ROW_HEIGHT_PX, $rowHeight);
return [$targetRows, $rowHeight];
} }
/** /**
* Rendert eine Teilnehmerseite als HTML-Tabelle fuer TCPDF. Die Zeilenhoehe * Rendert eine Teilnehmerseite als HTML-Tabelle fuer TCPDF.
* richtet sich nach der Ziel-Zeilenzahl (Mitglieder plus ggf. Fuellzeilen),
* damit wenige Mitglieder groessere statt winziger Zeilen ergeben.
* *
* @param list<array> $teilnehmer * @param list<array> $teilnehmer
*/ */
function export_render_page_html(array $teilnehmer, string $titel, string $hinweisText, string $markPrice, int $targetRows, bool $showEmptyRows, ?string $seitenHinweis): string function export_render_page_html(array $teilnehmer, string $titel, string $hinweisText, string $markPrice, bool $showEmptyRows, int $adminRowHeightPx, ?string $seitenHinweis): string
{ {
$rowHeight = export_row_height_px($showEmptyRows ? $targetRows : max(1, count($teilnehmer))); [$targetRows, $rowHeight] = export_compute_layout(count($teilnehmer), $showEmptyRows, $adminRowHeightPx);
$html = ' $html = '
<table border="1" style="white-space:nowrap;"> <table border="1" style="white-space:nowrap;">
@@ -146,8 +160,8 @@ if (!$isMultiPage) {
'Kaffeeliste', 'Kaffeeliste',
'background-color: rgb(0, 94, 63);color: rgb(255, 255, 255);', 'background-color: rgb(0, 94, 63);color: rgb(255, 255, 255);',
$markPrice, $markPrice,
EXPORT_MULTI_PAGE_THRESHOLD,
$showEmptyRows, $showEmptyRows,
$adminRowHeightPx,
null null
), ),
true, false, true, false, '' true, false, true, false, ''
@@ -168,13 +182,13 @@ if (!$isMultiPage) {
$pdf->AddPage(); $pdf->AddPage();
$pdf->writeHTML( $pdf->writeHTML(
export_render_page_html($front, $frontTitel, 'background-color: rgb(0, 94, 63);color: rgb(255, 255, 255);', $markPrice, EXPORT_MULTI_PAGE_FILL_ROWS, $showEmptyRows, 'Rückseite beachten!'), export_render_page_html($front, $frontTitel, 'background-color: rgb(0, 94, 63);color: rgb(255, 255, 255);', $markPrice, $showEmptyRows, $adminRowHeightPx, 'Rückseite beachten!'),
true, false, true, false, '' true, false, true, false, ''
); );
$pdf->AddPage(); $pdf->AddPage();
$pdf->writeHTML( $pdf->writeHTML(
export_render_page_html($back, $backTitel, 'background-color: rgb(91, 209, 215);color: rgb(0, 0, 0);', $markPrice, EXPORT_MULTI_PAGE_FILL_ROWS, $showEmptyRows, 'Vorderseite beachten!'), export_render_page_html($back, $backTitel, 'background-color: rgb(91, 209, 215);color: rgb(0, 0, 0);', $markPrice, $showEmptyRows, $adminRowHeightPx, 'Vorderseite beachten!'),
true, false, true, false, '' true, false, true, false, ''
); );
} }
+5
View File
@@ -34,6 +34,7 @@ if ($canManageSettings) {
'negative_warning_cents' => -abs(saas_parse_money_cents($_POST['negative_warning'] ?? '') ?? 0), 'negative_warning_cents' => -abs(saas_parse_money_cents($_POST['negative_warning'] ?? '') ?? 0),
'pdf_show_empty_rows' => !empty($_POST['pdf_show_empty_rows']) ? 1 : 0, 'pdf_show_empty_rows' => !empty($_POST['pdf_show_empty_rows']) ? 1 : 0,
'pdf_split_mode' => $_POST['pdf_split_mode'] ?? 'drinking_behavior', 'pdf_split_mode' => $_POST['pdf_split_mode'] ?? 'drinking_behavior',
'pdf_row_height_px' => $_POST['pdf_row_height_px'] ?? 16,
]; ];
} }
} else { } else {
@@ -127,6 +128,10 @@ include 'nav.php';
<option value="alphabetical" <?php echo $settings['pdf_split_mode'] === 'alphabetical' ? 'selected' : ''; ?>>Alphabetisch</option> <option value="alphabetical" <?php echo $settings['pdf_split_mode'] === 'alphabetical' ? 'selected' : ''; ?>>Alphabetisch</option>
</select> </select>
</div> </div>
<div class="col-6 col-12-small">
<label for="pdf_row_height_px">Zeilenhöhe im Ausdruck (1060px)</label>
<input type="number" name="pdf_row_height_px" id="pdf_row_height_px" min="10" max="60" value="<?php echo saas_html($settings['pdf_row_height_px']); ?>" required>
</div>
</div> </div>
<ul class="actions"> <ul class="actions">
<li><button type="submit">Speichern</button></li> <li><button type="submit">Speichern</button></li>