';
+
$viewmode .= ''; // To add a space before the navigation tools
@@ -614,7 +616,7 @@ if (!empty($conf->use_javascript_ajax)) { // If javascript on
$default = '';
}
- $s .= '
';
+ $s .= '
';
}
}
@@ -1009,9 +1011,13 @@ if ($mode == 'show_day') {
// Request only leaves for the current selected day
$sql .= " AND '".$db->escape($year)."-".$db->escape($month)."-".$db->escape($day)."' BETWEEN x.date_debut AND x.date_fin"; // date_debut and date_fin are date without time
} elseif ($mode == 'show_week') {
- // TODO: Add filter to reduce database request
+ // Restrict on current month (we get more, but we will filter later)
+ $sql .= " AND date_debut < '".dol_get_last_day($year, $month)."'";
+ $sql .= " AND date_fin >= '".dol_get_first_day($year, $month)."'";
} elseif ($mode == 'show_month') {
- // TODO: Add filter to reduce database request
+ // Restrict on current month
+ $sql .= " AND date_debut <= '".dol_get_last_day($year, $month)."'";
+ $sql .= " AND date_fin >= '".dol_get_first_day($year, $month)."'";
}
$resql = $db->query($sql);
@@ -1082,8 +1088,11 @@ if (count($listofextcals)) {
$colorcal = $extcal['color'];
$buggedfile = $extcal['buggedfile'];
+ $pathforcachefile = dol_sanitizePathName($conf->user->dir_temp).'/'.dol_sanitizeFileName('extcal_'.$namecal.'_user'.$user->id).'.cache';
+ //var_dump($pathforcachefile);exit;
+
$ical = new ICal();
- $ical->parse($url);
+ $ical->parse($url, $pathforcachefile, $DELAYFORCACHE);
// After this $ical->cal['VEVENT'] contains array of events, $ical->cal['DAYLIGHT'] contains daylight info, $ical->cal['STANDARD'] contains non daylight info, ...
//var_dump($ical->cal); exit;
diff --git a/htdocs/comm/action/list.php b/htdocs/comm/action/list.php
index 4be3195561e..ab2037d5f76 100644
--- a/htdocs/comm/action/list.php
+++ b/htdocs/comm/action/list.php
@@ -600,7 +600,7 @@ $num = $db->num_rows($resql);
$arrayofselected = is_array($toselect) ? $toselect : array();
// Local calendar
-$newtitle = '
';
+ // cache of user list (owners)
+ if ($obj->fk_user_action > 0 && !isset($cache_user_list[$obj->fk_user_action])) {
+ $userstatic = new User($db);
+ $res = $userstatic->fetch($obj->fk_user_action);
+ if ($res > 0) {
+ $cache_user_list[$obj->fk_user_action] = $userstatic;
+ }
+ }
+
+ // get event style for user owner
+ $event_owner_style = '';
+ // We decide to choose color of owner of event (event->userownerid is user id of owner, event->userassigned contains all users assigned to event)
+ if ($cache_user_list[$obj->fk_user_action]->color != '') {
+ $event_owner_style .= 'border-left: #' . $cache_user_list[$obj->fk_user_action]->color . ' 5px solid;';
+ }
+
+ // get event style for start and end date
+ $event_more_class = '';
+ $event_start_date_css = '';
+ $event_end_date_css = '';
+ $event_start_date_time = $actionstatic->datep;
+ if ($event_start_date_time > $now) {
+ // future event
+ $event_more_class = 'event-future';
+ $event_start_date_css = $event_end_date_css = $event_more_class;
+ } else {
+ if ($obj->fulldayevent == 1) {
+ $today_start_date_time = $today_start_time;
+ } else {
+ $today_start_date_time = $now;
+ }
+
+ // check event end date
+ $event_end_date_time = $db->jdate($obj->dp2);
+ if ($event_end_date_time != null && $event_end_date_time < $today_start_date_time) {
+ // past event
+ $event_more_class = 'event-past';
+ } elseif ($event_end_date_time == null && $event_start_date_time < $today_start_date_time) {
+ // past event
+ $event_more_class = 'event-past';
+ } else {
+ // current event
+ $event_more_class = 'event-current';
+ }
+ $event_start_date_css = $event_end_date_css = $event_more_class;
+ }
+ $event_start_date_css = $event_end_date_css = $event_more_class;
+
+ print '
';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '
';
@@ -955,10 +1005,16 @@ while ($i < $imaxinloop) {
// User owner
if (!empty($arrayfields['owner']['checked'])) {
- print '
'; // With edge and chrome the td overflow is not supported correctly when content is not full text.
- if ($obj->fk_user_action > 0) {
- $userstatic->fetch($obj->fk_user_action);
- print $userstatic->getNomUrl(-1);
+ print '
'; // With edge and chrome the td overflow is not supported correctly when content is not full text.
+ if ($obj->fk_user_action > 0 && !isset($cache_user_list[$obj->fk_user_action])) {
+ $userstatic = new User($db);
+ $res = $userstatic->fetch($obj->fk_user_action);
+ if ($res > 0) {
+ $cache_user_list[$obj->fk_user_action] = $userstatic;
+ }
+ }
+ if (isset($cache_user_list[$obj->fk_user_action])) {
+ print $cache_user_list[$obj->fk_user_action]->getNomUrl(-1);
} else {
print ' ';
}
@@ -1006,13 +1062,14 @@ while ($i < $imaxinloop) {
// Start date
if (!empty($arrayfields['a.datep']['checked'])) {
- print '
';
- if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
- $selected = 0;
- if (in_array($obj->rowid, $arrayofselected)) {
- $selected = 1;
+ // Action column
+ if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
+ print '
';
+ if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+ $selected = 0;
+ if (in_array($obj->rowid, $arrayofselected)) {
+ $selected = 1;
+ }
+ print '';
}
- print '';
- }
- print '
';
- if (!$i) {
- $totalarray['nbfield']++;
- }
- }
-
- if (!empty($arrayfields['p.ref']['checked'])) {
- print '
';
- if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
- $selected = 0;
- if (in_array($obj->rowid, $arrayofselected)) {
- $selected = 1;
+ // Date modification
+ if (!empty($arrayfields['p.tms']['checked'])) {
+ print '
';
+ if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+ $selected = 0;
+ if (in_array($obj->rowid, $arrayofselected)) {
+ $selected = 1;
+ }
+ print '';
+ }
+ print '
';
- if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
- $selected = 0;
- if (in_array($objecttmp->id, $arrayofselected)) {
- $selected = 1;
+ if ($mode == 'kanban') {
+ if ($i == 0) {
+ print '
';
+ if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+ $selected = 0;
+ if (in_array($objecttmp->id, $arrayofselected)) {
+ $selected = 1;
+ }
+ print '';
}
- print '';
+ print '
';
- if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
- $selected = 0;
- if (in_array($objecttmp->id, $arrayofselected)) {
- $selected = 1;
+ print '
';
+ if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+ $selected = 0;
+ if (in_array($objecttmp->id, $arrayofselected)) {
+ $selected = 1;
+ }
+ print '';
+ }
+ print '
';
- if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
- $selected = 0;
- if (in_array($obj->rowid, $arrayofselected)) {
- $selected = 1;
- }
- print '';
- }
- print '
';
+ if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+ $selected = 0;
+ if (in_array($obj->rowid, $arrayofselected)) {
+ $selected = 1;
}
+ print '';
}
- //else print $langs->trans("NoSalesRepresentativeAffected");
- } else {
- print ' ';
+ print '
';
}
- print '';
- }
- // Date
- if (!empty($arrayfields['c.date_contrat']['checked'])) {
- print '
';
- }
- // Extra fields
- include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
- // Fields from hook
- $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray);
- $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
- print $hookmanager->resPrint;
- // Date creation
- if (!empty($arrayfields['c.datec']['checked'])) {
- print '
';
- if (!$i) {
- $totalarray['nbfield']++;
- }
- }
- // Date lower end date
- if (!empty($arrayfields['lower_planned_end_date']['checked'])) {
- print '
';
- if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
- $selected = 0;
- if (in_array($obj->rowid, $arrayofselected)) {
- $selected = 1;
+ // Ref
+ if (!empty($arrayfields['c.ref']['checked'])) {
+ print '
';
+ }
+ // Extra fields
+ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
+ // Fields from hook
+ $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray);
+ $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+ print $hookmanager->resPrint;
+ // Date creation
+ if (!empty($arrayfields['c.datec']['checked'])) {
+ print '
';
+ if (!$i) {
+ $totalarray['nbfield']++;
+ }
+ }
+ // Date lower end date
+ if (!empty($arrayfields['lower_planned_end_date']['checked'])) {
+ print '
';
+ if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+ $selected = 0;
+ if (in_array($obj->rowid, $arrayofselected)) {
+ $selected = 1;
+ }
+ print '';
+ }
+ print '
';
+ }
+ if (!$i) {
+ $totalarray['nbfield']++;
+ }
+
+ print "\n";
+ }
$i++;
}
diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php
index 23c2159bc8f..ab041e63385 100644
--- a/htdocs/core/actions_massactions.inc.php
+++ b/htdocs/core/actions_massactions.inc.php
@@ -1708,6 +1708,66 @@ if (!$error && ($massaction == 'increaseholiday' || ($action == 'increaseholiday
}
}
+//if (!$error && $massaction == 'clonetasks' && $user->rights->projet->creer) {
+if (!$error && ($massaction == 'clonetasks' || ($action == 'clonetasks' && $confirm == 'yes'))) {
+ $num = 0;
+
+ dol_include_once('/projet/class/task.class.php');
+
+ $origin_task = new Task($db);
+ $clone_task = new Task($db);
+
+ foreach (GETPOST('selected') as $task) {
+ $origin_task->fetch($task, $ref = '', $loadparentdata = 0);
+
+ $defaultref = '';
+ $obj = empty($conf->global->PROJECT_TASK_ADDON) ? 'mod_task_simple' : $conf->global->PROJECT_TASK_ADDON;
+ if (!empty($conf->global->PROJECT_TASK_ADDON) && is_readable(DOL_DOCUMENT_ROOT . "/core/modules/project/task/" . $conf->global->PROJECT_TASK_ADDON . ".php")) {
+ require_once DOL_DOCUMENT_ROOT . "/core/modules/project/task/" . $conf->global->PROJECT_TASK_ADDON . '.php';
+ $modTask = new $obj;
+ $defaultref = $modTask->getNextValue(0, $clone_task);
+ }
+
+ if (!$error) {
+ $clone_task->fk_project = GETPOST('projectid', 'int');
+ $clone_task->ref = $defaultref;
+ $clone_task->label = $origin_task->label;
+ $clone_task->description = $origin_task->description;
+ $clone_task->planned_workload = $origin_task->planned_workload;
+ $clone_task->fk_task_parent = $origin_task->fk_task_parent;
+ $clone_task->date_c = dol_now();
+ $clone_task->date_start = $origin_task->date_start;
+ $clone_task->date_end = $origin_task->date_end;
+ $clone_task->progress = $origin_task->progress;
+
+ // Fill array 'array_options' with data from add form
+ $ret = $extrafields->setOptionalsFromPost(null, $clone_task);
+
+ $taskid = $clone_task->create($user);
+
+ if ($taskid > 0) {
+ $result = $clone_task->add_contact(GETPOST("userid", 'int'), 'TASKEXECUTIVE', 'internal');
+ $num++;
+ } else {
+ if ($db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
+ $langs->load("projects");
+ setEventMessages($langs->trans('NewTaskRefSuggested'), '', 'warnings');
+ $duplicate_code_error = true;
+ } else {
+ setEventMessages($clone_task->error, $clone_task->errors, 'errors');
+ }
+ $action = 'list';
+ $error++;
+ }
+ }
+ }
+
+ if (!$error) {
+ setEventMessage($langs->trans('NumberOfTasksCloned', $num));
+ header("Refresh: 1;URL=".DOL_URL_ROOT.'/projet/tasks.php?id=' . GETPOST('projectid', 'int'));
+ }
+}
+
$parameters['toselect'] = (empty($toselect) ? array() : $toselect);
$parameters['uploaddir'] = $uploaddir;
$parameters['massaction'] = $massaction;
diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php
index abf30f2f3ee..7c136f446d9 100644
--- a/htdocs/core/class/commondocgenerator.class.php
+++ b/htdocs/core/class/commondocgenerator.class.php
@@ -1288,7 +1288,8 @@ abstract class CommonDocGenerator
}
$extrafields = $this->extrafieldsCache;
- $extrafieldOutputContent = $extrafields->showOutputField($extrafieldKey, $object->array_options[$extrafieldOptionsKey], '', $object->table_element);
+ $extrafieldOutputContent = '';
+ if (isset($object->array_options[$extrafieldOptionsKey])) $extrafieldOutputContent = $extrafields->showOutputField($extrafieldKey, $object->array_options[$extrafieldOptionsKey], '', $object->table_element);
// TODO : allow showOutputField to be pdf public friendly, ex: in a link to object, clean getNomUrl to remove link and images... like a getName methode ...
if ($extrafields->attributes[$object->table_element]['type'][$extrafieldKey] == 'link') {
diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php
index a23c0611589..93a3e1b5536 100644
--- a/htdocs/core/class/commonobject.class.php
+++ b/htdocs/core/class/commonobject.class.php
@@ -16,6 +16,7 @@
* Copyright (C) 2018 Josep Lluís Amador
* Copyright (C) 2021 Gauthier VERDOL
* Copyright (C) 2021 Grégory Blémand
+ * Copyright (C) 2023 Lenin Rivas
*
* 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
@@ -5740,15 +5741,16 @@ abstract class CommonObject
*
* @param string $fieldname Name of field
* @param string $alternatevalue Alternate value to use
+ * @param string $type Type of data
* @return string|string[] Default value (can be an array if the GETPOST return an array)
**/
- public function getDefaultCreateValueFor($fieldname, $alternatevalue = null)
+ public function getDefaultCreateValueFor($fieldname, $alternatevalue = null, $type = 'alphanohtml')
{
global $conf, $_POST;
// If param here has been posted, we use this value first.
if (GETPOSTISSET($fieldname)) {
- return GETPOST($fieldname, 'alphanohtml', 3);
+ return GETPOST($fieldname, $type, 3);
}
if (isset($alternatevalue)) {
diff --git a/htdocs/core/class/dolgeoip.class.php b/htdocs/core/class/dolgeoip.class.php
index a2eea7023d9..e5001270131 100644
--- a/htdocs/core/class/dolgeoip.class.php
+++ b/htdocs/core/class/dolgeoip.class.php
@@ -144,10 +144,12 @@ class DolGeoIP
return '';
}
} else {
- if (!function_exists('geoip_country_code_by_addr_v6')) {
+ if (function_exists('geoip_country_code_by_addr_v6')) {
+ return strtolower(geoip_country_code_by_addr_v6($this->gi, $ip));
+ } elseif (function_exists('geoip_country_code_by_name_v6')) {
return strtolower(geoip_country_code_by_name_v6($this->gi, $ip));
}
- return strtolower(geoip_country_code_by_addr_v6($this->gi, $ip));
+ return '';
}
}
}
diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php
index 0659240c8c7..bcd5a506946 100644
--- a/htdocs/core/class/hookmanager.class.php
+++ b/htdocs/core/class/hookmanager.class.php
@@ -162,84 +162,44 @@ class HookManager
//dol_syslog(get_class($this).'::executeHooks method='.$method." action=".$action." context=".$parameters['context']);
// Define type of hook ('output' or 'addreplace').
- // TODO Remove hooks with type 'output' (exemple getNomUrl). All hooks must be converted into 'addreplace' hooks.
- $hooktype = 'output';
- if (in_array(
- $method,
- array(
- 'addCalendarChoice',
- 'addCalendarView',
- 'addMoreActionsButtons',
- 'addMoreMassActions',
- 'addSearchEntry',
- 'addStatisticLine',
- 'addSectionECMAuto',
- 'checkSecureAccess',
- 'createDictionaryFieldlist',
- 'editDictionaryFieldlist',
- 'getFormMail',
- 'deleteFile',
- 'doActions',
- 'doMassActions',
- 'formatEvent',
- 'formConfirm',
- 'formCreateThirdpartyOptions',
- 'formObjectOptions',
- 'formattachOptions',
- 'formBuilddocLineOptions',
- 'formatNotificationMessage',
- 'formConfirm',
- 'getAccessForbiddenMessage',
- 'getDirList',
- 'hookGetEntity',
- 'getFormMail',
- 'getFormatedCustomerRef',
- 'getFormatedSupplierRef',
- 'getIdProfUrl',
- 'getInputIdProf',
- 'isPaymentOK',
- 'llxFooter',
- 'menuDropdownQuickaddItems',
- 'menuLeftMenuItems',
- 'moveUploadedFile',
- 'moreHtmlStatus',
- 'pdf_build_address',
- 'pdf_writelinedesc',
- 'pdf_getlinenum',
- 'pdf_getlineref',
- 'pdf_getlineref_supplier',
- 'pdf_getlinevatrate',
- 'pdf_getlineupexcltax',
- 'pdf_getlineupwithtax',
- 'pdf_getlineqty',
- 'pdf_getlineqty_asked',
- 'pdf_getlineqty_shipped',
- 'pdf_getlineqty_keeptoship',
- 'pdf_getlineunit',
- 'pdf_getlineremisepercent',
- 'pdf_getlineprogress',
- 'pdf_getlinetotalexcltax',
- 'pdf_getlinetotalwithtax',
- 'paymentsupplierinvoices',
- 'printAddress',
- 'printEmail',
- 'printSearchForm',
- 'printTabsHead',
- 'printObjectLine',
- 'printObjectSubLine',
- 'restrictedArea',
- 'sendMail',
- 'sendMailAfter',
- 'showOptionals',
- 'showLinkToObjectBlock',
- 'setContentSecurityPolicy',
- 'setHtmlTitle',
- 'completeTabsHead',
- 'formDolBanner',
- 'displayMarginInfos',
- )
- )) {
- $hooktype = 'addreplace';
+ $hooktype = 'addreplace';
+ // TODO Remove hooks with type 'output' (exemple createFrom). All hooks must be converted into 'addreplace' hooks.
+ if (in_array($method, array(
+ 'createFrom',
+ 'dashboardMembers',
+ 'dashboardEmailings',
+ 'dashboardPropals',
+ 'dashboardPropals',
+ 'dashboardCommercials',
+ 'dashboardOrders',
+ 'dashboardSpecialBills',
+ 'dashboardAccountancy',
+ 'dashboardContracts',
+ 'dashboardDonation',
+ 'dashboardWarehouseSendings',
+ 'dashboardExpenseReport',
+ 'dashboardInterventions',
+ 'dashboardOrdersSuppliers',
+ 'dashboardHRM',
+ 'dashboardMRP',
+ 'dashboardOpensurvey',
+ 'dashboardWarehouse',
+ 'dashboardProductServices',
+ 'dashboardActivities',
+ 'dashboardProjects',
+ 'dashboardWarehouseReceptions',
+ 'dashboardThirdparties',
+ 'dashboardSupplierProposal',
+ 'dashboardTickets',
+ 'dashboardUsersGroups',
+ 'insertExtraHeader',
+ 'insertExtraFooter',
+ 'printLeftBlock',
+ 'formAddObjectLine',
+ 'formBuilddocOption',
+ 'showSocinfoOnPrint'
+ ))) {
+ $hooktype = 'output';
}
// Init return properties
diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php
index 1c54df24e06..276f7bacd69 100644
--- a/htdocs/core/class/html.form.class.php
+++ b/htdocs/core/class/html.form.class.php
@@ -2137,10 +2137,7 @@ class Form
$out .= ' selected';
}
$out .= ' data-html="';
- $outhtml = '';
- // if (!empty($obj->photo)) {
- $outhtml .= $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' ';
- // }
+ $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' ';
if ($showstatus >= 0 && $obj->status == 0) {
$outhtml .= '';
}
@@ -2344,11 +2341,7 @@ class Form
}
}
// mode=1 means customers products
- $urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&status_purchase='.$status_purchase.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
- //Price by customer
- if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
- $urloption .= '&socid='.$socid;
- }
+ $urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&status_purchase='.$status_purchase.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
if (isModEnabled('variants') && is_array($selected_combinations)) {
@@ -3247,6 +3240,7 @@ class Form
// mode=2 means suppliers products
$urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
+
print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'';
} else {
print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
diff --git a/htdocs/core/class/html.formadmin.class.php b/htdocs/core/class/html.formadmin.class.php
index a0d0dd2758e..2cc15a3dd42 100644
--- a/htdocs/core/class/html.formadmin.class.php
+++ b/htdocs/core/class/html.formadmin.class.php
@@ -36,7 +36,7 @@ class FormAdmin
/**
* Constructor
*
- * @param DoliDB $db Database handler
+ * @param DoliDB|null $db Database handler
*/
public function __construct($db)
{
diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php
index 7f5c2887e8b..b2bb2a5f8fa 100644
--- a/htdocs/core/class/html.formfile.class.php
+++ b/htdocs/core/class/html.formfile.class.php
@@ -449,6 +449,15 @@ class FormFile
$titletoshow = ($title == 'none' ? '' : $title);
}
+ $submodulepart = $modulepart;
+
+ // modulepart = 'nameofmodule' or 'nameofmodule:NameOfObject'
+ $tmp = explode(':', $modulepart);
+ if (!empty($tmp[1])) {
+ $modulepart = $tmp[0];
+ $submodulepart = $tmp[1];
+ }
+
// Show table
if ($genallowed) {
$modellist = array();
@@ -648,15 +657,6 @@ class FormFile
$modellist = ModelePDFUserGroup::liste_modeles($this->db);
}
} else {
- $submodulepart = $modulepart;
-
- // modulepart = 'nameofmodule' or 'nameofmodule:NameOfObject'
- $tmp = explode(':', $modulepart);
- if (!empty($tmp[1])) {
- $modulepart = $tmp[0];
- $submodulepart = $tmp[1];
- }
-
// For normalized standard modules
$file = dol_buildpath('/core/modules/'.$modulepart.'/modules_'.strtolower($submodulepart).'.php', 0);
if (file_exists($file)) {
diff --git a/htdocs/core/class/stats.class.php b/htdocs/core/class/stats.class.php
index c8dbca747b9..60cdc5d5226 100644
--- a/htdocs/core/class/stats.class.php
+++ b/htdocs/core/class/stats.class.php
@@ -237,7 +237,7 @@ abstract class Stats
/**
* @param int $year year number
- * @return int value
+ * @return array array of values
*/
protected abstract function getAverageByMonth($year);
diff --git a/htdocs/core/class/translate.class.php b/htdocs/core/class/translate.class.php
index 3f2f756977d..2315428b37a 100644
--- a/htdocs/core/class/translate.class.php
+++ b/htdocs/core/class/translate.class.php
@@ -932,8 +932,10 @@ class Translate
$fonc = 'numberwords';
if (file_exists($newdir.'/functions_'.$fonc.'.lib.php')) {
include_once $newdir.'/functions_'.$fonc.'.lib.php';
- $newnumber = numberwords_getLabelFromNumber($this, $number, $isamount);
- break;
+ if (function_exists('numberwords_getLabelFromNumber')) {
+ $newnumber = numberwords_getLabelFromNumber($this, $number, $isamount);
+ break;
+ }
}
}
diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php
index d58854ed9d0..0241431c8b7 100644
--- a/htdocs/core/class/utils.class.php
+++ b/htdocs/core/class/utils.class.php
@@ -34,6 +34,9 @@ class Utils
*/
public $db;
+ public $error;
+ public $errors;
+
public $output; // Used by Cron method to return message
public $result; // Used by Cron method to return data
diff --git a/htdocs/core/class/vcard.class.php b/htdocs/core/class/vcard.class.php
index 8a62c0aea5e..7b5a320f678 100644
--- a/htdocs/core/class/vcard.class.php
+++ b/htdocs/core/class/vcard.class.php
@@ -31,7 +31,7 @@
*/
function encode($string)
{
- return str_replace(";", "\;", (dol_quoted_printable_encode(utf8_decode($string))));
+ return str_replace(";", "\;", (dol_quoted_printable_encode($string)));
}
@@ -117,22 +117,25 @@ class vCard
if ($type != "") {
$key .= ";".$type;
}
- $key .= ";".$this->encoding;
- $this->properties[$key] = 'VALUE=uri:tel:'.encode($number);
+ $key .= ";VALUE=uri";
+ //$key .= ";".$this->encoding;
+ $this->properties[$key] = 'tel:'.$number;
}
/**
* mise en forme de la photo
* warning NON TESTE !
*
- * @param string $type Type 'image/gif'
+ * @param string $type Type 'image/jpeg' or 'JPEG'
* @param string $photo Photo
* @return void
*/
public function setPhoto($type, $photo)
{
// $type = "GIF" | "JPEG"
- $this->properties["PHOTO;MEDIATYPE=$type;ENCODING=BASE64"] = base64_encode($photo);
+ //$this->properties["PHOTO;MEDIATYPE=$type;ENCODING=BASE64"] = base64_encode($photo);
+ $this->properties["PHOTO;MEDIATYPE=$type"] = $photo; // must be url of photo
+ //$this->properties["PHOTO;TYPE=$type;ENCODING=BASE64"] = base64_encode($photo); // must be content of image
}
/**
@@ -152,13 +155,14 @@ class vCard
* @param string $family Family name
* @param string $first First name
* @param string $additional Additional (e.g. second name, nick name)
- * @param string $prefix Prefix (e.g. "Mr.", "Ms.", "Prof.")
+ * @param string $prefix Title prefix (e.g. "Mr.", "Ms.", "Prof.")
* @param string $suffix Suffix (e.g. "sen." for senior, "jun." for junior)
* @return void
*/
public function setName($family = "", $first = "", $additional = "", $prefix = "", $suffix = "")
{
- $this->properties["N;".$this->encoding] = encode($family).";".encode($first).";".encode($additional).";".encode($prefix).";".encode($suffix);
+ //$this->properties["N;".$this->encoding] = encode($family).";".encode($first).";".encode($additional).";".encode($prefix).";".encode($suffix);
+ $this->properties["N"] = encode($family).";".encode($first).";".encode($additional).";".encode($prefix).";".encode($suffix);
$this->filename = "$first%20$family.vcf";
if (empty($this->properties["FN"])) {
$this->setFormattedName(trim("$prefix $first $additional $family $suffix"));
@@ -173,12 +177,13 @@ class vCard
*/
public function setBirthday($date)
{
- // $date format is YYYY-MM-DD - RFC 2425 and RFC 2426
- $this->properties["BDAY"] = dol_print_date($date, 'dayrfc');
+ // $date format is YYYY-MM-DD - RFC 2425 and RFC 2426 for vcard v3
+ // $date format is YYYYMMDD or ISO8601 for vcard v4
+ $this->properties["BDAY"] = dol_print_date($date, 'dayxcard');
}
/**
- * mise en forme de l'adresse
+ * Address
*
* @param string $postoffice Postoffice
* @param string $extended Extended
@@ -191,7 +196,7 @@ class vCard
* @param string $label Label
* @return void
*/
- public function setAddress($postoffice = "", $extended = "", $street = "", $city = "", $region = "", $zip = "", $country = "", $type = "HOME", $label = '')
+ public function setAddress($postoffice = "", $extended = "", $street = "", $city = "", $region = "", $zip = "", $country = "", $type = "", $label = "")
{
// $type may be DOM | INTL | POSTAL | PARCEL | HOME | WORK or any combination of these: e.g. "WORK;PARCEL;POSTAL"
$key = "ADR";
@@ -202,7 +207,7 @@ class vCard
$key .= ';LABEL="'.encode($label).'"';
}
$key .= ";".$this->encoding;
- $this->properties[$key] = ";".encode($extended).";".encode($street).";".encode($city).";".encode($region).";".encode($zip).";".encode($country);
+ $this->properties[$key] = encode($postoffice).";".encode($extended).";".encode($street).";".encode($city).";".encode($region).";".encode($zip).";".encode($country);
//if ($this->properties["LABEL;".$type.";".$this->encoding] == '') {
//$this->setLabel($postoffice, $extended, $street, $city, $region, $zip, $country, $type);
@@ -210,7 +215,7 @@ class vCard
}
/**
- * mise en forme du label
+ * Address (old standard)
*
* @param string $postoffice Postoffice
* @param string $extended Extended
@@ -221,6 +226,7 @@ class vCard
* @param string $country Country
* @param string $type Type
* @return void
+ * @deprecated
*/
public function setLabel($postoffice = "", $extended = "", $street = "", $city = "", $region = "", $zip = "", $country = "", $type = "HOME")
{
@@ -309,7 +315,7 @@ class vCard
*/
public function setProdId($prodid)
{
- $this->properties["PRODID;".$this->encoding] = encode($prodid);
+ $this->properties["PRODID"] = encode($prodid);
}
@@ -321,7 +327,7 @@ class vCard
*/
public function setUID($uid)
{
- $this->properties["UID;".$this->encoding] = encode($uid);
+ $this->properties["UID"] = encode($uid);
}
@@ -353,9 +359,10 @@ class vCard
$text .= "VERSION:4.0\r\n"; // With V4, all encoding are UTF-8
//$text.= "VERSION:2.1\r\n";
foreach ($this->properties as $key => $value) {
- $text .= $key.":".$value."\r\n";
+ $newkey = preg_replace('/-.*$/', '', $key); // remove suffix -twitter, -facebook, ...
+ $text .= $newkey.":".$value."\r\n";
}
- $text .= "REV:".date("Y-m-d")."T".date("H:i:s")."Z\r\n";
+ $text .= "REV:".date("Ymd")."T".date("His")."Z\r\n";
//$text .= "MAILER: Dolibarr\r\n";
$text .= "END:VCARD\r\n";
return $text;
@@ -373,13 +380,15 @@ class vCard
/**
* Return a VCARD string
+ * See RFC https://datatracker.ietf.org/doc/html/rfc6350
*
- * @param Object $object Object (User, Contact)
- * @param Societe $company Company
- * @param Translate $langs Lang object
- * @return string String
+ * @param Object $object Object (User or Contact)
+ * @param Societe|null $company Company. May be null
+ * @param Translate $langs Lang object
+ * @param string $urlphoto Full public URL of photo
+ * @return string String
*/
- public function buildVCardString($object, $company, $langs)
+ public function buildVCardString($object, $company, $langs, $urlphoto = '')
{
global $dolibarr_main_instance_unique_id;
@@ -389,70 +398,136 @@ class vCard
$this->setName($object->lastname, $object->firstname, "", $object->civility_code, "");
$this->setFormattedName($object->getFullName($langs, 1));
- $this->setPhoneNumber($object->office_phone, "TYPE=WORK,VOICE");
- $this->setPhoneNumber($object->personal_mobile, "TYPE=HOME,VOICE");
- $this->setPhoneNumber($object->user_mobile, "TYPE=CELL,VOICE");
- $this->setPhoneNumber($object->office_fax, "TYPE=WORK,FAX");
-
- $country = $object->country_code ? $object->country : '';
-
- $this->setAddress("", "", $object->address, $object->town, $object->state, $object->zip, $country, "TYPE=WORK");
- //$this->setLabel("", "", $object->address, $object->town, $object->state, $object->zip, $country, "TYPE=WORK");
-
- $this->setEmail($object->email, "TYPE=WORK");
- $this->setNote($object->note_public);
- $this->setTitle($object->job);
-
- // For user, type=home
- // For contact, this is not defined
- $this->setURL($object->url, "TYPE=HOME");
-
- if (is_object($company)) {
- $this->setURL($company->url, "TYPE=WORK");
-
- if (!$object->office_phone) {
- $this->setPhoneNumber($company->phone, "TYPE=WORK,VOICE");
- }
- if (!$object->office_fax) {
- $this->setPhoneNumber($company->fax, "TYPE=WORK,FAX");
- }
- if (!$object->zip) {
- $this->setAddress("", "", $company->address, $company->town, $company->state, $company->zip, $company->country, "TYPE=WORK");
- }
-
- // when company e-mail is empty, use only user e-mail
- if (empty(trim($company->email))) {
- // was set before, don't set twice
- } elseif (empty(trim($object->email))) {
- // when user e-mail is empty, use only company e-mail
- $this->setEmail($company->email, "TYPE=WORK");
- } else {
- $tmpuser2 = explode("@", trim($object->email));
- $tmpcompany = explode("@", trim($company->email));
-
- if (strtolower(end($tmpuser2)) == strtolower(end($tmpcompany))) {
- // when e-mail domain of user and company are the same, use user e-mail at first (and company e-mail at second)
- $this->setEmail($object->email, "TYPE=WORK");
-
- // support by Microsoft Outlook (2019 and possible earlier)
- $this->setEmail($company->email, '');
- } else {
- // when e-mail of user and company complete different use company e-mail at first (and user e-mail at second)
- $this->setEmail($company->email, "TYPE=WORK");
-
- // support by Microsoft Outlook (2019 and possible earlier)
- $this->setEmail($object->email, '');
- }
- }
-
- // Si user lie a un tiers non de type "particulier"
- if ($company->typent_code != 'TE_PRIVATE') {
- $this->setOrg($company->name);
+ if ($urlphoto) {
+ $mimetype = dol_mimetype($urlphoto);
+ if ($mimetype) {
+ $this->setPhoto($mimetype, $urlphoto);
}
}
- // Personal informations
- $this->setPhoneNumber($object->personal_mobile, "TYPE=HOME,VOICE");
+ if ($object->office_phone) {
+ $this->setPhoneNumber($object->office_phone, "TYPE=WORK,VOICE");
+ }
+ /* disabled
+ if ($object->personal_mobile) {
+ $this->setPhoneNumber($object->personal_mobile, "TYPE=CELL,VOICE");
+ }*/
+ if ($object->user_mobile) {
+ $this->setPhoneNumber($object->user_mobile, "TYPE=CELL,VOICE");
+ }
+ if ($object->office_fax) {
+ $this->setPhoneNumber($object->office_fax, "TYPE=WORK,FAX");
+ }
+
+ if (!empty($object->socialnetworks)) {
+ foreach ($object->socialnetworks as $key => $val) {
+ $urlsn = '';
+ if ($key == 'linkedin') {
+ if (!preg_match('/^http/', $val)) {
+ $urlsn = 'https://www.'.$key.'.com/company/'.urlencode($val);
+ } else {
+ $urlsn = $val;
+ }
+ } elseif ($key == 'youtube') {
+ if (!preg_match('/^http/', $val)) {
+ $urlsn = 'https://www.'.$key.'.com/user/'.urlencode($val);
+ } else {
+ $urlsn = $val;
+ }
+ } else {
+ if (!preg_match('/^http/', $val)) {
+ $urlsn = 'https://www.'.$key.'.com/'.urlencode($val);
+ } else {
+ $urlsn = $val;
+ }
+ }
+ if ($urlsn) {
+ $this->properties["SOCIALPROFILE;TYPE=WORK-".$key] = $key.':'.$urlsn;
+ }
+ }
+ }
+
+ $country = $object->country_code ? $object->country : '';
+
+ if ($object->address || $object->town || $object->state || $object->zip || $object->country) {
+ $this->setAddress("", "", $object->address, $object->town, $object->state, $object->zip, $country, "");
+ //$this->setLabel("", "", $object->address, $object->town, $object->state, $object->zip, $country, "TYPE=HOME");
+ }
+
+ if ($object->email) {
+ $this->setEmail($object->email, "TYPE=WORK");
+ }
+ /* disabled
+ if ($object->personal_email) {
+ $this->setEmail($object->personal_email, "TYPE=HOME");
+ } */
+ if ($object->note_public) {
+ $this->setNote($object->note_public);
+ }
+ if ($object->job) {
+ $this->setTitle($object->job);
+ }
+
+ // For user, $object->url is not defined
+ // For contact, $object->url is not defined
+ if (!empty($object->url)) {
+ $this->setURL($object->url, "");
+ }
+
+ if (is_object($company)) {
+ // Si user linked to a thirdparty and not a physical people
+ if ($company->typent_code != 'TE_PRIVATE') {
+ $this->setOrg($company->name);
+ }
+
+ $this->setURL($company->url, "");
+
+ if ($company->phone && $company->phone != $object->office_phone) {
+ $this->setPhoneNumber($company->phone, "TYPE=WORK,VOICE");
+ }
+ if ($company->fax && $company->fax != $object->office_fax) {
+ $this->setPhoneNumber($company->fax, "TYPE=WORK,FAX");
+ }
+ if ($company->address || $company->town || $company->state || $company->zip || $company->country) {
+ $this->setAddress("", "", $company->address, $company->town, $company->state, $company->zip, $company->country, "TYPE=WORK");
+ }
+
+ if ($company->email && $company->email != $object->email) {
+ $this->setEmail($company->email, "TYPE=WORK");
+ }
+
+ /*
+ if (!empty($company->socialnetworks)) {
+ foreach ($company->socialnetworks as $key => $val) {
+ $urlsn = '';
+ if ($key == 'linkedin') {
+ if (!preg_match('/^http/', $val)) {
+ $urlsn = 'https://www.'.$key.'.com/company/'.urlencode($val);
+ } else {
+ $urlsn = $val;
+ }
+ } elseif ($key == 'youtube') {
+ if (!preg_match('/^http/', $val)) {
+ $urlsn = 'https://www.'.$key.'.com/user/'.urlencode($val);
+ } else {
+ $urlsn = $val;
+ }
+ } else {
+ if (!preg_match('/^http/', $val)) {
+ $urlsn = 'https://www.'.$key.'.com/'.urlencode($val);
+ } else {
+ $urlsn = $val;
+ }
+ }
+ if ($urlsn) {
+ $this->properties["socialProfile;type=".$key] = $urlsn;
+ }
+ }
+ }
+ */
+ }
+
+ // Birthday
if ($object->birth) {
$this->setBirthday($object->birth);
}
diff --git a/htdocs/core/lib/admin.lib.php b/htdocs/core/lib/admin.lib.php
index 71bcc082961..92895793082 100644
--- a/htdocs/core/lib/admin.lib.php
+++ b/htdocs/core/lib/admin.lib.php
@@ -1084,11 +1084,12 @@ function purgeSessions($mysessionid)
/**
* Enable a module
*
- * @param string $value Name of module to activate
- * @param int $withdeps Activate/Disable also all dependencies
- * @return array array('nbmodules'=>nb modules activated with success, 'errors=>array of error messages, 'nbperms'=>Nb permission added);
+ * @param string $value Name of module to activate
+ * @param int $withdeps Activate/Disable also all dependencies
+ * @param int $noconfverification Remove verification of $conf variable for module
+ * @return array array('nbmodules'=>nb modules activated with success, 'errors=>array of error messages, 'nbperms'=>Nb permission added);
*/
-function activateModule($value, $withdeps = 1)
+function activateModule($value, $withdeps = 1, $noconfverification = 0)
{
global $db, $langs, $conf, $mysoc;
@@ -1144,8 +1145,10 @@ function activateModule($value, $withdeps = 1)
}
$const_name = $objMod->const_name;
- if (!empty($conf->global->$const_name)) {
- return $ret;
+ if ($noconfverification == 0) {
+ if (!empty($conf->global->$const_name)) {
+ return $ret;
+ }
}
$result = $objMod->init(); // Enable module
diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php
index 03223a7b65a..773cb6a1a97 100644
--- a/htdocs/core/lib/date.lib.php
+++ b/htdocs/core/lib/date.lib.php
@@ -117,6 +117,7 @@ function getServerTimeZoneInt($refgmtdate = 'now')
* @param int $duration_unit Unit of added delay (d, m, y, w, h, i)
* @param int $ruleforendofmonth Change the behavior of PHP over data-interval, 0 or 1
* @return int New timestamp
+ * @see convertSecondToTime(), convertTimeToSeconds()
*/
function dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth = 0)
{
diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php
index ad7d7cecfa5..207f5bafeb7 100644
--- a/htdocs/core/lib/files.lib.php
+++ b/htdocs/core/lib/files.lib.php
@@ -2058,13 +2058,13 @@ function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring
dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile);
$data = implode("", file(dol_osencode($inputfile)));
- if ($mode == 'gz') {
+ if ($mode == 'gz' && function_exists('gzencode')) {
$foundhandler = 1;
$compressdata = gzencode($data, 9);
- } elseif ($mode == 'bz') {
+ } elseif ($mode == 'bz' && function_exists('bzcompress')) {
$foundhandler = 1;
$compressdata = bzcompress($data, 9);
- } elseif ($mode == 'zstd') {
+ } elseif ($mode == 'zstd' && function_exists('zstd_compress')) {
$foundhandler = 1;
$compressdata = zstd_compress($data, 9);
} elseif ($mode == 'zip') {
diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index 30d2d2327d8..3e3a87c7bd0 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -116,7 +116,7 @@ function getDolUserString($key, $default = '', $tmpuser = null)
}
// return $conf->global->$key ?? $default;
- return (string) (empty($tmpuser->conf->$key) ? $default : $$tmpuser->conf->$key);
+ return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
}
/**
@@ -3170,7 +3170,7 @@ function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetwor
if (!empty($type)) {
$htmllink = '