kundenkarte/ajax/export_tree_pdf.php

432 lines
13 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 Alles Watt lauft
*
* PDF Export for Anlage Tree
*/
$res = 0;
if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
if (!$res && file_exists("../../../../main.inc.php")) $res = @include "../../../../main.inc.php";
if (!$res) die("Include of main fails");
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
dol_include_once('/kundenkarte/class/anlage.class.php');
dol_include_once('/kundenkarte/class/anlagetype.class.php');
dol_include_once('/kundenkarte/class/anlagefile.class.php');
$langs->loadLangs(array('companies', 'kundenkarte@kundenkarte'));
// Get parameters
$socId = GETPOSTINT('socid');
$contactId = GETPOSTINT('contactid');
$systemId = GETPOSTINT('system');
// Security check
if (!$user->hasRight('kundenkarte', 'read')) {
accessforbidden();
}
// Load company
$societe = new Societe($db);
$societe->fetch($socId);
// Load contact if specified
$contact = null;
if ($contactId > 0) {
$contact = new Contact($db);
$contact->fetch($contactId);
}
// Load system info
$systemLabel = '';
$sql = "SELECT label FROM ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system WHERE rowid = ".((int) $systemId);
$resql = $db->query($sql);
if ($resql && $obj = $db->fetch_object($resql)) {
$systemLabel = $obj->label;
}
// Load tree
$anlage = new Anlage($db);
if ($contactId > 0) {
$tree = $anlage->fetchTreeByContact($socId, $contactId, $systemId);
} else {
$tree = $anlage->fetchTree($socId, $systemId);
}
// Load all type fields for display (including headers)
$typeFieldsMap = array();
$sql = "SELECT f.*, f.fk_anlage_type FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_type_field f WHERE f.active = 1 ORDER BY f.position ASC";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
if (!isset($typeFieldsMap[$obj->fk_anlage_type])) {
$typeFieldsMap[$obj->fk_anlage_type] = array();
}
$typeFieldsMap[$obj->fk_anlage_type][] = $obj;
}
}
// Create PDF
$pdf = pdf_getInstance();
$pdf->SetCreator('Dolibarr - Kundenkarte');
$pdf->SetAuthor($user->getFullName($langs));
$title = $systemLabel.' - '.$societe->name;
if ($contact) {
$title .= ' - '.$contact->getFullName($langs);
}
$pdf->SetTitle($title);
$pdf->SetMargins(15, 15, 15);
$pdf->SetAutoPageBreak(true, 15);
$pdf->SetFont('dejavusans', '', 9);
// Check for PDF template
$tplidx = null;
$templateFile = $conf->kundenkarte->dir_output.'/templates/export_template.pdf';
if (file_exists($templateFile) && is_readable($templateFile)) {
try {
$pagecount = $pdf->setSourceFile($templateFile);
$tplidx = $pdf->importPage(1);
} catch (Exception $e) {
// Template could not be loaded, continue without
$tplidx = null;
}
}
$pdf->AddPage();
if (!empty($tplidx)) {
$pdf->useTemplate($tplidx);
}
// Compact header - left aligned
$pdf->SetFont('dejavusans', 'B', 14);
$pdf->Cell(120, 6, $systemLabel, 0, 1, 'L');
$pdf->SetFont('dejavusans', '', 9);
$pdf->SetTextColor(80, 80, 80);
// Customer info in one compact block
$customerInfo = $societe->name;
if ($contact) {
$customerInfo .= ' | '.$contact->getFullName($langs);
}
$pdf->Cell(120, 4, $customerInfo, 0, 1, 'L');
// Address
$address = array();
if ($societe->address) $address[] = $societe->address;
if ($societe->zip || $societe->town) $address[] = trim($societe->zip.' '.$societe->town);
if (!empty($address)) {
$pdf->Cell(120, 4, implode(', ', $address), 0, 1, 'L');
}
// Date and count
$totalElements = countTreeElements($tree);
$pdf->Cell(120, 4, dol_print_date(dol_now(), 'day').' | '.$totalElements.' Elemente', 0, 1, 'L');
$pdf->SetTextColor(0, 0, 0);
$pdf->Ln(2);
// Separator line
$pdf->SetDrawColor(200, 200, 200);
$pdf->Line(15, $pdf->GetY(), $pdf->getPageWidth() - 15, $pdf->GetY());
$pdf->Ln(4);
// Get font size settings
$fontSettings = array(
'header' => getDolGlobalInt('KUNDENKARTE_PDF_FONT_HEADER', 9),
'content' => getDolGlobalInt('KUNDENKARTE_PDF_FONT_CONTENT', 7),
'fields' => getDolGlobalInt('KUNDENKARTE_PDF_FONT_FIELDS', 7)
);
// Draw tree
if (!empty($tree)) {
drawTreePdf($pdf, $tree, $typeFieldsMap, $langs, 0, $tplidx, $fontSettings);
} else {
$pdf->SetFont('dejavusans', 'I', 10);
$pdf->Cell(0, 10, $langs->trans('NoInstallations'), 0, 1);
}
/**
* Count total elements in tree
*/
function countTreeElements($nodes) {
$count = 0;
if (!empty($nodes)) {
foreach ($nodes as $node) {
$count++;
if (!empty($node->children)) {
$count += countTreeElements($node->children);
}
}
}
return $count;
}
// Output PDF
$filename = 'Export_'.$systemLabel.'_'.dol_sanitizeFileName($societe->name);
if ($contact) {
$filename .= '_'.dol_sanitizeFileName($contact->lastname);
}
$filename .= '_'.date('Y-m-d').'.pdf';
$pdf->Output($filename, 'D');
/**
* Draw tree recursively in PDF with visual hierarchy
*/
function drawTreePdf(&$pdf, $nodes, $typeFieldsMap, $langs, $level = 0, $tplidx = null, $fontSettings = null)
{
// Default font settings if not provided
if ($fontSettings === null) {
$fontSettings = array('header' => 9, 'content' => 7, 'fields' => 7);
}
$indent = $level * 12;
$leftMargin = 15;
$pageWidth = $pdf->getPageWidth() - 30;
$contentWidth = $pageWidth - $indent;
// Subtle gray tones - darker for higher levels, lighter for deeper levels
$levelColors = array(
0 => array('bg' => array(70, 70, 70), 'border' => array(50, 50, 50)), // Dark gray
1 => array('bg' => array(100, 100, 100), 'border' => array(80, 80, 80)), // Medium dark
2 => array('bg' => array(130, 130, 130), 'border' => array(110, 110, 110)), // Medium
3 => array('bg' => array(150, 150, 150), 'border' => array(130, 130, 130)), // Medium light
4 => array('bg' => array(170, 170, 170), 'border' => array(150, 150, 150)), // Light gray
);
$colorIndex = min($level, count($levelColors) - 1);
$colors = $levelColors[$colorIndex];
$nodeCount = count($nodes);
$nodeIndex = 0;
foreach ($nodes as $node) {
$nodeIndex++;
$isLast = ($nodeIndex == $nodeCount);
// Calculate content height to check page break
$estimatedHeight = 12; // Header height
$fieldValues = $node->getFieldValues();
if (!empty($typeFieldsMap[$node->fk_anlage_type])) {
foreach ($typeFieldsMap[$node->fk_anlage_type] as $fieldDef) {
if ($fieldDef->field_type === 'header') {
$estimatedHeight += 5;
} else {
$value = isset($fieldValues[$fieldDef->field_code]) ? $fieldValues[$fieldDef->field_code] : '';
if ($value !== '') $estimatedHeight += 4;
}
}
}
if ($node->note_private) $estimatedHeight += 8;
if ($node->image_count > 0 || $node->doc_count > 0) $estimatedHeight += 4;
// Check if we need a new page
if ($pdf->GetY() + $estimatedHeight > 265) {
$pdf->AddPage();
if (!empty($tplidx)) {
$pdf->useTemplate($tplidx);
}
}
$startY = $pdf->GetY();
$boxX = $leftMargin + $indent;
// Draw tree connector lines
if ($level > 0) {
$pdf->SetDrawColor(180, 180, 180);
$pdf->SetLineWidth(0.3);
// Horizontal line to element
$lineStartX = $boxX - 8;
$lineEndX = $boxX - 2;
$lineY = $startY + 4;
$pdf->Line($lineStartX, $lineY, $lineEndX, $lineY);
// Vertical line segment
$pdf->Line($lineStartX, $startY - 2, $lineStartX, $lineY);
}
// Draw element box with rounded corners
$pdf->SetDrawColor($colors['border'][0], $colors['border'][1], $colors['border'][2]);
$pdf->SetLineWidth(0.4);
// Header bar with color
$pdf->SetFillColor($colors['bg'][0], $colors['bg'][1], $colors['bg'][2]);
$pdf->RoundedRect($boxX, $startY, $contentWidth, 8, 1.5, '1100', 'DF');
// Content area with light background
$pdf->SetFillColor(250, 250, 250);
$pdf->SetDrawColor(220, 220, 220);
// Element header text (white on colored background)
$pdf->SetXY($boxX + 3, $startY + 1.5);
$pdf->SetFont('dejavusans', 'B', $fontSettings['header']);
$pdf->SetTextColor(255, 255, 255);
$headerText = $node->label;
if ($node->type_label) {
$headerText .= ' · '.$node->type_label;
}
$pdf->Cell($contentWidth - 6, 5, $headerText, 0, 1, 'L');
$pdf->SetTextColor(0, 0, 0);
$contentStartY = $startY + 8;
$pdf->SetY($contentStartY);
// Collect content to measure height
$hasContent = false;
$contentY = $contentStartY + 2;
// Draw fields
if (!empty($typeFieldsMap[$node->fk_anlage_type])) {
foreach ($typeFieldsMap[$node->fk_anlage_type] as $fieldDef) {
// Handle header fields as section titles
if ($fieldDef->field_type === 'header') {
$pdf->SetXY($boxX + 4, $contentY);
$pdf->SetFont('dejavusans', 'B', $fontSettings['fields']);
$pdf->SetTextColor(100, 100, 100);
$pdf->Cell($contentWidth - 8, 4, strtoupper($fieldDef->field_label), 0, 1);
$pdf->SetTextColor(0, 0, 0);
$contentY += 4;
$hasContent = true;
continue;
}
$value = isset($fieldValues[$fieldDef->field_code]) ? $fieldValues[$fieldDef->field_code] : '';
if ($value !== '') {
// Format date values
if ($fieldDef->field_type === 'date' && $value) {
$value = dol_print_date(strtotime($value), 'day');
}
$pdf->SetXY($boxX + 4, $contentY);
$pdf->SetFont('dejavusans', '', $fontSettings['fields']);
$pdf->SetTextColor(120, 120, 120);
$pdf->Cell(30, 3.5, $fieldDef->field_label.':', 0, 0);
$pdf->SetFont('dejavusans', '', $fontSettings['content']);
$pdf->SetTextColor(50, 50, 50);
$pdf->Cell($contentWidth - 38, 3.5, $value, 0, 1);
$contentY += 3.5;
$hasContent = true;
}
}
}
// Notes
if ($node->note_private) {
$pdf->SetXY($boxX + 4, $contentY);
$pdf->SetFont('dejavusans', 'I', $fontSettings['content']);
$pdf->SetTextColor(100, 100, 100);
$noteText = strip_tags($node->note_private);
if (strlen($noteText) > 80) {
$noteText = substr($noteText, 0, 77).'...';
}
$pdf->Cell($contentWidth - 8, 3.5, $noteText, 0, 1);
$contentY += 3.5;
$hasContent = true;
}
// File counts
if ($node->image_count > 0 || $node->doc_count > 0) {
$pdf->SetXY($boxX + 4, $contentY);
$pdf->SetFont('dejavusans', '', $fontSettings['content']);
$pdf->SetTextColor(150, 150, 150);
$fileInfo = array();
if ($node->image_count > 0) {
$fileInfo[] = $node->image_count.' '.($node->image_count == 1 ? 'Bild' : 'Bilder');
}
if ($node->doc_count > 0) {
$fileInfo[] = $node->doc_count.' '.($node->doc_count == 1 ? 'Dok.' : 'Dok.');
}
$pdf->Cell($contentWidth - 8, 3.5, implode(' | ', $fileInfo), 0, 1);
$contentY += 3.5;
$hasContent = true;
}
// Draw content box if there's content
if ($hasContent) {
$contentHeight = $contentY - $contentStartY + 2;
$pdf->SetDrawColor(220, 220, 220);
$pdf->SetFillColor(252, 252, 252);
$pdf->RoundedRect($boxX, $contentStartY, $contentWidth, $contentHeight, 1.5, '0011', 'DF');
// Redraw content on top of box
$contentY = $contentStartY + 2;
if (!empty($typeFieldsMap[$node->fk_anlage_type])) {
foreach ($typeFieldsMap[$node->fk_anlage_type] as $fieldDef) {
if ($fieldDef->field_type === 'header') {
$pdf->SetXY($boxX + 4, $contentY);
$pdf->SetFont('dejavusans', 'B', $fontSettings['fields']);
$pdf->SetTextColor(100, 100, 100);
$pdf->Cell($contentWidth - 8, 4, strtoupper($fieldDef->field_label), 0, 1);
$pdf->SetTextColor(0, 0, 0);
$contentY += 4;
continue;
}
$value = isset($fieldValues[$fieldDef->field_code]) ? $fieldValues[$fieldDef->field_code] : '';
if ($value !== '') {
if ($fieldDef->field_type === 'date' && $value) {
$value = dol_print_date(strtotime($value), 'day');
}
$pdf->SetXY($boxX + 4, $contentY);
$pdf->SetFont('dejavusans', '', $fontSettings['fields']);
$pdf->SetTextColor(120, 120, 120);
$pdf->Cell(30, 3.5, $fieldDef->field_label.':', 0, 0);
$pdf->SetFont('dejavusans', '', $fontSettings['content']);
$pdf->SetTextColor(50, 50, 50);
$pdf->Cell($contentWidth - 38, 3.5, $value, 0, 1);
$contentY += 3.5;
}
}
}
if ($node->note_private) {
$pdf->SetXY($boxX + 4, $contentY);
$pdf->SetFont('dejavusans', 'I', $fontSettings['content']);
$pdf->SetTextColor(100, 100, 100);
$noteText = strip_tags($node->note_private);
if (strlen($noteText) > 80) {
$noteText = substr($noteText, 0, 77).'...';
}
$pdf->Cell($contentWidth - 8, 3.5, $noteText, 0, 1);
$contentY += 3.5;
}
if ($node->image_count > 0 || $node->doc_count > 0) {
$pdf->SetXY($boxX + 4, $contentY);
$pdf->SetFont('dejavusans', '', $fontSettings['content']);
$pdf->SetTextColor(150, 150, 150);
$fileInfo = array();
if ($node->image_count > 0) {
$fileInfo[] = $node->image_count.' '.($node->image_count == 1 ? 'Bild' : 'Bilder');
}
if ($node->doc_count > 0) {
$fileInfo[] = $node->doc_count.' '.($node->doc_count == 1 ? 'Dok.' : 'Dok.');
}
$pdf->Cell($contentWidth - 8, 3.5, implode(' | ', $fileInfo), 0, 1);
$contentY += 3.5;
}
$pdf->SetY($contentStartY + $contentHeight + 3);
} else {
$pdf->SetY($startY + 11);
}
$pdf->SetTextColor(0, 0, 0);
// Children
if (!empty($node->children)) {
drawTreePdf($pdf, $node->children, $typeFieldsMap, $langs, $level + 1, $tplidx, $fontSettings);
}
}
}