diff --git a/api/delete_photo.php b/api/delete_photo.php new file mode 100644 index 0000000..7d18b3d --- /dev/null +++ b/api/delete_photo.php @@ -0,0 +1,42 @@ +hasRight('bericht', 'write')) api_fail('Permission denied', 403); + +$in = api_input(); +$relpath = (string) ($in['relpath'] ?? ''); +if (empty($relpath)) api_fail('relpath fehlt'); + +if (!preg_match('#^(facture|commande|propal)/[^/]+/[^/]+$#', $relpath)) { + api_fail('Pfad nicht erlaubt: '.$relpath, 403); +} + +$full = bericht_resolve_data_path($relpath); +if (!$full || !file_exists($full)) api_fail('Datei nicht gefunden', 404); + +if (!@unlink($full)) api_fail('Löschen fehlgeschlagen', 500); + +// Thumbs bereinigen +$dir = dirname($full); +$base = pathinfo($full, PATHINFO_FILENAME); +$ext = pathinfo($full, PATHINFO_EXTENSION); +foreach (array('_mini', '_small') as $suffix) { + $thumb = $dir.'/thumbs/'.$base.$suffix.'.'.$ext; + if (file_exists($thumb)) @unlink($thumb); +} + +// ECM cleanup +$db->query("DELETE FROM ".$db->prefix()."ecm_files" + ." WHERE filepath = '".$db->escape(dirname($relpath))."'" + ." AND filename = '".$db->escape(basename($relpath))."'"); + +api_ok(array('deleted' => $relpath)); diff --git a/api/reports.php b/api/reports.php index 328e4f7..3b22f42 100644 --- a/api/reports.php +++ b/api/reports.php @@ -7,11 +7,56 @@ require_once __DIR__.'/_inc.php'; api_authenticate(); -global $db, $user; +global $db, $user, $conf, $langs; $id = (int) ($_GET['id'] ?? 0); $action = $_GET['action'] ?? ''; +/* ----- LISTE aller Berichte für den User ----- */ +if (!$id && $action === '') { + // Multi-User-Filter: Berichte an Aufträgen, die der User angelegt/validiert/modifiziert hat + // PLUS eigene Berichte (fk_user_creat) + $extra = ''; + if (empty($user->admin)) { + $extra = " AND (b.fk_user_creat = ".((int) $user->id) + ." OR EXISTS (SELECT 1 FROM ".$db->prefix()."commande c WHERE c.rowid = b.fk_element AND b.element_type='order' AND (c.fk_user_author = ".((int) $user->id)." OR c.fk_user_valid = ".((int) $user->id)." OR c.fk_user_modif = ".((int) $user->id)."))" + ." OR EXISTS (SELECT 1 FROM ".$db->prefix()."facture f WHERE f.rowid = b.fk_element AND b.element_type='invoice' AND (f.fk_user_author = ".((int) $user->id)." OR f.fk_user_valid = ".((int) $user->id)." OR f.fk_user_modif = ".((int) $user->id)."))" + .")"; + } + $sql = "SELECT b.rowid, b.ref, b.titel, b.element_type, b.fk_element, b.status, b.datec, b.auftragsnummer," + ." (SELECT COUNT(*) FROM ".$db->prefix()."bericht_page WHERE fk_bericht = b.rowid) AS page_count" + ." FROM ".$db->prefix()."bericht b" + ." WHERE b.entity IN (".getEntity('bericht').") ".$extra + ." ORDER BY b.datec DESC LIMIT 200"; + $r = $db->query($sql); + if (!$r) api_fail('DB-Fehler: '.$db->lasterror(), 500); + $items = array(); + while ($o = $db->fetch_object($r)) { + // Parent-Ref für Anzeige ermitteln + $parent_ref = ''; + if ($o->element_type === 'order') { + $pr = $db->query("SELECT ref FROM ".$db->prefix()."commande WHERE rowid = ".((int) $o->fk_element)); + if ($pr && ($p = $db->fetch_object($pr))) $parent_ref = $p->ref; + } elseif ($o->element_type === 'invoice') { + $pr = $db->query("SELECT ref FROM ".$db->prefix()."facture WHERE rowid = ".((int) $o->fk_element)); + if ($pr && ($p = $db->fetch_object($pr))) $parent_ref = $p->ref; + } + $items[] = array( + 'id' => (int) $o->rowid, + 'ref' => $o->ref, + 'titel' => $o->titel, + 'element_type' => $o->element_type, + 'fk_element' => (int) $o->fk_element, + 'parent_ref' => $parent_ref, + 'status' => (int) $o->status, + 'datec' => $db->jdate($o->datec), + 'auftragsnummer'=> $o->auftragsnummer, + 'page_count' => (int) $o->page_count, + ); + } + api_ok(array('reports' => $items, 'count' => count($items))); +} + if (!$id) api_fail('id erforderlich'); $bericht = new Bericht($db); @@ -19,11 +64,79 @@ if ($bericht->fetch($id) <= 0) api_fail('Bericht nicht gefunden', 404); if ($action === 'finalize') { if (!$user->hasRight('bericht', 'write')) api_fail('Schreibrechte fehlen', 403); - // Wir rufen generate_pdf.php intern auf, indem wir die Logik laden — einfacher: redirect - // Hier simpler Ansatz: setze Status auf Final (echte PDF-Generierung sollte separat triggern) + + // Wir laden generate_pdf.php inline — es erwartet aber POST mit berichtid und ausreichend + // gesetzter Token-Kontext. Einfacher: Wir replizieren die Kernlogik hier direkt. + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; + + $parent = bericht_fetch_parent($db, $bericht->element_type, $bericht->fk_element); + if (!$parent) api_fail('Parent-Objekt nicht gefunden', 404); + + $pages = BerichtPage::fetchAllForBericht($db, $bericht->id); + if (empty($pages)) api_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) api_fail('TCPDF nicht gefunden', 500); + $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; } } + + $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 (PWA)'); + $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); + + foreach ($pages as $page) { + bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded); + } + + $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)) api_fail('PDF-Output fehlgeschlagen', 500); + + $ecmfile = new EcmFiles($db); + $ecmfile->filepath = $dir_key.'/'.dol_sanitizeFileName($parent->ref); + $ecmfile->filename = $filename; + $ecmfile->fullpath_orig = $target_path; + $ecmfile->src_object_type = $dir_key; + $ecmfile->src_object_id = $parent->id; + $ecmfile->label = md5_file($target_path); + @$ecmfile->create($user); + $bericht->status = Bericht::STATUS_FINAL; + $bericht->final_pdf_path = str_replace(DOL_DATA_ROOT.'/', '', $target_path); $bericht->update($user); - api_ok(array('status' => 'final')); + + api_ok(array( + 'status' => 'final', + 'filename' => $filename, + 'path' => $bericht->final_pdf_path, + )); } // Detail diff --git a/api/voice.php b/api/voice.php new file mode 100644 index 0000000..9db3c08 --- /dev/null +++ b/api/voice.php @@ -0,0 +1,39 @@ + + * multipart: file= — speichert Audio-Notiz zum Auftrag + * + * Audio wird als Anhang im Auftrags-Verzeichnis abgelegt. + * Dateiname: voice_.webm (oder .mp3/.ogg je nach mime) + */ +require_once __DIR__.'/_inc.php'; + +api_authenticate(); +global $db, $user, $conf; + +if (!$user->hasRight('bericht', 'write')) api_fail('Permission denied', 403); + +$order_id = (int) ($_GET['order_id'] ?? 0); +if (!$order_id) api_fail('order_id fehlt'); + +if (empty($_FILES['file']['tmp_name'])) api_fail('file fehlt'); + +require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + +$cmd = new Commande($db); +if ($cmd->fetch($order_id) <= 0) api_fail('Auftrag nicht gefunden', 404); + +$upload_dir = $conf->commande->multidir_output[$cmd->entity].'/'.dol_sanitizeFileName($cmd->ref); +if (!is_dir($upload_dir)) dol_mkdir($upload_dir); + +$mime = $_FILES['file']['type'] ?? 'audio/webm'; +$ext = 'webm'; +if (strpos($mime, 'mp4') !== false) $ext = 'mp4'; +elseif (strpos($mime, 'mp3') !== false || strpos($mime, 'mpeg') !== false) $ext = 'mp3'; +elseif (strpos($mime, 'ogg') !== false) $ext = 'ogg'; + +$filename = 'voice_'.dol_print_date(dol_now(), '%Y%m%d_%H%M%S').'.'.$ext; +$target = $upload_dir.'/'.$filename; +if (!move_uploaded_file($_FILES['file']['tmp_name'], $target)) api_fail('Upload fehlgeschlagen', 500); + +api_ok(array('filename' => $filename, 'path' => 'commande/'.dol_sanitizeFileName($cmd->ref).'/'.$filename));