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.negative_warning_cents,
ts.pdf_show_empty_rows,
ts.pdf_split_mode
ts.pdf_split_mode,
ts.pdf_row_height_px
FROM tenants t
LEFT JOIN tenant_settings ts ON ts.tenant_id = 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'],
'pdf_show_empty_rows' => (int)$settings['pdf_show_empty_rows'],
'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'] ?? '');
$paypalUrlTemplate = trim((string)($input['paypal_url_template'] ?? ''));
$pdfSplitMode = trim((string)($input['pdf_split_mode'] ?? 'drinking_behavior'));
$pdfRowHeightPx = filter_var($input['pdf_row_height_px'] ?? null, FILTER_VALIDATE_INT);
$errors = [];
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)) {
$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 !== []) {
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
(tenant_id, mark_price_cents, self_entry_enabled, paypal_enabled,
paypal_url_template, sheet_window_days, negative_warning_cents,
pdf_show_empty_rows, pdf_split_mode)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
pdf_show_empty_rows, pdf_split_mode, pdf_row_height_px)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
mark_price_cents = VALUES(mark_price_cents),
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),
negative_warning_cents = VALUES(negative_warning_cents),
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([
$tenantId,
@@ -398,6 +405,7 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
-abs($negativeWarningCents),
$pdfShowEmptyRows,
$pdfSplitMode,
(int)$pdfRowHeightPx,
]);
$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, ',', '.');
$showEmptyRows = (int)($settings['pdf_show_empty_rows'] ?? 1) === 1;
$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
// 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
// an der bisherigen Ausgabe (63 Zeilen a 16px auf einer vollen A4-Seite).
define('EXPORT_PAGE_ROW_BUDGET_PX', 63 * 16);
define('EXPORT_MIN_ROW_HEIGHT_PX', 16);
define('EXPORT_MAX_ROW_HEIGHT_PX', 40);
// Ziel-Zeilenzahl je Seite im Zweiseiten-Modus, wenn freie Zeilen erwuenscht
// sind - identisch zur bisherigen, getesteten Dichte (63 Zeilen a 16px).
define('EXPORT_MULTI_PAGE_FILL_ROWS', 63);
// Technischer Mindestwert, nur als letzte Bremse gegen 0/negative Hoehen bei
// absurd hohen Teilnehmerzahlen - kein gestalterisches Minimum.
define('EXPORT_HARD_MIN_ROW_HEIGHT_PX', 6);
$allActive = ledger_fetch_participant_summaries($pdo, $tenantId, ['active_only' => true]);
$memberCount = count($allActive);
$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
* richtet sich nach der Ziel-Zeilenzahl (Mitglieder plus ggf. Fuellzeilen),
* damit wenige Mitglieder groessere statt winziger Zeilen ergeben.
* Rendert eine Teilnehmerseite als HTML-Tabelle fuer TCPDF.
*
* @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 = '
<table border="1" style="white-space:nowrap;">
@@ -146,8 +160,8 @@ if (!$isMultiPage) {
'Kaffeeliste',
'background-color: rgb(0, 94, 63);color: rgb(255, 255, 255);',
$markPrice,
EXPORT_MULTI_PAGE_THRESHOLD,
$showEmptyRows,
$adminRowHeightPx,
null
),
true, false, true, false, ''
@@ -168,13 +182,13 @@ if (!$isMultiPage) {
$pdf->AddPage();
$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, ''
);
$pdf->AddPage();
$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, ''
);
}
+5
View File
@@ -34,6 +34,7 @@ if ($canManageSettings) {
'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_split_mode' => $_POST['pdf_split_mode'] ?? 'drinking_behavior',
'pdf_row_height_px' => $_POST['pdf_row_height_px'] ?? 16,
];
}
} else {
@@ -127,6 +128,10 @@ include 'nav.php';
<option value="alphabetical" <?php echo $settings['pdf_split_mode'] === 'alphabetical' ? 'selected' : ''; ?>>Alphabetisch</option>
</select>
</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>
<ul class="actions">
<li><button type="submit">Speichern</button></li>