hasRight('bericht', 'write')) bericht_ajax_fail('Permission denied', 403); $berichtid = (int) ($_POST['berichtid'] ?? 0); $bericht = new Bericht($db); if ($bericht->fetch($berichtid) <= 0) bericht_ajax_fail('Bericht nicht gefunden', 404); $parent = bericht_fetch_parent($db, $bericht->element_type, $bericht->fk_element); if (!$parent) bericht_ajax_fail('Parent nicht gefunden', 404); $pages = BerichtPage::fetchAllForBericht($db, $bericht->id); if (empty($pages)) bericht_ajax_fail('Bericht enthält keine Seiten'); // TCPDF + FPDI laden $tcpdf_loaded = false; foreach (array( DOL_DOCUMENT_ROOT.'/includes/tecnickcom/tcpdf/tcpdf.php', DOL_DOCUMENT_ROOT.'/includes/tcpdf/tcpdf.php', ) as $p) { if (file_exists($p)) { require_once $p; $tcpdf_loaded = true; break; } } if (!$tcpdf_loaded) bericht_ajax_fail('TCPDF nicht gefunden'); $fpdi_loaded = false; foreach (array( DOL_DOCUMENT_ROOT.'/includes/setasign/vendor/setasign/fpdi/src/Tcpdf/Fpdi.php', DOL_DOCUMENT_ROOT.'/includes/fpdi/src/Tcpdf/Fpdi.php', ) as $p) { if (file_exists($p)) { require_once $p; $fpdi_loaded = true; break; } } // FPDI ist optional — wenn fehlt, können wir keine bestehenden PDFs einbetten, // aber Bilder + Annotationen funktionieren weiterhin. $ori = in_array($bericht->page_orientation, array('P','L'), true) ? $bericht->page_orientation : 'P'; $fmt = in_array($bericht->page_format, array('A4','A3','A5','Letter'), true) ? $bericht->page_format : 'A4'; if ($fpdi_loaded) { $pdf = new \setasign\Fpdi\Tcpdf\Fpdi($ori, 'mm', $fmt, true, 'UTF-8', false); } else { $pdf = new TCPDF($ori, 'mm', $fmt, true, 'UTF-8', false); } $pdf->SetCreator('Dolibarr Bericht-Modul'); $pdf->SetAuthor($user->getFullName($langs)); $pdf->SetTitle($bericht->titel ?: $bericht->ref); $pdf->SetMargins(10, 10, 10); $pdf->SetAutoPageBreak(true, 10); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); // --- Deckblatt aus ODT-Template --- $tempdir = DOL_DATA_ROOT.'/bericht/temp/'.$berichtid; if (!is_dir($tempdir)) dol_mkdir($tempdir); if (!empty($bericht->template_odt)) { $template_path = DOL_DATA_ROOT.'/bericht/templates/'.dol_sanitizeFileName($bericht->template_odt); if (file_exists($template_path)) { $cover_pdf = bericht_render_cover($template_path, $bericht, $parent, $tempdir); if ($cover_pdf && file_exists($cover_pdf) && $fpdi_loaded) { $cover_pages = $pdf->setSourceFile($cover_pdf); for ($cp = 1; $cp <= $cover_pages; $cp++) { $tpl = $pdf->importPage($cp); $size = $pdf->getTemplateSize($tpl); $pdf->AddPage($size['orientation'] ?? 'P', array($size['width'], $size['height'])); $pdf->useTemplate($tpl); } } } } // --- Seiten --- foreach ($pages as $page) { bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded); } // --- Speichern --- $dir_key = bericht_element_to_dir_key($bericht->element_type); $target_dir = $conf->{$dir_key}->multidir_output[$parent->entity].'/'.dol_sanitizeFileName($parent->ref); if (!is_dir($target_dir)) dol_mkdir($target_dir); $filename = 'Bericht_'.dol_sanitizeFileName($bericht->auftragsnummer ?: $bericht->ref).'_'.dol_print_date(dol_now(), '%Y%m%d_%H%M%S').'.pdf'; $target_path = $target_dir.'/'.$filename; $pdf->Output($target_path, 'F'); if (!file_exists($target_path)) bericht_ajax_fail('PDF wurde nicht erzeugt'); // In ECM registrieren (taucht unter Verknüpfte Dokumente auf) require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; $register_ecm = function ($obj_type, $obj_id, $filepath_dir, $filename, $target_path) use ($db, $user) { $ecmfile = new EcmFiles($db); $ecmfile->filepath = $filepath_dir; $ecmfile->filename = $filename; $ecmfile->fullpath_orig = $target_path; $ecmfile->src_object_type = $obj_type; $ecmfile->src_object_id = $obj_id; $ecmfile->label = md5_file($target_path); @$ecmfile->create($user); }; $register_ecm($dir_key, $parent->id, $dir_key.'/'.dol_sanitizeFileName($parent->ref), $filename, $target_path); // Wenn der Bericht zusätzlich per llx_element_element verknüpfte Elemente hat, // dort ebenfalls ECM-Eintrag anlegen + PDF-Kopie ablegen. $res_links = $db->query("SELECT targettype, fk_target FROM ".$db->prefix()."element_element WHERE sourcetype='bericht' AND fk_source=".((int) $bericht->id)); if ($res_links) { while ($lnk = $db->fetch_object($res_links)) { $tdir = bericht_element_to_dir_key($lnk->targettype === 'facture' ? 'invoice' : ($lnk->targettype === 'commande' ? 'order' : ($lnk->targettype === 'propal' ? 'propal' : $lnk->targettype))); if (!$tdir) continue; // Ziel-Objekt fetchen für ref $linked_obj = bericht_fetch_parent($db, $tdir === 'facture' ? 'invoice' : ($tdir === 'commande' ? 'order' : 'propal'), (int) $lnk->fk_target); if (!$linked_obj) continue; $linked_dir = $conf->{$tdir}->multidir_output[$linked_obj->entity].'/'.dol_sanitizeFileName($linked_obj->ref); if (!is_dir($linked_dir)) dol_mkdir($linked_dir); $linked_target = $linked_dir.'/'.$filename; @copy($target_path, $linked_target); $register_ecm($tdir, $linked_obj->id, $tdir.'/'.dol_sanitizeFileName($linked_obj->ref), $filename, $linked_target); } } // Bericht-Status auf Final $bericht->status = Bericht::STATUS_FINAL; $bericht->final_pdf_path = str_replace(DOL_DATA_ROOT.'/', '', $target_path); $bericht->update($user); bericht_ajax_ok(array( 'filename' => $filename, 'path' => $bericht->final_pdf_path, )); // bericht_render_cover, bericht_burn_annotations und bericht_hex_to_rgb // liegen jetzt in lib/bericht.lib.php (gemeinsam genutzt von generate_pdf und preview_pdf) function bericht_render_cover($template_path, $bericht, $parent, $tempdir) { return bericht_render_cover_internal($template_path, $bericht, $parent, $tempdir); }