false, 'message' => $data['message']]); exit; } require $baseDir . '/../scripts/db/db-tables.php'; require $baseDir . '/../scripts/db/db-functions.php'; $wkName = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['wkName']); $wkName = ($wkName === null) ? 'Keinen Wettkampfname angegeben. Setzen unter: /intern/wk-leitung/einstellungen' : $wkName; $normalFontSize = 11; $marginSide = 10; $marginTop = 10; $minMarginBottomTable = 20; $format = 'A4'; $orientation = 'L'; $svgs = [ '1' => '', '2' => '', '3' => '' ]; $now = trim($_POST['date'] ?? date('Y-m-d H:i:s')); $logEntries = db_select($mysqli, $tableOrdersLog, "*"); $personen = db_select($mysqli, $tableInternUsers, "`id`, `name_person`, `username`"); $indexedPersonen = array_column($personen, null, 'id'); $entriesArray = []; foreach ($logEntries as $slE) { // $value = ($slE['old_order_status'] !== null) ? ($svgs[$slE['old_order_status']] ?? $slE['old_order_status']) . ' ' . json_decode('"\u2192"') . ' ' . ($svgs[$slE['new_order_status'] ?? ''] ?? $slE['new_order_status'] ?? '') : ($svgs[$slE['new_order_status'] ?? ''] ?? $slE['new_order_status'] ?? ''); $valueArray = [ 1 => $svgs[$slE['old_order_status'] ?? ''] ?? '', 2 => isset($svgs[$slE['old_order_status']]), 3 => $svgs[$slE['new_order_status'] ?? ''] ?? '', 4 => isset($svgs[$slE['new_order_status']]) ]; $entriesArray[] = [ 'order_id' => $slE['order_id'] ?? '', 'value' => $valueArray, 'edited_by' => $indexedPersonen[$slE['edited_by']]['name_person'] ?? 'Unbekannter User', 'timestamp' => new DateTime($slE['edited_at'])->format('d.m.Y H:i:s') ?? '---' ]; } // Load TCPDF require $baseDir . '/../composer/vendor/autoload.php'; class ProtokollPDF extends TCPDF { public $columns; public $wkName; public $marginSide; public $marginTop; public $pdfHeight; public $pdfWidth; public $headerType; public $now; // Page header public $headerBottomY = 0; public function Header() { $this->SetFillColor(255, 255, 255); $this->Rect(0, 0, $this->pdfWidth, $this->pdfHeight, 'F'); $arrayTitles = []; $image_file = $_SERVER['DOCUMENT_ROOT'] . '/intern/img/logo-normal.png'; $this->SetY($this->marginTop); $this->SetX(($this->marginSide ?? 10)); $this->SetFont('freesans', '', 20); $this->Cell(0, 0, 'Protokoll Rechnungen ' . $this->wkName, 0, 1, 'L', 0, '', 0, false, 'T', 'M'); $preimageX = $this->GetX(); $preimageY = $this->GetY(); $this->Image($image_file, $this->pdfWidth - 10 - $this->marginSide, $this->marginTop, '', 10, 'png', '', 'T'); $this->SetY($preimageY + 5); $this->SetX($this->marginSide ?? 10); // Force back to left margin $this->SetFont('freesans', '', 11); $this->Ln(5); $columns = $this->columns; $startY = $this->GetY(); $this->SetFont('', 'B'); $this->SetX($this->marginSide ?? 10); foreach ($columns as $col) { $title = $col['header']; if (($col['rotate'] ?? false)) { $x = $this->GetX(); $y = $this->GetY() + 7; $this->StartTransform(); $this->Rotate(45, $x, $y); $lineY = $startY + 7; if (($col['id'] ?? '') === 'gesamt') { $this->SetLineWidth(0.6); } else { $this->SetLineWidth(0.2); } $this->Line($x, $lineY, $x + ($col['width_header'] ?? 0), $lineY); $this->SetLineWidth(0.2); $this->Cell($col['width_header'] ?? 0, 7, $title ?? '', 0, 0, 'C'); $this->StopTransform(); $this->SetX($x + ($col['max_width'] ?? 0)); } else { $this->Cell($col['max_width'] ?? 0, 7, $title ?? '', 0, 0, $col['align'] ?? 'L'); } } $this->Ln(); $this->headerBottomY = $this->GetY(); } // Page footer public function Footer() { $this->SetLineWidth(0.6); $this->Line($this->marginSide ?? 10, $this->headerBottomY, $this->pdfWidth - ($this->marginSide ?? 10), $this->headerBottomY); $this->SetLineWidth(0.2); $this->SetY(0); $this->SetX(0); $this->SetFillColor(255, 255, 255); // white $this->Cell(($this->marginSide ?? 10), $this->pdfHeight, '', 0, 0, 'L', true); $this->SetY(0); $this->SetX($this->pdfWidth - ($this->marginSide ?? 10)); $this->Cell(($this->marginSide ?? 10), $this->pdfHeight, '', 0, 0, 'L', true); $this->SetY(-15); $this->SetFont('freesans', 'I', 8); // 1. Page Number - Centered $this->Cell(0, 10, 'Seite ' . $this->getAliasNumPage() . ' von ' . $this->getAliasNbPages(), 0, false, 'C'); // 2. Timestamp - Force to Left $this->SetX($this->getMargins()['left']); // Reset to left margin $this->Cell(0, 10, 'Zeitstempel: ' . $this->now, 0, false, 'L'); // 3. Host - Force to Right (Cell with width 0 and align 'R' handles this) $this->SetX($this->getMargins()['left']); // Reset again so 'R' alignment works from the start $this->Cell(0, 10, $_SERVER['HTTP_HOST'], 0, 0, 'R', false, 'https://'.$_SERVER['HTTP_HOST']); } } $pdf = new ProtokollPDF($orientation, 'mm', $format, true, 'UTF-8', false); $pdfHeight = $pdf->getPageHeight(); $pdfWidth = $pdf->getPageWidth(); $pdf->wkName = $wkName; $pdf->marginSide = $marginSide; $pdf->marginTop = $marginTop; $pdf->pdfHeight = $pdfHeight; $pdf->pdfWidth = $pdfWidth; $pdf->now = $now; $pdf->SetCreator(PDF_CREATOR); $pdf->SetAuthor($wkName); $pdf->SetTitle($wkName . "_Protokoll.pdf"); $pdf->SetAutoPageBreak(FALSE); $pdf->SetFont('freesans', '', 11); // Define columns dynamically $columns = [ ['id' => 'order_id', 'header' => 'Rechnungsnummer', 'align' => 'L', 'flex' => true, 'type' => 'link', 'field' => 'order_id'], ['id' => 'value', 'header' => 'Änderung', 'align' => 'L', 'flex' => true, 'type' => 'value', 'field' => 'value'], ['id' => 'edited_by', 'header' => 'Geändert durch', 'align' => 'C', 'flex' => true, 'type' => 'field', 'field' => 'edited_by'], ['id' => 'timestamp', 'header' => 'Zeitstempel', 'align' => 'C', 'flex' => true, 'type' => 'field', 'field' => 'timestamp'], ]; $padding = 4; // 1. Calculate initial max widths based on headers foreach ($columns as &$col) { $col['width_header'] = $pdf->GetStringWidth($col['header']) + ($padding * 2); if ($col['type'] !== 'note') { $col['max_width'] = $col['width_header']; } else { $col['max_width'] = 0; } } unset($col); foreach ($entriesArray as $row) { foreach ($columns as $col) { $text = ''; if ($col['type'] !== 'value') { if (isset($row[$col['field']])) { $text = $row[$col['field']]; } $width = $pdf->GetStringWidth($text) + ($padding * 2); if ($width > $col['max_width']) { $col['max_width'] = $width; } } else { if (40 > $col['max_width']) { $col['max_width'] = 40; } } } } $fixedWidth = 0; foreach ($columns as $col) { if ($col['flex'] ?? false) { $flexCols[] = $col['id']; $fixedWidth += $col['max_width']; } else { $fixedWidth += $col['max_width']; } } $tablew = $pdfWidth - (2 * $marginSide); $effTableWidth = $tablew - $fixedWidth; if (!empty($flexCols) && $effTableWidth > 0) { $flexTotalInitial = 0; foreach ($columns as $col) { if ($col['flex'] ?? false) $flexTotalInitial += $col['max_width']; } foreach ($columns as &$col) { if ($col['flex'] ?? false) { $col['max_width'] += ($col['max_width'] / $flexTotalInitial) * $effTableWidth; } } unset($col); } $pdf->columns = $columns; $pdf->AddPage(); $margin_top = $pdf->headerBottomY; $pdf->SetMargins($marginSide, $margin_top, $marginSide); // +5 mm padding below header $pdf->SetY($margin_top); // Move cursor below header manually $pdf->SetFont('', ''); foreach ($entriesArray as $row) { $rowHeight = 10; foreach ($columns as $col) { $pdf->setFillColor(255, 255, 255); if ($pdf->getY() + $rowHeight > $pdfHeight - $minMarginBottomTable) { $pdf->addPage(); $margin_top = $pdf->headerBottomY; $pdf->setY($margin_top); } $customFontSize = (isset($col['font_size']) && $col['font_size'] != 0); if ($customFontSize) { $pdf->SetFont('', '', $col['font_size']); } $startX = $pdf->GetX(); $startY = $pdf->GetY(); if ($col['type'] === 'field') { $text = $row[$col['field']] ?? ''; $pdf->MultiCell($col['max_width'], $rowHeight, $text, 'B', $col['align'], true, 0, $startX, $startY, true, 0, false, true, $rowHeight, 'M'); } elseif ($col['type'] === 'value') { $pdf->MultiCell($col['max_width'], $rowHeight, '', 'B', $col['align'], true, 0, $startX, $startY, true, 0, false, true, $rowHeight, 'M'); $valuesArrary = $row[$col['field']]; if (isset($valuesArrary[1]) && isset($valuesArrary[2]) && $valuesArrary[2]) { $pdf->ImageSVG('@' . $valuesArrary[1], $startX, $startY + 2, $rowHeight - 4, $rowHeight - 4); $pdf->MultiCell(10, $rowHeight, json_decode('"\u2192"'), '', 'C', false, 0, $startX + $rowHeight - 4, $startY, true, 0, false, true, $rowHeight, 'M'); } if (isset($valuesArrary[3]) && isset($valuesArrary[3]) && $valuesArrary[4]) { $pdf->ImageSVG('@' . $valuesArrary[3], $startX + $rowHeight - 4 + 10, $startY + 2, $rowHeight - 4, $rowHeight - 4); } $pdf->SetX($startX + $col['max_width']); } elseif ($col['type'] === 'link') { $text = $row[$col['field']] ?? ''; $pdf->MultiCell($col['max_width'], $rowHeight, $text, 'B', $col['align'], true, 0, $startX, $startY, true, 0, false, true, $rowHeight, 'M'); $pdf->Link($startX, $startY, $col['max_width'], $rowHeight, 'https://'.$_SERVER['HTTP_HOST'].'/intern/wk-leitung/rechnungen-viewer?order_id='.$text); } if ($customFontSize) { $pdf->SetFont('', '', $normalFontSize); } } $pdf->SetY($startY + $rowHeight); } $textanzEintaege = (count($entriesArray) > 1) ? 'Einträge': 'Eintrag'; $pdf->SetFont('', '', 7); $pdf->Cell(20, 6, count($entriesArray).' '.$textanzEintaege, 0, 0, 'L'); $pdf->SetFont('', '', $normalFontSize); $pdf->Output($wkName . "_Protokoll_Rechnungen.pdf", 'I'); exit;