432 lines
13 KiB
PHP
Executable file
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);
|
|
}
|
|
}
|
|
}
|