All checks were successful
Deploy bericht / deploy (push) Successful in 1s
- bericht_card.php: Plain-Textarea durch DolEditor (CKEditor, dolibarr_notes-Toolbar) ersetzt, damit Notizen formatiert werden können. - editor.js: getNoteValue()/setNoteValue() Helper für transparentes CKEditor/Textarea-Handling an allen Zugriffsstellen. - lib/bericht.lib.php: * bericht_write_note_html() rendert CKEditor-HTML via TCPDF::writeHTMLCell * Composite-Branch: Notiz direkt unter dem Bild statt mit SetY(-20) unten * bericht_ensure_hack_font() registriert Hack-TTFs beim ersten PDF-Run * Alle helvetica-SetFont-Calls auf Hack umgestellt (Corporate-Font) - fonts/: Hack-Regular/Bold/Italic/BoldItalic.ttf (Eddys Corporate-Font) - bericht_batch.php: ebenfalls Hack-Font
173 lines
7.5 KiB
PHP
173 lines
7.5 KiB
PHP
<?php
|
||
/* Batch-Modus: mehrere Berichte zu einem Sammel-PDF zusammenführen.
|
||
* Nur finale Berichte mit existierendem final_pdf_path werden berücksichtigt.
|
||
*
|
||
* GET: filter per Datum-Von/Bis, Element-Typ, Kundensuche, Status
|
||
* POST: action=generate + ids[] → liefert ein zusammengesetztes PDF aus den ausgewählten
|
||
*/
|
||
|
||
$res = 0;
|
||
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
|
||
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1;
|
||
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; }
|
||
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
|
||
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/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 __DIR__.'/class/bericht.class.php';
|
||
require_once __DIR__.'/lib/bericht.lib.php';
|
||
|
||
if (!$user->hasRight('bericht', 'read')) accessforbidden();
|
||
|
||
$langs->loadLangs(array("bericht@bericht", "main"));
|
||
|
||
$action = GETPOST('action', 'alpha');
|
||
$datefrom = GETPOST('datefrom', 'alpha');
|
||
$dateto = GETPOST('dateto', 'alpha');
|
||
$q = GETPOST('q', 'alpha');
|
||
|
||
/* ---------- Batch-PDF generieren ---------- */
|
||
if ($action === 'generate') {
|
||
$ids = GETPOST('ids', 'array');
|
||
if (empty($ids)) {
|
||
setEventMessages('Keine Berichte ausgewählt', null, 'errors');
|
||
header("Location: ".$_SERVER['PHP_SELF']); exit;
|
||
}
|
||
|
||
// 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) { http_response_code(500); exit('TCPDF fehlt'); }
|
||
|
||
$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; } }
|
||
if (!$fpdi_loaded) { http_response_code(500); exit('FPDI wird für Batch-Modus benötigt'); }
|
||
|
||
$pdf = new \setasign\Fpdi\Tcpdf\Fpdi('P', 'mm', 'A4', true, 'UTF-8', false);
|
||
$pdf->SetCreator('Dolibarr Bericht-Modul Batch');
|
||
$pdf->SetAuthor($user->getFullName($langs));
|
||
$pdf->SetTitle('Bericht-Sammlung '.dol_print_date(dol_now(), '%Y-%m-%d'));
|
||
$pdf->setPrintHeader(false);
|
||
$pdf->setPrintFooter(false);
|
||
|
||
// Inhaltsverzeichnis-Seite
|
||
$pdf->AddPage('P', 'A4');
|
||
$pdf->SetFont(bericht_ensure_hack_font(), 'B', 18);
|
||
$pdf->Cell(0, 12, 'Bericht-Sammlung', 0, 1, 'C');
|
||
$pdf->SetFont(bericht_ensure_hack_font(), '', 11);
|
||
$pdf->Cell(0, 8, 'Erstellt: '.dol_print_date(dol_now(), 'dayhour'), 0, 1, 'C');
|
||
$pdf->Ln(8);
|
||
$pdf->SetFont(bericht_ensure_hack_font(), 'B', 13);
|
||
$pdf->Cell(0, 8, 'Enthaltene Berichte ('.count($ids).')', 0, 1, 'L');
|
||
$pdf->SetFont(bericht_ensure_hack_font(), '', 10);
|
||
|
||
$berichte = array();
|
||
foreach ($ids as $id) {
|
||
$b = new Bericht($db);
|
||
if ($b->fetch((int) $id) > 0 && $b->status == Bericht::STATUS_FINAL && !empty($b->final_pdf_path)) {
|
||
$pp = bericht_resolve_data_path($b->final_pdf_path);
|
||
if ($pp && file_exists($pp)) {
|
||
$berichte[] = array('bericht' => $b, 'pdf' => $pp);
|
||
$pdf->Cell(0, 6, '• '.$b->ref.' – '.($b->titel ?: '').' ('.$b->auftragsnummer.')', 0, 1, 'L');
|
||
}
|
||
}
|
||
}
|
||
|
||
if (empty($berichte)) {
|
||
exit('Keine gültigen (finalisierten) Berichte in der Auswahl');
|
||
}
|
||
|
||
// Jede Bericht-PDF als volle Seiten einbauen
|
||
foreach ($berichte as $entry) {
|
||
try {
|
||
$page_count = $pdf->setSourceFile($entry['pdf']);
|
||
for ($n = 1; $n <= $page_count; $n++) {
|
||
$tpl = $pdf->importPage($n);
|
||
$size = $pdf->getTemplateSize($tpl);
|
||
$pdf->AddPage($size['orientation'] ?? 'P', array($size['width'], $size['height']));
|
||
$pdf->useTemplate($tpl);
|
||
}
|
||
} catch (Throwable $e) { continue; }
|
||
}
|
||
|
||
$filename = 'Bericht-Sammlung_'.dol_print_date(dol_now(), '%Y%m%d_%H%M%S').'.pdf';
|
||
header('Content-Type: application/pdf');
|
||
header('Content-Disposition: attachment; filename="'.$filename.'"');
|
||
$pdf->Output($filename, 'D');
|
||
exit;
|
||
}
|
||
|
||
/* ---------- Listen-Ansicht ---------- */
|
||
llxHeader('', 'Bericht-Batch-Modus');
|
||
print load_fiche_titre('📦 Bericht-Batch — Mehrere Berichte zu einem PDF', '', 'bill');
|
||
|
||
// Filter
|
||
print '<form method="get" class="bericht-batch-filter" style="margin-bottom:16px;padding:12px;background:var(--colorbacktitle1,#f5f5f5);border-radius:6px;">';
|
||
print '<label>Von: <input type="date" name="datefrom" value="'.dol_escape_htmltag($datefrom).'"></label> ';
|
||
print '<label>Bis: <input type="date" name="dateto" value="'.dol_escape_htmltag($dateto).'"></label> ';
|
||
print '<label>Suche: <input type="text" name="q" value="'.dol_escape_htmltag($q).'" placeholder="Ref, Titel, Auftragsnr"></label> ';
|
||
print '<button type="submit" class="butAction">🔍 Filtern</button>';
|
||
print '</form>';
|
||
|
||
// Query: nur finale Berichte mit PDF, gefiltert
|
||
$where = "status = 1 AND final_pdf_path IS NOT NULL AND COALESCE(is_template,0) = 0 AND entity IN (".getEntity('bericht').")";
|
||
if ($datefrom) {
|
||
$where .= " AND datec >= '".$db->escape($datefrom." 00:00:00")."'";
|
||
}
|
||
if ($dateto) {
|
||
$where .= " AND datec <= '".$db->escape($dateto." 23:59:59")."'";
|
||
}
|
||
if ($q) {
|
||
$qe = $db->escape($q);
|
||
$where .= " AND (ref LIKE '%$qe%' OR titel LIKE '%$qe%' OR auftragsnummer LIKE '%$qe%')";
|
||
}
|
||
|
||
$sql = "SELECT rowid, ref, titel, auftragsnummer, element_type, fk_element, datec FROM ".$db->prefix()."bericht WHERE ".$where." ORDER BY datec DESC LIMIT 500";
|
||
$resq = $db->query($sql);
|
||
|
||
print '<form method="post" action="'.$_SERVER['PHP_SELF'].'">';
|
||
print '<input type="hidden" name="token" value="'.newToken().'">';
|
||
print '<input type="hidden" name="action" value="generate">';
|
||
print '<table class="noborder centpercent">';
|
||
print '<tr class="liste_titre">';
|
||
print '<th><input type="checkbox" onclick="document.querySelectorAll(\'.bt-check\').forEach(c => c.checked = this.checked)"></th>';
|
||
print '<th>Ref</th>';
|
||
print '<th>Titel</th>';
|
||
print '<th>Auftragsnummer</th>';
|
||
print '<th>Datum</th>';
|
||
print '</tr>';
|
||
|
||
$count = 0;
|
||
if ($resq) {
|
||
while ($o = $db->fetch_object($resq)) {
|
||
print '<tr class="oddeven">';
|
||
print '<td><input type="checkbox" class="bt-check" name="ids[]" value="'.$o->rowid.'"></td>';
|
||
print '<td>'.dol_escape_htmltag($o->ref).'</td>';
|
||
print '<td>'.dol_escape_htmltag($o->titel).'</td>';
|
||
print '<td>'.dol_escape_htmltag($o->auftragsnummer).'</td>';
|
||
print '<td>'.dol_print_date($db->jdate($o->datec), 'dayhour').'</td>';
|
||
print '</tr>';
|
||
$count++;
|
||
}
|
||
}
|
||
print '</table>';
|
||
|
||
if ($count === 0) {
|
||
print '<p class="opacitymedium">Keine finalisierten Berichte gefunden.</p>';
|
||
} else {
|
||
print '<div style="margin-top:16px;text-align:right;">';
|
||
print '<button type="submit" class="butActionConfirm">📦 Ausgewählte als Sammel-PDF herunterladen</button>';
|
||
print '</div>';
|
||
}
|
||
print '</form>';
|
||
|
||
llxFooter();
|
||
$db->close();
|