* GPL v3+ */ /** * Hilfs-Funktionen für das Bericht-Modul. */ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; /** * Erzeugt die Tab-Header-Leiste für die Editor-Seite (Übersicht / Editor). * * @param Bericht $object * @return array */ function bericht_prepare_head($object) { global $langs, $conf; $langs->load("bericht@bericht"); $h = 0; $head = array(); $head[$h][0] = dol_buildpath('/bericht/bericht_card.php', 1).'?id='.$object->id; $head[$h][1] = $langs->trans("BerichtEditor"); $head[$h][2] = 'editor'; $h++; return $head; } /** * Lädt das Parent-Objekt anhand des element_type. * * @return CommonObject|null */ function bericht_fetch_parent(DoliDB $db, $element_type, $id) { if ($element_type === 'invoice') { require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; $o = new Facture($db); } elseif ($element_type === 'order') { require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; $o = new Commande($db); } elseif ($element_type === 'propal') { require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; $o = new Propal($db); } else { return null; } if ($o->fetch($id) <= 0) return null; $o->fetch_thirdparty(); if (method_exists($o, 'fetch_optionals')) { $o->fetch_optionals(); } return $o; } /** * Mappt einen element_type-Code auf den Dolibarr-internen Element-Namen * für das Verzeichnis der Anhänge (multidir_output). */ function bericht_element_to_dir_key($element_type) { return array( 'invoice' => 'facture', 'order' => 'commande', 'propal' => 'propal', )[$element_type] ?? null; } /** * Sammelt alle Anhänge eines Parent-Objekts UND der direkt verknüpften Objekte * (z. B. der Auftrag/Angebot, die mit dieser Rechnung verknüpft sind). * * @return array Liste mit ['source','source_id','source_ref','filename','fullpath','relpath','size','mime','date'] */ function bericht_collect_attachments(DoliDB $db, CommonObject $parent, $element_type) { global $conf; $result = array(); // 1) Eigene Anhänge $dir_key = bericht_element_to_dir_key($element_type); if ($dir_key && !empty($conf->{$dir_key}->multidir_output[$parent->entity])) { $upload_dir = $conf->{$dir_key}->multidir_output[$parent->entity].'/'.dol_sanitizeFileName($parent->ref); if (is_dir($upload_dir)) { $files = dol_dir_list($upload_dir, 'files', 1, '', '(\.meta|_preview.*\.png|thumbs)$'); foreach ($files as $f) { $result[] = array( 'source' => $element_type, 'source_id' => $parent->id, 'source_ref' => $parent->ref, 'filename' => $f['name'], 'fullpath' => $f['fullname'], 'relpath' => str_replace(DOL_DATA_ROOT.'/', '', $f['fullname']), 'size' => $f['size'], 'mime' => dol_mimetype($f['name']), 'date' => $f['date'], ); } } } // 2) Verknüpfte Objekte: order, propal — auch deren Anhänge anbieten $parent->fetchObjectLinked(); $linked_types = array('commande' => 'order', 'propal' => 'propal', 'facture' => 'invoice'); foreach ($linked_types as $linked_dolibarr_type => $linked_module_type) { if (empty($parent->linkedObjects[$linked_dolibarr_type])) continue; foreach ($parent->linkedObjects[$linked_dolibarr_type] as $lobj) { if (empty($conf->{$linked_dolibarr_type}->multidir_output[$lobj->entity])) continue; $linked_dir = $conf->{$linked_dolibarr_type}->multidir_output[$lobj->entity].'/'.dol_sanitizeFileName($lobj->ref); if (!is_dir($linked_dir)) continue; $files = dol_dir_list($linked_dir, 'files', 1, '', '(\.meta|_preview.*\.png|thumbs)$'); foreach ($files as $f) { $result[] = array( 'source' => $linked_module_type, 'source_id' => $lobj->id, 'source_ref' => $lobj->ref, 'filename' => $f['name'], 'fullpath' => $f['fullname'], 'relpath' => str_replace(DOL_DATA_ROOT.'/', '', $f['fullname']), 'size' => $f['size'], 'mime' => dol_mimetype($f['name']), 'date' => $f['date'], ); } } } return $result; } /** * Liest die Auftragsnummer aus dem Parent-Objekt. * Reihenfolge: extrafield 'auftragsnummer' → ref_client → ref */ function bericht_get_auftragsnummer(CommonObject $parent) { if (!empty($parent->array_options['options_auftragsnummer'])) { return $parent->array_options['options_auftragsnummer']; } if (!empty($parent->ref_client)) { return $parent->ref_client; } return $parent->ref; } /** * Listet alle ODT-Templates im Templates-Verzeichnis auf. * * @return string[] Dateinamen */ function bericht_list_templates() { $dir = DOL_DATA_ROOT.'/bericht/templates'; if (!is_dir($dir)) return array(); $files = scandir($dir); return array_values(array_filter($files, function ($f) { return preg_match('/\.odt$/i', $f); })); } /** * Sicherer absolute-Pfad-Resolver für Dateien unterhalb DOL_DATA_ROOT. * Verhindert Path-Traversal. */ function bericht_resolve_data_path($relpath) { $base = realpath(DOL_DATA_ROOT); $full = realpath($base.'/'.$relpath); if ($full === false) return null; if (strpos($full, $base) !== 0) return null; return $full; }