* GPL v3+ * * Visueller Editor fuer die Unterschriftsbox auf Lieferschein-PDFs. * Laedt ein Beispiel-Lieferschein-PDF (PDF.js), zeigt die aktuelle Box als * Fabric.js-Rechteck und speichert die mm-Geometrie in llx_bericht_signature_box. */ $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__.'/../lib/bericht.lib.php'; require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; if (!$user->admin && !$user->hasRight('bericht', 'admin')) accessforbidden(); $langs->loadLangs(array("admin", "bericht@bericht")); // Verfuegbare Templates: PDF-Module + ODT-Module + ODT-Dateien aus doctemplates/shipments/ $tpl_dir = DOL_DOCUMENT_ROOT.'/core/modules/expedition/doc'; $pdf_modules = array(); // ['espadon' => 'espadon', ...] $odt_modules = array(); // ['generic_shipment_odt' => 'generic_shipment_odt'] if (is_dir($tpl_dir)) { foreach (glob($tpl_dir.'/pdf_*.modules.php') as $f) { $name = basename($f); if (preg_match('/^pdf_(.+)\.modules\.php$/', $name, $m)) { $pdf_modules[$m[1]] = $m[1]; } } foreach (glob($tpl_dir.'/doc_*.modules.php') as $f) { $name = basename($f); if (preg_match('/^doc_(.+)\.modules\.php$/', $name, $m)) { $odt_modules[$m[1]] = $m[1]; } } } // ODT-Dateien aus doctemplates/shipments/ — pro Datei eine eigene Box konfigurierbar // EXPEDITION_ADDON_PDF_ODT_PATH enthaelt 'DOL_DATA_ROOT' woertlich + ist komma/zeilengetrennt $odt_files = array(); $raw_dirs = getDolGlobalString('EXPEDITION_ADDON_PDF_ODT_PATH', 'DOL_DATA_ROOT/doctemplates/shipments'); foreach (explode(',', preg_replace('/[\r\n]+/', ',', trim($raw_dirs))) as $d) { $d = trim($d); if (!$d) continue; $d = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $d); if (!is_dir($d)) continue; foreach (glob($d.'/*.odt') as $f) { $name = basename($f); $key = 'odt:'.preg_replace('/\.odt$/i', '', $name); $odt_files[$key] = $name; } } $active_template = getDolGlobalString('EXPEDITION_ADDON_PDF', 'merou'); $selected = GETPOST('template', 'alphanohtml') ?: $active_template; // Wenn nichts uebergeben + es gibt ODTs + Aktives Modul ist generic_shipment_odt → erstes ODT vorauswaehlen if (!GETPOST('template', 'alphanohtml') && $active_template === 'generic_shipment_odt' && !empty($odt_files)) { $selected = array_key_first($odt_files); } // Auswahl validieren $all_choices = array_merge($pdf_modules, $odt_modules, $odt_files); if (!isset($all_choices[$selected])) { $selected = $active_template; if (!isset($all_choices[$selected]) && !empty($all_choices)) { $selected = array_key_first($all_choices); } } // Aktuelle Box-Geometrie fuer das ausgewaehlte Template laden (oder Default) $box = bericht_get_signature_box($db, $selected); // Letzte vorhandene Expedition fuer Preview suchen — sonst Hinweis ausgeben $preview_shipment_id = 0; $r = $db->query("SELECT rowid FROM ".$db->prefix()."expedition" ." WHERE entity IN (".getEntity('expedition').")" ." ORDER BY rowid DESC LIMIT 1"); if ($r && ($o = $db->fetch_object($r))) $preview_shipment_id = (int) $o->rowid; llxHeader('', $langs->trans("BerichtSignatureBoxConfig")); $linkback = ''.$langs->trans("BackToSetup").''; print load_fiche_titre($langs->trans("BerichtSignatureBoxConfig"), $linkback, 'title_setup'); print '

'.$langs->trans("BerichtSignatureBoxConfigDesc").'

'; // Template-Wahl mit Gruppen print '
'; print ''; print ''; print ' ★ = aktuell in Dolibarr aktiv'; print '
'; // Hinweis bei ODT-Auswahl: mm-Editor ist hier NICHT relevant. // Stattdessen: Bild-Platzhalter "signature" im ODT einbauen — die Position waechst dann automatisch mit dem PDF-Inhalt mit. $is_odt = (strpos($selected, 'odt:') === 0); if ($is_odt) { $sig_ratio = getDolGlobalString('BERICHT_SIGNATURE_IMAGE_RATIO', '0.35'); print '
'; print '

📄 ODT-Template — Platzhalter-Methode (wie EPCQR/{qrcode})

'; print '

Bei ODT-Vorlagen ist die mm-Box nicht sinnvoll: das PDF wird je nach Positionsmenge unterschiedlich lang — fixe Position würde mitten in den Zeilen landen.

'; print '

Stattdessen:

'; print '
    '; print '
  1. In deinem ODT ('.dol_escape_htmltag($odt_files[$selected] ?? '').') an die gewünschte Stelle den Text-Platzhalter {signature} schreiben — irgendwo, wo die Unterschrift erscheinen soll.
  2. '; print '
  3. Drumherum optional Text-Variablen einsetzen: {signer_name}, {signed_at}, {gps}, {kunde_name}, {kunde_adresse}, {shipment_ref}, {order_ref}, {auftragsnummer}, {datum}.
  4. '; print '
  5. Speichern. Fertig.
  6. '; print '
'; print '

Beim Bestätigen in der PWA ersetzt setImage() den {signature}-Text durch ein <draw:frame> mit der Kunden-Unterschrift. Die Größe wird durch den Faktor BERICHT_SIGNATURE_IMAGE_RATIO (aktuell '.dol_escape_htmltag($sig_ratio).') gesteuert — bei 0.35 ergibt das ca. 7×3.5 cm.

'; print '

Die mm-Felder rechts sind hier ohne Wirkung — sie gelten nur für reine PDF-Module (espadon/merou/rouget).

'; print '
'; } if (!$preview_shipment_id) { print '
'.$langs->trans("BerichtSignatureBoxNoPreviewShipment").'
'; } else { // PDF-URL fuer die Vorschau: nutzt den shipments.php-Endpoint mit JWT // Hier brauchen wir keinen JWT, weil wir admin sind und das PDF lokal lesen. // Stattdessen: Vorschau-Endpoint nimmt nur die Expedition-ID und laedt das PDF. $preview_url = dol_buildpath('/bericht/admin/signature_box_preview.php', 1) .'?id='.$preview_shipment_id .'&template='.urlencode($selected); print '
'; print '
'; // Linke Spalte: PDF-Vorschau mit Box print '
'; print '

'.$langs->trans("BerichtPreviewWithBox").'

'; print ''; print '
'; print '
'; print '
'; print '
'; print ''; print ''; print ''; print '
'; print '
'; // Rechte Spalte: Werte editierbar + Speichern (bei ODT optisch gedimmt) $right_attr = $is_odt ? ' style="flex:0 0 280px;opacity:0.5;pointer-events:none;"' : ' style="flex:0 0 280px;"'; print ''; print '

'.$langs->trans("BerichtBoxGeometry").($is_odt ? ' (bei ODT inaktiv)' : '').'

'; print '
'; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print '
'.$langs->trans("BerichtBoxPage").'
X (mm)
Y (mm)
'.$langs->trans("Width").' (mm)
'.$langs->trans("Height").' (mm)
'.$langs->trans("BerichtBoxLabel").'
'; print '
'; print ''; print ''; print '
'; print '
'; print '
'; // rechte Spalte print '
'; // Flex print ''; // section // PDF.js einbinden + Editor-JS $pdfjs_url = dol_buildpath('/bericht/js/lib/pdf.min.js', 1); $pdfjs_worker_url = dol_buildpath('/bericht/js/lib/pdf.worker.min.js', 1); $fabric_url = dol_buildpath('/bericht/js/lib/fabric.min.js', 1); $save_url = dol_buildpath('/bericht/ajax/save_signature_box.php', 1); ?> close();