bericht/bericht_batch.php
Eduard Wisch 021ef1cbb2
All checks were successful
Deploy bericht / deploy (push) Successful in 1s
DolEditor für Notiz + Notiz unter Bild + Hack-Font im PDF [deploy]
- 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
2026-04-09 15:25:10 +02:00

173 lines
7.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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> &nbsp; ';
print '<label>Bis: <input type="date" name="dateto" value="'.dol_escape_htmltag($dateto).'"></label> &nbsp; ';
print '<label>Suche: <input type="text" name="q" value="'.dol_escape_htmltag($q).'" placeholder="Ref, Titel, Auftragsnr"></label> &nbsp; ';
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();