Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur
2024-01-18 00:43:04 +01:00
33 changed files with 2024 additions and 290 deletions

View File

@@ -49,8 +49,10 @@ repos:
hooks:
- id: php-cbf
files: \.(php)$
args: [--standard=dev/setup/codesniffer/ruleset.xml, -p]
args: [--standard=dev/setup/codesniffer/ruleset.xml -p]
- id: php-cs
files: \.(php)$
args: [--standard=dev/setup/codesniffer/ruleset.xml -p]
- id: php-lint
# Prettier (format code, only for non common files)

View File

@@ -11,10 +11,22 @@
# ```shell
# echo > dev/tools/codespell/codespell-lines-ignore.txt
# ```
# and then execute this script
# and then execute this script.
#
# author: https://github.com/mdeweerd
#
# :warning:
#
# This script only works properly if codespell is install for your CLI.
# As the configuration is in pyproject.toml, you also need tomli.
#
# ```shell
# python -m pip install codespell tomli
# # or
# pip install codespell tomli
# ```
codespell_ignore_file=dev/tools/codespell/codespell-lines-ignore.txt
if [ -z "${0##*.sh}" ] ; then
# Suppose running from inside script

View File

@@ -323,7 +323,7 @@ if (empty($reshook)) {
}
$object->birth = $birthdate;
$object->default_lang = GETPOST('default_lang', 'alpha');
$object->typeid = GETPOST("typeid", 'int');
$object->typeid = GETPOSTINT("typeid");
//$object->note = trim(GETPOST("comment", "restricthtml"));
$object->morphy = GETPOST("morphy", 'alpha');
@@ -1118,7 +1118,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
// Birth Date
print "<tr><td>".$langs->trans("DateOfBirth")."</td><td>\n";
print $form->selectDate(($object->birth ? $object->birth : -1), 'birth', '', '', 1, 'formsoc');
print img_picto('', 'object_calendar', 'class="pictofixedwidth"').$form->selectDate(($object->birth ? $object->birth : -1), 'birth', '', '', 1, 'formsoc');
print "</td></tr>\n";
// Public profil
@@ -1364,13 +1364,13 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
// Birth Date
print "<tr><td>".$langs->trans("DateOfBirth")."</td><td>\n";
print $form->selectDate(($object->birth ? $object->birth : -1), 'birth', '', '', 1, 'formsoc');
print img_picto('', 'object_calendar', 'class="pictofixedwidth"').$form->selectDate(($object->birth ? $object->birth : -1), 'birth', '', '', 1, 'formsoc');
print "</td></tr>\n";
// Default language
if (getDolGlobalInt('MAIN_MULTILANGS')) {
print '<tr><td>'.$form->editfieldkey('DefaultLang', 'default_lang', '', $object, 0).'</td><td colspan="3">'."\n";
print img_picto('', 'language').$formadmin->select_language($object->default_lang, 'default_lang', 0, 0, 1);
print img_picto('', 'language', 'class="pictofixedwidth"').$formadmin->select_language($object->default_lang, 'default_lang', 0, 0, 1);
print '</td>';
print '</tr>';
}

14
htdocs/ai/README.md Normal file
View File

@@ -0,0 +1,14 @@
# AI FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
## Features
Provides an api key for chatchpt for use it in other modules
### Main code
GPLv3 or (at your option) any later version. See file COPYING for more information.
### Documentation
All texts and readmes are licensed under GFDL.

239
htdocs/ai/admin/setup.php Normal file
View File

@@ -0,0 +1,239 @@
<?php
/* Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2022 Alice Adminson <aadminson@example.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file ai/admin/setup.php
* \ingroup ai
* \brief Ai setup page.
*/
// Load Dolibarr environment
require '../../main.inc.php';
global $langs, $user;
// Libraries
require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
require_once '../lib/ai.lib.php';
// Access control
if (!$user->admin) {
accessforbidden();
}
// Parameters
$action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha');
$modulepart = GETPOST('modulepart', 'aZ09'); // Used by actions_setmoduleoptions.inc.php
$value = GETPOST('value', 'alpha');
$label = GETPOST('label', 'alpha');
$scandir = GETPOST('scan_dir', 'alpha');
$type = 'myobject';
$error = 0;
$setupnotempty = 0;
// Set this to 1 to use the factory to manage constants. Warning, the generated module will be compatible with version v15+ only
$useFormSetup = 1;
if (!class_exists('FormSetup')) {
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php';
}
$formSetup = new FormSetup($db);
// Setup conf AI_PUBLIC_INTERFACE_TOPIC
$item = $formSetup->newItem('AI_KEY_API_CHATGPT');
$item->defaultFieldValue = '';
// Save API Key
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$apiKey = GETPOST('api_key', 'alpha');
// Validate and clean $apiKey here
dolibarr_set_const($db, 'MAIN_AI_CHATGPT_API_KEY', $apiKey, 'chaine', 0, '', $conf->entity);
}
// Retrieve existing API Key
$apiKey = dolibarr_get_const($db, 'MAIN_AI_CHATGPT_API_KEY');
$setupnotempty =+ count($formSetup->items);
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
/*
* Actions
*/
// For retrocompatibility Dolibarr < 15.0
if (versioncompare(explode('.', DOL_VERSION), array(15)) < 0 && $action == 'update' && !empty($user->admin)) {
$formSetup->saveConfFromPost();
}
include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
if ($action == 'updateMask') {
$maskconst = GETPOST('maskconst', 'aZ09');
$maskvalue = GETPOST('maskvalue', 'alpha');
if ($maskconst && preg_match('/_MASK$/', $maskconst)) {
$res = dolibarr_set_const($db, $maskconst, $maskvalue, 'chaine', 0, '', $conf->entity);
if (!($res > 0)) {
$error++;
}
}
if (!$error) {
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
} else {
setEventMessages($langs->trans("Error"), null, 'errors');
}
} elseif ($action == 'specimen') {
$modele = GETPOST('module', 'alpha');
$tmpobjectkey = GETPOST('object');
$tmpobject = new $tmpobjectkey($db);
$tmpobject->initAsSpecimen();
// Search template files
$file = '';
$classname = '';
$filefound = 0;
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
foreach ($dirmodels as $reldir) {
$file = dol_buildpath($reldir."core/modules/ai/doc/pdf_".$modele."_".strtolower($tmpobjectkey).".modules.php", 0);
if (file_exists($file)) {
$filefound = 1;
$classname = "pdf_".$modele."_".strtolower($tmpobjectkey);
break;
}
}
if ($filefound) {
require_once $file;
$module = new $classname($db);
if ($module->write_file($tmpobject, $langs) > 0) {
header("Location: ".DOL_URL_ROOT."/document.php?modulepart=bookcal-".strtolower($tmpobjectkey)."&file=SPECIMEN.pdf");
return;
} else {
setEventMessages($module->error, null, 'errors');
dol_syslog($module->error, LOG_ERR);
}
} else {
setEventMessages($langs->trans("ErrorModuleNotFound"), null, 'errors');
dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR);
}
} elseif ($action == 'setmod') {
// TODO Check if numbering module chosen can be activated by calling method canBeActivated
$tmpobjectkey = GETPOST('object');
if (!empty($tmpobjectkey)) {
$constforval = 'Ai_'.strtoupper($tmpobjectkey)."_ADDON";
dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity);
}
} elseif ($action == 'set') {
// Activate a model
$ret = addDocumentModel($value, $type, $label, $scandir);
} elseif ($action == 'del') {
$ret = delDocumentModel($value, $type);
if ($ret > 0) {
$tmpobjectkey = GETPOST('object');
if (!empty($tmpobjectkey)) {
$constforval = 'Ai_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
if (getDolGlobalString($constforval) == "$value") {
dolibarr_del_const($db, $constforval, $conf->entity);
}
}
}
} elseif ($action == 'setdoc') {
// Set or unset default model
$tmpobjectkey = GETPOST('object');
if (!empty($tmpobjectkey)) {
$constforval = 'Ai_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
if (dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity)) {
// The constant that was read before the new set
// We therefore requires a variable to have a coherent view
$conf->global->$constforval = $value;
}
// We disable/enable the document template (into llx_document_model table)
$ret = delDocumentModel($value, $type);
if ($ret > 0) {
$ret = addDocumentModel($value, $type, $label, $scandir);
}
}
} elseif ($action == 'unsetdoc') {
$tmpobjectkey = GETPOST('object');
if (!empty($tmpobjectkey)) {
$constforval = 'Ai_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
dolibarr_del_const($db, $constforval, $conf->entity);
}
}
/*
* View
*/
$form = new Form($db);
$help_url = '';
$page_name = "AiSetup";
llxHeader('', $langs->trans($page_name), $help_url);
// Subheader
$linkback = '<a href="'.($backtopage ? $backtopage : DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1').'">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup');
// Configuration header
$head = aiAdminPrepareHead();
print dol_get_fiche_head($head, 'settings', $langs->trans($page_name), -1, "fa-microchip");
// Setup page goes here
//echo '<span class="opacitymedium">'.$langs->trans("AiSetupPage").'</span><br><br>';
if ($action == 'edit') {
print $formSetup->generateOutput(true);
print '<br>';
} elseif (!empty($formSetup->items)) {
print $formSetup->generateOutput();
print '<div class="tabsAction">';
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>';
print '</div>';
} else {
print '<br>'.$langs->trans("NothingToSetup");
}
if (empty($setupnotempty)) {
print '<br>'.$langs->trans("NothingToSetup");
}
// Page end
print dol_get_fiche_end();
llxFooter();
$db->close();

View File

@@ -0,0 +1,90 @@
<?php
/* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2016 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2012 J. Fernando Lagrange <fernando@demo-tic.org>
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
* Copyright (C) 2023 Eric Seigne <eric.seigne@cap-rel.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* or see https://www.gnu.org/
*/
/**
* Class for AI
*/
class Ai
{
/**
* @var DoliDB $db Database object
*/
protected $db;
/**
* @var string $apiEndpoint
*/
private $apiEndpoint;
/**
* @var string $apiKey
*/
private $apiKey;
/**
* Constructor
*
* @param string $apiEndpoint Endpoint of api
* @param boolean $apiKey key of api
*/
public function __construct($apiEndpoint, $apiKey)
{
$this->apiEndpoint = $apiEndpoint;
$this->apiKey = $apiKey;
}
/**
* Generate response of instructions
* @param string $instructions instruction for generate content
* @return mixed $response
*/
public function generateContent($instructions)
{
try {
$ch = curl_init($this->apiEndpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['prompt' => $instructions]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('cURL error: ' . curl_error($ch));
}
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($statusCode != 200) {
throw new Exception('API request failed with status code ' . $statusCode);
}
return $response;
} catch (Exception $e) {
error_log($e->getMessage());
return null;
} finally {
curl_close($ch);
}
}
}

63
htdocs/ai/lib/ai.lib.php Normal file
View File

@@ -0,0 +1,63 @@
<?php
/* Copyright (C) 2022 Alice Adminson <aadminson@example.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file ai/lib/ai.lib.php
* \ingroup ai
* \brief Library files with common functions for Ai
*/
/**
* Prepare admin pages header
*
* @return array
*/
function aiAdminPrepareHead()
{
global $langs, $conf;
$langs->load("agenda");
$h = 0;
$head = array();
$head[$h][0] = dol_buildpath("/ai/admin/setup.php", 1);
$head[$h][1] = $langs->trans("Settings");
$head[$h][2] = 'settings';
$h++;
/*
$head[$h][0] = dol_buildpath("/ai/admin/myobject_extrafields.php", 1);
$head[$h][1] = $langs->trans("ExtraFields");
$head[$h][2] = 'myobject_extrafields';
$h++;
*/
// Show more tabs from modules
// Entries must be declared in modules descriptor with line
//$this->tabs = array(
// 'entity:+tabname:Title:@ai:/ai/mypage.php?id=__ID__'
//); // to add new tab
//$this->tabs = array(
// 'entity:-tabname:Title:@ai:/ai/mypage.php?id=__ID__'
//); // to remove a tab
complete_head_from_modules($conf, $langs, null, $head, $h, 'ai@ai');
complete_head_from_modules($conf, $langs, null, $head, $h, 'ai@ai', 'remove');
return $head;
}

View File

@@ -0,0 +1,70 @@
<?php
/* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2016 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2012 J. Fernando Lagrange <fernando@demo-tic.org>
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
* Copyright (C) 2023 Eric Seigne <eric.seigne@cap-rel.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* or see https://www.gnu.org/
*/
/**
* \file htdocs/ai/lib/generate_content.lib.php
* \brief Library of ai script
*/
if (!defined('NOTOKENRENEWAL')) {
define('NOTOKENRENEWAL', '1'); // Disables token renewal
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
if (!defined('NOREQUIREHTML')) {
define('NOREQUIREHTML', '1');
}
if (!defined('NOREQUIREAJAX')) {
define('NOREQUIREAJAX', '1');
}
if (!defined('NOREQUIRESOC')) {
define('NOREQUIRESOC', '1');
}
require_once '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/ai/class/ai.class.php';
//get data from AJAX
$rawData = file_get_contents('php://input');
$jsonData = json_decode($rawData, true);
if (is_null($jsonData)) {
dol_print_error('data with format JSON valide.');
}
$token = GETPOST('token');
if ($token !== currentToken()) { // Remplacez 'newToken' par le nom de votre variable de session contenant le token
dol_print_error('CSRF token validation failed.');
exit;
}
$chatGPT = new Ai('API_ENDPOINT', 'API_KEY');
$instructions = dol_string_nohtmltag($jsonData['instructions'], 1, 'UTF-8');
$generatedContent = $chatGPT->generateContent($instructions);
if ($generatedContent) {
print $generatedContent;
} else {
dol_print_error('error!!');
}

View File

@@ -22,62 +22,14 @@
* \brief Tab of events on Calendar
*/
//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db
//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user
//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc
//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs
//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters
//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters
//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on)
//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data
//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu
//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php
//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library
//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too.
//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip
//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value
//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler
//if (! defined("MAIN_SECURITY_FORCECSP")) define('MAIN_SECURITY_FORCECSP', 'none'); // Disable all Content Security Policies
//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET
//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification
// Load Dolibarr environment
$res = 0;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
$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";
}
// Try main.inc.php using relative path
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 && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require '../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
dol_include_once('/bookcal/class/calendar.class.php');
dol_include_once('/bookcal/lib/bookcal_calendar.lib.php');
require_once DOL_DOCUMENT_ROOT.'/bookcal/class/calendar.class.php';
require_once DOL_DOCUMENT_ROOT.'/bookcal/lib/bookcal_calendar.lib.php';
// Load translation files required by the page
$langs->loadLangs(array("bookcal@bookcal", "other"));

View File

@@ -169,6 +169,12 @@ class FormAdvTargetEmailing extends Form
if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX')) {
$sql_usr .= " AND u2.statut <> 0";
}
if (!empty($conf->global->USER_HIDE_NONEMPLOYEE_IN_COMBOBOX)) {
$sql_usr .= " AND u2.employee<>0 ";
}
if (!empty($conf->global->USER_HIDE_EXTERNAL_IN_COMBOBOX)) {
$sql_usr .= " AND u2.fk_soc IS NULL ";
}
$sql_usr .= " ORDER BY name ASC";
// print $sql_usr;exit;

View File

@@ -47,6 +47,8 @@ if ($action == 'update' && is_array($arrayofparameters) && !empty($user->admin))
} else {
$val_const = GETPOST($key, 'int');
}
} else if ($val['type'] == 'html') {
$val_const = GETPOST($key, 'restricthtml');
} else {
$val_const = GETPOST($key, 'alpha');
}

View File

@@ -2081,6 +2081,12 @@ class Form
if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
$sql .= " AND u.statut <> 0";
}
if (!empty($conf->global->USER_HIDE_NONEMPLOYEE_IN_COMBOBOX) || $notdisabled) {
$sql .= " AND u.employee <> 0";
}
if (!empty($conf->global->USER_HIDE_EXTERNAL_IN_COMBOBOX) || $notdisabled) {
$sql .= " AND u.fk_soc IS NULL";
}
if (!empty($morefilter)) {
$sql .= " " . $morefilter;
}

View File

@@ -755,7 +755,7 @@ class FormMail extends Form
if (!empty($this->withtoccuser) && is_array($this->withtoccuser) && getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')) {
$out .= '<tr><td>';
$out .= $langs->trans("MailToCCUsers");
$out .= '</td><td>';
$out .= '</td>';
// multiselect array convert html entities into options tags, even if we don't want this, so we encode them a second time
$tmparray = $this->withtoccuser;
@@ -887,6 +887,11 @@ class FormMail extends Form
$out .= "</td></tr>\n";
}
//input prompt AI
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
if (isModEnabled('ai')) {
$out .= $this->getHtmlForInstruction();
}
// Message
if (!empty($this->withbody)) {
$defaultmessage = GETPOST('message', 'restricthtml');
@@ -1363,6 +1368,57 @@ class FormMail extends Form
return $out;
}
/**
* get Html For instruction of message
* @return string Text for instructions
*/
public function getHtmlForInstruction()
{
global $langs, $form;
$baseUrl = dol_buildpath('/', 1);
$out = '<tr>';
$out .= '<td>';
$out .= $form->textwithpicto($langs->trans('helpWithAi'), $langs->trans("YouCanMakeSomeInstructionForEmail"));
$out .= '</td>';
$out .= '<td>';
$out .= '<input type="hidden" id="csrf_token" name="token" value="'.newToken().'">';
$out .= '<input type="text" class="quatrevingtpercent" id="ai_instructions" name="instruction" placeholder="message with AI"/>';
$out .= '<button id="generate_button" type="button" class="button smallpaddingimp">'.$langs->trans('Generate').'</button>';
$out .= "</td></tr>\n";
$out .= "<script type='text/javascript'>
$(document).ready(function() {
$('#generate_button').click(function() {
var instructions = $('#ai_instructions').val();
var token = $('#csrf_token').val();
$.ajax({
url: '".$baseUrl."ai/lib/generate_content.lib.php',
method: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({
'token': token,
'instructions': instructions,
}),
success: function(response) {
console.log(response);
},
error: function(xhr, status, error) {
console.error('error ajax', status, error);
}
});
});
});
</script>
";
return $out;
}
/**
* Return templates of email with type = $type_template or type = 'all'.
* This search into table c_email_templates. Used by the get_form function.

View File

@@ -522,6 +522,15 @@ class FormOther
if (!empty($user->socid)) {
$sql_usr .= " AND u.fk_soc = ".((int) $user->socid);
}
if (!empty($conf->global->USER_HIDE_NONEMPLOYEE_IN_COMBOBOX)) {
$sql_usr .= " AND u.employee <> 0";
}
if (!empty($conf->global->USER_HIDE_EXTERNAL_IN_COMBOBOX)) {
$sql_usr .= " AND u.fk_soc IS NULL";
}
if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX)) {
$sql_usr .= " AND u.statut <> 0";
}
//Add hook to filter on user (for example on usergroup define in custom modules)
if (!empty($reshook)) {

View File

@@ -3,6 +3,7 @@
* Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
* Copyright (C) 2005-2021 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2006-2021 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,12 +45,12 @@ class Ldap
public $errors = array();
/**
* Tableau des serveurs (IP addresses ou nom d'hotes)
* @var array Servers (IP addresses or hostnames)
*/
public $server = array();
/**
* Current connected server
* @var string Current connected server
*/
public $connectedServer;
@@ -59,51 +60,62 @@ class Ldap
public $serverPort;
/**
* Base DN (e.g. "dc=foo,dc=com")
* @var string Base DN (e.g. "dc=foo,dc=com")
*/
public $dn;
/**
* type de serveur, actuellement OpenLdap et Active Directory
* @var string Server type: OpenLDAP or Active Directory
*/
public $serverType;
/**
* Version du protocole ldap
* @var string LDAP protocol version
*/
public $ldapProtocolVersion;
/**
* Server DN
* @var string Server DN
*/
public $domain;
/**
* @var string Server FQDN
*/
public $domainFQDN;
/**
* @var int bind
* @var bool LDAP bind
*/
public $bind;
/**
* User administrateur Ldap
* @var string LDAP administrator user
* Active Directory does not allow anonymous connections
*/
public $searchUser;
/**
* Administraot Password
* @var string LDAP administrator password
* Active Directory does not allow anonymous connections
*/
public $searchPassword;
/**
* Users DN
* @var string Users DN
*/
public $people;
/**
* Groups DN
* @var string Groups DN
*/
public $groups;
/**
* @var string|null Error code provided by the LDAP server
* @var int|null Error code provided by the LDAP server
*/
public $ldapErrorCode;
/**
* @var string|null Error text message
*/
@@ -113,10 +125,12 @@ class Ldap
* @var string
*/
public $filter;
/**
* @var string
*/
public $filtergroup;
/**
* @var string
*/
@@ -168,56 +182,91 @@ class Ldap
public $badpwdtime;
/**
* @var string ladpUserDN
* @var string LDAP user DN
*/
public $ldapUserDN;
//Fetch user
/**
* @var string Fetched username
*/
public $name;
/**
* @var string Fetched user first name
*/
public $firstname;
/**
* @var string Fetched user login
*/
public $login;
/**
* @var string Fetched user phone number
*/
public $phone;
/**
* @var string Fetched user fax number
*/
public $fax;
/**
* @var string Fetched user email
*/
public $mail;
/**
* @var string Fetched user mobile number
*/
public $mobile;
/**
* @var array UserAccountControl Flags
*/
public $uacf;
/**
* @var int Password last set time
*/
public $pwdlastset;
public $ldapcharset = 'UTF-8'; // LDAP should be UTF-8 encoded
/**
* @var string LDAP charset.
* LDAP should be UTF-8 encoded
*/
public $ldapcharset = 'UTF-8';
/**
* The internal LDAP connection handle
* @var bool|resource The internal LDAP connection handle
*/
public $connection;
/**
* Result of any connections etc.
* @var bool|resource Result of any connections or search.
*/
public $result;
/**
* No Ldap synchronization
* @var int No LDAP synchronization
*/
const SYNCHRO_NONE = 0;
/**
* Dolibarr to Ldap synchronization
* @var int Dolibarr to LDAP synchronization
*/
const SYNCHRO_DOLIBARR_TO_LDAP = 1;
/**
* Ldap to Dolibarr synchronization
* @var int LDAP to Dolibarr synchronization
*/
const SYNCHRO_LDAP_TO_DOLIBARR = 2;
/**
* Constructor
*/
public function __construct()
{
global $conf;
// Server
if (getDolGlobalString('LDAP_SERVER_HOST')) {
@@ -260,17 +309,16 @@ class Ldap
* Use this->server, this->serverPort, this->ldapProtocolVersion, this->serverType, this->searchUser, this->searchPassword
* After return, this->connection and $this->bind are defined
*
* @return int Return integer <0 if KO, 1 if bind anonymous, 2 if bind auth
* @return int if KO: <0 || if bind anonymous: 1 || if bind auth: 2
*/
public function connect_bind()
{
// phpcs:enable
global $conf;
global $dolibarr_main_auth_ldap_debug;
$connected = 0;
$this->bind = 0;
$this->error = 0;
$this->bind = false;
$this->error = '';
$this->connectedServer = '';
$ldapdebug = ((empty($dolibarr_main_auth_ldap_debug) || $dolibarr_main_auth_ldap_debug == "false") ? false : true);
@@ -290,7 +338,7 @@ class Ldap
if (!function_exists("ldap_connect")) {
$this->error = 'LDAPFunctionsNotAvailableOnPHP';
dol_syslog(get_class($this)."::connect_bind ".$this->error, LOG_WARNING);
$return = -1;
return -1;
}
if (empty($this->error)) {
@@ -303,9 +351,9 @@ class Ldap
continue;
}
if ($this->serverPing($host, $this->serverPort) === true) {
if ($this->serverPing($host, $this->serverPort)) {
if ($ldapdebug) {
dol_syslog(get_class($this)."::connect_bind serverPing true, we try ldap_connect to ".$host);
dol_syslog(get_class($this)."::connect_bind serverPing true, we try ldap_connect to ".$host, LOG_DEBUG);
}
$this->connection = ldap_connect($host, $this->serverPort);
} else {
@@ -313,10 +361,13 @@ class Ldap
// With host = ldaps://server, the serverPing to ssl://server sometimes fails, even if the ldap_connect succeed, so
// we test this case and continue in such a case even if serverPing fails.
if ($ldapdebug) {
dol_syslog(get_class($this)."::connect_bind serverPing false, we try ldap_connect to ".$host);
dol_syslog(get_class($this)."::connect_bind serverPing false, we try ldap_connect to ".$host, LOG_DEBUG);
}
$this->connection = ldap_connect($host, $this->serverPort);
} else {
if ($ldapdebug) {
dol_syslog(get_class($this)."::connect_bind serverPing false, no ldap_connect ".$host, LOG_DEBUG);
}
continue;
}
}
@@ -344,8 +395,7 @@ class Ldap
// Execute the ldap_set_option here (after connect and before bind)
$this->setVersion();
ldap_set_option($this->connection, LDAP_OPT_SIZELIMIT, 0); // no limit here. should return true.
$this->setSizeLimit();
if ($this->serverType == "activedirectory") {
$result = $this->setReferrals();
@@ -396,15 +446,13 @@ class Ldap
}
if ($connected) {
$return = $connected;
dol_syslog(get_class($this)."::connect_bind return=".$return, LOG_DEBUG);
dol_syslog(get_class($this)."::connect_bind ".$connected, LOG_DEBUG);
return $connected;
} else {
$this->error = 'Failed to connect to LDAP'.($this->error ? ': '.$this->error : '');
$return = -1;
dol_syslog(get_class($this)."::connect_bind return=".$return.' - '.$this->error, LOG_WARNING);
dol_syslog(get_class($this)."::connect_bind ".$this->error, LOG_WARNING);
return -1;
}
return $return;
}
/**
@@ -481,50 +529,57 @@ class Ldap
/**
* Verification de la version du serveur ldap.
* Verify LDAP server version
*
* @return string version
* @return int version
*/
public function getVersion()
{
$version = 0;
$version = @ldap_get_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $version);
@ldap_get_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $version);
return $version;
}
/**
* Change ldap protocol version to use.
* Set LDAP protocol version.
* LDAP_OPT_PROTOCOL_VERSION is a constant equal to 3
*
* @return boolean version
* @return boolean if set LDAP option OK: true, if KO: false
*/
public function setVersion()
{
// LDAP_OPT_PROTOCOL_VERSION est une constante qui vaut 17
$ldapsetversion = ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->ldapProtocolVersion);
return $ldapsetversion;
return ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->ldapProtocolVersion);
}
/**
* changement du referrals.
* Set LDAP size limit.
*
* @return boolean referrals
* @return boolean if set LDAP option OK: true, if KO: false
*/
public function setSizeLimit()
{
return ldap_set_option($this->connection, LDAP_OPT_SIZELIMIT, 0);
}
/**
* Set LDAP referrals.
* LDAP_OPT_REFERRALS is a constant equal to ?
*
* @return boolean if set LDAP option OK: true, if KO: false
*/
public function setReferrals()
{
// LDAP_OPT_REFERRALS est une constante qui vaut ?
$ldapreferrals = ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
return $ldapreferrals;
return ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
}
/**
* Add a LDAP entry
* Ldap object connect and bind must have been done
* Add an LDAP entry
* LDAP object connect and bind must have been done
*
* @param string $dn DN entry key
* @param array $info Attributes array
* @param User $user Object user that create
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function add($dn, $info, $user)
{
@@ -566,13 +621,13 @@ class Ldap
}
/**
* Modify a LDAP entry
* Ldap object connect and bind must have been done
* Modify an LDAP entry
* LDAP object connect and bind must have been done
*
* @param string $dn DN entry key
* @param array $info Attributes array
* @param User $user Object user that modify
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function modify($dn, $info, $user)
{
@@ -622,15 +677,15 @@ class Ldap
}
/**
* Rename a LDAP entry
* Ldap object connect and bind must have been done
* Rename an LDAP entry
* LDAP object connect and bind must have been done
*
* @param string $dn Old DN entry key (uid=qqq,ou=xxx,dc=aaa,dc=bbb) (before update)
* @param string $newrdn New RDN entry key (uid=qqq)
* @param string $newparent New parent (ou=xxx,dc=aaa,dc=bbb)
* @param User $user Object user that modify
* @param bool $deleteoldrdn If true the old RDN value(s) is removed, else the old RDN value(s) is retained as non-distinguished values of the entry.
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function rename($dn, $newrdn, $newparent, $user, $deleteoldrdn = true)
{
@@ -665,8 +720,8 @@ class Ldap
}
/**
* Modify a LDAP entry (to use if dn != olddn)
* Ldap object connect and bind must have been done
* Modify an LDAP entry (to use if dn != olddn)
* LDAP object connect and bind must have been done
*
* @param string $dn DN entry key
* @param array $info Attributes array
@@ -674,7 +729,7 @@ class Ldap
* @param string $olddn Old DN entry key (before update)
* @param string $newrdn New RDN entry key (uid=qqq) (for ldap_rename)
* @param string $newparent New parent (ou=xxx,dc=aaa,dc=bbb) (for ldap_rename)
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function update($dn, $info, $user, $olddn, $newrdn = '', $newparent = '')
{
@@ -720,11 +775,11 @@ class Ldap
/**
* Delete a LDAP entry
* Ldap object connect and bind must have been done
* Delete an LDAP entry
* LDAP object connect and bind must have been done
*
* @param string $dn DN entry key
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function delete($dn)
{
@@ -753,7 +808,7 @@ class Ldap
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Build a LDAP message
* Build an LDAP message
*
* @param string $dn DN entry key
* @param array $info Attributes array
@@ -790,29 +845,32 @@ class Ldap
}
/**
* Dump a LDAP message to ldapinput.in file
* Dump an LDAP message to ldapinput.in file
*
* @param string $dn DN entry key
* @param array $info Attributes array
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function dump($dn, $info)
{
global $conf;
$ldapDirTemp = $conf->ldap->dir_temp;
// Create content
$content = $this->dump_content($dn, $info);
//Create file
$result = dol_mkdir($conf->ldap->dir_temp);
$outputfile = $conf->ldap->dir_temp.'/ldapinput.in';
$fp = fopen($outputfile, "w");
if ($fp) {
fputs($fp, $content);
fclose($fp);
dolChmod($outputfile);
return 1;
//Create directory & file
$result = dol_mkdir($ldapDirTemp);
if ($result != 0) {
$outputfile = $ldapDirTemp.'/ldapinput.in';
$fp = fopen($outputfile, "w");
if ($fp) {
fputs($fp, $content);
fclose($fp);
dolChmod($outputfile);
return 1;
} else {
return -1;
}
} else {
return -1;
}
@@ -821,10 +879,10 @@ class Ldap
/**
* Ping a server before ldap_connect for avoid waiting
*
* @param string $host Server host or address
* @param int $port Server port (default 389)
* @param int $timeout Timeout in second (default 1s)
* @return boolean true or false
* @param string $host Server host or address
* @param int $port Server port (default 389)
* @param int $timeout Timeout in second (default 1s)
* @return boolean true or false
*/
public function serverPing($host, $port = 389, $timeout = 1)
{
@@ -865,13 +923,13 @@ class Ldap
// Attribute methods -----------------------------------------------------
/**
* Add a LDAP attribute in entry
* Ldap object connect and bind must have been done
* Add an LDAP attribute in entry
* LDAP object connect and bind must have been done
*
* @param string $dn DN entry key
* @param array $info Attributes array
* @param User $user Object user that create
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function addAttribute($dn, $info, $user)
{
@@ -911,13 +969,13 @@ class Ldap
}
/**
* Update a LDAP attribute in entry
* Ldap object connect and bind must have been done
* Update an LDAP attribute in entry
* LDAP object connect and bind must have been done
*
* @param string $dn DN entry key
* @param array $info Attributes array
* @param User $user Object user that create
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function updateAttribute($dn, $info, $user)
{
@@ -957,13 +1015,13 @@ class Ldap
}
/**
* Delete a LDAP attribute in entry
* Ldap object connect and bind must have been done
* Delete an LDAP attribute in entry
* LDAP object connect and bind must have been done
*
* @param string $dn DN entry key
* @param array $info Attributes array
* @param User $user Object user that create
* @return int Return integer <0 if KO, >0 if OK
* @return int if KO: <0 || if OK: >0
*/
public function deleteAttribute($dn, $info, $user)
{
@@ -1007,7 +1065,7 @@ class Ldap
*
* @param string $dn DN entry key
* @param string $filter Filter
* @return int|array Return integer <0 or false if KO, array if OK
* @return int|array if KO: <=0 || if OK: array
*/
public function getAttribute($dn, $filter)
{
@@ -1046,9 +1104,9 @@ class Ldap
/**
* Returns an array containing values for an attribute and for first record matching filterrecord
*
* @param string $filterrecord Record
* @param string $attribute Attributes
* @return array|boolean
* @param string $filterrecord Record
* @param string $attribute Attributes
* @return array|boolean
*/
public function getAttributeValues($filterrecord, $attribute)
{
@@ -1082,16 +1140,16 @@ class Ldap
}
/**
* Returns an array containing a details or list of LDAP record(s).
* ldapsearch -LLLx -hlocalhost -Dcn=admin,dc=parinux,dc=org -w password -b "ou=adherents,ou=people,dc=parinux,dc=org" userPassword
* Returns an array containing a details or list of LDAP record(s).
* ldapsearch -LLLx -hlocalhost -Dcn=admin,dc=parinux,dc=org -w password -b "ou=adherents,ou=people,dc=parinux,dc=org" userPassword
*
* @param string $search Value of field to search, '*' for all. Not used if $activefilter is set.
* @param string $userDn DN (Ex: ou=adherents,ou=people,dc=parinux,dc=org)
* @param string $useridentifier Name of key field (Ex: uid).
* @param array $attributeArray Array of fields required. Note this array must also contains field $useridentifier (Ex: sn,userPassword)
* @param array $attributeArray Array of fields required. Note this array must also contain field $useridentifier (Ex: sn,userPassword)
* @param int $activefilter '1' or 'user'=use field this->filter as filter instead of parameter $search, 'group'=use field this->filtergroup as filter, 'member'=use field this->filtermember as filter
* @param array $attributeAsArray Array of fields wanted as an array not a string
* @return array|int Array of [id_record][ldap_field]=value
* @return array|int if KO: <0 || if OK: array of [id_record][ldap_field]=value
*/
public function getRecords($search, $userDn, $useridentifier, $attributeArray, $activefilter = 0, $attributeAsArray = array())
{
@@ -1179,7 +1237,7 @@ class Ldap
}
/**
* Converts a little-endian hex-number to one, that 'hexdec' can convert
* Converts a little-endian hex-number to one, that 'hexdec' can convert
* Required by Active Directory
*
* @param string $hex Hex value
@@ -1196,11 +1254,11 @@ class Ldap
/**
* Recupere le SID de l'utilisateur
* Gets LDAP user SID.
* Required by Active Directory
*
* @param string $ldapUser Login de l'utilisateur
* @return string Sid
* @param string $ldapUser User login
* @return int|string if SID OK: SID string, if KO: -1
*/
public function getObjectSid($ldapUser)
{
@@ -1241,13 +1299,13 @@ class Ldap
return $SIDText;
} else {
$this->error = ldap_errno($this->connection)." ".ldap_error($this->connection);
return '?';
return -1;
}
}
/**
* Returns the textual SID
* Indispensable pour Active Directory
* Required by Active Directory
*
* @param string $binsid Binary SID
* @return string Textual SID
@@ -1267,15 +1325,17 @@ class Ldap
/**
* Fonction de recherche avec filtre
* this->connection doit etre defini donc la methode bind ou bindauth doit avoir deja ete appelee
* Ne pas utiliser pour recherche d'une liste donnee de proprietes
* car conflict majuscule-minuscule. A n'utiliser que pour les pages
* 'Fiche LDAP' qui affiche champ lisibles par default.
* Search method with filter
* this->connection must be defined. The bind or bindauth methods must already have been called.
* Do not use for search of a given properties list because of upper-lower case conflict.
* Only use for pages.
* 'Fiche LDAP' shows readable fields by default.
* @see bind
* @see bindauth
*
* @param string $checkDn DN de recherche (Ex: ou=users,cn=my-domain,cn=com)
* @param string $filter Search filter (ex: (sn=nom_personne) )
* @return array|int Array with answers (key lowercased - value)
* @param string $checkDn Search DN (Ex: ou=users,cn=my-domain,cn=com)
* @param string $filter Search filter (ex: (sn=name_person) )
* @return array|int Array with answers (lowercase key - value)
*/
public function search($checkDn, $filter)
{
@@ -1303,12 +1363,12 @@ class Ldap
/**
* Load all attribute of a LDAP user
* Load all attributes of an LDAP user
*
* @param User|string $user Not used.
* @param string $filter Filter for search. Must start with &.
* Examples: &(objectClass=inetOrgPerson) &(objectClass=user)(objectCategory=person) &(isMemberOf=cn=Sales,ou=Groups,dc=opencsi,dc=com)
* @return int >0 if OK, <0 if KO
* @param User|string $user Not used.
* @param string $filter Filter for search. Must start with &.
* Examples: &(objectClass=inetOrgPerson) &(objectClass=user)(objectCategory=person) &(isMemberOf=cn=Sales,ou=Groups,dc=opencsi,dc=com)
* @return int if KO: <0 || if OK: > 0
*/
public function fetch($user, $filter)
{
@@ -1363,14 +1423,14 @@ class Ldap
$this->uacf = $this->parseUACF($this->convToOutputCharset($result[0]["useraccountcontrol"][0], $this->ldapcharset));
if (isset($result[0]["pwdlastset"][0])) { // If expiration on password exists
$this->pwdlastset = ($result[0]["pwdlastset"][0] != 0) ? $this->convert_time($this->convToOutputCharset($result[0]["pwdlastset"][0], $this->ldapcharset)) : 0;
$this->pwdlastset = ($result[0]["pwdlastset"][0] != 0) ? $this->convertTime($this->convToOutputCharset($result[0]["pwdlastset"][0], $this->ldapcharset)) : 0;
} else {
$this->pwdlastset = -1;
}
if (!$this->name && !$this->login) {
$this->pwdlastset = -1;
}
$this->badpwdtime = $this->convert_time($this->convToOutputCharset($result[0]["badpasswordtime"][0], $this->ldapcharset));
$this->badpwdtime = $this->convertTime($this->convToOutputCharset($result[0]["badpasswordtime"][0], $this->ldapcharset));
// FQDN domain
$domain = str_replace('dc=', '', $this->domain);
@@ -1390,7 +1450,7 @@ class Ldap
// helper methods
/**
* Returns the correct user identifier to use, based on the ldap server type
* Returns the correct user identifier to use, based on the LDAP server type
*
* @return string Login
*/
@@ -1404,7 +1464,7 @@ class Ldap
}
/**
* UserAccountControl Flgs to more human understandable form...
* UserAccountControl Flags to more human understandable form...
*
* @param string $uacf UACF
* @return array
@@ -1482,16 +1542,14 @@ class Ldap
return $retval;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Convertit le temps ActiveDirectory en Unix timestamp
* Converts ActiveDirectory time to Unix timestamp
*
* @param string $value AD time to convert
* @return integer Unix timestamp
*/
public function convert_time($value)
public function convertTime($value)
{
// phpcs:enable
$dateLargeInt = $value; // nano secondes depuis 1601 !!!!
$secsAfterADEpoch = $dateLargeInt / (10000000); // secondes depuis le 1 jan 1601
$ADToUnixConvertor = ((1970 - 1601) * 365.242190) * 86400; // UNIX start date - AD start date * jours * secondes
@@ -1503,9 +1561,9 @@ class Ldap
/**
* Convert a string into output/memory charset
*
* @param string $str String to convert
* @param string $str String to convert
* @param string $pagecodefrom Page code of src string
* @return string Converted string
* @return string Converted string
*/
private function convToOutputCharset($str, $pagecodefrom = 'UTF-8')
{
@@ -1522,9 +1580,9 @@ class Ldap
/**
* Convert a string from output/memory charset
*
* @param string $str String to convert
* @param string $str String to convert
* @param string $pagecodeto Page code for result string
* @return string Converted string
* @return string Converted string
*/
public function convFromOutputCharset($str, $pagecodeto = 'UTF-8')
{
@@ -1547,7 +1605,6 @@ class Ldap
*/
public function getNextGroupGid($keygroup = 'LDAP_KEY_GROUPS')
{
global $conf;
if (empty($keygroup)) {
$keygroup = 'LDAP_KEY_GROUPS';

View File

@@ -587,7 +587,7 @@ function dol_get_next_week($day, $week, $month, $year)
* True or 1 or 'gmt' to compare with GMT date.
* Example: dol_get_first_day(1970,1,false) will return -3600 with TZ+1, a dol_print_date on it will return 1970-01-01 00:00:00
* Example: dol_get_first_day(1970,1,true) will return 0 whatever is TZ, a dol_print_date on it will return 1970-01-01 00:00:00
* @return int Date for first day, '' if error
* @return int|string Date as a timestamp, '' if error
*/
function dol_get_first_day($year, $month = 1, $gm = false)
{
@@ -606,7 +606,7 @@ function dol_get_first_day($year, $month = 1, $gm = false)
* @param int $month Month
* @param mixed $gm False or 0 or 'tzserver' = Return date to compare with server TZ,
* True or 1 or 'gmt' to compare with GMT date.
* @return int Date for first day, '' if error
* @return int|string Date as a timestamp, '' if error
*/
function dol_get_last_day($year, $month = 12, $gm = false)
{
@@ -1187,5 +1187,5 @@ function getWeekNumber($day, $month, $year)
{
$date = new DateTime($year.'-'.$month.'-'.$day);
$week = $date->format("W");
return $week;
return (int) $week;
}

View File

@@ -186,7 +186,36 @@ function user_prepare_head(User $object)
$h++;
$head[$h][0] = DOL_URL_ROOT.'/user/info.php?id='.$object->id;
$head[$h][1] = $langs->trans("Info");
$head[$h][1] = $langs->trans("Events");
if (isModEnabled('agenda')&& ($user->hasRight('agenda', 'myactions', 'read') || $user->hasRight('agenda', 'allactions', 'read'))) {
$nbEvent = 0;
// Enable caching of thirdparty count actioncomm
require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
$cachekey = 'count_events_user_'.$object->id;
$dataretrieved = dol_getcache($cachekey);
if (!is_null($dataretrieved)) {
$nbEvent = $dataretrieved;
} else {
$sql = "SELECT COUNT(id) as nb";
$sql .= " FROM ".MAIN_DB_PREFIX."actioncomm";
$sql .= " WHERE fk_user_done = ".((int) $object->id);
$sql .= " AND entity IN (".getEntity('agenda').")";
$resql = $db->query($sql);
if ($resql) {
$obj = $db->fetch_object($resql);
$nbEvent = $obj->nb;
} else {
dol_syslog('Failed to count actioncomm '.$db->lasterror(), LOG_ERR);
}
dol_setcache($cachekey, $nbEvent, 120); // If setting cache fails, this is not a problem, so we do not test result.
}
$head[$h][1] .= '/';
$head[$h][1] .= $langs->trans("Agenda");
if ($nbEvent > 0) {
$head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbEvent.'</span>';
}
}
$head[$h][2] = 'info';
$h++;
}
@@ -1173,3 +1202,523 @@ function showSkins($fuser, $edit = 0, $foruserprofile = false)
print '</table>';
print '</div>';
}
/**
* Show html area with actions (done or not, ignore the name of function).
* Note: Global parameter $param must be defined.
*
* @param Conf $conf Object conf
* @param Translate $langs Object langs
* @param DoliDB $db Object db
* @param mixed $filterobj Filter on object Adherent|Societe|Project|Product|CommandeFournisseur|Dolresource|Ticket... to list events linked to an object
* @param Contact $objcon Filter on object contact to filter events on a contact
* @param int $noprint Return string but does not output it
* @param string|string[] $actioncode Filter on actioncode
* @param string $donetodo Filter on event 'done' or 'todo' or ''=nofilter (all).
* @param array $filters Filter on other fields
* @param string $sortfield Sort field
* @param string $sortorder Sort order
* @param string $module You can add module name here if elementtype in table llx_actioncomm is objectkey@module
* @return string|void Return html part or void if noprint is 1
*/
function show_actions_done_user($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC', $module = '')
{
global $user, $conf, $hookmanager;
global $form;
global $param, $massactionbutton;
$start_year = GETPOST('dateevent_startyear', 'int');
$start_month = GETPOST('dateevent_startmonth', 'int');
$start_day = GETPOST('dateevent_startday', 'int');
$end_year = GETPOST('dateevent_endyear', 'int');
$end_month = GETPOST('dateevent_endmonth', 'int');
$end_day = GETPOST('dateevent_endday', 'int');
$tms_start = '';
$tms_end = '';
if (!empty($start_year) && !empty($start_month) && !empty($start_day)) {
$tms_start = dol_mktime(0, 0, 0, $start_month, $start_day, $start_year, 'tzuserrel');
}
if (!empty($end_year) && !empty($end_month) && !empty($end_day)) {
$tms_end = dol_mktime(23, 59, 59, $end_month, $end_day, $end_year, 'tzuserrel');
}
if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All test are required to be compatible with all browsers
$tms_start = '';
$tms_end = '';
}
dol_include_once('/comm/action/class/actioncomm.class.php');
// Check parameters
if (!is_object($filterobj) && !is_object($objcon)) {
dol_print_error('', 'BadParameter');
}
$out = '';
$histo = array();
$numaction = 0;
$now = dol_now('tzuser');
// Open DSI -- Fix order by -- Begin
$sortfield_list = explode(',', $sortfield);
$sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
$sortfield_new_list = array();
foreach ($sortfield_list as $sortfield_value) {
$sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
}
$sortfield_new = implode(',', $sortfield_new_list);
$sql = '';
if (isModEnabled('agenda')) {
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
$hookmanager->initHooks(array('agendadao'));
// Recherche histo sur actioncomm
if (is_object($objcon) && $objcon->id > 0) {
$sql = "SELECT DISTINCT a.id, a.label as label,";
} else {
$sql = "SELECT a.id, a.label as label,";
}
$sql .= " a.datep as dp,";
$sql .= " a.datep2 as dp2,";
$sql .= " a.percent as percent, 'action' as type,";
$sql .= " a.fk_element, a.elementtype,";
$sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
$sql .= " u.rowid as user_id, u.login as user_login, u.photo as user_photo, u.firstname as user_firstname, u.lastname as user_lastname";
if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur'))) {
$sql .= ", sp.lastname, sp.firstname";
} elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
/* Nothing */
} elseif (is_object($filterobj) && get_class($filterobj) == 'Project') {
/* Nothing */
} elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
$sql .= ", m.lastname, m.firstname";
} elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
$sql .= ", o.ref";
} elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
$sql .= ", o.ref";
} elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
$sql .= ", o.ref";
} elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
$sql .= ", o.ref";
} elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
$sql .= ", o.ref";
} elseif (is_object($filterobj) && is_array($filterobj->fields) && is_array($filterobj->fields['rowid']) && $filterobj->table_element && $filterobj->element) {
if (!empty($filterobj->fields['ref'])) {
$sql .= ", o.ref";
} elseif (!empty($filterobj->fields['label'])) {
$sql .= ", o.label";
}
}
// Fields from hook
$parameters = array('sql' => &$sql, 'filterobj' => $filterobj, 'objcon' => $objcon);
$reshook = $hookmanager->executeHooks('showActionsDoneListSelect', $parameters); // Note that $action and $object may have been modified by hook
if (!empty($hookmanager->resPrint)) {
$sql.= $hookmanager->resPrint;
}
$sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
$force_filter_contact = false;
if (is_object($objcon) && $objcon->id > 0) {
$force_filter_contact = true;
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
$sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
}
// Fields from hook
$parameters = array('sql' => &$sql, 'filterobj' => $filterobj, 'objcon' => $objcon);
$reshook = $hookmanager->executeHooks('showActionsDoneListFrom', $parameters); // Note that $action and $object may have been modified by hook
if (!empty($hookmanager->resPrint)) {
$sql.= $hookmanager->resPrint;
}
$sql .= " WHERE a.entity IN (".getEntity('agenda').")";
$sql .= " AND u.rowid = ".((int) $filterobj->id);
if (!empty($tms_start) && !empty($tms_end)) {
$sql .= " AND ((a.datep BETWEEN '".$db->idate($tms_start)."' AND '".$db->idate($tms_end)."') OR (a.datep2 BETWEEN '".$db->idate($tms_start)."' AND '".$db->idate($tms_end)."'))";
} elseif (empty($tms_start) && !empty($tms_end)) {
$sql .= " AND ((a.datep <= '".$db->idate($tms_end)."') OR (a.datep2 <= '".$db->idate($tms_end)."'))";
} elseif (!empty($tms_start) && empty($tms_end)) {
$sql .= " AND ((a.datep >= '".$db->idate($tms_start)."') OR (a.datep2 >= '".$db->idate($tms_start)."'))";
}
if (is_array($actioncode) && !empty($actioncode)) {
$sql .= ' AND (';
foreach ($actioncode as $key => $code) {
if ($key != 0) {
$sql .= " OR ";
}
if (!empty($code)) {
addEventTypeSQL($sql, $code, "");
}
}
$sql .= ')';
} elseif (!empty($actioncode)) {
addEventTypeSQL($sql, $actioncode);
}
addOtherFilterSQL($sql, $donetodo, $now, $filters);
// Fields from hook
$parameters = array('sql' => &$sql, 'filterobj' => $filterobj, 'objcon' => $objcon, 'module' => $module);
$reshook = $hookmanager->executeHooks('showActionsDoneListWhere', $parameters); // Note that $action and $object may have been modified by hook
if (!empty($hookmanager->resPrint)) {
$sql.= $hookmanager->resPrint;
}
if (is_array($actioncode)) {
foreach ($actioncode as $code) {
$sql2 = addMailingEventTypeSQL($code, $objcon, $filterobj);
if (!empty($sql2)) {
if (!empty($sql)) {
$sql = $sql." UNION ".$sql2;
} elseif (empty($sql)) {
$sql = $sql2;
}
break;
}
}
} else {
$sql2 = addMailingEventTypeSQL($actioncode, $objcon, $filterobj);
if (!empty($sql) && !empty($sql2)) {
$sql = $sql." UNION ".$sql2;
} elseif (empty($sql) && !empty($sql2)) {
$sql = $sql2;
}
}
}
//TODO Add limit in nb of results
if ($sql) {
$sql .= $db->order($sortfield_new, $sortorder);
dol_syslog("usergroups.lib::show_actions_dones", LOG_DEBUG);
$resql = $db->query($sql);
if ($resql) {
$i = 0;
$num = $db->num_rows($resql);
while ($i < $num) {
$obj = $db->fetch_object($resql);
if ($obj->type == 'action') {
$contactaction = new ActionComm($db);
$contactaction->id = $obj->id;
$result = $contactaction->fetchResources();
if ($result < 0) {
dol_print_error($db);
setEventMessage("user.lib::show_actions_done Error fetch resource", 'errors');
}
//if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
//elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
$tododone = '';
if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && (!empty($obj->datep) && $obj->datep > $now))) {
$tododone = 'todo';
}
$histo[$numaction] = array(
'type'=>$obj->type,
'tododone'=>$tododone,
'id'=>$obj->id,
'datestart'=>$db->jdate($obj->dp),
'dateend'=>$db->jdate($obj->dp2),
'note'=>$obj->label,
'percent'=>$obj->percent,
'userid'=>$obj->user_id,
'login'=>$obj->user_login,
'userfirstname'=>$obj->user_firstname,
'userlastname'=>$obj->user_lastname,
'userphoto'=>$obj->user_photo,
'contact_id'=>$obj->fk_contact,
'socpeopleassigned' => $contactaction->socpeopleassigned,
'lastname' => empty($obj->lastname) ? '' : $obj->lastname,
'firstname' => empty($obj->firstname) ? '' : $obj->firstname,
'fk_element'=>$obj->fk_element,
'elementtype'=>$obj->elementtype,
// Type of event
'acode'=>$obj->acode,
'alabel'=>$obj->alabel,
'libelle'=>$obj->alabel, // deprecated
'apicto'=>$obj->apicto
);
} else {
$histo[$numaction] = array(
'type'=>$obj->type,
'tododone'=>'done',
'id'=>$obj->id,
'datestart'=>$db->jdate($obj->dp),
'dateend'=>$db->jdate($obj->dp2),
'note'=>$obj->label,
'percent'=>$obj->percent,
'acode'=>$obj->acode,
'userid'=>$obj->user_id,
'login'=>$obj->user_login,
'userfirstname'=>$obj->user_firstname,
'userlastname'=>$obj->user_lastname,
'userphoto'=>$obj->user_photo
);
}
$numaction++;
$i++;
}
} else {
dol_print_error($db);
}
}
if (isModEnabled('agenda')|| (isModEnabled('mailing') && !empty($objcon->email))) {
$delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
$formactions = new FormActions($db);
$actionstatic = new ActionComm($db);
$userstatic = new User($db);
$userlinkcache = array();
$contactstatic = new Contact($db);
$elementlinkcache = array();
$out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'?id='.$filterobj->id.'" method="POST">';
$out .= '<input type="hidden" name="token" value="'.newToken().'">';
if ($objcon && get_class($objcon) == 'User' &&
(is_null($filterobj) || get_class($filterobj) == 'User')) {
$out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
} else {
$out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
}
if ($filterobj && get_class($filterobj) == 'User') {
$out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
}
$out .= "\n";
$out .= '<div class="div-table-responsive-no-min">';
$out .= '<table class="noborder centpercent">';
$out .= '<tr class="liste_titre">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
$out .= '<th class="liste_titre width50 middle">';
$searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
$out .= $searchpicto;
$out .= '</th>';
}
if ($donetodo) {
$out .= '<td class="liste_titre"></td>';
}
$out .= '<td class="liste_titre"><input type="text" class="width50" name="search_rowid" value="'.(isset($filters['search_rowid']) ? $filters['search_rowid'] : '').'"></td>';
$out .= '<td class="liste_titre"></td>';
$out .= '<td class="liste_titre">';
$out .= $formactions->select_type_actions($actioncode, "actioncode", '', !getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : -1, 0, (!getDolGlobalString('AGENDA_USE_MULTISELECT_TYPE') ? 0 : 1), 1, 'minwidth100 maxwidth150');
$out .= '</td>';
$out .= '<td class="liste_titre maxwidth100onsmartphone"><input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'"></td>';
$out .= '<td class="liste_titre center">';
$out .= $form->selectDateToDate($tms_start, $tms_end, 'dateevent', 1);
$out .= '</td>';
$out .= '<td class="liste_titre"></td>';
$out .= '<td class="liste_titre"></td>';
// Action column
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
$out .= '<td class="liste_titre" align="middle">';
$searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
$out .= $searchpicto;
$out .= '</td>';
}
$out .= '</tr>';
$out .= '<tr class="liste_titre">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
$out .= getTitleFieldOfList('', 0, $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'maxwidthsearch ');
}
if ($donetodo) {
$tmp = '';
if (get_class($filterobj) == 'User') {
$tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&userid='.$filterobj->id.'&status=done">';
}
$tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
$tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
$tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
//$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
if (get_class($filterobj) == 'User') {
$tmp .= '</a>';
}
$out .= getTitleFieldOfList($tmp);
}
$out .= getTitleFieldOfList("Ref", 0, $_SERVER["PHP_SELF"], 'a.id', '', $param, '', $sortfield, $sortorder);
$out .= getTitleFieldOfList("Owner");
$out .= getTitleFieldOfList("Type");
$out .= getTitleFieldOfList("Label", 0, $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder);
$out .= getTitleFieldOfList("Date", 0, $_SERVER["PHP_SELF"], 'a.datep,a.id', '', $param, '', $sortfield, $sortorder, 'center ');
$out .= getTitleFieldOfList("Status", 0, $_SERVER["PHP_SELF"], 'a.percent', '', $param, '', $sortfield, $sortorder, 'center ');
// Action column
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
$out .= getTitleFieldOfList('', 0, $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'maxwidthsearch ');
}
$out .= '<td></td>';
$out .= '</tr>';
require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
$caction = new CActionComm($db);
$arraylist = $caction->liste_array(1, 'code', '', (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : 0), '', 1);
foreach ($histo as $key => $value) {
$actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
$actionstatic->type_picto = $histo[$key]['apicto'];
$actionstatic->type_code = $histo[$key]['acode'];
$out .= '<tr class="oddeven">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
$out .= '<td></td>';
}
// Done or todo
if ($donetodo) {
$out .= '<td class="nowrap">';
$out .= '</td>';
}
// Ref
$out .= '<td class="nowraponall">';
if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
$out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
$out .= $histo[$key]['id'];
$out .= '</a>';
} else {
$out .= $actionstatic->getNomUrl(1, -1);
}
$out .= '</td>';
// Author of event
$out .= '<td class="tdoverflowmax125">';
if ($histo[$key]['userid'] > 0) {
if (isset($userlinkcache[$histo[$key]['userid']])) {
$link = $userlinkcache[$histo[$key]['userid']];
} else {
$userstatic->fetch($histo[$key]['userid']);
$link = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
$userlinkcache[$histo[$key]['userid']] = $link;
}
$out .= $link;
}
$out .= '</td>';
// Type
$labeltype = $actionstatic->type_code;
if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
$labeltype = 'AC_OTH';
}
if (!empty($actionstatic->code) && preg_match('/^TICKET_MSG/', $actionstatic->code)) {
$labeltype = $langs->trans("Message");
} else {
if (!empty($arraylist[$labeltype])) {
$labeltype = $arraylist[$labeltype];
}
if ($actionstatic->type_code == 'AC_OTH_AUTO' && ($actionstatic->type_code != $actionstatic->code) && $labeltype && !empty($arraylist[$actionstatic->code])) {
$labeltype .= ' - '.$arraylist[$actionstatic->code]; // Use code in priority on type_code
}
}
$out .= '<td class="tdoverflowmax125" title="'.$labeltype.'">';
$out .= $actionstatic->getTypePicto();
//if (empty($conf->dol_optimize_smallscreen)) {
$out .= $labeltype;
//}
$out .= '</td>';
// Title/Label of event
$out .= '<td class="tdoverflowmax300"';
if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'action') {
$transcode = $langs->trans("Action".$histo[$key]['acode']);
//$libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
$libelle = $histo[$key]['note'];
$actionstatic->id = $histo[$key]['id'];
$out .= ' title="'.dol_escape_htmltag($libelle).'">';
$out .= dol_trunc($libelle, 120);
}
if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
$out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
$transcode = $langs->trans("Action".$histo[$key]['acode']);
$libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
$out .= ' title="'.dol_escape_htmltag($libelle).'">';
$out .= dol_trunc($libelle, 120);
}
$out .= '</td>';
// Date
$out .= '<td class="center nowraponall">';
$out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
$tmpa = dol_getdate($histo[$key]['datestart'], true);
$tmpb = dol_getdate($histo[$key]['dateend'], true);
if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
$out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
} else {
$out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
}
}
$late = 0;
if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
$late = 1;
}
if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
$late = 1;
}
if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
$late = 1;
}
if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
$late = 1;
}
if ($late) {
$out .= img_warning($langs->trans("Late")).' ';
}
$out .= "</td>\n";
// Status
$out .= '<td class="nowrap center">'.$actionstatic->LibStatut($histo[$key]['percent'], 2, 0, $histo[$key]['datestart']).'</td>';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
$out .= '<td></td>';
}
$out .= "</tr>\n";
$i++;
}
if (empty($histo)) {
$colspan = 9;
$out .= '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
}
$out .= "</table>\n";
$out .= "</div>\n";
$out .= '</form>';
}
if ($noprint) {
return $out;
} else {
print $out;
}
}

View File

@@ -1,6 +1,7 @@
<?php
/* Copyright (C) 2006-2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2012 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -651,11 +652,11 @@ class ExportExcel2007 extends ModeleExports
/**
* Set a value cell and merging it by giving a starting cell and a length
*
* @param string $val Cell value
* @param string $startCell Starting cell
* @param int $length Length
* @param int $offset Starting offset
* @return string Coordinate or -1 if KO
* @param string $val Cell value
* @param string $startCell Starting cell
* @param int $length Length
* @param int $offset Starting offset
* @return int|string Coordinate or if KO: -1
*/
public function setMergeCellValueByLength($val, $startCell, $length, $offset = 0)
{

View File

@@ -0,0 +1,570 @@
<?php
/* Copyright (C) 2004-2018 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2018-2019 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2019-2022 Frédéric France <frederic.france@netlogic.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \defgroup ai Module Ai
* \brief Ai module descriptor.
*
* \file htdocs/ai/core/modules/modAi.class.php
* \ingroup ai
* \brief Description and activation file for module Ai
*/
include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';
/**
* Description and activation class for module Ai
*/
class modAi extends DolibarrModules
{
/**
* Constructor. Define names, constants, directories, boxes, permissions
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
global $langs, $conf;
$this->db = $db;
// Id for module (must be unique).
// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
$this->numero = 4560;
// Key text used to identify module (for permissions, menus, etc...)
$this->rights_class = 'ai';
// Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...'
// It is used to group modules by family in module setup page
$this->family = "mailings";
// Module position in the family on 2 digits ('01', '10', '20', ...)
$this->module_position = '50';
// Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
//$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));
// Module label (no space allowed), used if translation string 'ModuleAiName' not found (Ai is name of module).
$this->name = preg_replace('/^mod/i', '', get_class($this));
// Module description, used if translation string 'ModuleAiDesc' not found (Ai is name of module).
$this->description = "AiDescription";
// Used only if file README.md and README-LL.md not found.
$this->descriptionlong = "AiDescription";
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'
$this->version = 'development';
// Key used in llx_const table to save module status enabled/disabled (where BOOKCAL is value of property name of module in uppercase)
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
// Name of image file used for this module.
// If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
// If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
// To use a supported fa-xxx css style of font awesome, use this->picto='xxx'
$this->picto = 'fa-microchip"';
// Define some features supported by module (triggers, login, substitutions, menus, css, etc...)
$this->module_parts = array(
// Set this to 1 if module has its own trigger directory (core/triggers)
'triggers' => 0,
// Set this to 1 if module has its own login method file (core/login)
'login' => 0,
// Set this to 1 if module has its own substitution function file (core/substitutions)
'substitutions' => 0,
// Set this to 1 if module has its own menus handler directory (core/menus)
'menus' => 0,
// Set this to 1 if module overwrite template dir (core/tpl)
'tpl' => 0,
// Set this to 1 if module has its own barcode directory (core/modules/barcode)
'barcode' => 0,
// Set this to 1 if module has its own models directory (core/modules/xxx)
'models' => 0,
// Set this to 1 if module has its own printing directory (core/modules/printing)
'printing' => 0,
// Set this to 1 if module has its own theme directory (theme)
'theme' => 0,
// Set this to relative path of css file if module has its own css file
'css' => array(
// '/ai/css/ai.css.php',
),
// Set this to relative path of js file if module must load a js on all pages
'js' => array(
// '/ai/js/ai.js.php',
),
// Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context to 'all'
'hooks' => array(
// 'data' => array(
// 'hookcontext1',
// 'hookcontext2',
// ),
// 'entity' => '0',
),
// Set this to 1 if features of module are opened to external users
'moduleforexternal' => 0,
);
// Data directories to create when module is enabled.
// Example: this->dirs = array("/ai/temp","/ai/subdir");
$this->dirs = array("/ai/temp");
// Config pages. Put here list of php page, stored into ai/admin directory, to use to setup module.
$this->config_page_url = array("setup.php@ai");
// Dependencies
// A condition to hide module
$this->hidden = false;
// List of module class names as string that must be enabled if this module is enabled. Example: array('always'=>array('modModuleToEnable1','modModuleToEnable2'), 'FR'=>array('modModuleToEnableFR'...))
$this->depends = array();
$this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...)
$this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...)
// The language file dedicated to your module
$this->langfiles = array("ai");
// Prerequisites
$this->phpmin = array(7, 0); // Minimum version of PHP required by module
// Messages at activation
$this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','MX'='textmx'...)
$this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','MX'='textmx'...)
//$this->automatic_activation = array('FR'=>'AiWasAutomaticallyActivatedBecauseOfYourCountryChoice');
//$this->always_enabled = true; // If true, can't be disabled
// Constants
// List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive)
// Example: $this->const=array(1 => array('BOOKCAL_MYNEWCONST1', 'chaine', 'myvalue', 'This is a constant to add', 1),
// 2 => array('BOOKCAL_MYNEWCONST2', 'chaine', 'myvalue', 'This is another constant to add', 0, 'current', 1)
// );
$this->const = array();
// Some keys to add into the overwriting translation tables
/*$this->overwrite_translation = array(
'en_US:ParentCompany'=>'Parent company or reseller',
'fr_FR:ParentCompany'=>'Maison mère ou revendeur'
)*/
if (!isset($conf->ai) || !isset($conf->ai->enabled)) {
$conf->ai = new stdClass();
$conf->ai->enabled = 0;
}
// Array to add new pages in new tabs
$this->tabs = array();
// Example:
// $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@ai:$user->rights->ai->read:/ai/mynewtab1.php?id=__ID__'); // To add a new tab identified by code tabname1
// $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@ai:$user->rights->othermodule->read:/ai/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
// $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname
//
// Where objecttype can be
// 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member)
// 'contact' to add a tab in contact view
// 'contract' to add a tab in contract view
// 'group' to add a tab in group view
// 'intervention' to add a tab in intervention view
// 'invoice' to add a tab in customer invoice view
// 'invoice_supplier' to add a tab in supplier invoice view
// 'member' to add a tab in foundation member view
// 'opensurveypoll' to add a tab in opensurvey poll view
// 'order' to add a tab in customer order view
// 'order_supplier' to add a tab in supplier order view
// 'payment' to add a tab in payment view
// 'payment_supplier' to add a tab in supplier payment view
// 'product' to add a tab in product view
// 'propal' to add a tab in propal view
// 'project' to add a tab in project view
// 'stock' to add a tab in stock view
// 'thirdparty' to add a tab in third party view
// 'user' to add a tab in user view
// Dictionaries
$this->dictionaries = array();
/* Example:
$this->dictionaries=array(
'langs'=>'ai@ai',
// List of tables we want to see into dictonnary editor
'tabname'=>array("table1", "table2", "table3"),
// Label of tables
'tablib'=>array("Table1", "Table2", "Table3"),
// Request to select fields
'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f', 'SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f', 'SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'),
// Sort order
'tabsqlsort'=>array("label ASC", "label ASC", "label ASC"),
// List of fields (result of select to show dictionary)
'tabfield'=>array("code,label", "code,label", "code,label"),
// List of fields (list of fields to edit a record)
'tabfieldvalue'=>array("code,label", "code,label", "code,label"),
// List of fields (list of fields for insert)
'tabfieldinsert'=>array("code,label", "code,label", "code,label"),
// Name of columns with primary key (try to always name it 'rowid')
'tabrowid'=>array("rowid", "rowid", "rowid"),
// Condition to show each dictionary
'tabcond'=>array($conf->ai->enabled, $conf->ai->enabled, $conf->ai->enabled)
// Help tooltip for each fields of the dictionary
'tabhelp'=>array(array('code'=>$langs->trans('CodeTooltipHelp')))
);
*/
// Boxes/Widgets
// Add here list of php file(s) stored in ai/core/boxes that contains a class to show a widget.
$this->boxes = array(
// 0 => array(
// 'file' => 'aiwidget1.php@ai',
// 'note' => 'Widget provided by Ai',
// 'enabledbydefaulton' => 'Home',
// ),
// ...
);
// Cronjobs (List of cron jobs entries to add when module is enabled)
// unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week
$this->cronjobs = array(
// 0 => array(
// 'label' => 'MyJob label',
// 'jobtype' => 'method',
// 'class' => '/ai/class/availabilities.class.php',
// 'objectname' => 'Availabilities',
// 'method' => 'doScheduledJob',
// 'parameters' => '',
// 'comment' => 'Comment',
// 'frequency' => 2,
// 'unitfrequency' => 3600,
// 'status' => 0,
// 'test' => '$conf->ai->enabled',
// 'priority' => 50,
// ),
);
// Example: $this->cronjobs=array(
// 0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->ai->enabled', 'priority'=>50),
// 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>'$conf->ai->enabled', 'priority'=>50)
// );
// Permissions provided by this module
$this->rights = array();
$r = 0;
// Add here entries to declare new permissions
/* BEGIN MODULEBUILDER PERMISSIONS */
$this->rights[$r][0] = $this->numero . sprintf('%02d', (0 * 10) + 1);
$this->rights[$r][1] = 'Read objects of Ai';
$this->rights[$r][4] = 'availabilities';
$this->rights[$r][5] = 'read';
$r++;
$this->rights[$r][0] = $this->numero . sprintf('%02d', (0 * 10) + 2);
$this->rights[$r][1] = 'Create/Update objects of Ai';
$this->rights[$r][4] = 'availabilities';
$this->rights[$r][5] = 'write';
$r++;
$this->rights[$r][0] = $this->numero . sprintf('%02d', (0 * 10) + 3);
$this->rights[$r][1] = 'Delete objects of Ai';
$this->rights[$r][4] = 'availabilities';
$this->rights[$r][5] = 'delete';
$r++;
$this->rights[$r][0] = $this->numero . sprintf('%02d', (1 * 10) + 1);
$this->rights[$r][1] = 'Read Calendar object of Ai';
$this->rights[$r][4] = 'calendar';
$this->rights[$r][5] = 'read';
$r++;
$this->rights[$r][0] = $this->numero . sprintf('%02d', (1 * 10) + 2);
$this->rights[$r][1] = 'Create/Update Calendar object of Ai';
$this->rights[$r][4] = 'calendar';
$this->rights[$r][5] = 'write';
$r++;
$this->rights[$r][0] = $this->numero . sprintf('%02d', (1 * 10) + 3);
$this->rights[$r][1] = 'Delete Calendar object of Ai';
$this->rights[$r][4] = 'calendar';
$this->rights[$r][5] = 'delete';
$r++;
/* END MODULEBUILDER PERMISSIONS */
// Main menu entries to add
$this->menu = array();
$r = 0;
// Add here entries to declare new menus
/* BEGIN MODULEBUILDER TOPMENU */
/*$this->menu[$r++] = array(
'fk_menu'=>'', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
'type'=>'top', // This is a Top menu entry
'titre'=>'ModuleAiName',
'prefix' => img_picto('', $this->picto, 'class="pictofixedwidth valignmiddle"'),
'mainmenu'=>'ai',
'leftmenu'=>'',
'url'=>'/ai/aiindex.php',
'langs'=>'ai', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position'=>1000 + $r,
'enabled'=>'$conf->ai->enabled', // Define condition to show or hide menu entry. Use '$conf->ai->enabled' if entry must be visible if module is enabled.
'perms'=>'$user->rights->ai->availabilities->read', // Use 'perms'=>'$user->rights->ai->availabilities->read' if you want your menu with a permission rules
'target'=>'',
'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
);*/
/* END MODULEBUILDER TOPMENU */
/* BEGIN MODULEBUILDER LEFTMENU CALENDAR */
$this->menu[$r++] = array(
'fk_menu'=>'fk_mainmenu=agenda',
'type'=>'left',
'titre'=> 'MenuBookcalIndex',
'prefix' => img_picto('', $this->picto, 'class="paddingright pictofixedwidth em92"'),
'mainmenu'=>'agenda',
'leftmenu'=> 'ai',
'url'=> '/ai/aiindex.php',
'langs'=> 'ai',
'position'=> 1100+$r,
'enabled'=> '1',
'perms'=> '$user->rights->ai->read',
'user'=> 0
);
$this->menu[$r++]=array(
// '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
'fk_menu'=>'fk_mainmenu=agenda,fk_leftmenu=ai',
// This is a Left menu entry
'type'=>'left',
'titre'=>'Calendar',
'mainmenu'=>'agenda',
'leftmenu'=>'ai_list',
'url'=>'/ai/list.php',
// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'langs'=>'ai',
'position'=>1100+$r,
// Define condition to show or hide menu entry. Use '$conf->ai->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
'enabled'=>'$conf->ai->enabled',
// Use 'perms'=>'$user->rights->ai->level1->level2' if you want your menu with a permission rules
'perms'=>'$user->rights->ai->read',
'target'=>'',
// 0=Menu for internal users, 1=external users, 2=both
'user'=>2,
);
$this->menu[$r++]=array(
// '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
'fk_menu'=>'fk_mainmenu=agenda,fk_leftmenu=ai_list',
// This is a Left menu entry
'type'=>'left',
'titre'=>'NewKey',
'mainmenu'=>'agenda',
'leftmenu'=>'ai_new_key',
'url'=>'/ai/ai_card.php?action=create',
// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'langs'=>'ai',
'position'=>1100+$r,
// Define condition to show or hide menu entry. Use '$conf->ai->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
'enabled'=>'$conf->ai->enabled',
// Use 'perms'=>'$user->rights->ai->level1->level2' if you want your menu with a permission rules
'perms'=>'$user->rights->ai->read',
'target'=>'',
// 0=Menu for internal users, 1=external users, 2=both
'user'=>2
);
/* END MODULEBUILDER LEFTMENU CALENDAR */
/* BEGIN MODULEBUILDER LEFTMENU AVAILABILITIES
$this->menu[$r++]=array(
'fk_menu'=>'fk_mainmenu=ai', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
'type'=>'left', // This is a Left menu entry
'titre'=>'Availabilities',
'prefix' => img_picto('', $this->picto, 'class="paddingright pictofixedwidth valignmiddle"'),
'mainmenu'=>'ai',
'leftmenu'=>'availabilities',
'url'=>'/ai/aiindex.php',
'langs'=>'ai@ai', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position'=>1000+$r,
'enabled'=>'$conf->ai->enabled', // Define condition to show or hide menu entry. Use '$conf->ai->enabled' if entry must be visible if module is enabled.
'perms'=>'$user->rights->ai->availabilities->read', // Use 'perms'=>'$user->rights->ai->level1->level2' if you want your menu with a permission rules
'target'=>'',
'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
);
$this->menu[$r++]=array(
'fk_menu'=>'fk_mainmenu=ai,fk_leftmenu=availabilities', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
'type'=>'left', // This is a Left menu entry
'titre'=>'List_Availabilities',
'mainmenu'=>'ai',
'leftmenu'=>'ai_availabilities_list',
'url'=>'/ai/availabilities_list.php',
'langs'=>'ai@ai', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position'=>1000+$r,
'enabled'=>'$conf->ai->enabled', // Define condition to show or hide menu entry. Use '$conf->ai->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
'perms'=>'$user->rights->ai->availabilities->read', // Use 'perms'=>'$user->rights->ai->level1->level2' if you want your menu with a permission rules
'target'=>'',
'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
);
$this->menu[$r++]=array(
'fk_menu'=>'fk_mainmenu=ai,fk_leftmenu=availabilities', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
'type'=>'left', // This is a Left menu entry
'titre'=>'New_Availabilities',
'mainmenu'=>'ai',
'leftmenu'=>'ai_availabilities_new',
'url'=>'/ai/availabilities_card.php?action=create',
'langs'=>'ai@ai', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position'=>1000+$r,
'enabled'=>'$conf->ai->enabled', // Define condition to show or hide menu entry. Use '$conf->ai->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
'perms'=>'$user->rights->ai->availabilities->write', // Use 'perms'=>'$user->rights->ai->level1->level2' if you want your menu with a permission rules
'target'=>'',
'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
);
*/
/* END MODULEBUILDER LEFTMENU AVAILABILITIES */
// Exports profiles provided by this module
$r = 1;
/* BEGIN MODULEBUILDER EXPORT AVAILABILITIES */
/*
$langs->load("agenda");
$this->export_code[$r]=$this->rights_class.'_'.$r;
$this->export_label[$r]='AvailabilitiesLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
$this->export_icon[$r]='availabilities@ai';
// Define $this->export_fields_array, $this->export_TypeFields_array and $this->export_entities_array
$keyforclass = 'Availabilities'; $keyforclassfile='/ai/class/availabilities.class.php'; $keyforelement='availabilities@ai';
include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
//$this->export_fields_array[$r]['t.fieldtoadd']='FieldToAdd'; $this->export_TypeFields_array[$r]['t.fieldtoadd']='Text';
//unset($this->export_fields_array[$r]['t.fieldtoremove']);
//$keyforclass = 'AvailabilitiesLine'; $keyforclassfile='/ai/class/availabilities.class.php'; $keyforelement='availabilitiesline@ai'; $keyforalias='tl';
//include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
$keyforselect='availabilities'; $keyforaliasextra='extra'; $keyforelement='availabilities@ai';
include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
//$keyforselect='availabilitiesline'; $keyforaliasextra='extraline'; $keyforelement='availabilitiesline@ai';
//include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
//$this->export_dependencies_array[$r] = array('availabilitiesline'=>array('tl.rowid','tl.ref')); // To force to activate one or several fields if we select some fields that need same (like to select a unique key if we ask a field of a child to avoid the DISTINCT to discard them, or for computed field than need several other fields)
//$this->export_special_array[$r] = array('t.field'=>'...');
//$this->export_examplevalues_array[$r] = array('t.field'=>'Example');
//$this->export_help_array[$r] = array('t.field'=>'FieldDescHelp');
$this->export_sql_start[$r]='SELECT DISTINCT ';
$this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'availabilities as t';
//$this->export_sql_end[$r] =' LEFT JOIN '.MAIN_DB_PREFIX.'availabilities_line as tl ON tl.fk_availabilities = t.rowid';
$this->export_sql_end[$r] .=' WHERE 1 = 1';
$this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('availabilities').')';
$r++; */
/* END MODULEBUILDER EXPORT AVAILABILITIES */
// Imports profiles provided by this module
$r = 1;
/* BEGIN MODULEBUILDER IMPORT AVAILABILITIES */
/*
$langs->load("agenda");
$this->import_code[$r]=$this->rights_class.'_'.$r;
$this->import_label[$r]='AvailabilitiesLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
$this->import_icon[$r]='availabilities@ai';
$this->import_tables_array[$r] = array('t' => MAIN_DB_PREFIX.'ai_availabilities', 'extra' => MAIN_DB_PREFIX.'ai_availabilities_extrafields');
$this->import_tables_creator_array[$r] = array('t' => 'fk_user_author'); // Fields to store import user id
$import_sample = array();
$keyforclass = 'Availabilities'; $keyforclassfile='/ai/class/availabilities.class.php'; $keyforelement='availabilities@ai';
include DOL_DOCUMENT_ROOT.'/core/commonfieldsinimport.inc.php';
$import_extrafield_sample = array();
$keyforselect='availabilities'; $keyforaliasextra='extra'; $keyforelement='availabilities@ai';
include DOL_DOCUMENT_ROOT.'/core/extrafieldsinimport.inc.php';
$this->import_fieldshidden_array[$r] = array('extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'ai_availabilities');
$this->import_regex_array[$r] = array();
$this->import_examplevalues_array[$r] = array_merge($import_sample, $import_extrafield_sample);
$this->import_updatekeys_array[$r] = array('t.ref' => 'Ref');
$this->import_convertvalue_array[$r] = array(
't.ref' => array(
'rule'=>'getrefifauto',
'class'=>(empty($conf->global->BOOKCAL_AVAILABILITIES_ADDON) ? 'mod_availabilities_standard' : $conf->global->BOOKCAL_AVAILABILITIES_ADDON),
'path'=>"/core/modules/commande/".(empty($conf->global->BOOKCAL_AVAILABILITIES_ADDON) ? 'mod_availabilities_standard' : $conf->global->BOOKCAL_AVAILABILITIES_ADDON).'.php'
'classobject'=>'Availabilities',
'pathobject'=>'/ai/class/availabilities.class.php',
),
't.fk_soc' => array('rule' => 'fetchidfromref', 'file' => '/societe/class/societe.class.php', 'class' => 'Societe', 'method' => 'fetch', 'element' => 'ThirdParty'),
't.fk_user_valid' => array('rule' => 'fetchidfromref', 'file' => '/user/class/user.class.php', 'class' => 'User', 'method' => 'fetch', 'element' => 'user'),
't.fk_mode_reglement' => array('rule' => 'fetchidfromcodeorlabel', 'file' => '/compta/paiement/class/cpaiement.class.php', 'class' => 'Cpaiement', 'method' => 'fetch', 'element' => 'cpayment'),
);
$r++; */
/* END MODULEBUILDER IMPORT AVAILABILITIES */
}
/**
* Function called when module is enabled.
* The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database.
* It also creates data directories
*
* @param string $options Options when enabling module ('', 'noboxes')
* @return int 1 if OK, 0 if KO
*/
public function init($options = '')
{
global $conf, $langs;
// $result = $this->_load_tables('/install/mysql/', 'ai');
// if ($result < 0) {
// return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
// }
// Create extrafields during init
//include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
//$extrafields = new ExtraFields($this->db);
//$result1=$extrafields->addExtraField('ai_myattr1', "New Attr 1 label", 'boolean', 1, 3, 'thirdparty', 0, 0, '', '', 1, '', 0, 0, '', '', 'ai@ai', '$conf->ai->enabled');
//$result2=$extrafields->addExtraField('ai_myattr2', "New Attr 2 label", 'varchar', 1, 10, 'project', 0, 0, '', '', 1, '', 0, 0, '', '', 'ai@ai', '$conf->ai->enabled');
//$result3=$extrafields->addExtraField('ai_myattr3', "New Attr 3 label", 'varchar', 1, 10, 'bank_account', 0, 0, '', '', 1, '', 0, 0, '', '', 'ai@ai', '$conf->ai->enabled');
//$result4=$extrafields->addExtraField('ai_myattr4', "New Attr 4 label", 'select', 1, 3, 'thirdparty', 0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1,'', 0, 0, '', '', 'ai@ai', '$conf->ai->enabled');
//$result5=$extrafields->addExtraField('ai_myattr5', "New Attr 5 label", 'text', 1, 10, 'user', 0, 0, '', '', 1, '', 0, 0, '', '', 'ai@ai', '$conf->ai->enabled');
// Permissions
$this->remove($options);
$sql = array();
// Document templates
$moduledir = dol_sanitizeFileName('ai');
$myTmpObjects = array();
$myTmpObjects['Availabilities'] = array('includerefgeneration'=>0, 'includedocgeneration'=>0);
// foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
// if ($myTmpObjectKey == 'Availabilities') {
// continue;
// }
// if ($myTmpObjectArray['includerefgeneration']) {
// $src = DOL_DOCUMENT_ROOT.'/install/doctemplates/'.$moduledir.'/template_availabilitiess.odt';
// $dirodt = DOL_DATA_ROOT.'/doctemplates/'.$moduledir;
// $dest = $dirodt.'/template_availabilitiess.odt';
// if (file_exists($src) && !file_exists($dest)) {
// require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
// dol_mkdir($dirodt);
// $result = dol_copy($src, $dest, 0, 0);
// if ($result < 0) {
// $langs->load("errors");
// $this->error = $langs->trans('ErrorFailToCopyFile', $src, $dest);
// return 0;
// }
// }
// $sql = array_merge($sql, array(
// "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = 'standard_".strtolower($myTmpObjectKey)."' AND type = '".$this->db->escape(strtolower($myTmpObjectKey))."' AND entity = ".((int) $conf->entity),
// "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('standard_".strtolower($myTmpObjectKey)."', '".$this->db->escape(strtolower($myTmpObjectKey))."', ".((int) $conf->entity).")",
// "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = 'generic_".strtolower($myTmpObjectKey)."_odt' AND type = '".$this->db->escape(strtolower($myTmpObjectKey))."' AND entity = ".((int) $conf->entity),
// "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('generic_".strtolower($myTmpObjectKey)."_odt', '".$this->db->escape(strtolower($myTmpObjectKey))."', ".((int) $conf->entity).")"
// ));
// }
// }
return $this->_init($sql, $options);
}
/**
* Function called when module is disabled.
* Remove from database constants, boxes and permissions from Dolibarr database.
* Data directories are not deleted
*
* @param string $options Options when enabling module ('', 'noboxes')
* @return int 1 if OK, 0 if KO
*/
public function remove($options = '')
{
$sql = array();
return $this->_remove($sql, $options);
}
}

View File

@@ -143,7 +143,7 @@ class pdf_zenith extends ModelePDFSupplierProposal
* @param int $hideref Do not show ref
* @return int 1=OK, 0=KO
*/
public function write_file($object, $outputlangs = '', $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
public function write_file($object, $outputlangs = null, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
{
// phpcs:enable
global $user, $langs, $conf, $hookmanager, $mysoc, $nblines;

View File

@@ -387,7 +387,6 @@ if ($action == 'presend') {
$formmail->param['id'] = $object->id;
$formmail->param['returnurl'] = $_SERVER["PHP_SELF"].'?id='.$object->id;
$formmail->param['fileinit'] = array($file);
// Show form
print $formmail->get_form();

View File

@@ -1020,7 +1020,6 @@ if ($resql) {
exit;
}
llxHeader('', $title, $help_url);
llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-supplier-order page-list');
$param = '';

View File

@@ -203,3 +203,5 @@ ALTER TABLE llx_expensereport DROP INDEX idx_expensereport_fk_refuse, ADD INDEX
INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle) VALUES (1,'66','Société publique locale');
ALTER TABLE llx_prelevement_lignes ADD COLUMN tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
ALTER TABLE llx_bom_bomline ADD COLUMN tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;

View File

@@ -19,6 +19,7 @@ CREATE TABLE llx_bom_bomline(
fk_bom integer NOT NULL,
fk_product integer NOT NULL,
fk_bom_child integer NULL,
tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
description text,
import_key varchar(14),
qty double(24,8) NOT NULL,

View File

@@ -1430,6 +1430,8 @@ DisableForgetPasswordLinkOnLogonPage=Do not show the "Password Forgotten" link o
UsersSetup=Users module setup
UserMailRequired=Email required to create a new user
UserHideInactive=Hide inactive users from all combo lists of users (Not recommended: this may means you won't be able to filter or search on old users on some pages)
UserHideExternal=Hide external users (not linked to a third party) from all combo lists of users (Not recommended: this may means you won't be able to filter or search on external users on some pages)
UserHideNonEmployee=Hide non employee users from all combo lists of users (Not recommended: this may means you won't be able to filter or search on non employee users on some pages)
UsersDocModules=Document templates for documents generated from user record
GroupsDocModules=Document templates for documents generated from a group record
##### HRM setup #####

View File

@@ -0,0 +1 @@
AI_KEY_API_CHATGPT= Key for IA api

View File

@@ -184,3 +184,5 @@ EmailOptedOut=Email owner has requested to not contact him with this email anymo
EvenUnsubscribe=Include opt-out emails
EvenUnsubscribeDesc=Include opt-out emails when you select emails as targets. Useful for mandatory service emails for example.
XEmailsDoneYActionsDone=%s emails pre-qualified, %s emails successfully processed (for %s record/actions done)
helpWithAi=Add instructions
YouCanMakeSomeInstructionForEmail=You Can Make Some Instruction For your Email (Exemple: generate image in email template...)

View File

@@ -1429,6 +1429,8 @@ DisableForgetPasswordLinkOnLogonPage=Cacher le lien "Mot de passe oublié" sur l
UsersSetup=Configuration du module utilisateurs
UserMailRequired=Email requis pour créer un nouvel utilisateur
UserHideInactive=Masquer les utilisateurs inactifs sur toutes les listes déroulantes d'utilisateurs (non recommandé: cela peut signifier que vous ne pourrez pas filtrer ou rechercher les anciens utilisateurs sur certaines pages)
UserHideExternal=Masquer les utilisateurs externes (non liés à un tiers) sur toutes les listes déroulantes d'utilisateurs (non recommandé: cela peut signifier que vous ne pourrez pas filtrer ou rechercher les utilisateurs externes sur certaines pages)
UserHideNonEmployee=Masquer les utilisateurs externes (non salariés) sur toutes les listes déroulantes d'utilisateurs (non recommandé: cela peut signifier que vous ne pourrez pas filtrer ou rechercher les utilisateurs non salariés sur certaines pages)
UsersDocModules=Modèles de documents pour les documents générés à partir de la fiche utilisateur
GroupsDocModules=Modèles de documents pour les documents générés à partir de la fiche d'un groupe
##### HRM setup #####

View File

@@ -0,0 +1 @@
AI_KEY_API_CHATGPT= Clé pour l'api IA

View File

@@ -27,33 +27,9 @@
*/
// Load Dolibarr environment
$res = 0;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
$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";
}
// Try main.inc.php using relative path
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 '../../main.inc.php';
global $conf, $langs, $user;
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/stock.lib.php';
@@ -94,7 +70,7 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
$textobject = $langs->transnoentitiesnoconv("Inventory");
llxHeader('', $langs->trans("InventorySetup"), $help_url);
llxHeader('', $langs->trans("InventorySetup"));
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';

View File

@@ -27,34 +27,7 @@
*/
// Load Dolibarr environment
$res = 0;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
$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";
}
// Try main.inc.php using relative path
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 '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/stock.lib.php';
@@ -94,7 +67,7 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
$textobject = $langs->transnoentitiesnoconv("StockMovement");
llxHeader('', $langs->trans("StockSetup"), $help_url);
llxHeader('', $langs->trans("StockSetup"));
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';

View File

@@ -22,35 +22,9 @@
*/
// Load Dolibarr environment
$res = 0;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
$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";
}
// Try main.inc.php using relative path
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 '../../main.inc.php';
global $langs, $user;
global $conf, $langs, $user;
// Libraries
require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";

View File

@@ -27,6 +27,7 @@ require '../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/usergroups.lib.php';
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
// Load translation files required by page
$langs->load("users");
@@ -39,6 +40,35 @@ if (!isset($id) || empty($id)) {
accessforbidden();
}
if (GETPOST('actioncode', 'array')) {
$actioncode = GETPOST('actioncode', 'array', 3);
if (!count($actioncode)) {
$actioncode = '0';
}
} else {
$actioncode = GETPOST("actioncode", "alpha", 3) ? GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : getDolGlobalString('AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT'));
}
$search_rowid = GETPOST('search_rowid');
$search_agenda_label = GETPOST('search_agenda_label');
$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;
$sortfield = GETPOST('sortfield', 'aZ09comma');
$sortorder = GETPOST('sortorder', 'aZ09comma');
$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
if (empty($page) || $page == -1) {
$page = 0;
} // If $page is not defined, or '' or -1
$offset = $limit * $page;
$pageprev = $page - 1;
$pagenext = $page + 1;
if (!$sortfield) {
$sortfield = 'a.datep,a.id';
}
if (!$sortorder) {
$sortorder = 'DESC,DESC';
}
$object = new User($db);
if ($id > 0 || !empty($ref)) {
$result = $object->fetch($id, $ref, '', 1);
@@ -59,6 +89,24 @@ if (($object->id != $user->id) && !$user->hasRight('user', 'user', 'lire')) {
accessforbidden();
}
$parameters = array('id'=>$userId);
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
if (empty($reshook)) {
// Cancel
if (GETPOST('cancel', 'alpha') && !empty($backtopage)) {
header("Location: ".$backtopage);
exit;
}
// Purge search criteria
if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
$actioncode = '';
$search_agenda_label = '';
}
}
/*
@@ -109,6 +157,62 @@ print '</div>';
print dol_get_fiche_end();
$objUser = $object;
$objcon = new stdClass();
$out = '';
$permok = $user->hasRight('agenda', 'myactions', 'create');
if ((!empty($objUser->id) || !empty($objcon->id)) && $permok) {
if (is_object($objUser) && get_class($objUser) == 'User') {
$out .= '&amp;originid='.$objUser->id.($objUser->id > 0 ? '&amp;userid='.$objUser->id : '').'&amp;backtopage='.urlencode($_SERVER['PHP_SELF'].($objUser->id > 0 ? '?userid='.$objUser->id : ''));
}
$out .= (!empty($objcon->id) ? '&amp;contactid='.$objcon->id : '');
$out .= '&amp;datep='.dol_print_date(dol_now(), 'dayhourlog', 'tzuserrel');
}
$morehtmlright = '';
$messagingUrl = DOL_URL_ROOT.'/societe/messaging.php?userid='.$object->id;
$morehtmlright .= dolGetButtonTitle($langs->trans('ShowAsConversation'), '', 'fa fa-comments imgforviewmode', $messagingUrl, '', 1);
$messagingUrl = DOL_URL_ROOT.'/user/info.php?id='.$object->id;
$morehtmlright .= dolGetButtonTitle($langs->trans('MessageListViewType'), '', 'fa fa-bars imgforviewmode', $messagingUrl, '', 2);
if (isModEnabled('agenda')) {
if ($user->hasRight('agenda', 'myactions', 'create') || $user->hasRight('agenda', 'allactions', 'create')) {
$morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/comm/action/card.php?action=create'.$out);
}
}
if (isModEnabled('agenda') && ($user->hasRight('agenda', 'myactions', 'read') || $user->hasRight('agenda', 'allaactions', 'read'))) {
print '<br>';
$param = '&id='.urlencode($id);
if ($limit > 0 && $limit != $conf->liste_limit) {
$param .= '&limit='.((int) $limit);
}
// Try to know count of actioncomm from cache
require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
$cachekey = 'count_events_user_'.$object->id;
$nbEvent = dol_getcache($cachekey);
$titlelist = $langs->trans("ActionsOnCompany").(is_numeric($nbEvent) ? '<span class="opacitymedium colorblack paddingleft">('.$nbEvent.')</span>' : '');
if (!empty($conf->dol_optimize_smallscreen)) {
$titlelist = $langs->trans("Actions").(is_numeric($nbEvent) ? '<span class="opacitymedium colorblack paddingleft">('.$nbEvent.')</span>' : '');
}
print_barre_liste($titlelist, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', 0, -1, '', 0, $morehtmlright, '', 0, 1, 0);
// List of all actions
$filters = array();
$filters['search_agenda_label'] = $search_agenda_label;
$filters['search_rowid'] = $search_rowid;
// TODO Replace this with same code than into list.php
show_actions_done_user($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder, $object->module);
}
// End of page
llxFooter();
$db->close();