diff --git a/README.md b/README.md index 35fb412..4e01910 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Informations - Numéro du module : 436310 -- Dernière mise à jour : 13/09/2023 +- Dernière mise à jour : 22/12/2023 - Éditeur : [Evarisk](https://evarisk.com) - Thème : Eldy Menu - Licence : GPLv3 @@ -11,9 +11,10 @@ ### Version -- Version : 1.4.0 -- Compatibilité : Dolibarr 16.0.0 - 17.0.3 -- Saturne Framework : 1.1.2 +- Version : 1.5.0 +- PHP : 7.4.33 +- Compatibilité : Dolibarr 16.0.0 - 18.0.4 +- Saturne Framework : 1.2.1 ## Liens diff --git a/class/actions_dolisirh.class.php b/class/actions_dolisirh.class.php index e78ba64..d68ed7d 100644 --- a/class/actions_dolisirh.class.php +++ b/class/actions_dolisirh.class.php @@ -97,14 +97,16 @@ public function doActions(array $parameters, $object, string $action): int $plannedWorkload = 0; if (is_array($object->lines) && !empty($object->lines)) { foreach ($object->lines as $factureLine) { - $product->fetch($factureLine->fk_product); - - $dateStart = $factureLine->date_start; - $dateEnd = $factureLine->date_end; - $quantity = $factureLine->qty; - $durationValue = $product->duration_value; - $durationUnit = $product->duration_unit; - $plannedWorkload = $quantity * dol_time_plus_duree(0, $durationValue, $durationUnit); + if ($factureLine->fk_product > 0) { + $product->fetch($factureLine->fk_product); + + $dateStart = $factureLine->date_start; + $dateEnd = $factureLine->date_end; + $quantity = $factureLine->qty; + $durationValue = $product->duration_value; + $durationUnit = $product->duration_unit; + $plannedWorkload = $quantity * dol_time_plus_duree(0, $durationValue, $durationUnit); + } } $project->fetch($object->fk_project); @@ -178,6 +180,13 @@ public function doActions(array $parameters, $object, string $action): int } } + if (preg_match('/categorycard/', $parameters['context'])) { + require_once __DIR__ . '/../class/timesheet.class.php'; + require_once __DIR__ . '/../class/certificate.class.php'; + require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; + require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture-rec.class.php'; + } + return 0; // or return 1 to replace standard code } @@ -196,14 +205,16 @@ public function addMoreActionsButtons(array $parameters, $object): int $product = new Product($this->db); if (is_array($object->lines) && !empty($object->lines)) { foreach ($object->lines as $factureLine) { - $product->fetch($factureLine->fk_product); - - $dateStart = $factureLine->date_start; - $dateEnd = $factureLine->date_end; - $quantity = $factureLine->qty; - $durationValue = $product->duration_value; - $durationUnit = $product->duration_unit; - $plannedWorkload = $quantity * dol_time_plus_duree(0, $durationValue, $durationUnit); + if ($factureLine->fk_product > 0) { + $product->fetch($factureLine->fk_product); + + $dateStart = $factureLine->date_start; + $dateEnd = $factureLine->date_end; + $quantity = $factureLine->qty; + $durationValue = $product->duration_value; + $durationUnit = $product->duration_unit; + $plannedWorkload = $quantity * dol_time_plus_duree(0, $durationValue, $durationUnit); + } } } @@ -220,54 +231,6 @@ public function addMoreActionsButtons(array $parameters, $object): int } } - if (preg_match('/categorycard/', $parameters['context'])) { - $id = GETPOST('id'); - $elementId = GETPOST('element_id'); - $type = GETPOST('type'); - if ($id > 0 && $elementId > 0 && ($type == 'timesheet' || $type == 'certificate' || $type == 'facture' || $type == 'facturerec') && ($user->rights->dolisirh->$type->write || $user->rights->facture->creer)) { - switch ($type) { - case 'facture' : - require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; - - $newobject = new Facture($this->db); - break; - case 'facturerec' : - require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture-rec.class.php'; - - $newobject = new FactureRec($this->db); - break; - default : - require_once __DIR__ . '/' . $type . '.class.php'; - - $classname = ucfirst($type); - $newobject = new $classname($this->db); - break; - } - - $newobject->fetch($elementId); - - if (GETPOST('action') == 'addintocategory') { - $result = $object->add_type($newobject, $type); - if ($result >= 0) { - setEventMessages($langs->trans("WasAddedSuccessfully", $newobject->ref), array()); - - } else { - if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { - setEventMessages($langs->trans("ObjectAlreadyLinkedToCategory"), array(), 'warnings'); - } else { - setEventMessages($object->error, $object->errors, 'errors'); - } - } - } elseif (GETPOST('action') == 'delintocategory') { - $result = $object->del_type($newobject, $type); - if ($result < 0) { - dol_print_error('', $object->error); - } - $action = ''; - } - } - } - return 0; // or return 1 to replace standard code } @@ -550,128 +513,7 @@ function getDiffTimestampEvent() { if (preg_match('/categoryindex/', $parameters['context'])) { print ''; - } elseif (preg_match('/categorycard/', $parameters['context']) && preg_match('/viewcat.php/', $_SERVER["PHP_SELF"])) { - require_once __DIR__ . '/../../saturne/lib/object.lib.php'; - - $id = GETPOST('id'); - $type = GETPOST('type'); - - // Load variable for pagination - $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 or if we click on clear filters or if we select empty mass action - $offset = $limit * $page; - - if ($type == 'timesheet' || $type == 'certificate' || $type == 'facture' || $type == 'facturerec') { - switch ($type) { - case 'facture' : - require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; - - $classname = 'Facture'; - $object = new $classname($this->db); - - $arrayObjects = saturne_fetch_all_object_type($classname); - break; - case 'facturerec' : - require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture-rec.class.php'; - - $classname = 'FactureRec'; - $object = new $classname($this->db); - - $arrayObjects = saturne_fetch_all_object_type($classname); - break; - default : - require_once __DIR__ . '/' . $type . '.class.php'; - - $classname = ucfirst($type); - $object = new $classname($this->db); - - $arrayObjects = $object->fetchAll(); - break; - } - - if (is_array($arrayObjects) && !empty($arrayObjects)) { - foreach ($arrayObjects as $objectsingle) { - if ($objectsingle->element == 'facturerec') { - $array[$objectsingle->id] = $objectsingle->titre; - } else { - $array[$objectsingle->id] = $objectsingle->ref; - } - } - } - - $category = new Categorie($this->db); - $category->fetch($id); - $objectsInCateg = $category->getObjectsInCateg($type, 0, $limit, $offset); - - $out = '
'; - - $out .= '
'; - $out .= ''; - $out .= ''; - - $out .= ''; - $out .= ''; - $out .= ''; - $out .= '
'; - $out .= $langs->trans('AddObjectIntoCategory') . ' '; - $out .= $form::selectarray('element_id', $array, '', 1); - $out .= '
'; - $out .= '
'; - - $out .= '
'; - - //$param = '&limit=' . $limit . '&id=' . $id . '&type=' . $type; - //$num = count($objectsInCateg); - //print_barre_liste($langs->trans(ucfirst($type)), $page, $_SERVER["PHP_SELF"], $param, '', '', '', $num, '', 'object_'.$type.'@dolisirh', 0, '', '', $limit); - - $out .= load_fiche_titre($langs->transnoentities($classname), '', 'object_' . $object->picto); - $out .= ''; - $out .= ''; - - if (is_array($objectsInCateg) && !empty($objectsInCateg)) { - // Form to add record into a category - if (count($objectsInCateg) > 0) { - $i = 0; - foreach ($objectsInCateg as $element) { - $i++; - if ($i > $limit) break; - - $out .= ''; - $out .= ''; - // Link to delete from category - $out .= ''; - $out .= ''; - } - } else { - $out .= ''; - } - } else { - $out .= ''; - } - - $out .= '
'.$langs->trans("Ref").'
'; - $out .= $element->getNomUrl(1); - $out .= ''; - if ($user->rights->categorie->creer) { - $out .= ''; - $out .= $langs->trans("DeleteFromCat"); - $out .= img_picto($langs->trans("DeleteFromCat"), 'unlink', '', false, 0, 0, '', 'paddingleft'); - $out .= ''; - } - $out .= '
'.$langs->trans("ThisCategoryHasNoItems").'
'.$langs->trans("ThisCategoryHasNoItems").'
'; - } ?> - - - id); } @@ -786,7 +628,7 @@ public function formObjectOptions(array $parameters, $object, string $action) $arrayselected[] = $cat->id; } } - print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0); + print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, (GETPOSTISSET('categories') ? GETPOST('categories', 'array') : $arrayselected), '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0); print ""; } } elseif ($action == '') { @@ -896,7 +738,15 @@ public function deleteFile(array $parameters, $object) } $usertmp->fetch($object->fk_user_assign); - $filter = ' AND ptt.task_date BETWEEN ' . "'" .dol_print_date($object->date_start, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($object->date_end, 'dayrfc'). "'"; + $versionEighteenOrMore = 0; + if ((float) DOL_VERSION >= 18.0) { + $versionEighteenOrMore = 1; + } + if ($versionEighteenOrMore) { + $filter = ' AND ptt.element_date BETWEEN ' . "'" .dol_print_date($object->date_start, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($object->date_end, 'dayrfc'). "'"; + } else { + $filter = ' AND ptt.task_date BETWEEN ' . "'" .dol_print_date($object->date_start, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($object->date_end, 'dayrfc'). "'"; + } $alltimespent = $task->fetchAllTimeSpent($usertmp, $filter); foreach ($alltimespent as $timespent) { $task->fetchObjectLinked(null, '', $timespent->timespent_id, 'project_task_time'); @@ -1122,12 +972,12 @@ public function printFieldListSearchParam(array $parameters, $object): int } /** - * Overloading the SaturneAdminObjectConst function : replacing the parent's function with the one below. + * Overloading the saturneAdminObjectConst function : replacing the parent's function with the one below. * * @param array $parameters Hook metadata (context, etc...) * @return int 0 < on error, 0 on success, 1 to replace standard code. */ - public function SaturneAdminObjectConst(array $parameters): int + public function saturneAdminObjectConst(array $parameters): int { if ($parameters['currentcontext'] == 'timesheetadmin') { $constArray['dolisirh'] = [ @@ -1160,12 +1010,12 @@ public function SaturneAdminObjectConst(array $parameters): int } /** - * Overloading the SaturneAdminDocumentData function : replacing the parent's function with the one below. + * Overloading the saturneAdminDocumentData function : replacing the parent's function with the one below. * * @param array $parameters Hook metadata (context, etc...) * @return int 0 < on error, 0 on success, 1 to replace standard code. */ - public function SaturneAdminDocumentData(array $parameters): int + public function saturneAdminDocumentData(array $parameters): int { if ($parameters['currentcontext'] == 'dolisirhadmindocuments') { $types = [ @@ -1185,12 +1035,12 @@ public function SaturneAdminDocumentData(array $parameters): int } /** - * Overloading the SaturneIndex function : replacing the parent's function with the one below. + * Overloading the saturneIndex function : replacing the parent's function with the one below. * * @param array $parameters Hook metadata (context, etc...) * @return void */ - public function SaturneIndex(array $parameters) + public function saturneIndex(array $parameters) { global $conf, $langs; diff --git a/class/timesheet.class.php b/class/timesheet.class.php index 533e95c..a4de574 100644 --- a/class/timesheet.class.php +++ b/class/timesheet.class.php @@ -436,7 +436,7 @@ class TimeSheetLine extends SaturneObject /** * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. */ - public array $fields = [ + public $fields = [ 'rowid' => ['type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => 'Id'], 'entity' => ['type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'position' => 5, 'notnull' => 1, 'visible' => 0], 'date_creation' => ['type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'visible' => 0], @@ -475,9 +475,9 @@ class TimeSheetLine extends SaturneObject public ?int $rang; /** - * @var string Description. + * @var string|null Description. */ - public string $description = ''; + public ?string $description = ''; /** * @var int|null Product type. diff --git a/core/modules/dolisirh/dolisirhdocuments/projectdocument/doc_projectdocument_odt.modules.php b/core/modules/dolisirh/dolisirhdocuments/projectdocument/doc_projectdocument_odt.modules.php index 3446dd0..120f968 100644 --- a/core/modules/dolisirh/dolisirhdocuments/projectdocument/doc_projectdocument_odt.modules.php +++ b/core/modules/dolisirh/dolisirhdocuments/projectdocument/doc_projectdocument_odt.modules.php @@ -115,6 +115,11 @@ public function fillTagsLines(Odf $odfHandler, Translate $outputLangs, array $mo $contacts = array_merge($contacts, $internalContacts); } + $versionEighteenOrMore = 0; + if ((float) DOL_VERSION >= 18.0) { + $versionEighteenOrMore = 1; + } + // Replace tags of lines. try { // Get project users. @@ -138,7 +143,11 @@ public function fillTagsLines(Odf $odfHandler, Translate $outputLangs, array $mo if (is_array($allTasks) && !empty($allTasks)) { $allTimespentUser = 0; foreach ($allTasks as $task) { - $filter = ' AND ptt.fk_task = ' . $task->id . ' AND ptt.fk_user = ' . $contact['id']; + if ($versionEighteenOrMore) { + $filter = ' AND fk_element = ' . $task->id . ' AND ptt.elementtype = "task" AND fk_user = ' . $contact['id']; + } else { + $filter = ' AND fk_element = ' . $task->id . ' AND fk_user = ' . $contact['id']; + } $timeSpentsUser = $saturneTask->fetchAllTimeSpentAllUsers($filter); foreach ($timeSpentsUser as $timespent) { $allTimespentUser += $timespent->timespent_duration; @@ -208,7 +217,11 @@ public function fillTagsLines(Odf $odfHandler, Translate $outputLangs, array $mo foreach ($contacts as $contact) { if (is_array($allTasks) && !empty($allTasks)) { foreach ($allTasks as $task) { - $filter = ' AND ptt.fk_task = ' . $task->id . ' AND ptt.fk_user = ' . $contact['id']; + if ($versionEighteenOrMore) { + $filter = ' AND fk_element = ' . $task->id . ' AND ptt.elementtype = "task" AND fk_user = ' . $contact['id']; + } else { + $filter = ' AND fk_element = ' . $task->id . ' AND fk_user = ' . $contact['id']; + } $timeSpentsUser = $saturneTask->fetchAllTimeSpentAllUsers($filter); foreach ($timeSpentsUser as $timespent) { $tmpArray['project_task_timespent_date'] = dol_print_date($timespent->timespent_datehour, (($timespent->timespent_withhour > 0) ? 'dayhour' : 'day')); diff --git a/core/modules/modDoliSIRH.class.php b/core/modules/modDoliSIRH.class.php index e371d4f..7c64ca4 100644 --- a/core/modules/modDoliSIRH.class.php +++ b/core/modules/modDoliSIRH.class.php @@ -78,7 +78,7 @@ public function __construct($db) $this->editor_url = 'https://evarisk.com'; // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'. - $this->version = '1.4.0'; + $this->version = '1.5.0'; // Url to the file with your last numberversion of this module. //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; @@ -162,7 +162,7 @@ public function __construct($db) $this->hidden = false; // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...). - $this->depends = ['modProjet', 'modBookmark', 'modHoliday', 'modFckeditor', 'modSalaries', 'modProduct', 'modService', 'modSociete', 'modECM', 'modCategorie', 'modSaturne', 'modCron']; + $this->depends = ['modAgenda', 'modProjet', 'modBookmark', 'modHoliday', 'modFckeditor', 'modSalaries', 'modProduct', 'modService', 'modSociete', 'modECM', 'modCategorie', 'modSaturne', 'modCron']; $this->requiredby = []; // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...). $this->conflictwith = []; // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...). @@ -513,20 +513,20 @@ public function __construct($db) ]; // PROJECT MENU. - $this->menu[$r++] = [ - 'fk_menu' => 'fk_mainmenu=project,fk_leftmenu=timespent', - 'type' => 'left', - 'titre' => '' . $langs->transnoentities('DoliSIRHTimeSpent'), - 'mainmenu' => 'project', - 'leftmenu' => 'dolisirh_timespent_list', - 'url' => '/dolisirh/view/timespent_list.php', - 'langs' => 'dolisirh@dolisirh', - 'position' => 1000 + $r, - 'enabled' => '$conf->dolisirh->enabled && $conf->projet->enabled', - 'perms' => '$user->rights->dolisirh->lire && $user->rights->projet->lire', - 'target' => '', - 'user' => 0, - ]; +// $this->menu[$r++] = [ +// 'fk_menu' => 'fk_mainmenu=project,fk_leftmenu=timespent', +// 'type' => 'left', +// 'titre' => '' . $langs->transnoentities('DoliSIRHTimeSpent'), +// 'mainmenu' => 'project', +// 'leftmenu' => 'dolisirh_timespent_list', +// 'url' => '/dolisirh/view/timespent_list.php', +// 'langs' => 'dolisirh@dolisirh', +// 'position' => 1000 + $r, +// 'enabled' => '$conf->dolisirh->enabled && $conf->projet->enabled', +// 'perms' => '$user->rights->dolisirh->lire && $user->rights->projet->lire', +// 'target' => '', +// 'user' => 0, +// ]; $this->menu[$r++] = [ 'fk_menu' => 'fk_mainmenu=project,fk_leftmenu=timespent', @@ -544,20 +544,20 @@ public function __construct($db) ]; // HRM MENU. - $this->menu[$r++] = [ - 'fk_menu' => 'fk_mainmenu=hrm,fk_leftmenu=timespent', - 'type' => 'left', - 'titre' => '' . $langs->transnoentities('DoliSIRHTimeSpent'), - 'mainmenu' => 'hrm', - 'leftmenu' => 'dolisirh_timespent_list', - 'url' => '/dolisirh/view/timespent_list.php', - 'langs' => 'dolisirh@dolisirh', - 'position' => 1000 + $r, - 'enabled' => '$conf->dolisirh->enabled && $conf->salaries->enabled', - 'perms' => '$user->rights->dolisirh->lire && $user->rights->projet->lire', - 'target' => '', - 'user' => 0, - ]; +// $this->menu[$r++] = [ +// 'fk_menu' => 'fk_mainmenu=hrm,fk_leftmenu=timespent', +// 'type' => 'left', +// 'titre' => '' . $langs->transnoentities('DoliSIRHTimeSpent'), +// 'mainmenu' => 'hrm', +// 'leftmenu' => 'dolisirh_timespent_list', +// 'url' => '/dolisirh/view/timespent_list.php', +// 'langs' => 'dolisirh@dolisirh', +// 'position' => 1000 + $r, +// 'enabled' => '$conf->dolisirh->enabled && $conf->salaries->enabled', +// 'perms' => '$user->rights->dolisirh->lire && $user->rights->projet->lire', +// 'target' => '', +// 'user' => 0, +// ]; $this->menu[$r++] = [ 'fk_menu' => 'fk_mainmenu=hrm,fk_leftmenu=timespent', diff --git a/core/triggers/interface_99_modDolisirh_DolisirhTriggers.class.php b/core/triggers/interface_99_modDolisirh_DolisirhTriggers.class.php index 5052e02..eb7da9b 100644 --- a/core/triggers/interface_99_modDolisirh_DolisirhTriggers.class.php +++ b/core/triggers/interface_99_modDolisirh_DolisirhTriggers.class.php @@ -49,7 +49,7 @@ public function __construct(DoliDB $db) $this->name = preg_replace('/^Interface/i', '', get_class($this)); $this->family = 'demo'; $this->description = 'DoliSIRH triggers.'; - $this->version = '1.4.0'; + $this->version = '1.5.0'; $this->picto = 'dolisirh@dolisirh'; } diff --git a/js/dolisirh.min.js b/js/dolisirh.min.js index c0a9542..72bf87a 100644 --- a/js/dolisirh.min.js +++ b/js/dolisirh.min.js @@ -1 +1 @@ -"use strict";window.dolisirh||(window.dolisirh={},window.dolisirh.scriptsLoaded=!1),window.dolisirh.scriptsLoaded||(window.dolisirh.init=function(){window.dolisirh.load_list_script()},window.dolisirh.load_list_script=function(){if(!window.dolisirh.scriptsLoaded){let i=void 0,t=void 0;for(i in window.dolisirh)for(t in window.dolisirh[i].init&&window.dolisirh[i].init(),window.dolisirh[i])window.dolisirh[i]&&window.dolisirh[i][t]&&window.dolisirh[i][t].init&&window.dolisirh[i][t].init();window.dolisirh.scriptsLoaded=!0}},window.dolisirh.refresh=function(){let i=void 0,t=void 0;for(i in window.dolisirh)for(t in window.dolisirh[i].refresh&&window.dolisirh[i].refresh(),window.dolisirh[i])window.dolisirh[i]&&window.dolisirh[i][t]&&window.dolisirh[i][t].refresh&&window.dolisirh[i][t].refresh()},$(document).ready(window.dolisirh.init)),window.dolisirh.certificate={},window.dolisirh.certificate.init=function(){window.dolisirh.certificate.event()},window.dolisirh.certificate.event=function(){$(document).on("change","#element_type",window.dolisirh.certificate.reloadField)},window.dolisirh.certificate.reloadField=function(){var i=$(this).val(),t=window.saturne.toolbox.getToken(),e=window.saturne.toolbox.getQuerySeparator(document.URL);$.ajax({url:document.URL+e+"element_type="+i+"&token="+t,type:"POST",processData:!1,contentType:!1,success:function(i){$(".field_element_type").replaceWith($(i).find(".field_element_type")),$(".field_fk_element").replaceWith($(i).find(".field_fk_element"))},error:function(){}})},window.dolisirh.task={},window.dolisirh.task.init=function(){window.dolisirh.task.event()},window.dolisirh.task.event=function(){$(document).on("click",".auto-fill-timespent",window.dolisirh.task.addTimeSpent),$(document).on("click",".auto-fill-timespent-project",window.dolisirh.task.divideTimeSpent),$(document).on("click",".show-only-favorite-tasks",window.dolisirh.task.showOnlyFavoriteTasks),$(document).on("click",".show-only-tasks-with-timespent",window.dolisirh.task.showOnlyTasksWithTimeSpent),$(document).on("click",".select-logic-operators-mode",window.dolisirh.task.selectLogicOperatorsMode),$(document).on("click",".show-closed-projects",window.dolisirh.task.showClosedProjects),$(document).on("click",".timespent-create",window.dolisirh.task.createTimeSpent),$(document).on("click",".toggleTaskFavorite",window.dolisirh.task.toggleTaskFavorite),$(document).on("submit","#addtimeform",window.dolisirh.task.searchForm)},window.dolisirh.task.addTimeSpent=function(){var i=$(".non-consumed-time-minute").val(),t=$(".non-consumed-time-hour").val();$(".inputhour").val(""),$(".inputminute").val(""),$(this).closest(".duration").find(".inputhour").val(t),$(this).closest(".duration").find(".inputminute").val(i)},window.dolisirh.task.divideTimeSpent=function(){var i=$(this).closest(".project-line").attr("id");let t,e;var o=+$(".non-consumed-time-minute").val()+60*+$(".non-consumed-time-hour").val(),n=$("."+i).length;let s=parseInt(o/n);$(".inputhour").val(""),$(".inputminute").val(""),$("."+i).each(function(){e=parseInt(s/60),t=s%60,$(this).find(".inputhour").val(e),$(this).find(".inputminute").val(t)})},window.dolisirh.task.showOnlyFavoriteTasks=function(){var i=$(".id-container").find('input[name="token"]').val();let t="?";document.URL.match(/\?/)&&(t="&");let e;e=$(this).is(":checked")?1:0,$.ajax({url:document.URL+t+"action=show_only_favorite_tasks&token="+i,type:"POST",processData:!1,data:JSON.stringify({showOnlyFavoriteTasks:e}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.showOnlyTasksWithTimeSpent=function(){var i=$(".id-container").find('input[name="token"]').val();let t="?";document.URL.match(/\?/)&&(t="&");let e;e=$(this).is(":checked")?1:0,$.ajax({url:document.URL+t+"action=show_only_tasks_with_timespent&token="+i,type:"POST",processData:!1,data:JSON.stringify({showOnlyTasksWithTimeSpent:e}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.selectLogicOperatorsMode=function(){var i=window.saturne.toolbox.getToken(),t=window.saturne.toolbox.getQuerySeparator(document.URL);let e;e=$(this).is(":checked")?1:0,$.ajax({url:document.URL+t+"action=select_logic_operators_mode&token="+i,type:"POST",processData:!1,data:JSON.stringify({selectLogicOperatorsMode:e}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.showClosedProjects=function(){var i=window.saturne.toolbox.getToken(),t=window.saturne.toolbox.getQuerySeparator(document.URL);let e;e=$(this).is(":checked")?1:0,$.ajax({url:document.URL+t+"action=show_closed_projects&token="+i,type:"POST",processData:!1,data:JSON.stringify({showClosedProjects:e}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.createTimeSpent=function(){var i=$(this).attr("value");let t=$(this).closest(".timespent-add-modal").find(".timespent-container");var e=t.find(".timespent-timestamp").val(),o=t.find(".timespent-datehour").val(),n=t.find(".timespent-datemin").val(),s=t.find(".timespent-comment").val(),a=t.find(".timespent-hour").val(),d=t.find(".timespent-min").val(),r=(window.saturne.loader.display($(this)),$(".fiche").find('input[name="token"]').val());let l="?";document.URL.match(/\?/)&&(l="&"),$.ajax({url:document.URL+l+"action=add_timespent&token="+r,data:JSON.stringify({taskID:i,timestamp:e,datehour:o,datemin:n,comment:s,hour:a,min:d}),type:"POST",processData:!1,contentType:!1,success:function(i){$(".loader-spin").remove(),$(".wpeo-loader").removeClass("wpeo-loader"),$("#timespent").removeClass("modal-active"),$("#tablelines3").html($(i).find("#tablelines3"))},error:function(i){}})},window.dolisirh.task.toggleTaskFavorite=function(){let t=$(this).attr("value");var i=$('form[name="addtime"]').find('input[name="token"]').val();let e="?";document.URL.match(/\?/)&&(e="&"),$.ajax({url:document.URL+e+"action=toggleTaskFavorite&taskId="+t+"&token="+i,type:"POST",processData:!1,contentType:!1,success:function(){let i=$("#"+t);i.hasClass("fas")?(i.removeClass("fas"),i.addClass("far")):i.hasClass("far")&&(i.removeClass("far"),i.addClass("fas"))},error:function(i){}})},window.saturne.modal.addMoreOpenModalData=function(i,t){let e=t.find(".timespent");var t=e.attr("data-task-id"),o=e.attr("data-timestamp"),n=e.attr("data-cell"),s=e.attr("data-date");$(".timespent-taskid").val(t),$(".timespent-timestamp").val(o),$(".timespent-cell").val(n),$(".timespent-create").attr("value",t),$(".timespent-date").html(s)},window.dolisirh.task.searchForm=function(i){i.preventDefault();i=document.getElementById("addtimeform"),i=new FormData(i);let t=new FormData;for(const e of i.entries())""!=e[1]&&t.append(e[0],e[1]);window.saturne.loader.display($("#addtimeform")),$.ajax({url:document.URL,type:"POST",data:t,processData:!1,contentType:!1,success:function(i){$(".wpeo-loader").removeClass("wpeo-loader"),$("#addtimeform").html($(i).find("#addtimeform").children())}})}; \ No newline at end of file +"use strict";window.dolisirh||(window.dolisirh={},window.dolisirh.scriptsLoaded=!1),window.dolisirh.scriptsLoaded||(window.dolisirh.init=function(){window.dolisirh.load_list_script()},window.dolisirh.load_list_script=function(){if(!window.dolisirh.scriptsLoaded){let t=void 0,i=void 0;for(t in window.dolisirh)for(i in window.dolisirh[t].init&&window.dolisirh[t].init(),window.dolisirh[t])window.dolisirh[t]&&window.dolisirh[t][i]&&window.dolisirh[t][i].init&&window.dolisirh[t][i].init();window.dolisirh.scriptsLoaded=!0}},window.dolisirh.refresh=function(){let t=void 0,i=void 0;for(t in window.dolisirh)for(i in window.dolisirh[t].refresh&&window.dolisirh[t].refresh(),window.dolisirh[t])window.dolisirh[t]&&window.dolisirh[t][i]&&window.dolisirh[t][i].refresh&&window.dolisirh[t][i].refresh()},$(document).ready(window.dolisirh.init)),window.dolisirh.certificate={},window.dolisirh.certificate.init=function(){window.dolisirh.certificate.event()},window.dolisirh.certificate.event=function(){$(document).on("change","#element_type",window.dolisirh.certificate.reloadField)},window.dolisirh.certificate.reloadField=function(){var t=$(this).val(),i=window.saturne.toolbox.getToken(),o=window.saturne.toolbox.getQuerySeparator(document.URL);$.ajax({url:document.URL+o+"element_type="+t+"&token="+i,type:"POST",processData:!1,contentType:!1,success:function(t){$(".field_element_type").replaceWith($(t).find(".field_element_type")),$(".field_fk_element").replaceWith($(t).find(".field_fk_element"))},error:function(){}})},window.dolisirh.task={},window.dolisirh.task.init=function(){window.dolisirh.task.event()},window.dolisirh.task.event=function(){$(document).on("click",".auto-fill-timespent",window.dolisirh.task.addTimeSpent),$(document).on("click",".auto-fill-timespent-project",window.dolisirh.task.divideTimeSpent),$(document).on("click",".show-only-favorite-tasks",window.dolisirh.task.showOnlyFavoriteTasks),$(document).on("click",".show-only-tasks-with-timespent",window.dolisirh.task.showOnlyTasksWithTimeSpent),$(document).on("click",".select-logic-operators-mode",window.dolisirh.task.selectLogicOperatorsMode),$(document).on("click",".show-closed-projects",window.dolisirh.task.showClosedProjects),$(document).on("click",".show-sticky-total-timespent-info",window.dolisirh.task.showStickyTotalTimeSpentInfo),$(document).on("click",".timespent-create",window.dolisirh.task.createTimeSpent),$(document).on("click",".toggleTaskFavorite",window.dolisirh.task.toggleTaskFavorite),$(document).on("submit","#addtimeform",window.dolisirh.task.searchForm)},window.dolisirh.task.addTimeSpent=function(){var t=$(".non-consumed-time-minute").val(),i=$(".non-consumed-time-hour").val();$(".inputhour").val(""),$(".inputminute").val(""),$(this).closest(".duration").find(".inputhour").val(i),$(this).closest(".duration").find(".inputminute").val(t)},window.dolisirh.task.divideTimeSpent=function(){var t=$(this).closest(".project-line").attr("id");let i,o;var e=+$(".non-consumed-time-minute").val()+60*+$(".non-consumed-time-hour").val(),n=$("."+t).length;let s=parseInt(e/n);$(".inputhour").val(""),$(".inputminute").val(""),$("."+t).each(function(){o=parseInt(s/60),i=s%60,$(this).find(".inputhour").val(o),$(this).find(".inputminute").val(i)})},window.dolisirh.task.showOnlyFavoriteTasks=function(){var t=$(".id-container").find('input[name="token"]').val();let i="?";document.URL.match(/\?/)&&(i="&");let o;o=$(this).is(":checked")?1:0,$.ajax({url:document.URL+i+"action=show_only_favorite_tasks&token="+t,type:"POST",processData:!1,data:JSON.stringify({showOnlyFavoriteTasks:o}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.showOnlyTasksWithTimeSpent=function(){var t=$(".id-container").find('input[name="token"]').val();let i="?";document.URL.match(/\?/)&&(i="&");let o;o=$(this).is(":checked")?1:0,$.ajax({url:document.URL+i+"action=show_only_tasks_with_timespent&token="+t,type:"POST",processData:!1,data:JSON.stringify({showOnlyTasksWithTimeSpent:o}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.selectLogicOperatorsMode=function(){var t=window.saturne.toolbox.getToken(),i=window.saturne.toolbox.getQuerySeparator(document.URL);let o;o=$(this).is(":checked")?1:0,$.ajax({url:document.URL+i+"action=select_logic_operators_mode&token="+t,type:"POST",processData:!1,data:JSON.stringify({selectLogicOperatorsMode:o}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.showClosedProjects=function(){var t=window.saturne.toolbox.getToken(),i=window.saturne.toolbox.getQuerySeparator(document.URL);let o;o=$(this).is(":checked")?1:0,$.ajax({url:document.URL+i+"action=show_closed_projects&token="+t,type:"POST",processData:!1,data:JSON.stringify({showClosedProjects:o}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.showStickyTotalTimeSpentInfo=function(){var t=window.saturne.toolbox.getToken(),i=window.saturne.toolbox.getQuerySeparator(document.URL);let o;o=$(this).is(":checked")?1:0,$.ajax({url:document.URL+i+"action=show_sticky_total_timespent_info&token="+t,type:"POST",processData:!1,data:JSON.stringify({showStickyTotalTimeSpentInfo:o}),contentType:!1,success:function(){window.location.reload()},error:function(){}})},window.dolisirh.task.createTimeSpent=function(){var t=$(this).attr("value");let i=$(this).closest(".timespent-add-modal").find(".timespent-container");var o=i.find(".timespent-timestamp").val(),e=i.find(".timespent-datehour").val(),n=i.find(".timespent-datemin").val(),s=i.find(".timespent-comment").val(),a=i.find(".timespent-hour").val(),d=i.find(".timespent-min").val(),r=(window.saturne.loader.display($(this)),$(".fiche").find('input[name="token"]').val());let l="?";document.URL.match(/\?/)&&(l="&"),$.ajax({url:document.URL+l+"action=add_timespent&token="+r,data:JSON.stringify({taskID:t,timestamp:o,datehour:e,datemin:n,comment:s,hour:a,min:d}),type:"POST",processData:!1,contentType:!1,success:function(t){$(".loader-spin").remove(),$(".wpeo-loader").removeClass("wpeo-loader"),$("#timespent").removeClass("modal-active"),$("#tablelines3").html($(t).find("#tablelines3"))},error:function(t){}})},window.dolisirh.task.toggleTaskFavorite=function(){let i=$(this).attr("value");var t=$('form[name="addtime"]').find('input[name="token"]').val();let o="?";document.URL.match(/\?/)&&(o="&"),$.ajax({url:document.URL+o+"action=toggleTaskFavorite&taskId="+i+"&token="+t,type:"POST",processData:!1,contentType:!1,success:function(){let t=$("#"+i);t.hasClass("fas")?(t.removeClass("fas"),t.addClass("far")):t.hasClass("far")&&(t.removeClass("far"),t.addClass("fas"))},error:function(t){}})},window.saturne.modal.addMoreOpenModalData=function(t,i){let o=i.find(".timespent");var i=o.attr("data-task-id"),e=o.attr("data-timestamp"),n=o.attr("data-cell"),s=o.attr("data-date");$(".timespent-taskid").val(i),$(".timespent-timestamp").val(e),$(".timespent-cell").val(n),$(".timespent-create").attr("value",i),$(".timespent-date").html(s)},window.dolisirh.task.searchForm=function(t){t.preventDefault();t=document.getElementById("addtimeform"),t=new FormData(t);let i=new FormData;for(const o of t.entries())""!=o[1]&&i.append(o[0],o[1]);window.saturne.loader.display($("#addtimeform")),$.ajax({url:document.URL,type:"POST",data:i,processData:!1,contentType:!1,success:function(t){$(".wpeo-loader").removeClass("wpeo-loader"),$("#addtimeform").html($(t).find("#addtimeform").children())}})}; \ No newline at end of file diff --git a/js/modules/task.js b/js/modules/task.js index 71a230f..22d0c4b 100644 --- a/js/modules/task.js +++ b/js/modules/task.js @@ -65,6 +65,7 @@ window.dolisirh.task.event = function() { $(document).on('click', '.show-only-tasks-with-timespent', window.dolisirh.task.showOnlyTasksWithTimeSpent); $(document).on('click', '.select-logic-operators-mode', window.dolisirh.task.selectLogicOperatorsMode); $(document).on('click', '.show-closed-projects', window.dolisirh.task.showClosedProjects); + $(document).on('click', '.show-sticky-total-timespent-info', window.dolisirh.task.showStickyTotalTimeSpentInfo); $(document).on('click', '.timespent-create', window.dolisirh.task.createTimeSpent); $(document).on('click', '.toggleTaskFavorite', window.dolisirh.task.toggleTaskFavorite); $(document).on('submit', '#addtimeform', window.dolisirh.task.searchForm ); @@ -272,6 +273,42 @@ window.dolisirh.task.showClosedProjects = function() { }); }; +/** + * Enables/disables the configuration to display sticky total time spent info in top or bottom + * + * @memberof DoliSIRH_Task + * + * @since 1.5.0 + * @version 1.5.0 + * + * @return {void} + */ +window.dolisirh.task.showStickyTotalTimeSpentInfo = function() { + let token = window.saturne.toolbox.getToken(); + let querySeparator = window.saturne.toolbox.getQuerySeparator(document.URL); + + let showStickyTotalTimeSpentInfo; + if ($(this).is(':checked')) { + showStickyTotalTimeSpentInfo = 1; + } else { + showStickyTotalTimeSpentInfo = 0; + } + + $.ajax({ + url: document.URL + querySeparator + "action=show_sticky_total_timespent_info&token=" + token, + type: "POST", + processData: false, + data: JSON.stringify({ + showStickyTotalTimeSpentInfo: showStickyTotalTimeSpentInfo + }), + contentType: false, + success: function() { + window.location.reload(); + }, + error: function() {} + }); +}; + /** * Action create timespent. * diff --git a/langs/fr_FR/dolisirh.lang b/langs/fr_FR/dolisirh.lang index 687e238..2eb7f78 100644 --- a/langs/fr_FR/dolisirh.lang +++ b/langs/fr_FR/dolisirh.lang @@ -145,6 +145,7 @@ TimeSpentList = Liste des temps consommés ShowOnlyTasksWithTimeSpent = Afficher uniquement les tâches avec du temps consommé sur cette période SelectLogicOperatorsMode = Sélection de l'opérateur logique 'ET/OU' par défaut : ET ShowClosedProjects = Afficher les projets clôturés +ShowStickyTotalTimeSpentInfo = Option d'affichage permettant de choisir l'endroit où se situent les informations totales du temps consommé 'Bas/Haut'
Par défaut : en bas de la page ExpectedWorkingHours = Heures de travail prévues ConsumedWorkingHours = Heures de travail consommées TimeSpentReportByFiscalYear = Rapport du temps consommé sur l'exercice fiscal diff --git a/lib/dolisirh_timespent.lib.php b/lib/dolisirh_timespent.lib.php index 9341814..3f3ec9f 100644 --- a/lib/dolisirh_timespent.lib.php +++ b/lib/dolisirh_timespent.lib.php @@ -101,8 +101,18 @@ function load_time_spent_on_tasks_within_range(int $timestampStart, int $timesta $userTmp->fetch($userID); } + $versionEighteenOrMore = 0; + if ((float) DOL_VERSION >= 18.0) { + $versionEighteenOrMore = 1; + } + if ($versionEighteenOrMore) { + $moreWhereFilter = 'AND (ptt.element_date >= "' . $db->idate($timestampStart) . '" AND ptt.element_date < "' . $db->idate($timestampEnd) . '")'; + } else { + $moreWhereFilter = 'AND (ptt.task_date >= "' . $db->idate($timestampStart) . '" AND ptt.task_date < "' . $db->idate($timestampEnd) . '")'; + } + $timeSpentOnTasks = ['days' => 0, 'hours' => 0, 'minutes' => 0, 'total' => 0]; - $timeSpentList = $task->fetchAllTimeSpent($userTmp, 'AND (ptt.task_date >= "' . $db->idate($timestampStart) . '" AND ptt.task_date < "' . $db->idate($timestampEnd) . '")'); + $timeSpentList = $task->fetchAllTimeSpent($userTmp, $moreWhereFilter); if (is_array($timeSpentList) && !empty($timeSpentList)) { $workingDays = []; foreach ($timeSpentList as $timeSpent) { @@ -279,6 +289,11 @@ function get_tasks_array($userT = null, $userP = null, int $projectID = 0, int $ $tasks = []; + $versionEighteenOrMore = 0; + if ((float) DOL_VERSION >= 18.0) { + $versionEighteenOrMore = 1; + } + // List of tasks (does not care about permissions. Filtering will be done later). $sql = 'SELECT '; if ($filterOnProjUser > 0 || $filterOnTaskUser > 0) { @@ -304,11 +319,11 @@ function get_tasks_array($userT = null, $userP = null, int $projectID = 0, int $ } if ($includeBillTime) { - $sql .= ', SUM(tt.task_duration * ' . $db->ifsql('invoice_id IS NULL', '1', '0') . ') as tobill, SUM(tt.task_duration * ' . $db->ifsql( - 'invoice_id IS NULL', - '0', - '1' - ) . ') as billed'; + if ($versionEighteenOrMore) { + $sql .= ', SUM(tt.element_duration * ' . $db->ifsql('invoice_id IS NULL', '1', '0') . ') as tobill, SUM(tt.element_duration * ' . $db->ifsql('invoice_id IS NULL', '0', '1') . ') as billed'; + } else { + $sql .= ', SUM(tt.task_duration * ' . $db->ifsql('invoice_id IS NULL', '1', '0') . ') as tobill, SUM(tt.task_duration * ' . $db->ifsql('invoice_id IS NULL', '0', '1') . ') as billed'; + } } $sql .= ' FROM ' .MAIN_DB_PREFIX . 'projet as p'; @@ -322,7 +337,11 @@ function get_tasks_array($userT = null, $userP = null, int $projectID = 0, int $ } $sql .= ', ' . MAIN_DB_PREFIX . 'projet_task as t'; if ($includeBillTime) { - $sql .= ' LEFT JOIN ' .MAIN_DB_PREFIX. 'projet_task_time as tt ON tt.fk_task = t.rowid'; + if ($versionEighteenOrMore) { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'element_time as tt ON (tt.fk_element = t.rowid AND tt.elementtype = "task")'; + } else { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as tt ON tt.fk_task = t.rowid'; + } } if ($filterOnTaskUser > 0) { $sql .= ', ' .MAIN_DB_PREFIX. 'element_contact as ec2'; @@ -332,7 +351,11 @@ function get_tasks_array($userT = null, $userP = null, int $projectID = 0, int $ $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . "element_element as elel ON (t.rowid = elel.fk_target AND elel.targettype='project_task')"; } if ($user->conf->DOLISIRH_SHOW_ONLY_TASKS_WITH_TIMESPENT > 0) { - $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as ptt ON (t.rowid = ptt.fk_task)'; + if ($versionEighteenOrMore) { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'element_time as ptt ON (ptt.fk_element = t.rowid AND ptt.elementtype = "task")'; + } else { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as ptt ON (t.rowid = ptt.fk_task)'; + } } $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_extrafields as efpt ON (t.rowid = efpt.fk_object)'; $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')'; @@ -342,15 +365,27 @@ function get_tasks_array($userT = null, $userP = null, int $projectID = 0, int $ $sql .= ' AND elel.fk_source = ' . $filterOnProjUser; } if ($user->conf->DOLISIRH_SHOW_ONLY_TASKS_WITH_TIMESPENT > 0) { - $sql .= ($user->conf->DOLISIRH_SELECT_LOGIC_OPERATORS_MODE && $user->conf->DOLISIRH_SHOW_ONLY_FAVORITE_TASKS ? ' OR (' : ' AND ') . 'ptt.fk_task = t.rowid AND ptt.fk_user = ' . $filterOnProjUser; - if ($timeMode == 'month') { - $sql .= ' AND MONTH(ptt.task_date) = ' . $timeArray['month']; - } elseif ($timeMode == 'week') { - $sql .= ' AND WEEK(ptt.task_date, 7) = ' . $timeArray['week']; - } elseif ($timeMode == 'day') { - $sql .= ' AND DAY(ptt.task_date) = ' . $timeArray['day']; + if ($versionEighteenOrMore) { + $sql .= ($user->conf->DOLISIRH_SELECT_LOGIC_OPERATORS_MODE && $user->conf->DOLISIRH_SHOW_ONLY_FAVORITE_TASKS ? ' OR (' : ' AND ') . '(ptt.fk_element = t.rowid AND ptt.elementtype = "task") AND ptt.fk_user = ' . $filterOnProjUser; + if ($timeMode == 'month') { + $sql .= ' AND MONTH(ptt.element_date) = ' . $timeArray['month']; + } elseif ($timeMode == 'week') { + $sql .= ' AND WEEK(ptt.element_date, 7) = ' . $timeArray['week']; + } elseif ($timeMode == 'day') { + $sql .= ' AND DAY(ptt.element_date) = ' . $timeArray['day']; + } + $sql .= ' AND YEAR(ptt.element_date) = ' . $timeArray['year']; + } else { + $sql .= ($user->conf->DOLISIRH_SELECT_LOGIC_OPERATORS_MODE && $user->conf->DOLISIRH_SHOW_ONLY_FAVORITE_TASKS ? ' OR (' : ' AND ') . 'ptt.fk_task = t.rowid AND ptt.fk_user = ' . $filterOnProjUser; + if ($timeMode == 'month') { + $sql .= ' AND MONTH(ptt.task_date) = ' . $timeArray['month']; + } elseif ($timeMode == 'week') { + $sql .= ' AND WEEK(ptt.task_date, 7) = ' . $timeArray['week']; + } elseif ($timeMode == 'day') { + $sql .= ' AND DAY(ptt.task_date) = ' . $timeArray['day']; + } + $sql .= ' AND YEAR(ptt.task_date) = ' . $timeArray['year']; } - $sql .= ' AND YEAR(ptt.task_date) = ' . $timeArray['year']; } $sql .= ($user->conf->DOLISIRH_SELECT_LOGIC_OPERATORS_MODE && $user->conf->DOLISIRH_SHOW_ONLY_FAVORITE_TASKS && $user->conf->DOLISIRH_SHOW_ONLY_TASKS_WITH_TIMESPENT ? '))' : ''); } elseif ($mode == 1) { @@ -361,14 +396,22 @@ function get_tasks_array($userT = null, $userP = null, int $projectID = 0, int $ if ($filterOnTaskUser > 0) { $sql .= ', ' . MAIN_DB_PREFIX . 'projet_task as t'; if ($includeBillTime) { - $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as tt ON tt.fk_task = t.rowid'; + if ($versionEighteenOrMore) { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'element_time as tt ON (tt.fk_element = t.rowid AND tt.elementtype = "task")'; + } else { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as tt ON tt.fk_task = t.rowid'; + } } $sql .= ', ' . MAIN_DB_PREFIX . 'element_contact as ec2'; $sql .= ', ' . MAIN_DB_PREFIX . 'c_type_contact as ctc2'; } else { $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task as t on t.fk_projet = p.rowid'; if ($includeBillTime) { - $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as tt ON tt.fk_task = t.rowid'; + if ($versionEighteenOrMore) { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'element_time as tt ON (tt.fk_element = t.rowid AND tt.elementtype = "task")'; + } else { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as tt ON tt.fk_task = t.rowid'; + } } } $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_extrafields as efpt ON (t.rowid = efpt.fk_object)'; @@ -696,7 +739,15 @@ function task_lines_within_range(int &$inc, int $timestampStart, int $timestampE if (!empty($arrayFields['timeconsumed']['checked'])) { // Time spent by user. print ''; - $filter = ' AND (t.task_date >= "' . $db->idate($timestampStart) . '" AND t.task_date < "' . $db->idate(dol_time_plus_duree($timestampEnd, 1, 'd')) . '")'; + $versionEighteenOrMore = 0; + if ((float) DOL_VERSION >= 18.0) { + $versionEighteenOrMore = 1; + } + if ($versionEighteenOrMore) { + $filter = ' AND (t.element_date >= "' . $db->idate($timestampStart) . '" AND t.element_date < "' . $db->idate(dol_time_plus_duree($timestampEnd, 1, 'd')) . '")'; + } else { + $filter = ' AND (t.task_date >= "' . $db->idate($timestampStart) . '" AND t.task_date < "' . $db->idate(dol_time_plus_duree($timestampEnd, 1, 'd')) . '")'; + } $summaryOfTimeSpent = $task->getSummaryOfTimeSpent($fuser->id, $filter); if ($summaryOfTimeSpent['total_duration']) { print convertSecondToTime($summaryOfTimeSpent['total_duration'], 'allhourmin'); diff --git a/view/certificate/certificate_card.php b/view/certificate/certificate_card.php index 62ea67a..85db223 100644 --- a/view/certificate/certificate_card.php +++ b/view/certificate/certificate_card.php @@ -276,7 +276,7 @@ $arraySelected[] = $cat->id; } } - print img_picto('', 'category') . $form::multiselectarray('categories', $cateArbo, $arraySelected, '', 0, 'quatrevingtpercent widthcentpercentminusx'); + print img_picto('', 'category') . $form::multiselectarray('categories', $cateArbo, (GETPOSTISSET('categories') ? GETPOST('categories', 'array') : $arraySelected), '', 0, 'quatrevingtpercent widthcentpercentminusx'); print ''; } diff --git a/view/certificate/certificate_list.php b/view/certificate/certificate_list.php index 2a2eb4c..f0b6247 100644 --- a/view/certificate/certificate_list.php +++ b/view/certificate/certificate_list.php @@ -89,13 +89,13 @@ $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); -// Default sort order (if not yet defined by previous GETPOST). +// Default sort order (if not yet defined by previous GETPOST) if (!$sortfield) { - reset($object->fields); // Reset is required to avoid key() to return null. - $sortfield = 't.' . key($object->fields); // Set here default search field. By default, 1st field in definition. + reset($object->fields); // Reset is required to avoid key() to return null + $sortfield = 't.date_creation'; // Set here default search field. By default, date_creation } if (!$sortorder) { - $sortorder = 'ASC'; + $sortorder = 'DESC'; } // Initialize array of search criterias. diff --git a/view/timesheet/timesheet_card.php b/view/timesheet/timesheet_card.php index 21ab484..e1561b3 100644 --- a/view/timesheet/timesheet_card.php +++ b/view/timesheet/timesheet_card.php @@ -141,7 +141,15 @@ $userTmp->fetch(GETPOST('fk_user_assign')); $dateStart = dol_mktime(0, 0, 0, GETPOST('date_startmonth', 'int'), GETPOST('date_startday', 'int'), GETPOST('date_startyear', 'int')); $dateEnd = dol_mktime(0, 0, 0, GETPOST('date_endmonth', 'int'), GETPOST('date_endday', 'int'), GETPOST('date_endyear', 'int')); - $filter = ' AND ptt.task_date BETWEEN ' . "'" . dol_print_date($dateStart, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($dateEnd, 'dayrfc') . "'"; + $versionEighteenOrMore = 0; + if ((float) DOL_VERSION >= 18.0) { + $versionEighteenOrMore = 1; + } + if ($versionEighteenOrMore) { + $filter = ' AND ptt.element_date BETWEEN ' . "'" . dol_print_date($dateStart, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($dateEnd, 'dayrfc') . "'"; + } else { + $filter = ' AND ptt.task_date BETWEEN ' . "'" . dol_print_date($dateStart, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($dateEnd, 'dayrfc') . "'"; + } $timeSpents = $task->fetchAllTimeSpent($userTmp, $filter); foreach ($timeSpents as $timespent) { $task->fetchObjectLinked(null, '', $timespent->timespent_id, 'project_task_time'); @@ -287,7 +295,15 @@ $object->fetch($id); if (!$error) { $userTmp->fetch($object->fk_user_assign); - $filter = ' AND ptt.task_date BETWEEN ' . "'" . dol_print_date($object->date_start, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($object->date_end, 'dayrfc') . "'"; + $versionEighteenOrMore = 0; + if ((float) DOL_VERSION >= 18.0) { + $versionEighteenOrMore = 1; + } + if ($versionEighteenOrMore) { + $filter = ' AND ptt.element_date BETWEEN ' . "'" . dol_print_date($object->date_start, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($object->date_end, 'dayrfc') . "'"; + } else { + $filter = ' AND ptt.task_date BETWEEN ' . "'" . dol_print_date($object->date_start, 'dayrfc') . "'" . ' AND ' . "'" . dol_print_date($object->date_end, 'dayrfc') . "'"; + } $timeSpents = $task->fetchAllTimeSpent($userTmp, $filter); foreach ($timeSpents as $timespent) { $task->fetchObjectLinked(null, '', $timespent->timespent_id, 'project_task_time'); @@ -468,7 +484,7 @@ $arraySelected[] = $cat->id; } } - print img_picto('', 'category') . $form::multiselectarray('categories', $cate_arbo, $arraySelected, '', 0, 'quatrevingtpercent widthcentpercentminusx'); + print img_picto('', 'category') . $form::multiselectarray('categories', $cate_arbo, (GETPOSTISSET('categories') ? GETPOST('categories', 'array') : $arraySelected), '', 0, 'quatrevingtpercent widthcentpercentminusx'); print ''; } diff --git a/view/timesheet/timesheet_list.php b/view/timesheet/timesheet_list.php index a0cfab5..70ac14b 100644 --- a/view/timesheet/timesheet_list.php +++ b/view/timesheet/timesheet_list.php @@ -96,13 +96,13 @@ $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); -// Default sort order (if not yet defined by previous GETPOST). +// Default sort order (if not yet defined by previous GETPOST) if (!$sortfield) { - reset($object->fields); // Reset is required to avoid key() to return null. - $sortfield = 't.' . key($object->fields); // Set here default search field. By default, 1st field in definition. + reset($object->fields); // Reset is required to avoid key() to return null + $sortfield = 't.date_creation'; // Set here default search field. By default, date_creation } if (!$sortorder) { - $sortorder = 'ASC'; + $sortorder = 'DESC'; } // Initialize array of search criterias. diff --git a/view/timespent_list.php b/view/timespent_list.php index 3319839..07b9bce 100644 --- a/view/timespent_list.php +++ b/view/timespent_list.php @@ -108,6 +108,11 @@ $hookmanager->initHooks(array('timespentlist')); // Note that conf->hooks_modules contains array +$versionEighteenOrMore = 0; +if ((float) DOL_VERSION >= 18.0) { + $versionEighteenOrMore = 1; +} + $arrayfields = array( 'rowid' => array('tablealias' => 's.', 'fieldalias' => 'socid', 'type' => 'Societe:societe/class/societe.class.php:1:status=1 AND entity IN (__SHARED_ENTITIES__)', 'label' => "Customer", 'checked' => 1, 'position' => 10, 'visible' => 1), 'ref' => array('tablealias' => 'p.', 'fieldalias' => 'projectref', 'type' => 'Project:projet/class/project.class.php:1', 'label' => "Project", 'checked' => 1, 'position' => 20, 'visible' => 1), @@ -125,7 +130,11 @@ // Default sort order (if not yet defined by previous GETPOST) if (!$sortfield) { - $sortfield = 'ptt.task_date'; // Set here default search field. By default 1st field in definition. + if ($versionEighteenOrMore) { + $sortfield = 'ptt.element_date'; // Set here default search field. By default 1st field in definition. + } else { + $sortfield = 'ptt.task_date'; // Set here default search field. By default 1st field in definition. + } } if (!$sortorder) { $sortorder = "ASC"; @@ -238,7 +247,11 @@ $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_lead_status as cls ON p.fk_opp_status = cls.rowid'; $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task as pt ON p.rowid = pt.fk_projet'; $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_extrafields as ef ON pt.rowid = ef.fk_object'; -$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as ptt ON pt.rowid = ptt.fk_task'; +if ($versionEighteenOrMore) { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'element_time as ptt ON (ptt.fk_element = t.rowid AND ptt.elementtype = "task")'; +} else { + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'projet_task_time as ptt ON pt.rowid = ptt.fk_task'; +} $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'societe as s ON p.fk_soc = s.rowid'; $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'facture as f ON ptt.invoice_id = f.rowid'; $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'element_element as ee on ( ee.sourcetype = "dolisirh_timesheet" AND ee.targettype = "project_task_time" AND ee.fk_target = ptt.rowid)'; @@ -253,15 +266,27 @@ } else { $sql .= " WHERE 1 = 1"; } -$sql .= ' AND ptt.task_duration IS NOT NULL'; +if ($versionEighteenOrMore) { + $sql .= ' AND ptt.element_duration IS NOT NULL'; +} else { + $sql .= ' AND ptt.task_duration IS NOT NULL'; +} foreach ($search as $key => $val) { if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { if (preg_match('/_dtstart$/', $key)) { - $sql .= " AND ptt.task_date >= '" . $db->idate($search[$key]) . "'"; + if ($versionEighteenOrMore) { + $sql .= " AND ptt.element_date >= '" . $db->idate($search[$key]) . "'"; + } else { + $sql .= " AND ptt.task_date >= '" . $db->idate($search[$key]) . "'"; + } } if (preg_match('/_dtend$/', $key)) { - $sql .= " AND ptt.task_date <= '" . $db->idate($search[$key]) . "'"; + if ($versionEighteenOrMore) { + $sql .= " AND ptt.element_date <= '" . $db->idate($search[$key]) . "'"; + } else { + $sql .= " AND ptt.task_date <= '" . $db->idate($search[$key]) . "'"; + } } } if ($key == 'socid' && !empty($val)) $sql .= ' AND s.rowid=' . (int) $val; diff --git a/view/timespent_range.php b/view/timespent_range.php index 12f3426..9c974a0 100644 --- a/view/timespent_range.php +++ b/view/timespent_range.php @@ -335,6 +335,16 @@ dol_set_user_param($db, $conf, $user, $tabParam); } + if ($action == 'show_sticky_total_timespent_info') { + $data = json_decode(file_get_contents('php://input'), true); + + $showStickyTotalTimeSpentInfo = $data['showStickyTotalTimeSpentInfo']; + + $tabParam['DOLISIRH_SHOW_STICKY_TOTAL_TIMESPENT_INFO'] = $showStickyTotalTimeSpentInfo; + + dol_set_user_param($db, $conf, $user, $tabParam); + } + if ($action == 'add_timespent' && $permissiontoAdd) { $data = json_decode(file_get_contents('php://input'), true); @@ -566,6 +576,9 @@ print ' '; print 'conf->DOLISIRH_SHOW_CLOSED_PROJECTS ? ' checked' : '') . '>'; print $form->textwithpicto('', $langs->trans('ShowClosedProjects')); +print ' '; +print 'conf->DOLISIRH_SHOW_STICKY_TOTAL_TIMESPENT_INFO ? ' checked' : '') . '>'; +print $form->textwithpicto('', $langs->trans('ShowStickyTotalTimeSpentInfo')); print ''; // TASK fields. if (!empty($arrayFields['timeconsumed']['checked'])) { @@ -604,7 +617,7 @@ $plannedWorkingTime = load_planned_time_within_range($firstDayToShow, dol_time_plus_duree($lastDayOfRange, 1, 'd'), $workingHours, $isAvailable); print ''; - print ''; + print ''; print $langs->trans('Total'); print ' - '; if ($viewMode == 'month') { @@ -635,9 +648,119 @@ print ''; print '
' . (($plannedHoursOnDay['minutes'] != 0) ? convertSecondToTime($plannedHoursOnDay['minutes'] * 60, 'allhourmin') : '00:00') . '
'; } - print ''; - print ''; + print ''; + + if ($user->conf->DOLISIRH_SHOW_STICKY_TOTAL_TIMESPENT_INFO > 0) { + // Passed working hours. + $passedWorkingTime = load_passed_time_within_range($firstDayToShow, dol_time_plus_duree($lastDayOfRange, 1, 'd'), $workingHours, $isAvailable); + + print ''; + print ''; + print $langs->trans('Total'); + print ' - '; + print $langs->trans('SpentWorkingHoursMonth', dol_print_date($firstDayToShow, 'dayreduceformat'), dol_print_date($lastDayOfRange, 'dayreduceformat')); + print ' : ' . (($passedWorkingTime['minutes'] != 0) ? convertSecondToTime($passedWorkingTime['minutes'] * 60, 'allhourmin') : '00:00') . ''; + print ''; + if (!empty($arrayFields['timeconsumed']['checked'])) { + print ''; + } + + // Fill days data. + for ($idw = 0; $idw < $daysInRange; $idw++) { + $cellCSS = ''; + $dayInLoop = dol_time_plus_duree($firstDayToShow, $idw, 'd'); + $passedHoursOnDay = load_passed_time_within_range($dayInLoop, dol_time_plus_duree($firstDayToShow, $idw + 1, 'd'), $workingHours, $isAvailable); + if (!$isAvailable[$dayInLoop]['morning'] && !$isAvailable[$dayInLoop]['afternoon']) { + if ($isAvailable[$dayInLoop]['morning_reason'] == 'public_holiday') { + $cellCSS = 'onholidayallday'; + } elseif ($isAvailable[$dayInLoop]['morning_reason'] == 'week_end') { + $cellCSS = 'weekend'; + } + } + print ''; + print (($passedHoursOnDay['minutes'] != 0) ? convertSecondToTime($passedHoursOnDay['minutes'] * 60, 'allhourmin') : '00:00') . ''; + } + print ''; + + // Spent hours within dates range. + $timeSpent = load_time_spent_on_tasks_within_range($firstDayToShow, dol_time_plus_duree($lastDayOfRange, 1, 'd'), $isAvailable, $userTmp->id); + + print ''; + print ''; + print $langs->trans('Total'); + $totalConsumedTime = $timeSpent['total']; + print ' - ' . $langs->trans('ConsumedWorkingHoursMonth', dol_print_date($firstDayToShow, 'dayreduceformat'), dol_print_date($lastDayOfRange, 'dayreduceformat')) . ' : ' . convertSecondToTime($totalConsumedTime, 'allhourmin') . ''; + print ''; + if (!empty($arrayFields['timeconsumed']['checked'])) { + print '' . convertSecondToTime($totalConsumedTime, 'allhourmin') . ''; + } + + for ($idw = 0; $idw < $daysInRange; $idw++) { + $cellCSS = ''; + $dayInLoop = dol_time_plus_duree($firstDayToShow, $idw, 'd'); + $timespentHoursOnDay = load_time_spent_on_tasks_within_range($dayInLoop, dol_time_plus_duree($firstDayToShow, $idw + 1, 'd'), $isAvailable, $userTmp->id); + if (!$isAvailable[$dayInLoop]['morning'] && !$isAvailable[$dayInLoop]['afternoon']) { + if ($isAvailable[$dayInLoop]['morning_reason'] == 'public_holiday') { + $cellCSS = 'onholidayallday'; + } elseif ($isAvailable[$dayInLoop]['morning_reason'] == 'week_end') { + $cellCSS = 'weekend'; + } + } + print ''; + print '
' . (($timespentHoursOnDay['minutes'] != 0) ? convertSecondToTime($timespentHoursOnDay['minutes'] * 60, 'allhourmin') : '00:00') . '
'; + } + print ''; + + //Difference between planned & working hours + $timeSpentDiff = load_difference_between_passed_and_spent_time_within_range($firstDayToShow, dol_time_plus_duree($lastDayOfRange, 1, 'd'), $workingHours, $isAvailable, $userTmp->id); + + print ''; + print ''; + print $langs->trans('Total'); + $diffTotalTime = $timeSpentDiff * 60; + if ($diffTotalTime < 0) { + $morecss = colorStringToArray($conf->global->DOLISIRH_EXCEEDED_TIME_SPENT_COLOR); + } elseif ($diffTotalTime > 0) { + $morecss = colorStringToArray($conf->global->DOLISIRH_NOT_EXCEEDED_TIME_SPENT_COLOR); + } elseif ($diffTotalTime == 0) { + $morecss = colorStringToArray($conf->global->DOLISIRH_PERFECT_TIME_SPENT_COLOR); + } else { + $morecss = ''; + } + print ' - ' . $langs->trans('DiffSpentAndConsumedWorkingHoursMonth', dol_print_date($firstDayToShow, 'dayreduceformat'), dol_print_date($lastDayOfRange, 'dayreduceformat')) . ' : ' . (($diffTotalTime != 0) ? convertSecondToTime(abs($diffTotalTime), 'allhourmin') : '00:00') . ''; + print ''; + if (!empty($arrayFields['timeconsumed']['checked'])) { + print '' . (($diffTotalTime != 0) ? convertSecondToTime(abs($diffTotalTime), 'allhourmin') : '00:00') . ''; + } + + for ($idw = 0; $idw < $daysInRange; $idw++) { + $cellCSS = ''; + $dayInLoop = dol_time_plus_duree($firstDayToShow, $idw, 'd'); + $timeSpentDiffThisDay = load_difference_between_passed_and_spent_time_within_range($dayInLoop, dol_time_plus_duree($firstDayToShow, $idw + 1, 'd'), $workingHours, $isAvailable, $userTmp->id); + if (!$isAvailable[$dayInLoop]['morning'] && !$isAvailable[$dayInLoop]['afternoon']) { + if ($isAvailable[$dayInLoop]['morning_reason'] == 'public_holiday') { + $cellCSS = 'onholidayallday'; + } elseif ($isAvailable[$dayInLoop]['morning_reason'] == 'week_end') { + $cellCSS = 'weekend'; + } + } + + if ($timeSpentDiffThisDay < 0) { + $morecss = colorStringToArray($conf->global->DOLISIRH_EXCEEDED_TIME_SPENT_COLOR); + } elseif ($timeSpentDiffThisDay > 0) { + $morecss = colorStringToArray($conf->global->DOLISIRH_NOT_EXCEEDED_TIME_SPENT_COLOR); + } elseif ($timeSpentDiffThisDay == 0) { + $morecss = colorStringToArray($conf->global->DOLISIRH_PERFECT_TIME_SPENT_COLOR); + } + + print '
'; + print (($timeSpentDiffThisDay != 0) ? convertSecondToTime(abs($timeSpentDiffThisDay * 60), 'allhourmin') : '00:00') . '
'; + } + print ''; + } } +print ''; // By default, we can edit only tasks we are assigned to. $restrictViewForMyTask = ((!isset($conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED)) ? 2 : $conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED); @@ -696,12 +819,14 @@ -use_javascript_ajax) { +use_javascript_ajax && $user->conf->DOLISIRH_SHOW_STICKY_TOTAL_TIMESPENT_INFO == 0) { + print ''; + // Passed working hours. $passedWorkingTime = load_passed_time_within_range($firstDayToShow, dol_time_plus_duree($lastDayOfRange, 1, 'd'), $workingHours, $isAvailable); print ''; - print ''; + print ''; print $langs->trans('Total'); print ' - '; print $langs->trans('SpentWorkingHoursMonth', dol_print_date($firstDayToShow, 'dayreduceformat'), dol_print_date($lastDayOfRange, 'dayreduceformat')); @@ -733,7 +858,7 @@ $timeSpent = load_time_spent_on_tasks_within_range($firstDayToShow, dol_time_plus_duree($lastDayOfRange, 1, 'd'), $isAvailable, $userTmp->id); print ''; - print ''; + print ''; print $langs->trans('Total'); $totalConsumedTime = $timeSpent['total']; print ' - ' . $langs->trans('ConsumedWorkingHoursMonth', dol_print_date($firstDayToShow, 'dayreduceformat'), dol_print_date($lastDayOfRange, 'dayreduceformat')) . ' : ' . convertSecondToTime($totalConsumedTime, 'allhourmin') . ''; @@ -763,7 +888,7 @@ $timeSpentDiff = load_difference_between_passed_and_spent_time_within_range($firstDayToShow, dol_time_plus_duree($lastDayOfRange, 1, 'd'), $workingHours, $isAvailable, $userTmp->id); print ''; - print ''; + print ''; print $langs->trans('Total'); $diffTotalTime = $timeSpentDiff * 60; if ($diffTotalTime < 0) { @@ -806,7 +931,7 @@ print (($timeSpentDiffThisDay != 0) ? convertSecondToTime(abs($timeSpentDiffThisDay * 60), 'allhourmin') : '00:00') . ''; } print ''; - print ''; + print ''; } if (count($tasksArray) == 0) {