dolibarr.filearchive/ajax/getdocuments.php
data cbf04e6cc9 FileArchiv: Tile/Gallery view with toggle buttons
- Added formObjectOptions hook for document pages
- CSS/JS injected via DOMContentLoaded for proper timing
- Toggle between list and tile view (localStorage persisted)
- Lightbox for image gallery with keyboard navigation
- Fixed hook contexts (productdocuments, invoicedocuments, etc.)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 16:59:19 +01:00

289 lines
8.4 KiB
PHP

<?php
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
*
* Get related documents for document browser
*/
if (!defined('NOTOKENRENEWAL')) {
define('NOTOKENRENEWAL', '1');
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
if (!defined('NOREQUIREAJAX')) {
define('NOREQUIREAJAX', '1');
}
// Load Dolibarr environment
$res = 0;
// Path from /custom/filearchiv/ajax/ to main.inc.php
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
// Fallback for different directory structures
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 DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
// Debug logging
$debugFile = '/tmp/filearchiv_getdocs_debug.log';
@file_put_contents($debugFile, date('Y-m-d H:i:s') . " === getdocuments.php called ===\n", FILE_APPEND);
// Security check
if (!isModEnabled('filearchiv')) {
http_response_code(403);
echo json_encode(array('success' => false, 'error' => 'Module not enabled'));
exit;
}
$element = GETPOST('element', 'aZ09');
$id = GETPOST('id', 'int');
if (empty($element) || empty($id)) {
echo json_encode(array('success' => false, 'error' => 'Missing parameters'));
exit;
}
$langs->load('filearchiv@filearchiv');
// Get the main object
$object = null;
$thirdparty = null;
switch ($element) {
case 'propal':
require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
$object = new Propal($db);
$object->fetch($id);
$object->fetch_thirdparty();
$thirdparty = $object->thirdparty;
break;
case 'commande':
require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
$object = new Commande($db);
$object->fetch($id);
$object->fetch_thirdparty();
$thirdparty = $object->thirdparty;
break;
case 'facture':
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
$object = new Facture($db);
$object->fetch($id);
$object->fetch_thirdparty();
$thirdparty = $object->thirdparty;
break;
case 'expedition':
require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
$object = new Expedition($db);
$object->fetch($id);
$object->fetch_thirdparty();
$thirdparty = $object->thirdparty;
break;
case 'order_supplier':
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
$object = new CommandeFournisseur($db);
$object->fetch($id);
$object->fetch_thirdparty();
$thirdparty = $object->thirdparty;
break;
case 'invoice_supplier':
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
$object = new FactureFournisseur($db);
$object->fetch($id);
$object->fetch_thirdparty();
$thirdparty = $object->thirdparty;
break;
default:
echo json_encode(array('success' => false, 'error' => 'Unknown element type'));
exit;
}
if (!$object || !$object->id) {
echo json_encode(array('success' => false, 'error' => 'Object not found'));
exit;
}
@file_put_contents($debugFile, "Element: $element, ID: $id\n", FILE_APPEND);
@file_put_contents($debugFile, "Object ref: " . $object->ref . ", entity: " . $object->entity . "\n", FILE_APPEND);
@file_put_contents($debugFile, "Thirdparty: " . ($thirdparty ? $thirdparty->id . " - " . $thirdparty->name : "none") . "\n", FILE_APPEND);
$categories = array();
// 1. Customer/Supplier documents
if ($thirdparty && $thirdparty->id) {
$socdir = $conf->societe->multidir_output[$thirdparty->entity] . '/' . dol_sanitizeFileName($thirdparty->id);
@file_put_contents($debugFile, "Societe dir: $socdir (exists: " . (is_dir($socdir) ? "yes" : "no") . ")\n", FILE_APPEND);
$files = getDocumentsForPath($socdir, $debugFile);
if (!empty($files)) {
$categories[] = array(
'title' => $langs->trans('CustomerDocuments'),
'icon' => 'fa-building',
'files' => $files
);
}
}
// 2. Current object documents
$objdir = '';
switch ($element) {
case 'propal':
$objdir = $conf->propal->multidir_output[$object->entity] . '/' . dol_sanitizeFileName($object->ref);
break;
case 'commande':
$objdir = $conf->commande->multidir_output[$object->entity] . '/' . dol_sanitizeFileName($object->ref);
break;
case 'facture':
$objdir = $conf->facture->multidir_output[$object->entity] . '/' . dol_sanitizeFileName($object->ref);
break;
case 'expedition':
$objdir = $conf->expedition->dir_output . '/sending/' . dol_sanitizeFileName($object->ref);
break;
case 'order_supplier':
$objdir = $conf->fournisseur->commande->multidir_output[$object->entity] . '/' . dol_sanitizeFileName($object->ref);
break;
case 'invoice_supplier':
$objdir = $conf->fournisseur->facture->multidir_output[$object->entity] . '/' . get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier') . dol_sanitizeFileName($object->ref);
break;
}
if ($objdir) {
@file_put_contents($debugFile, "Object dir: $objdir (exists: " . (is_dir($objdir) ? "yes" : "no") . ")\n", FILE_APPEND);
$files = getDocumentsForPath($objdir, $debugFile);
@file_put_contents($debugFile, "Files found: " . count($files) . "\n", FILE_APPEND);
if (!empty($files)) {
$titleKey = ucfirst($element) . 'Documents';
$categories[] = array(
'title' => $langs->trans($titleKey),
'icon' => getIconForElement($element),
'files' => $files
);
}
}
// 3. Product documents from object lines
$productFiles = array();
@file_put_contents($debugFile, "Lines count: " . (isset($object->lines) ? count($object->lines) : "not set") . "\n", FILE_APPEND);
if (!empty($object->lines)) {
foreach ($object->lines as $line) {
if (!empty($line->fk_product) && $line->fk_product > 0) {
$proddir = $conf->product->multidir_output[$conf->entity] . '/' . dol_sanitizeFileName($line->fk_product);
@file_put_contents($debugFile, "Product dir: $proddir\n", FILE_APPEND);
$files = getDocumentsForPath($proddir, $debugFile);
foreach ($files as $file) {
$file['product_ref'] = $line->ref;
$file['product_label'] = $line->product_label;
$productFiles[] = $file;
}
}
}
}
if (!empty($productFiles)) {
$categories[] = array(
'title' => $langs->trans('ProductDocuments'),
'icon' => 'fa-cube',
'files' => $productFiles
);
}
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(array('success' => true, 'categories' => $categories));
/**
* Get documents from a directory path
*
* @param string $path Directory path
* @param string $debugFile Debug file path (optional)
* @return array Array of file info
*/
function getDocumentsForPath($path, $debugFile = null)
{
global $langs;
$files = array();
if (!is_dir($path)) {
if ($debugFile) {
@file_put_contents($debugFile, " Path not a dir: $path\n", FILE_APPEND);
}
return $files;
}
if ($debugFile) {
@file_put_contents($debugFile, " Scanning dir: $path\n", FILE_APPEND);
}
$filearray = dol_dir_list($path, 'files', 0, '', '(\.meta|_preview.*\.png)$');
foreach ($filearray as $file) {
$files[] = array(
'name' => $file['name'],
'fullpath' => $file['fullname'],
'relativepath' => $file['relativename'],
'size' => $file['size'],
'size_formatted' => dol_print_size($file['size']),
'date' => dol_print_date($file['date'], 'day'),
'icon' => getIconForFile($file['name'])
);
}
return $files;
}
/**
* Get Font Awesome icon for file type
*
* @param string $filename Filename
* @return string Icon class
*/
function getIconForFile($filename)
{
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$icons = array(
'pdf' => 'fa-file-pdf',
'doc' => 'fa-file-word',
'docx' => 'fa-file-word',
'xls' => 'fa-file-excel',
'xlsx' => 'fa-file-excel',
'ppt' => 'fa-file-powerpoint',
'pptx' => 'fa-file-powerpoint',
'jpg' => 'fa-file-image',
'jpeg' => 'fa-file-image',
'png' => 'fa-file-image',
'gif' => 'fa-file-image',
'zip' => 'fa-file-archive',
'rar' => 'fa-file-archive',
'txt' => 'fa-file-alt',
'csv' => 'fa-file-csv',
);
return isset($icons[$ext]) ? $icons[$ext] : 'fa-file';
}
/**
* Get icon for element type
*
* @param string $element Element type
* @return string Icon class
*/
function getIconForElement($element)
{
$icons = array(
'propal' => 'fa-file-signature',
'commande' => 'fa-file-invoice',
'facture' => 'fa-file-invoice-dollar',
'expedition' => 'fa-truck',
'order_supplier' => 'fa-shopping-cart',
'invoice_supplier' => 'fa-file-invoice',
);
return isset($icons[$element]) ? $icons[$element] : 'fa-file';
}