From 8f0c06dece9ecbf86ac7d19633ece05057169141 Mon Sep 17 00:00:00 2001 From: Patrick Delcroix Date: Tue, 26 May 2020 21:03:56 +0200 Subject: [PATCH 1/9] new: show the total of non editable tasktime (when several for a day) --- .../timesheet/class/TimesheetTask.class.php | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/htdocs/timesheet/class/TimesheetTask.class.php b/htdocs/timesheet/class/TimesheetTask.class.php index 176ef455..c28adde1 100644 --- a/htdocs/timesheet/class/TimesheetTask.class.php +++ b/htdocs/timesheet/class/TimesheetTask.class.php @@ -557,12 +557,13 @@ public function getActuals($timeStart = 0, $timeEnd = 0, $userid = 0) dol_syslog(__METHOD__, LOG_DEBUG); for($i = 0;$i<$dayelapsed;$i++) { - $this->tasklist[$i] = array('id' => 0, 'duration' => 0, 'date'=>$timeStart+SECINDAY*$i+SECINDAY/4); + $this->tasklist[$i] = array('id' => 0, 'duration' => 0, 'date'=>$timeStart+SECINDAY*$i+SECINDAY/4, 'other' => 0); } $resql = $this->db->query($sql); if($resql) { $num = $this->db->num_rows($resql); $i = 0; + unset($this->tasklistAll); // Loop on each record found, so each couple (project id, task id) while($i < $num) { @@ -570,7 +571,10 @@ public function getActuals($timeStart = 0, $timeEnd = 0, $userid = 0) $obj = $this->db->fetch_object($resql); $dateCur = $this->db->jdate($obj->task_date); $day = getDayInterval($timeStart, $dateCur); - $this->tasklist[$day] = array('id'=>$obj->rowid, 'date'=>$dateCur, 'duration'=>$obj->task_duration, 'note'=>$obj->note, 'invoiced' => $obj->invoiced); + $this->tasklist[$day] = array('id'=>$obj->rowid, 'date'=>$dateCur, 'duration'=> $obj->task_duration, 'note'=>$obj->note, + 'invoiced' => $obj->invoiced, 'other' => ($this->tasklist[$day]['duration'] + $this->tasklist[$day]['other']), + 'noteOther' => ($this->tasklist[$day]['note']."\n".$this->tasklist[$day]['noteOther'])); + // $this->tasklistAll[] = array('day' => $day, 'id'=>$obj->rowid, 'date'=>$dateCur, 'duration'=>$obj->task_duration, 'note'=>$obj->note, 'invoiced' => $obj->invoiced); $i++; } $this->db->free($resql); @@ -622,6 +626,7 @@ public function getTimesheetLine($headers, $tsUserId = 0, $openOveride = 0) $html .= $this->getHTMLlineInfoCell($headers); $html .= $this->getHTMLLineDayCell($isOpenStatus); $html .= "\n"; + return $html.$htmltail; } /** @@ -653,6 +658,8 @@ public function getHTMLLineDayCell($isOpenStatus) // to avoid editing if the task is closed $dayWorkLoadSec = isset($this->tasklist[$dayCur])?$this->tasklist[$dayCur]['duration']:0; $dayWorkLoad = formatTime($dayWorkLoadSec, -1); + $otherSec = isset($this->tasklist[$dayCur])?$this->tasklist[$dayCur]['other']:0; + $other = formatTime($otherSec, -1); $startDates = ($this->date_start>$this->startDatePjct)?$this->date_start:$this->startDatePjct; $stopDates = (($this->date_end<$this->stopDatePjct && $this->date_end!=0) || $this->stopDatePjct == 0)?$this->date_end:$this->stopDatePjct; @@ -682,6 +689,7 @@ public function getHTMLLineDayCell($isOpenStatus) if($isInvoiced){ $bkcolor = 'background:#'.$statusColor[INVOICED]; } + $html .= "\n"; // add note popup if($isOpen && $conf->global->TIMESHEET_SHOW_TIMESPENT_NOTE) { @@ -704,6 +712,15 @@ public function getHTMLLineDayCell($isOpenStatus) $html .= 'onkeypress = "return regexEvent(this,event,\'timeChar\')" '; $html .= 'onblur = "validateTime(this, \''.$this->userId.'_'.$dayCur.'\')" />'; //end note code + if( $otherSec > 0){ + $html .= '
tasklist[$dayCur]['noteOther']))$html .= ' title = "'.htmlentities($this->tasklist[$dayCur]['noteOther']).'"'; + //$html .= ' name = "task['.$this->id.']['.$dayCur.']" '; + $html .= ' style = "width: 90%;"'; + $html .= ' >'.((($hidezeros == 1) && ($otherSec == 0))?"":$other); + $html .= ' '; + } + $html .= "\n"; } else { $html .= ' Date: Tue, 26 May 2020 21:06:25 +0200 Subject: [PATCH 2/9] rev 4.2.2 --- htdocs/timesheet/ChangeLog.md | 6 ++++++ htdocs/timesheet/core/modules/modtimesheet.class.php | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/htdocs/timesheet/ChangeLog.md b/htdocs/timesheet/ChangeLog.md index 6d82a081..f0e4d8d3 100644 --- a/htdocs/timesheet/ChangeLog.md +++ b/htdocs/timesheet/ChangeLog.md @@ -1,4 +1,10 @@ # dolibarr_project_timesheet changelog +4.2.2 +- new: show the time not editable (when there is several task time for ady/task) + +4.2.1 +- fix: blank timesheet page + 4.2.0 - fix: send approval reminder - fix: favorite edit card update the task when the project is selected diff --git a/htdocs/timesheet/core/modules/modtimesheet.class.php b/htdocs/timesheet/core/modules/modtimesheet.class.php index 1dcef9d9..952cf368 100644 --- a/htdocs/timesheet/core/modules/modtimesheet.class.php +++ b/htdocs/timesheet/core/modules/modtimesheet.class.php @@ -52,7 +52,7 @@ public function __construct($db) // Module description, used if translation string 'ModuleXXXDesc' not found(where XXX is value of numeric property 'numero' of module) $this->description = "TimesheetView"; // Possible values for version are: 'development', 'experimental', 'dolibarr' or version - $this->version = '4.2.1'; + $this->version = '4.2.2'; // Key used in llx_cons table to save module status enabled/disabled(where timesheet is value of property name of module in uppercase) $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); // Where to store the module in setup page(0=common, 1=interface, 2=others, 3=very specific) From 26692aa676488b670557feb3167e638bdeb13dd1 Mon Sep 17 00:00:00 2001 From: Patrick Delcroix Date: Tue, 26 May 2020 22:02:04 +0200 Subject: [PATCH 3/9] new: include not editable timespend in submission --- .../timesheet/class/TimesheetTask.class.php | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/htdocs/timesheet/class/TimesheetTask.class.php b/htdocs/timesheet/class/TimesheetTask.class.php index c28adde1..1c47e445 100644 --- a/htdocs/timesheet/class/TimesheetTask.class.php +++ b/htdocs/timesheet/class/TimesheetTask.class.php @@ -420,6 +420,9 @@ public function delete($user, $notrigger = 0) if(!is_array($this->tasklist)) $this->getActuals($this->date_start_approval, $this->date_end_approval, $this->userId); if(is_array($this->tasklist))foreach($this->tasklist as $item) { if($item['id']!='')$idList[] = $item['id']; + if(is_array($item['other'])){ + $idList = array_merge($idList, array_column($item['other'], 'id')); + } } $ids = implode(', ', $idList); $sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET fk_task_time_approval = \''; @@ -555,11 +558,14 @@ public function getActuals($timeStart = 0, $timeEnd = 0, $userid = 0) $sql .= " AND (DATE(ptt.task_datehour)<'".$this->db->idate($timeEnd)."')"; } dol_syslog(__METHOD__, LOG_DEBUG); + $other = array(); for($i = 0;$i<$dayelapsed;$i++) { - $this->tasklist[$i] = array('id' => 0, 'duration' => 0, 'date'=>$timeStart+SECINDAY*$i+SECINDAY/4, 'other' => 0); + $other[$i] = array(); + $this->tasklist[$i] = array('id' => 0, 'duration' => 0, 'date'=>$timeStart+SECINDAY*$i+SECINDAY/4, 'other' => null); } $resql = $this->db->query($sql); + if($resql) { $num = $this->db->num_rows($resql); $i = 0; @@ -568,12 +574,17 @@ public function getActuals($timeStart = 0, $timeEnd = 0, $userid = 0) while($i < $num) { $error = 0; + $obj = $this->db->fetch_object($resql); $dateCur = $this->db->jdate($obj->task_date); $day = getDayInterval($timeStart, $dateCur); + if($this->tasklist[$day]['duration'] > 0 || strlen($this->tasklist[$day]['note']) > 0){ + $other[$day][] = array( 'duration' => $this->tasklist[$day]['duration'], 'id' => $this->tasklist[$day]['id'], 'note' => $this->tasklist[$day]['note']); + } + $this->tasklist[$day] = array('id'=>$obj->rowid, 'date'=>$dateCur, 'duration'=> $obj->task_duration, 'note'=>$obj->note, - 'invoiced' => $obj->invoiced, 'other' => ($this->tasklist[$day]['duration'] + $this->tasklist[$day]['other']), - 'noteOther' => ($this->tasklist[$day]['note']."\n".$this->tasklist[$day]['noteOther'])); + 'invoiced' => $obj->invoiced); + if(is_array($other[$day]) > 0)$this->tasklist[$day]['other'] = $other[$day]; // $this->tasklistAll[] = array('day' => $day, 'id'=>$obj->rowid, 'date'=>$dateCur, 'duration'=>$obj->task_duration, 'note'=>$obj->note, 'invoiced' => $obj->invoiced); $i++; } @@ -658,13 +669,20 @@ public function getHTMLLineDayCell($isOpenStatus) // to avoid editing if the task is closed $dayWorkLoadSec = isset($this->tasklist[$dayCur])?$this->tasklist[$dayCur]['duration']:0; $dayWorkLoad = formatTime($dayWorkLoadSec, -1); - $otherSec = isset($this->tasklist[$dayCur])?$this->tasklist[$dayCur]['other']:0; - $other = formatTime($otherSec, -1); + + $startDates = ($this->date_start>$this->startDatePjct)?$this->date_start:$this->startDatePjct; $stopDates = (($this->date_end<$this->stopDatePjct && $this->date_end!=0) || $this->stopDatePjct == 0)?$this->date_end:$this->stopDatePjct; //take the end of the day - + + $noteother = ''; + $otherSec = 0; + if(is_array($this->tasklist[$dayCur]['other'])){ + $noteother = implode("\n", array_column($this->tasklist[$dayCur]['other'], 'note')); + $otherSec = array_sum(array_column($this->tasklist[$dayCur]['other'], 'duration')); + } + $other = formatTime($otherSec, -1); if($isOpenStatus) { $isOpen = $isOpenStatus && (($startDates == 0) || ($startDates <= $today_end )); @@ -714,7 +732,7 @@ public function getHTMLLineDayCell($isOpenStatus) //end note code if( $otherSec > 0){ $html .= '
tasklist[$dayCur]['noteOther']))$html .= ' title = "'.htmlentities($this->tasklist[$dayCur]['noteOther']).'"'; + if(!empty($noteother))$html .= ' title = "'.htmlentities($noteother).'"'; //$html .= ' name = "task['.$this->id.']['.$dayCur.']" '; $html .= ' style = "width: 90%;"'; $html .= ' >'.((($hidezeros == 1) && ($otherSec == 0))?"":$other); @@ -724,10 +742,14 @@ public function getHTMLLineDayCell($isOpenStatus) $html .= "\n"; } else { $html .= ' tasklist[$dayCur]['note']))$html .= ' title = "'.htmlentities($this->tasklist[$dayCur]['note']).'"'; + if(!empty($this->tasklist[$dayCur]['note'])){ + $html .= ' title = "'.htmlentities($this->tasklist[$dayCur]['note'].((strlen($noteother)>0)?"\n".$noteother:'')).'"'; + } + $dayWorkLoadAllSec = $dayWorkLoadSec + $otherSec; + $dayWorkLoadAll = formatTime($dayWorkLoadAllSec, -1); $html .= ' name = "task['.$this->id.']['.$dayCur.']" '; $html .= ' style = "width: 90%;"'; - $html .= ' >'.((($hidezeros == 1) && ($dayWorkLoadSec == 0))?"":$dayWorkLoad); + $html .= ' >'.((($hidezeros == 1) && ($dayWorkLoadAllSec == 0))?"":$dayWorkLoadAll); $html .= ' '; $html .= "\n"; } From 10a1321a73d84294c06fb68df0abb8a74bbd831a Mon Sep 17 00:00:00 2001 From: Patrick Delcroix Date: Sun, 5 Jul 2020 10:58:40 +0200 Subject: [PATCH 4/9] remove task for closed project --- htdocs/timesheet/class/AttendanceEvent.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/timesheet/class/AttendanceEvent.class.php b/htdocs/timesheet/class/AttendanceEvent.class.php index 149c4380..a3455c60 100644 --- a/htdocs/timesheet/class/AttendanceEvent.class.php +++ b/htdocs/timesheet/class/AttendanceEvent.class.php @@ -789,7 +789,9 @@ public function fetchTasks($userid = '', $date = '') $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as prj ON prj.rowid = tsk.fk_projet '; $sql .= " WHERE ec.fk_socpeople = '".$userid."' AND ctc.element = 'project_task' "; if($conf->global->TIMESHEET_HIDE_DRAFT == '1') { - $sql .= ' AND prj.fk_statut>\'0\' '; + $sql .= ' AND prj.fk_statut = 1'; + }else{ + $sql .= ' AND prj.fk_statut in (0, 1)'; } $sql .= ' AND (prj.datee >= \''.$this->db->idate($datestart).'\' OR prj.datee IS NULL)'; $sql .= ' AND (prj.dateo <= \''.$this->db->idate($datestop).'\' OR prj.dateo IS NULL)'; From 60c102325c1303f10611641918f584aadb70a950 Mon Sep 17 00:00:00 2001 From: Patrick Delcroix Date: Sun, 5 Jul 2020 11:24:24 +0200 Subject: [PATCH 5/9] hide task from closed project --- htdocs/timesheet/class/AttendanceEvent.class.php | 6 +++--- htdocs/timesheet/class/TimesheetUserTasks.class.php | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/htdocs/timesheet/class/AttendanceEvent.class.php b/htdocs/timesheet/class/AttendanceEvent.class.php index a3455c60..0b0f6702 100644 --- a/htdocs/timesheet/class/AttendanceEvent.class.php +++ b/htdocs/timesheet/class/AttendanceEvent.class.php @@ -779,8 +779,8 @@ public function fetchTasks($userid = '', $date = '') $userid = $this->userid; } $this->userid = $userid; - $datestart = strtotime('yesterday midnight', $date); - $datestop = strtotime('today midnight', $date); + $datestart = strtotime('today midnight', $date); + $datestop = strtotime(' tomorrow midnight', $date) -1; $tasksList = array(); $sql = 'SELECT DISTINCT element_id as taskid, prj.fk_soc, prj.ref, tsk.ref'; $sql .= " FROM ".MAIN_DB_PREFIX."element_contact as ec"; @@ -789,7 +789,7 @@ public function fetchTasks($userid = '', $date = '') $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet as prj ON prj.rowid = tsk.fk_projet '; $sql .= " WHERE ec.fk_socpeople = '".$userid."' AND ctc.element = 'project_task' "; if($conf->global->TIMESHEET_HIDE_DRAFT == '1') { - $sql .= ' AND prj.fk_statut = 1'; + $sql .= ' AND prj.fk_statut = 1)'; }else{ $sql .= ' AND prj.fk_statut in (0, 1)'; } diff --git a/htdocs/timesheet/class/TimesheetUserTasks.class.php b/htdocs/timesheet/class/TimesheetUserTasks.class.php index 62f05c05..6d75e314 100644 --- a/htdocs/timesheet/class/TimesheetUserTasks.class.php +++ b/htdocs/timesheet/class/TimesheetUserTasks.class.php @@ -527,7 +527,9 @@ public function fetchTaskTimesheet($userid = '') //end approval $sql .= " WHERE ec.fk_socpeople = '".$userid."' AND ctc.element = 'project_task' "; if($conf->global->TIMESHEET_HIDE_DRAFT == '1') { - $sql .= ' AND prj.fk_statut>\'0\' '; + $sql .= ' AND prj.fk_statut = 1)'; + }else{ + $sql .= ' AND prj.fk_statut in (0, 1)'; } $sql .= ' AND (prj.datee >= \''.$this->db->idate($datestart).'\' OR prj.datee IS NULL)'; $sql .= ' AND (prj.dateo <= \''.$this->db->idate($datestop).'\' OR prj.dateo IS NULL)'; From e3ac2bf48dbc04551f4eb9450799a80ba416e072 Mon Sep 17 00:00:00 2001 From: Patrick Delcroix Date: Sun, 5 Jul 2020 12:46:40 +0200 Subject: [PATCH 6/9] add ts to submit to box --- htdocs/timesheet/core/boxes/box_approval.php | 85 ++++++++++++------- htdocs/timesheet/langs/de_DE/timesheet.lang | 1 + htdocs/timesheet/langs/en_US/timesheet.lang | 1 + htdocs/timesheet/langs/es_ES/timesheet.lang | 1 + htdocs/timesheet/langs/fr_FR/timesheet.lang | 1 + htdocs/timesheet/langs/it_IT/timesheet.lang | 1 + .../sql/llx_project_task_time_approval.sql | 2 +- 7 files changed, 62 insertions(+), 30 deletions(-) diff --git a/htdocs/timesheet/core/boxes/box_approval.php b/htdocs/timesheet/core/boxes/box_approval.php index e9f8ba12..90a1b197 100644 --- a/htdocs/timesheet/core/boxes/box_approval.php +++ b/htdocs/timesheet/core/boxes/box_approval.php @@ -54,11 +54,12 @@ public function loadBox($max = 5) 'limit' => dol_strlen($text) ); if($user->rights->timesheet->approval) { - $sql = 'SELECT'; - $subordinate = implode(', ', getSubordinates($db, $userid, 2)); - if($subordinate == '')$subordinate = 0; - $tasks = implode(', ', array_keys(getTasks($db, $userid))); - if($tasks == '')$tasks = 0; + + $subordinate = implode(', ', getSubordinates($db, $userid, 2)); + if($subordinate == '')$subordinate = 0; + $tasks = implode(', ', array_keys(getTasks($db, $userid))); + if($tasks == '')$tasks = 0; + $sql = 'SELECT'; // $sql .= ' COUNT(t.rowid) as nb, '; $sql .= ' COUNT(DISTINCT t.rowid) as nbtsk, count(DISTINCT fk_project_task_timesheet) as nbtm, t.recipient'; $sql .= ' FROM '.MAIN_DB_PREFIX.'project_task_time_approval as t'; @@ -66,41 +67,67 @@ public function loadBox($max = 5) $sql .= ' AND t.fk_userid in ('.$subordinate.'))';//fixme should check subordinate and project $sql .= ' OR (t.recipient='.PROJECT.' and fk_projet_task in ('.$tasks.')))'; $sql .= ' GROUP BY t.recipient '; + $sql .= ' UNION SELECT \'0\' as nbtsk, COUNT(utt.rowid) as nbtm, \''.USER.'\' as recipient '; + $sql .= ' FROM '.MAIN_DB_PREFIX.'project_task_timesheet as utt'; + $sql .= ' WHERE utt.status = '.DRAFT.' AND utt.fk_userid= '.$userid; $result = $db->query($sql); if($result) { $num = $db->num_rows($result); while($num>0) { $obj = $db->fetch_object($result); - if($obj->recipient == 'project') { + if($obj->recipient == PROJECT) { $nbPrj = $obj->nbtsk; - } elseif($obj->recipient == 'team') { + } elseif($obj->recipient == TEAM) { $nbTm = $obj->nbtm; + }elseif($obj->recipient == USER) { + $nbUsr = $obj->nbtm; } $num--; } - $this->info_box_contents[0][] = array( - 'td' => 'align = "left"', - 'text' => $langs->trans('team').': ', - 'text2'=> $langs->trans('nbTsToApprove'), - 'asis' => 1, - ); - $this->info_box_contents[0][] = array( - 'td' => 'align = "right"', - 'text' => $nbTm, - 'asis' => 1, - ); - $this->info_box_contents[1][] = array( - 'td' => 'align = "left"', - 'text' => $langs->trans('project').': ', - 'text2'=> $langs->trans('nbTsToApprove'), - 'asis' => 1, - ); - $this->info_box_contents[1][] = array( - 'td' => 'align = "right"', - 'text' => $nbPrj, - 'asis' => 1, - ); + $i=0; + if($nbTm>0){ + $this->info_box_contents[$i][] = array( + 'td' => 'align = "left"', + 'text' => $langs->trans('team').': ', + 'text2'=> $langs->trans('nbTsToApprove'), + 'asis' => 1, + ); + $this->info_box_contents[$i][] = array( + 'td' => 'align = "right"', + 'text' => $nbTm, + 'asis' => 1, + ); + $i++; + } + if($nbPrj>0){ + $this->info_box_contents[$i][] = array( + 'td' => 'align = "left"', + 'text' => $langs->trans('project').': ', + 'text2'=> $langs->trans('nbTsToApprove'), + 'asis' => 1, + ); + $this->info_box_contents[$i][] = array( + 'td' => 'align = "right"', + 'text' => $nbPrj, + 'asis' => 1, + ); + $i++; + } + if($nbUsr>0){ + $this->info_box_contents[$i][] = array( + 'td' => 'align = "left"', + 'text' => $langs->trans('Timesheet').': ', + 'text2'=> $langs->trans('nbTsToSubmit'), + 'asis' => 1, + ); + $this->info_box_contents[$i][] = array( + 'td' => 'align = "right"', + 'text' => $nbUsr, + 'asis' => 1, + ); + $i++; + } $db->free($result); } else { $this->info_box_contents[0][0] = array( diff --git a/htdocs/timesheet/langs/de_DE/timesheet.lang b/htdocs/timesheet/langs/de_DE/timesheet.lang index b7b328fa..e590f557 100644 --- a/htdocs/timesheet/langs/de_DE/timesheet.lang +++ b/htdocs/timesheet/langs/de_DE/timesheet.lang @@ -236,3 +236,4 @@ updateError = Fehler während der Aktualisierung NoActiveEvent = Kein aktives Ereignis gefunden EventNotActive = Ereignis nicht aktiv DbError = Datenbank-Fehler +nbTsToSubmit = Anzahl der einzureichenden Stundenzettel diff --git a/htdocs/timesheet/langs/en_US/timesheet.lang b/htdocs/timesheet/langs/en_US/timesheet.lang index 6d40086a..5f2043a6 100644 --- a/htdocs/timesheet/langs/en_US/timesheet.lang +++ b/htdocs/timesheet/langs/en_US/timesheet.lang @@ -236,3 +236,4 @@ updateError = Error during update NoActiveEvent = No active event found EventNotActive = Event not active DbError = Database error +nbTsToSubmit = Number of timesheet to submit diff --git a/htdocs/timesheet/langs/es_ES/timesheet.lang b/htdocs/timesheet/langs/es_ES/timesheet.lang index 717b2d9a..41f366d9 100644 --- a/htdocs/timesheet/langs/es_ES/timesheet.lang +++ b/htdocs/timesheet/langs/es_ES/timesheet.lang @@ -236,3 +236,4 @@ updateError = Error durante la actualización NoActiveEvent = No se ha encontrado ningún evento activo EventNotActive = Evento no activo DbError = Error de la base de datos +nbTsToSubmit = Número de hoja de trabajo para enviar diff --git a/htdocs/timesheet/langs/fr_FR/timesheet.lang b/htdocs/timesheet/langs/fr_FR/timesheet.lang index 02334678..b6bd1c41 100644 --- a/htdocs/timesheet/langs/fr_FR/timesheet.lang +++ b/htdocs/timesheet/langs/fr_FR/timesheet.lang @@ -236,3 +236,4 @@ updateError = Erreur lors de la mise à jour NoActiveEvent = Aucun événement actif trouvé EventNotActive = Evénement non actif DbError = Erreur de base de données +nbTsToSubmit = Nombre de feuilles de temps à soumettre diff --git a/htdocs/timesheet/langs/it_IT/timesheet.lang b/htdocs/timesheet/langs/it_IT/timesheet.lang index 9520fb8a..77df900a 100644 --- a/htdocs/timesheet/langs/it_IT/timesheet.lang +++ b/htdocs/timesheet/langs/it_IT/timesheet.lang @@ -236,3 +236,4 @@ updateError = Errore durante l'aggiornamento NoActiveEvent = Nessun evento attivo trovato EventNotActive = Evento non attivo DbError = Errore del database +nbTsToSubmit = Numero di fogli di orario da presentare diff --git a/htdocs/timesheet/sql/llx_project_task_time_approval.sql b/htdocs/timesheet/sql/llx_project_task_time_approval.sql index 12b085d5..8fec7904 100644 --- a/htdocs/timesheet/sql/llx_project_task_time_approval.sql +++ b/htdocs/timesheet/sql/llx_project_task_time_approval.sql @@ -26,7 +26,7 @@ rowid serial , date_start DATE NOT NULL, -- start date of the period date_end DATE NOT NULL, -- start date of the period status integer default 1, -- enum('DRAFT','SUBMITTED','APPROVED','CANCELLED','REJECTED','CHALLENGED','INVOICED','UNDERAPPROVAL','PLANNED') DEFAULT 'DRAFT', -sender integer default 1, -- enum('team','project','customer','provider','other','user') DEFAULT 'user', -- a team ts is always needed +sender integer default 0, -- enum('team','project','customer','provider','other','user') DEFAULT 'user', -- a team ts is always needed recipient integer default 1, -- enum('team','project','customer','provider','other','user') DEFAULT 'team', -- a team ts is always needed note VARCHAR(1024), -- in case target is not team, querry on task planned_workload integer DEFAULT NULL, From b3d5e6067507490d8e5081b46ed9e21d1a779df5 Mon Sep 17 00:00:00 2001 From: Patrick Delcroix Date: Sun, 5 Jul 2020 12:46:57 +0200 Subject: [PATCH 7/9] code coherence --- htdocs/timesheet/class/TimesheetReport.class.php | 6 ++++-- htdocs/timesheet/class/TimesheetTask.class.php | 10 +++++----- htdocs/timesheet/core/lib/timesheet.lib.php | 6 ++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/htdocs/timesheet/class/TimesheetReport.class.php b/htdocs/timesheet/class/TimesheetReport.class.php index 3239e5fc..42b93b5e 100644 --- a/htdocs/timesheet/class/TimesheetReport.class.php +++ b/htdocs/timesheet/class/TimesheetReport.class.php @@ -267,7 +267,7 @@ public function getReportArray() $first = false; } if(is_array($this->taskarray) && count($this->taskarray)>1) { - $sql .= ($first?'':'AND ').'tsk.rowid in ('.explode($taskarray, ', ').') '; + $sql .= ($first?'':'AND ').'tsk.rowid in ('.explode($this->taskarray, ', ').') '; } if($this->invoiceableOnly == 1) { $sql .= ($first?'':'AND ').'tske.invoiceable = \'1\''; @@ -410,6 +410,7 @@ public function getHTMLreport($short, $periodTitle) { // HTML buffer global $langs; + $HTMLRes = ''; $lvl0HTML = $lvl1HTML = $lvl3HTML = $lvl2HTML = ''; // partial totals $lvl3Total = $lvl2Total = $lvl1Total = $lvl0Total = 0; @@ -669,8 +670,9 @@ public function getLvl0HTML($lvl0title, $lvl1Total, $lvl1HTML, $short) */ public function getLvl3HTML($item) { + $lvl3HTML = ''; $lvl3HTML .= '' - .$item[$this->lvl3Title].''; + .$item[$this->lvl3Link].''; $lvl3HTML .= $item['durationHours'].''; $lvl3HTML .= $item['durationDays'].''; $lvl3HTML .= $item['note']; diff --git a/htdocs/timesheet/class/TimesheetTask.class.php b/htdocs/timesheet/class/TimesheetTask.class.php index 1c47e445..0c896fe7 100644 --- a/htdocs/timesheet/class/TimesheetTask.class.php +++ b/htdocs/timesheet/class/TimesheetTask.class.php @@ -543,7 +543,7 @@ public function getActuals($timeStart = 0, $timeEnd = 0, $userid = 0) if($dayelapsed<1)return -1; $sql = "SELECT ptt.rowid, ptt.task_duration, DATE(ptt.task_datehour) AS task_date, ptt.note"; if(version_compare(DOL_VERSION, "4.9.9") >= 0) { - $sql .= ', (ptt.invoice_id > 0) AS invoiced'; + $sql .= ', (ptt.invoice_id > 0 or invoice_line_id>0) AS invoiced'; }else{ $sql .= ', 0 AS invoiced'; } @@ -616,7 +616,7 @@ public function getTimesheetLine($headers, $tsUserId = 0, $openOveride = 0) $htmltail = ''; $linestyle = ''; if(($this->pStatus == "2")) { - $linestyle .= 'background:#'.$statusColor['FROZEN'].';'; + $linestyle .= 'background:#'.$statusColor[FROZEN].';'; } elseif($statusColor[$this->status]!='' && $statusColor[$this->status]!='FFFFFF') { $linestyle .= 'background:#'.$statusColor[$this->status].';'; } @@ -695,14 +695,14 @@ public function getHTMLLineDayCell($isOpenStatus) $bkcolor = ''; if(!$isOpenDay){ - $bkcolor = 'background:#'.$statusColor['FROZEN']; + $bkcolor = 'background:#'.$statusColor[FROZEN]; }elseif($isOpen) { $bkcolor = 'background:#'.$statusColor[$this->status]; if($dayWorkLoadSec!=0 && $this->status == DRAFT){ - $bkcolor = 'background:#'.$statusColor['VALUE']; + $bkcolor = 'background:#'.$statusColor[VALUE]; } }else { - $bkcolor = 'background:#'.$statusColor['FROZEN']; + $bkcolor = 'background:#'.$statusColor[FROZEN]; } if($isInvoiced){ $bkcolor = 'background:#'.$statusColor[INVOICED]; diff --git a/htdocs/timesheet/core/lib/timesheet.lib.php b/htdocs/timesheet/core/lib/timesheet.lib.php index ef280f46..81df3573 100644 --- a/htdocs/timesheet/core/lib/timesheet.lib.php +++ b/htdocs/timesheet/core/lib/timesheet.lib.php @@ -27,6 +27,8 @@ Define("UNDERAPPROVAL", 8); Define("PLANNED", 9); Define("STATUSMAX", 10); +Define("VALUE", 100); +Define("FROZEN", 101); //APPFLOW //const LINKED_ITEM = [ Define("USER", 0); @@ -40,8 +42,8 @@ // back ground colors $statusColor = array( DRAFT=>$conf->global->TIMESHEET_COL_DRAFT, - 'VALUE'=>$conf->global->TIMESHEET_COL_VALUE, - 'FROZEN'=>$conf->global->TIMESHEET_COL_FROZEN, + VALUE=>$conf->global->TIMESHEET_COL_VALUE, + FROZEN=>$conf->global->TIMESHEET_COL_FROZEN, SUBMITTED=>$conf->global->TIMESHEET_COL_SUBMITTED, APPROVED=>$conf->global->TIMESHEET_COL_APPROVED, CANCELLED=>$conf->global->TIMESHEET_COL_CANCELLED, From 1368c1972ec729569e04633efa159ce3716ce3d6 Mon Sep 17 00:00:00 2001 From: Patrick Delcroix Date: Sun, 5 Jul 2020 17:29:08 +0200 Subject: [PATCH 8/9] new: add invoiced column in reports --- htdocs/timesheet/ChangeLog.md | 4 + htdocs/timesheet/TimesheetReportProject.php | 48 ++-- htdocs/timesheet/TimesheetReportUser.php | 52 ++-- htdocs/timesheet/admin/timesheetsetup.php | 18 +- .../timesheet/class/TimesheetReport.class.php | 227 ++++++++++++------ .../timesheet/class/TimesheetTask.class.php | 2 +- .../core/modules/modtimesheet.class.php | 2 +- .../core/modules/pdf/pdf_rat.modules.php | 2 +- htdocs/timesheet/langs/de_DE/timesheet.lang | 4 + htdocs/timesheet/langs/en_US/timesheet.lang | 4 + htdocs/timesheet/langs/es_ES/timesheet.lang | 4 + htdocs/timesheet/langs/fr_FR/timesheet.lang | 4 + htdocs/timesheet/langs/it_IT/timesheet.lang | 4 + 13 files changed, 259 insertions(+), 116 deletions(-) diff --git a/htdocs/timesheet/ChangeLog.md b/htdocs/timesheet/ChangeLog.md index f0e4d8d3..db6922d0 100644 --- a/htdocs/timesheet/ChangeLog.md +++ b/htdocs/timesheet/ChangeLog.md @@ -1,4 +1,8 @@ # dolibarr_project_timesheet changelog +4.3.0 +- new: possibility to ungroup reports +- + 4.2.2 - new: show the time not editable (when there is several task time for ady/task) diff --git a/htdocs/timesheet/TimesheetReportProject.php b/htdocs/timesheet/TimesheetReportProject.php index 6bbc464c..feefa2a2 100644 --- a/htdocs/timesheet/TimesheetReportProject.php +++ b/htdocs/timesheet/TimesheetReportProject.php @@ -30,10 +30,17 @@ $exportfriendly = GETPOST('exportfriendly', 'alpha'); $optioncss = GETPOST('optioncss', 'alpha'); $short = GETPOST('short', 'int'); +$invoicedCol = GETPOST('invoicedcol', 'int'); + +$ungroup = GETPOST('ungroup', 'int'); + $mode = GETPOST('mode', 'alpha'); + $model = GETPOST('model', 'alpha'); if(empty($mode)){ $mode = 'UTD'; + $ungroup = $conf->global->TIMESHEET_REPORT_UNGROUP; + $invoicedCol = $conf->global->TIMESHEET_REPORT_INVOICED_COL; } $projectSelectedId = GETPOST('projectSelected'); @@ -108,7 +115,7 @@ $projectIdlist = array_keys($projectList); } $reportStatic = new TimesheetReport($db); -$reportStatic->initBasic($projectIdlist, '', '', $dateStart, $dateEnd, $mode, $invoicabletaskOnly); +$reportStatic->initBasic($projectIdlist, '', '', $dateStart, $dateEnd, $mode, $invoicabletaskOnly,$short,$invoicedCol,$ungroup); if($action == 'getpdf') { $pdf = new pdf_rat($db); //$outputlangs = $langs; @@ -169,10 +176,8 @@ '.$langs->trans('Project').' '.$langs->trans('DateStart').' '.$langs->trans('DateEnd').' - '.$langs->trans('short').' - '.$langs->trans('InvoicableOnly').' - '.$langs->trans('exportfriendly').' '.$langs->trans('Mode').' + '.$langs->trans('Options').' @@ -191,15 +196,6 @@ // select end date $Form .= ''.$form->select_date($dateEnd, 'dateEnd', 0, 0, 0, "", 1, 1, 1).""; //$Form .= ' '.$htmlother->select_month($month, 'month').' - '.$htmlother->selectyear($year, 'year', 0, 10, 3) -// Select short -$Form .= ' ':'>').'' ; -// Select invoiceable only -$Form .= '':'>').''; -// Select Export friendly -$Form .= '':'>').''; // Select mode $Form .= 'trans('User').' / '.$langs->trans('Task').' / '.$langs->trans('Date').'
'; @@ -208,15 +204,33 @@ $Form .= 'trans('Date').' / '.$langs->trans('User').' / '.$langs->trans('Task').'
'; - $Form .= ''; + $Form .= ''; +// select short +$Form .= ' ':'>').$langs->trans('short').'
' ; +// Select invoiceable only +$Form .= '':'>').$langs->trans('InvoicableOnly').'
'; +// Select Export friendly +$Form .= '':'>').$langs->trans('exportfriendly').'
'; +// Select show invoice +$Form .= '':'>'). $langs->trans('reportInvoicedCol').'
'; +// Select Export friendly +$Form .= '':'>').$langs->trans('reportUngroup').''; + + $Form .= ''; + //submit $model = $conf->global->TIMESHEET_EXPORT_FORMAT; $Form .= ''; if(!empty($querryRes) && ($user->rights->facture->creer || version_compare(DOL_VERSION, "3.7") <= 0))$Form .= ''.$langs->trans('Invoice').''; -if(!empty($querryRes))$Form .= ''.$langs->trans('TimesheetPDF').''; -if(!empty($querryRes) && $conf->global->MAIN_MODULE_EXPORT)$Form .= ''.$langs->trans('Export').''; -if(!empty($querryRes))$Form .= ''.$langs->trans('Refresh').''; +if(!empty($querryRes))$Form .= ''.$langs->trans('TimesheetPDF').''; +if(!empty($querryRes) && $conf->global->MAIN_MODULE_EXPORT)$Form .= ''.$langs->trans('Export').''; +if(!empty($querryRes))$Form .= ''.$langs->trans('Refresh').''; $Form .= ''; if(!($optioncss != '' && !empty($_POST['userSelected']))) echo $Form; echo $querryRes; diff --git a/htdocs/timesheet/TimesheetReportUser.php b/htdocs/timesheet/TimesheetReportUser.php index 8fb95e0c..01a56a64 100644 --- a/htdocs/timesheet/TimesheetReportUser.php +++ b/htdocs/timesheet/TimesheetReportUser.php @@ -42,11 +42,21 @@ //$toDatemonth = GETPOST('toDatemonth', 'int'); //$toDateyear = GETPOST('toDateyear', 'int'); $mode = GETPOST('mode', 'alpha'); +$short = GETPOST('short', 'int'); +$invoicedCol = GETPOST('invoicedcol', 'int'); +$ungroup = GETPOST('ungroup', 'int'); $model = GETPOST('model', 'alpha'); -if(empty($mode))$mode = 'PTD'; -$short = GETPOST('short', 'int');; +if(empty($mode)){ + $mode = 'PTD'; + $ungroup = $conf->global->TIMESHEET_REPORT_UNGROUP; + $invoicedCol = $conf->global->TIMESHEET_REPORT_INVOICED_COL; +} +$short = GETPOST('short', 'int'); +$invoicedCol = GETPOST('invoicedcol', 'int'); +$ungroup = GETPOST('ungroup', 'int'); + //$userSelected = $userList[$userIdSelected]; -$year = GETPOST('year', 'int');; +$year = GETPOST('year', 'int'); //$month = GETPOST('month', 'int');;//strtotime(str_replace('/', '-', $_POST['Date'])); //$firstDay = ($month)?strtotime('01-'.$month.'-'. $year):strtotime('first day of previous month'); //$lastDay = ($month)?strtotime('last day of this month', $firstDay):strtotime('last day of previous month'); @@ -110,7 +120,7 @@ $userIdlist = array_keys($userList); } $reportStatic = new TimesheetReport($db); -$reportStatic->initBasic('', $userIdlist, $reportName, $dateStart, $dateEnd, $mode, $invoicabletaskOnly); +$reportStatic->initBasic('', $userIdlist, $reportName, $dateStart, $dateEnd, $mode, $invoicabletaskOnly,$short,$invoicedCol,$ungroup); if($action == 'getpdf') { $pdf = new pdf_rat($db); //$outputlangs = $langs; @@ -163,11 +173,8 @@ '.$langs->trans('User').' '.$langs->trans('DateStart').' '.$langs->trans('DateEnd').' - '.$langs->trans('short').' - '.$langs->trans('InvoicableOnly').' - '.$langs->trans('exportfriendly').' '.$langs->trans('Mode').' - + '.$langs->trans('Options').' ':'>').'' ; -// Select invoiceable only -$Form .= '':'>').''; -// Select Export friendly -$Form .= '':'>').''; // Select mode $Form .= 'trans('Project').' / '.$langs->trans('Task').' / '.$langs->trans('Date').'
'; @@ -209,11 +208,28 @@ $Form .= '> '.$langs->trans('Project').' / '.$langs->trans('Date').' / '.$langs->trans('Task').'
'; $Form .= 'trans('Date').' / '.$langs->trans('Project').' / '.$langs->trans('Task').'
'; - $Form .= ''; + $Form .= ''; +// select short +$Form .= ' ':'>').$langs->trans('short').'
' ; +// Select invoiceable only +$Form .= '':'>').$langs->trans('InvoicableOnly').'
'; +// Select Export friendly +$Form .= '':'>').$langs->trans('exportfriendly').'
'; +// Select show invoice +$Form .= '':'>'). $langs->trans('reportInvoicedCol').'
'; +// Select Export friendly +$Form .= '':'>').$langs->trans('reportUngroup').''; + + $Form .= ''; $Form .= ''; $model = $conf->global->TIMESHEET_EXPORT_FORMAT; //if(!empty($querryRes))$Form .= ''.$langs->trans('TimesheetPDF').''; -if(!empty($querryRes) && $conf->global->MAIN_MODULE_EXPORT)$Form .= ''.$langs->trans('Export').''; +if(!empty($querryRes) && $conf->global->MAIN_MODULE_EXPORT)$Form .= ''.$langs->trans('Export').''; $Form .= ''; if(!($optioncss != '' && !empty($userIdSelected))) echo $Form; // section to generate diff --git a/htdocs/timesheet/admin/timesheetsetup.php b/htdocs/timesheet/admin/timesheetsetup.php index f8072348..1588337a 100644 --- a/htdocs/timesheet/admin/timesheetsetup.php +++ b/htdocs/timesheet/admin/timesheetsetup.php @@ -93,7 +93,8 @@ $searchbox = intval($conf->global->TIMESHEET_SEARCHBOX); $unblockInvoiced = $conf->global->TIMESHEET_UNBLOCK_INVOICED; $unblockClosed = $conf->global->TIMESHEET_UNBLOCK_CLOSED; - +$reportInvoicedCol= $conf->global->TIMESHEET_REPORT_INVOICED_COL; +$reportUngroup = $conf->global->TIMESHEET_REPORT_UNGROUP; if(count($opendays)!=8) { $opendays = array('_', '0', '0', '0', '0', '0', '0', '0'); @@ -253,6 +254,10 @@ function null2int($var, $int = 0) dolibarr_set_const($db, "TIMESHEET_UNBLOCK_INVOICED", $unblockInvoiced, 'int', 0, '', $conf->entity); $unblockClosed = getpost('unblockClosed', 'int'); dolibarr_set_const($db, "TIMESHEET_UNBLOCK_CLOSED", $unblockClosed, 'int', 0, '', $conf->entity); + $reportInvoicedCol = getpost('reportInvoicedCol', 'int'); + dolibarr_set_const($db, "TIMESHEET_REPORT_INVOICED_COL", $reportInvoicedCol, 'int', 0, '', $conf->entity); + $reportUngroup = getpost('reportUngroup', 'int'); + dolibarr_set_const($db, "TIMESHEET_REPORT_UNGROUP", $reportUngroup, 'int', 0, '', $conf->entity); $tsRound = getpost('tsRound', 'int'); dolibarr_set_const($db, "TIMESHEET_ROUND", $tsRound, 'int', 0, '', $conf->entity); @@ -645,6 +650,17 @@ function null2int($var, $int = 0) echo ''.$langs->trans("unblockClosedDesc").''; echo '\n\t\t"; +// show invoiced col in reports +echo ''.$langs->trans("reportInvoicedCol"); +echo ''.$langs->trans("reportInvoicedColDesc").''; +echo '\n\t\t"; +// ungroup lvl3 reports +echo ''.$langs->trans("reportUngroup"); +echo ''.$langs->trans("reportUngroupDesc").''; +echo '\n\t\t"; + echo ''."\n\t\t"; diff --git a/htdocs/timesheet/class/TimesheetReport.class.php b/htdocs/timesheet/class/TimesheetReport.class.php index 42b93b5e..3a38a6eb 100644 --- a/htdocs/timesheet/class/TimesheetReport.class.php +++ b/htdocs/timesheet/class/TimesheetReport.class.php @@ -46,6 +46,9 @@ class TimesheetReport public $thirdparty; public $project; public $user; + public $short; + public $ungroup; + public $invoicedCol; /** constructor * * @param DATABASE $db db object @@ -68,7 +71,7 @@ public function __construct($db) * @param int[] $taskarray array of task id on which the report should be * @return null */ - public function initBasic($projectid, $userid, $name, $startDate, $stopDate, $mode, $invoiceableOnly = '0', $taskarray = null) + public function initBasic($projectid, $userid, $name, $startDate, $stopDate, $mode, $invoiceableOnly = '0',$short = 0,$invoicedCol = 0,$ungroup = 0, $taskarray = null) { global $conf, $user, $langs; if($userid && !$user->admin && empty($projectid)){ @@ -118,6 +121,9 @@ public function initBasic($projectid, $userid, $name, $startDate, $stopDate, $mo $this->startDate = $startDate; $this->stopDate = $stopDate; $this->mode = $mode; + $this->short = $short; + $this->ungroup = $ungroup; + $this->invoicedCol = $invoicedCol; if(count($this->ref) == 1){ $this->name = reset($this->ref); }else{ @@ -231,32 +237,34 @@ public function initBasic($projectid, $userid, $name, $startDate, $stopDate, $mo } } /* Function to generate array for the resport - * @param int $invoiceableOnly will return only the invoicable task - * @param array(int) $taskarray return the report only for those tasks - * @param string $sqltail sql tail after the where + * @param int $forceGroup will return only the invoicable task * @return array() */ - public function getReportArray() + public function getReportArray($forceGroup = false) { global $conf; $resArray = array(); $first = true; - $sql = 'SELECT tsk.fk_projet as projectid, ptt.fk_user as userid, tsk.fk_projet as taskid,'; - if($this->db->type!='pgsql') { -// $sql .= ' MAX(prj.title) as projecttitle, MAX(prj.ref) as projectref, MAX(usr.firstname) as firstname, MAX(usr.lastname) as lastname, '; -// $sql .= " MAX(tsk.ref) as taskref, MAX(tsk.label) as tasktitle,"; - $sql .= " GROUP_CONCAT(ptt.note SEPARATOR '. ') as note, MAX(tske.invoiceable) as invoicable, "; - } else { -// $sql .= ' prj.title as projecttitle, prj.ref as projectref, usr.firstname, usr.lastname, '; -// $sql .= " tsk.ref as taskref, tsk.label as tasktitle,"; - $sql .= " STRING_AGG(ptt.note, '. ') as note, MAX(tske.invoiceable) as invoicable, "; + $sql = 'SELECT tsk.fk_projet as projectid, ptt.fk_user as userid, tsk.fk_projet as taskid, ptt.rowid as id,'; + if(version_compare(DOL_VERSION, "4.9.9") >= 0) { + $sql .= ' (ptt.invoice_id > 0 or ptt.invoice_line_id>0) AS invoiced,'; + }else{ + $sql .= ' 0 AS invoiced,'; } - $sql .= ' DATE(ptt.task_datehour) AS task_date, SUM(ptt.task_duration) as duration '; + if($forceGroup == 1){ + if($this->db->type!='pgsql') { + $sql .= " GROUP_CONCAT(ptt.note SEPARATOR '. ') as note, MAX(tske.invoiceable) as invoicable, "; + } else { + $sql .= " STRING_AGG(ptt.note, '. ') as note, MAX(tske.invoiceable) as invoicable, "; + } + $sql .= ' DATE(ptt.task_datehour) AS task_date, SUM(ptt.task_duration) as duration '; + }else{ + $sql .= " ptt.note as note, tske.invoiceable as invoicable, "; + $sql .= ' DATE(ptt.task_datehour) AS task_date, ptt.task_duration as duration '; + } $sql .= ' FROM '.MAIN_DB_PREFIX.'projet_task_time as ptt '; $sql .= ' JOIN '.MAIN_DB_PREFIX.'projet_task as tsk ON tsk.rowid = fk_task '; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'projet_task_extrafields as tske ON tske.fk_object = fk_task '; - // $sql .= ' JOIN '.MAIN_DB_PREFIX.'projet as prj ON prj.rowid = tsk.fk_projet '; - // $sql .= ' JOIN '.MAIN_DB_PREFIX.'user as usr ON ptt.fk_user = usr.rowid '; $sql .= ' WHERE '; if(!empty($this->userid)) { $sql .= ' ptt.fk_user IN (\''.implode("','", $this->userid).'\') '; @@ -272,14 +280,10 @@ public function getReportArray() if($this->invoiceableOnly == 1) { $sql .= ($first?'':'AND ').'tske.invoiceable = \'1\''; } - /*if(!empty($startDay))$sql .= 'AND task_date >= \''.$this->db->idate($startDay).'\''; - else */$sql .= ($first?'':'AND ').' DATE(task_datehour) >= \''.$this->db->idate($this->startDate).'\''; - /*if(!empty($stopDay))$sql .= ' AND task_date <= \''.$this->db->idate($stopDay).'\''; - else */$sql .= ' AND DATE(task_datehour) <= \''.$this->db->idate($this->stopDate).'\''; - $sql .= ' GROUP BY ptt.fk_user, tsk.fk_projet, tsk.rowid, DATE(ptt.task_datehour) '; - /*if(!empty($sqltail)) { - $sql .= $sqltail; - }*/ + $sql .= ($first?'':'AND ').' DATE(task_datehour) >= \''.$this->db->idate($this->startDate).'\''; + $sql .= ' AND DATE(task_datehour) <= \''.$this->db->idate($this->stopDate).'\''; + $sql .= ' AND (ptt.task_duration > 0 or LENGTH(ptt.note)>0)'; + if($forceGroup == 1)$sql .= ' GROUP BY ptt.fk_user, tsk.fk_projet, tsk.rowid, DATE(ptt.task_datehour) '; $sql .= $this->modeSQLOrder; dol_syslog(__METHOD__, LOG_DEBUG); $resql = $this->db->query($sql); @@ -312,7 +316,7 @@ public function getReportArray() $objpjt->fetch($obj->projectid); $odlpjtid = $obj->projectid; } - $resArray[$i] = array('projectId' => $obj->projectid, + $resArray[$obj->id] = array('projectId' => $obj->projectid, 'projectLabel' => $objpjt->ref.(($conf->global->TIMESHEET_HIDE_REF == 0)?'':' - '.$objpjt->title), 'projectRef' => $objpjt->ref, 'projectTitle' => $objpjt->title, @@ -333,7 +337,8 @@ public function getReportArray() 'lastName' => trim($objusr->lastname), 'userLink' => $objusr->getNomUrl(0), 'note' =>($obj->note), - 'invoiceable' => $obj->invoiceable); + 'invoiceable' => ($obj->invoiceable==1)?'1':'0', + 'invoiced' => ($obj->invoiced==1)?'1':'0'); $i++; } $this->db->free($resql); @@ -381,7 +386,7 @@ public function getHTMLreportExport() */ public function getHTMLReportHeaders() { - global $langs; + global $langs,$conf;; $HTMLHeaders = '

'.$this->name.'

'; $title = array('projectLabel' => 'Project', 'dateDisplay' => 'Day', 'taskLabel' => 'Tasks', 'userName' => 'User'); $titleWidth = array('4' => '120', '7' => '200'); @@ -390,32 +395,35 @@ public function getHTMLReportHeaders() $HTMLHeaders .= ''.$langs->trans($title[$this->lvl0Title]).''; $HTMLHeaders .= ''.$langs->trans($title[$this->lvl1Title]).''; $HTMLHeaders .= ''.$langs->trans($title[$this->lvl2Title]).''; - $HTMLHeaders .= ''.$langs->trans($title[$this->lvl3Title]).''; + if($this->short == 0)$HTMLHeaders .= ''.$langs->trans($title[$this->lvl3Title]).''; $HTMLHeaders .= ''.$langs->trans('Duration').':'.$langs->trans('hours').''; $HTMLHeaders .= ''.$langs->trans('Duration').':'.$langs->trans('Days').''; - $HTMLHeaders .= ''.$langs->trans('Note').''; + $HTMLHeaders .= ''.$langs->trans('Note').''; + if($this->invoicedCol == 1) $HTMLHeaders .= ''.$langs->trans('Invoiced').''; + $HTMLHeaders .= ''; return $HTMLHeaders; } /** * Function to generate HTML for the report - * @param string $short show or hide the lvl3 detail * @param string $periodTitle title of the period * @return string * mode layout PTD project/task /day, PDT, DPT * periodeTitle give a name to the report * timemode show time using day or hours(== 0) */ - public function getHTMLreport($short, $periodTitle) + public function getHTMLreport( $periodTitle) { // HTML buffer - global $langs; + global $langs,$conf; $HTMLRes = ''; $lvl0HTML = $lvl1HTML = $lvl3HTML = $lvl2HTML = ''; // partial totals - $lvl3Total = $lvl2Total = $lvl1Total = $lvl0Total = 0; + $lvl3SubTotal = $lvl3Total = $lvl2Total = $lvl1Total = $lvl0Total = 0; $Curlvl0 = $Curlvl1 = $Curlvl2 = $Curlvl3 = 0; $lvl3Notes = ""; + $lvl3SubNotes = ""; + $lvl3SubInvoiced = ''; $sqltail = ''; $resArray = $this->getReportArray(); $numTaskTime = count($resArray); @@ -423,10 +431,17 @@ public function getHTMLreport($short, $periodTitle) $Curlvl0 = 0; // related to get array $Curlvl1 = 0; $Curlvl2 = 0; + $Curlvl3 = ''; + $lvl3SubPrev = 0; if($numTaskTime > 0){ // current - foreach($resArray as $key => $item) { + if($i == 0){ + $Curlvl0 = $key; // related to get array + $Curlvl1 = $key; + $Curlvl2 = $key; + $Curlvl3 = $item[$this->lvl3Title]; + } // reformat date to avoid UNIX time //add the LVL 2 total when change detected in Lvl 2 & 1 &0 @@ -435,11 +450,13 @@ public function getHTMLreport($short, $periodTitle) || ($resArray[$Curlvl0][$this->lvl0Key] != $item[$this->lvl0Key])) { //Link, total,short, lvl3Html, lvl3 notes - $lvl2HTML .= $this->getLvl2HTML($resArray[$Curlvl2][$this->lvl2Link], $lvl3Total, $lvl3HTML, $short, $lvl3Notes); + $lvl2HTML .= $this->getLvl2HTML($resArray[$Curlvl2][$this->lvl2Link], $lvl3Total, $lvl3HTML, $lvl3Notes); //empty lvl 3 Notes to start anew $lvl3Notes = ''; //empty lvl 3 HTML to start anew $lvl3HTML = ''; + // empty lvl3 invoiced + $lvl3Invoice = ''; //add the LVL 3 total to LVL3 $lvl2Total += $lvl3Total; //empty lvl 3 total to start anew @@ -450,7 +467,7 @@ public function getHTMLreport($short, $periodTitle) if(($resArray[$Curlvl1][$this->lvl1Key] != $item[$this->lvl1Key]) ||($resArray[$Curlvl0][$this->lvl0Key] != $item[$this->lvl0Key])) { - $lvl1HTML .= $this->getLvl1HTML($resArray[$Curlvl1][$this->lvl1Link], $lvl2Total, $lvl2HTML, $short); + $lvl1HTML .= $this->getLvl1HTML($resArray[$Curlvl1][$this->lvl1Link], $lvl2Total, $lvl2HTML); //addlvl 2 total to lvl1 $lvl1Total += $lvl2Total; //empty lvl 2 total tyo start anew @@ -461,7 +478,7 @@ public function getHTMLreport($short, $periodTitle) //creat the LVL 0 Link line when lvl 0 change detected if(($resArray[$Curlvl0][$this->lvl0Key]!=$item[$this->lvl0Key])) { - $lvl0HTML .= $this->getLvl0HTML($resArray[$Curlvl0][$this->lvl0Link], $lvl1Total, $lvl1HTML, $short); + $lvl0HTML .= $this->getLvl0HTML($resArray[$Curlvl0][$this->lvl0Link], $lvl1Total, $lvl1HTML); //addlvl 2 total to lvl1 $lvl0Total += $lvl1Total; //empty lvl 2 total tyo start anew @@ -472,16 +489,52 @@ public function getHTMLreport($short, $periodTitle) } } } - // show the LVL 3 only if not short - if(!$short) { - $lvl3HTML .= $this->getLvl3HTML($item); - } elseif(!empty($item['note'])) { - $lvl3Notes .= "
".$item['note']; + + // add lvl3 lines + if(!empty($item['note'])) { + if(strlen($lvl3Notes)>0) $lvl3Notes .= "
"; + $lvl3Notes .= $item['note']; } $lvl3Total += $item['duration']; + // show the LVL 3 only if not short + if($this->short == 0) { + if($this->ungroup == 0){ + // erase previous value + if($item[$this->lvl3Title] != $Curlvl3 + || ($resArray[$Curlvl2][$this->lvl2Key] != $item[$this->lvl2Key]) + || ($resArray[$Curlvl1][$this->lvl1Key] != $item[$this->lvl1Key]) + || ($resArray[$Curlvl0][$this->lvl0Key] != $item[$this->lvl0Key])){ + $lvl3HTML .= $this->getLvl3HTML($item[$this->lvl3Link], $lvl3SubTotal, $lvl3SubNotes, $lvl3SubInvoiced); + $Curlvl3 = $item[$this->lvl3Title]; + $lvl3SubTotal = 0; + $lvl3SubNotes = ''; + $lvl3SubPrev = 0; + $lvl3SubInvoiced = ''; + } + if(is_numeric($lvl3SubInvoiced)>0){ + $lvl3SubInvoiced = 'id['.$lvl3SubPrev.']:'.$lvl3SubInvoiced."
"; + $lvl3SubInvoiced .= 'id['.$key.']:'.$item['invoiced']; + }elseif(strlen($lvl3SubInvoiced)>0) + { + $lvl3SubInvoiced .= "
"; + $lvl3SubInvoiced .= 'id['.$key.']:'.$item['invoiced']; + }else{ + $lvl3SubInvoiced = $item['invoiced']; + } + $lvl3SubPrev = $key; + $lvl3SubTotal += $item['duration']; + if(strlen($lvl3SubNotes)>0) $lvl3SubNotes .= "
"; + $lvl3SubNotes .= $item['note']; + }else{ + $lvl3HTML .= $this->getLvl3HTML($item[$this->lvl3Link], $item['duration'], $item['note'], $item['invoiced']); + } + + } $i++; + // show the last block if ( $i == $numTaskTime){ - $lvl2HTML .= $this->getLvl2HTML($resArray[$Curlvl2][$this->lvl2Link], $lvl3Total, $lvl3HTML, $short, $lvl3Notes); + if($this->ungroup == 0 && $this->short == 0) $lvl3HTML .= $this->getLvl3HTML($item[$this->lvl3Link], $lvl3SubTotal, $lvl3SubNotes, $lvl3SubInvoiced); + $lvl2HTML .= $this->getLvl2HTML($resArray[$Curlvl2][$this->lvl2Link], $lvl3Total, $lvl3HTML, $lvl3Notes); //empty lvl 3 Notes to start anew $lvl3Notes = ''; //empty lvl 3 HTML to start anew @@ -491,15 +544,15 @@ public function getHTMLreport($short, $periodTitle) //empty lvl 3 total to start anew $lvl3Total = 0; //creat the LVL 1 Link line - $lvl1HTML .= $this->getLvl1HTML($resArray[$Curlvl1][$this->lvl1Link], $lvl2Total, $lvl2HTML, $short); + $lvl1HTML .= $this->getLvl1HTML($resArray[$Curlvl1][$this->lvl1Link], $lvl2Total, $lvl2HTML); //addlvl 2 total to lvl1 $lvl1Total += $lvl2Total; //empty lvl 2 total tyo start anew $lvl2HTML = ''; $lvl2Total = 0; } - } + } - $lvl0HTML .= $this->getLvl0HTML($resArray[$Curlvl0][$this->lvl0Link], $lvl1Total, $lvl1HTML, $short); + $lvl0HTML .= $this->getLvl0HTML($resArray[$Curlvl0][$this->lvl0Link], $lvl1Total, $lvl1HTML); $lvl0Total += $lvl1Total; // make the whole result $HTMLRes .= $lvl0HTML; @@ -529,11 +582,11 @@ public function buildFile($model = 'excel2017', $save = false) $classname = "Export".ucfirst($model); require_once $dir.$file; $objmodel = new $classname($this->db); - $arrayTitle = array('projectRef' => 'projectRef', 'projectTitle' => 'projectTitle', 'taskRef' => 'taskRef', 'tasktitle' => 'taskTitle', 'dateDisplay' => 'Date', 'durationHours' => 'Hours', 'durationDays' => 'Days', 'userId' => 'userId', 'firstName' => 'Firstname', 'lastName' => 'Lastname', 'note' => 'Note', 'invoiceable' => 'Invoiceable'); - $arrayTypes = array('projectRef' => 'TextAuto', 'projectTitle' => 'TextAuto', 'taskRef' => 'TextAuto', 'tasktitle' => 'TextAuto', 'dateDisplay' => 'Date', 'durationHours' => 'TextAuto', 'durationDays' => 'Numeric', 'userId' => 'Numeric', 'firstName' => 'TextAuto', 'lastName' => 'TextAuto', 'note' => 'TextAuto', 'invoiceable' => 'Numeric'); - $arraySelected = array('projectRef' => 'projectRef', 'projectTitle' => 'projectTitle', 'taskRef' => 'taskRef', 'tasktitle' => 'tasktitle', 'userId' => 'userId', 'firstName' => 'firstName', 'lastName' => 'lastName', 'dateDisplay' => 'date', 'durationHours' => 'durationHours', 'durationDays' => 'durationDays', 'note' => 'note', 'invoiceable' => 'invoiceable'); + $arrayTitle = array('projectRef' => 'projectRef', 'projectTitle' => 'projectTitle', 'taskRef' => 'taskRef', 'tasktitle' => 'taskTitle', 'dateDisplay' => 'Date', 'durationHours' => 'Hours', 'durationDays' => 'Days', 'userId' => 'userId', 'firstName' => 'Firstname', 'lastName' => 'Lastname', 'note' => 'Note', 'invoiceable' => 'Invoiceable','invoiced' => 'Invoiced'); + $arrayTypes = array('projectRef' => 'TextAuto', 'projectTitle' => 'TextAuto', 'taskRef' => 'TextAuto', 'tasktitle' => 'TextAuto', 'dateDisplay' => 'Date', 'durationHours' => 'TextAuto', 'durationDays' => 'Numeric', 'userId' => 'Numeric', 'firstName' => 'TextAuto', 'lastName' => 'TextAuto', 'note' => 'TextAuto', 'invoiceable' => 'Numeric','invoiced' => 'TextAuto'); + $arraySelected = array('projectRef' => 'projectRef', 'projectTitle' => 'projectTitle', 'taskRef' => 'taskRef', 'tasktitle' => 'tasktitle', 'userId' => 'userId', 'firstName' => 'firstName', 'lastName' => 'lastName', 'dateDisplay' => 'date', 'durationHours' => 'durationHours', 'durationDays' => 'durationDays', 'note' => 'note', 'invoiceable' => 'invoiceable','invoiced' => 'invoiced'); - $resArray = $this->getReportArray(); + $resArray = $this->getReportArray(!($this->ungroup ==1)); if(is_array($resArray)) { @@ -598,22 +651,26 @@ public function buildFile($model = 'excel2017', $save = false) * @param string $lvl2title title to show * @param int $lvl3Total total to show * @param string $lvl3HTML LV3 content to embed - * @param bool $short hide lvl3 * @param string $lvl3Notes Lvl3 in case lvl3 details is hiden * @return string */ - public function getLvl2HTML($lvl2title, $lvl3Total, $lvl3HTML, $short, $lvl3Notes) + public function getLvl2HTML($lvl2title, $lvl3Total, $lvl3HTML, $lvl3Notes) { - $lvl2HTML .= '' + global $conf; + $lvl2HTML = '' .$lvl2title.''; // add an empty cell on row if short version(in none short mode tdere is an additionnal column - if(!$short)$lvl2HTML .= ''; + if($this->short == 0)$lvl2HTML .= ''; // add tde LVL 3 total hours on tde LVL 2 title $lvl2HTML .= ''.formatTime($lvl3Total, 0).''; // add tde LVL 3 total day on tde LVL 2 title $lvl2HTML .= ''.formatTime($lvl3Total, -3).''; - if($short) { + if($this->short == 1) { $lvl2HTML .= $lvl3Notes; + + } + if ($this->invoicedCol){ + $lvl2HTML .= ""; } $lvl2HTML .= ''; //add the LVL 3 content(details) @@ -628,14 +685,19 @@ public function getLvl2HTML($lvl2title, $lvl3Total, $lvl3HTML, $short, $lvl3Note * @param bool $short hide lvl3 * @return string */ - public function getLvl1HTML($lvl1title, $lvl2Total, $lvl2HTML, $short) + public function getLvl1HTML($lvl1title, $lvl2Total, $lvl2HTML) { - $lvl1HTML .= '' + global $conf; + $lvl1HTML = '' .$lvl1title.''; // add an empty cell on row if short version(in none short mode there is an additionnal column - if(!$short)$lvl1HTML .= ''; + if($this->short == 0)$lvl1HTML .= ''; $lvl1HTML .= ''.formatTime($lvl2Total, 0).''; - $lvl1HTML .= ''.formatTime($lvl2Total, -3).''; + $lvl1HTML .= ''.formatTime($lvl2Total, -3).''; + if ($this->invoicedCol == 1){ + $lvl1HTML .= ""; + } + $lvl1HTML .= ''; //add the LVL 3 HTML content in lvl1 $lvl1HTML .= $lvl2HTML; //empty lvl 3 HTML to start anew @@ -646,37 +708,48 @@ public function getLvl1HTML($lvl1title, $lvl2Total, $lvl2HTML, $short) * @param string $lvl0title title to show * @param int $lvl1Total total to show * @param string $lvl1HTML LV3 content to embed - * @param bool $short hide lvl3 * @return string */ - public function getLvl0HTML($lvl0title, $lvl1Total, $lvl1HTML, $short) + public function getLvl0HTML($lvl0title, $lvl1Total, $lvl1HTML) { + global $conf; // make the whole result - $lvl0HTML .= $this->getHTMLReportHeaders(); - $lvl0HTML .= ''.$lvl0title.''; - $lvl0HTML .= ((!$short)?'':'').' TOTAL'; - $lvl0HTML .= ''.formatTime($lvl1Total, 0).''; - $lvl0HTML .= ''.formatTime($lvl1Total, -3).''; - //add the LVL 3 HTML content in lvl1 - $lvl0HTML .= $lvl1HTML; - $lvl0HTML .= ''; + $lvl0HTML = $this->getHTMLReportHeaders(); + $lvl0HTML .= ''.$lvl0title.''; + $lvl0HTML .= (($this->short == 0)?'':'').' TOTAL'; + $lvl0HTML .= ''.formatTime($lvl1Total, 0).''; + $lvl0HTML .= ''.formatTime($lvl1Total, -3).''; + if ($this->invoicedCol){ + $lvl0HTML .= ""; + } + $lvl0HTML .= ''; + //add the LVL 3 HTML content in lvl1 + $lvl0HTML .= $lvl1HTML; + $lvl0HTML .= ''; return $lvl0HTML; } /** Generate LVL HTML report * - * @param array $item value to display + * @param string $lvl3title title to show + * @param int $lvl3Total total to show + * @param string $lvl3note LV3 cnotes + * @param string $lvl3Invoiced LV3 invoiced * @return string */ - public function getLvl3HTML($item) + public function getLvl3HTML($lvl3title, $lvl3Total, $lvl3Note, $lvl3Invoiced) { + global $conf; $lvl3HTML = ''; $lvl3HTML .= '' - .$item[$this->lvl3Link].''; - $lvl3HTML .= $item['durationHours'].''; - $lvl3HTML .= $item['durationDays'].''; - $lvl3HTML .= $item['note']; - $lvl3HTML .= ''; + .$lvl3title.''; + $lvl3HTML .= ''.formatTime($lvl3Total, 0).''; + $lvl3HTML .= ''.formatTime($lvl3Total, -3).''; + $lvl3HTML .= ''.$lvl3Note.'';; + if ($this->invoicedCol == 1){ + $lvl3HTML .= "".$lvl3Invoiced.''; + } + $lvl3HTML .= ''; return $lvl3HTML; } } diff --git a/htdocs/timesheet/class/TimesheetTask.class.php b/htdocs/timesheet/class/TimesheetTask.class.php index 0c896fe7..0a791b3e 100644 --- a/htdocs/timesheet/class/TimesheetTask.class.php +++ b/htdocs/timesheet/class/TimesheetTask.class.php @@ -543,7 +543,7 @@ public function getActuals($timeStart = 0, $timeEnd = 0, $userid = 0) if($dayelapsed<1)return -1; $sql = "SELECT ptt.rowid, ptt.task_duration, DATE(ptt.task_datehour) AS task_date, ptt.note"; if(version_compare(DOL_VERSION, "4.9.9") >= 0) { - $sql .= ', (ptt.invoice_id > 0 or invoice_line_id>0) AS invoiced'; + $sql .= ', (ptt.invoice_id > 0 or ptt.invoice_line_id>0) AS invoiced'; }else{ $sql .= ', 0 AS invoiced'; } diff --git a/htdocs/timesheet/core/modules/modtimesheet.class.php b/htdocs/timesheet/core/modules/modtimesheet.class.php index 952cf368..46f6dfc2 100644 --- a/htdocs/timesheet/core/modules/modtimesheet.class.php +++ b/htdocs/timesheet/core/modules/modtimesheet.class.php @@ -52,7 +52,7 @@ public function __construct($db) // Module description, used if translation string 'ModuleXXXDesc' not found(where XXX is value of numeric property 'numero' of module) $this->description = "TimesheetView"; // Possible values for version are: 'development', 'experimental', 'dolibarr' or version - $this->version = '4.2.2'; + $this->version = '4.3.0'; // Key used in llx_cons table to save module status enabled/disabled(where timesheet is value of property name of module in uppercase) $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); // Where to store the module in setup page(0=common, 1=interface, 2=others, 3=very specific) diff --git a/htdocs/timesheet/core/modules/pdf/pdf_rat.modules.php b/htdocs/timesheet/core/modules/pdf/pdf_rat.modules.php index 5e057a84..e3f1b125 100644 --- a/htdocs/timesheet/core/modules/pdf/pdf_rat.modules.php +++ b/htdocs/timesheet/core/modules/pdf/pdf_rat.modules.php @@ -143,7 +143,7 @@ public function writeFile($object, $outputlangs) $tplidx = $pdf->importPage(1); } //get data - $tasktimearray = $object->getReportArray(); + $tasktimearray = $object->getReportArray(!($object->ungroup == 1)); $TotalLines = array(); $userTaskArray = array(); //order data per user id and calc total per user diff --git a/htdocs/timesheet/langs/de_DE/timesheet.lang b/htdocs/timesheet/langs/de_DE/timesheet.lang index e590f557..6159a66f 100644 --- a/htdocs/timesheet/langs/de_DE/timesheet.lang +++ b/htdocs/timesheet/langs/de_DE/timesheet.lang @@ -237,3 +237,7 @@ NoActiveEvent = Kein aktives Ereignis gefunden EventNotActive = Ereignis nicht aktiv DbError = Datenbank-Fehler nbTsToSubmit = Anzahl der einzureichenden Stundenzettel +reportInvoicedColDesc = Spalte "Fakturiert" in der Berichtstabelle +reportInvoicedCol = In Rechnung gestellte Spalte +reportUngroup = Stufe 3 in Berichten aufheben +reportUngroupDesc = Gruppierung von Elementen der Ebene 3 im Bericht aufheben, z.B. mehrere Aufgabenzeiten für einen einzigen Tag resultieren aus mehreren Berichtszeilen. diff --git a/htdocs/timesheet/langs/en_US/timesheet.lang b/htdocs/timesheet/langs/en_US/timesheet.lang index 5f2043a6..35319452 100644 --- a/htdocs/timesheet/langs/en_US/timesheet.lang +++ b/htdocs/timesheet/langs/en_US/timesheet.lang @@ -237,3 +237,7 @@ NoActiveEvent = No active event found EventNotActive = Event not active DbError = Database error nbTsToSubmit = Number of timesheet to submit +reportInvoicedColDesc = Invoiced column in report table +reportInvoicedCol = Invoiced column +reportUngroup = Ungroup level 3 in reports +reportUngroupDesc = Ungroup level 3 item in report, for example multiple tasktime for a single day will result of multiple report lines. diff --git a/htdocs/timesheet/langs/es_ES/timesheet.lang b/htdocs/timesheet/langs/es_ES/timesheet.lang index 41f366d9..d5e4ce69 100644 --- a/htdocs/timesheet/langs/es_ES/timesheet.lang +++ b/htdocs/timesheet/langs/es_ES/timesheet.lang @@ -237,3 +237,7 @@ NoActiveEvent = No se ha encontrado ningún evento activo EventNotActive = Evento no activo DbError = Error de la base de datos nbTsToSubmit = Número de hoja de trabajo para enviar +reportInvoicedColDesc = Columna de facturación en el cuadro del informe +reportInvoicedCol = Columna facturada +reportUngroup = Desagrupar el nivel 3 en los informes +reportUngroupDesc = Desagrupar el elemento de nivel 3 en el informe, por ejemplo, el tiempo de tarea múltiple para un solo día resultará en múltiples líneas de informe. diff --git a/htdocs/timesheet/langs/fr_FR/timesheet.lang b/htdocs/timesheet/langs/fr_FR/timesheet.lang index b6bd1c41..4049f7b0 100644 --- a/htdocs/timesheet/langs/fr_FR/timesheet.lang +++ b/htdocs/timesheet/langs/fr_FR/timesheet.lang @@ -237,3 +237,7 @@ NoActiveEvent = Aucun événement actif trouvé EventNotActive = Evénement non actif DbError = Erreur de base de données nbTsToSubmit = Nombre de feuilles de temps à soumettre +reportInvoicedColDesc = Colonnes facturées dans le tableau du rapport +reportInvoicedCol = Colonne facturée +reportUngroup = Dégrouper le niveau 3 dans les rapports +reportUngroupDesc = Dégroupez les éléments de niveau 3 dans le rapport, par exemple, les multiples heures de travail pour une seule journée résulteront de plusieurs lignes de rapport. diff --git a/htdocs/timesheet/langs/it_IT/timesheet.lang b/htdocs/timesheet/langs/it_IT/timesheet.lang index 77df900a..f04d2fa3 100644 --- a/htdocs/timesheet/langs/it_IT/timesheet.lang +++ b/htdocs/timesheet/langs/it_IT/timesheet.lang @@ -237,3 +237,7 @@ NoActiveEvent = Nessun evento attivo trovato EventNotActive = Evento non attivo DbError = Errore del database nbTsToSubmit = Numero di fogli di orario da presentare +reportInvoicedColDesc = Colonna fatturata nella tabella dei rapporti +reportInvoicedCol = Colonna fatturata +reportUngroup = Disaggregare il livello 3 nei rapporti +reportUngroupDesc = Disaggregare l'elemento di livello 3 nel report, ad esempio più tasktime per un singolo giorno risulterà da più righe di report. From 7510ee428fc316f8904e0dbb3d2930a6cd40c50a Mon Sep 17 00:00:00 2001 From: Patrick Delcroix Date: Sun, 5 Jul 2020 17:31:15 +0200 Subject: [PATCH 9/9] REV 4.3.0 --- htdocs/timesheet/ChangeLog.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/timesheet/ChangeLog.md b/htdocs/timesheet/ChangeLog.md index db6922d0..e692cfa0 100644 --- a/htdocs/timesheet/ChangeLog.md +++ b/htdocs/timesheet/ChangeLog.md @@ -1,7 +1,8 @@ # dolibarr_project_timesheet changelog 4.3.0 - new: possibility to ungroup reports -- +- fix: remove closed project (without end date) task +- new: improve timesheet box (add ts to submit and layout imnprovement) 4.2.2 - new: show the time not editable (when there is several task time for ady/task)