diff --git a/htdocs/core/js/timesheet.js b/htdocs/core/js/timesheet.js new file mode 100644 index 0000000000000000000000000000000000000000..7c85cb1afd0bca53f02308f699210555db0e681a --- /dev/null +++ b/htdocs/core/js/timesheet.js @@ -0,0 +1,176 @@ +//FIXME total not working +/* Copyright (C) 2014 delcroip <delcroip@gmail.com> + * Laurent Destailleur 2015 <eldy@users.sourceforge.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +/* Parse en input data for time entry into timesheet */ +function regexEvent(objet,evt,type) +{ + console.log('regexEvent type='+type); + switch(type) + { + case 'days': + var regex= /^[0-9]{1}([.,]{1}[0-9]{1})?$/; + + if(regex.test(objet.value) ) + { + var tmp=objet.value.replace(',','.'); + if(tmp<=1.5){ + var tmpint=parseInt(tmp); + if(tmp-tmpint>=0.5){ + objet.value= tmpint+0.5; + }else{ + objet.value= tmpint; + } + }else{ + objet.value= '1.5'; + } + }else{ + objet.value= '0'; + } + break; + case 'hours': + var regex= /^[0-9]{1,2}:[0-9]{2}$/; + var regex2=/^[0-9]{1,2}$/; + if(!regex.test(objet.value)) + { + if(regex2.test(objet.value)) + objet.value=objet.value+':00'; + else + objet.value=''; + } + /* alert(jQuery("#"+id).val()); */ + break; + case 'timeChar': + //var regex= /^[0-9:]{1}$/; + //alert(event.charCode); + var charCode = (evt.which) ? evt.which : event.keyCode; + + if(((charCode >= 48) && (charCode <= 57)) || //num + (charCode===46) || (charCode===8)||// comma & periode + (charCode === 58) || (charCode==44) )// : & all charcode + { + // ((charCode>=96) && (charCode<=105)) || //numpad + return true; + + }else + { + return false; + } + + break; + default: + break; + } +} + + +function pad(n) { + return (n < 10) ? ("0" + n) : n; +} + + + +/* function from http://www.timlabonne.com/2013/07/parsing-a-time-string-with-javascript/ */ +function parseTime(timeStr, dt) +{ + if (!dt) { + dt = new Date(); + } + + var time = timeStr.match(/(\d+)(?::(\d\d))?\s*(p?)/i); + if (!time) { + return -1; + } + var hours = parseInt(time[1], 10); + if (hours == 12 && !time[3]) { + hours = 0; + } + else { + hours += (hours < 12 && time[3]) ? 12 : 0; + } + + dt.setHours(hours); + dt.setMinutes(parseInt(time[2], 10) || 0); + dt.setSeconds(0, 0); + return 0; +} + +/* Update total. days = column nb staring from 0 */ +function updateTotal(days,mode) +{ + console.log('updateTotal days='+days+' mode='+mode); + if(mode=="hours") + { + var total = new Date(0); + total.setHours(0); + total.setMinutes(0); + var nbline = document.getElementById('numberOfLines').value; + for (var i=0;i<nbline;i++) + { + var id='task['+i+']['+days+']'; + var taskTime= new Date(0); + var element=document.getElementById(id); + if(element) + { + /* alert(element.value);*/ + if (element.value) + { + result=parseTime(element.value,taskTime); + } + else + { + result=parseTime(element.innerHTML,taskTime); + } + if (result >= 0) + { + total.setHours(total.getHours()+taskTime.getHours()); + total.setMinutes(total.getMinutes()+taskTime.getMinutes()); + } + } + } + document.getElementById('totalDay['+days+']').innerHTML = pad(total.getHours())+':'+pad(total.getMinutes()); + //addText(,total.getHours()+':'+total.getMinutes()); + } + else + { + var total =0; + var nbline = document.getElementById('numberOfLines').value; + for (var i=0;i<nbline;i++) + { + var id='task['+i+']['+days+']'; + var taskTime= new Date(0); + var element=document.getElementById(id); + if(element) + { + if (element.value) + { + total+=parseInt(element.value); + + } + else + { + total+=parseInt(element.innerHTML); + } + } + } + document.getElementById('totalDay['+days+']').innerHTML = total; + } + +} + + \ No newline at end of file diff --git a/htdocs/core/lib/agenda.lib.php b/htdocs/core/lib/agenda.lib.php index e5260c172d3a3049cbe3a0457c7d0ebbde14d259..38e783765f9a12cfb93e55d11040e4e4e05c395d 100644 --- a/htdocs/core/lib/agenda.lib.php +++ b/htdocs/core/lib/agenda.lib.php @@ -71,9 +71,9 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh if ($canedit) { print '<tr>'; - print '<td class="nowrap">'; + print '<td class="nowrap" style="padding-bottom: 2px;">'; print $langs->trans("ActionsToDoBy").' '; - print '</td><td class="nowrap maxwidthonsmartphone">'; + print '</td><td class="nowrap maxwidthonsmartphone" style="padding-bottom: 2px;">'; print $form->select_dolusers($filtert, 'usertodo', 1, '', ! $canedit); if (empty($conf->dol_optimize_smallscreen)) print ' '.$langs->trans("or") . ' '.$langs->trans("Group").' '; print $form->select_dolgroups($usergroupid, 'usergroup', 1, '', ! $canedit); @@ -83,16 +83,16 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh $formactions=new FormActions($db); print '<tr>'; - print '<td class="nowrap">'; + print '<td class="nowrap" style="padding-bottom: 2px;">'; print $langs->trans("Type"); - print ' </td><td class="nowrap maxwidthonsmartphone">'; + print ' </td><td class="nowrap maxwidthonsmartphone" style="padding-bottom: 2px;">'; print $formactions->select_type_actions($actioncode, "actioncode", '', (empty($conf->global->AGENDA_USE_EVENT_TYPE) ? 1 : 0)); print '</td></tr>'; print '<tr>'; - print '<td class="nowrap">'; + print '<td class="nowrap" style="padding-bottom: 2px;">'; print $langs->trans("Status"); - print ' </td><td class="nowrap maxwidthonsmartphone">'; + print ' </td><td class="nowrap maxwidthonsmartphone" style="padding-bottom: 2px;">'; $formactions->form_select_status_action('formaction',$status,1,'status',1,2); print '</td></tr>'; } @@ -100,9 +100,9 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh if (! empty($conf->societe->enabled) && $user->rights->societe->lire) { print '<tr>'; - print '<td class="nowrap">'; + print '<td class="nowrap" style="padding-bottom: 2px;">'; print $langs->trans("ThirdParty").' '; - print '</td><td class="nowrap maxwidthonsmartphone">'; + print '</td><td class="nowrap maxwidthonsmartphone" style="padding-bottom: 2px;">'; print $form->select_thirdparty($socid, 'socid'); print '</td></tr>'; } @@ -113,9 +113,9 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh $formproject=new FormProjets($db); print '<tr>'; - print '<td class="nowrap">'; + print '<td class="nowrap" style="padding-bottom: 2px;">'; print $langs->trans("Project").' '; - print '</td><td class="nowrap maxwidthonsmartphone">'; + print '</td><td class="nowrap maxwidthonsmartphone" style="padding-bottom: 2px;">'; $formproject->select_projects($socid?$socid:-1, $pid, 'projectid', 0); print '</td></tr>'; } @@ -124,7 +124,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh { // Filter on hours print '<tr>'; - print '<td class="nowrap">'.$langs->trans("WorkingTimeRange").'</td>'; + print '<td class="nowrap" style="padding-bottom: 2px;">'.$langs->trans("WorkingTimeRange").'</td>'; print "<td class='nowrap maxwidthonsmartphone'>"; print '<input type="number" class="short" name="begin_h" value="'.$begin_h.'" min="0" max="23">'; if (empty($conf->dol_use_jmobile)) print ' - '; @@ -140,10 +140,6 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh if (empty($conf->dol_use_jmobile)) print ' - '; print '<input type="number" class="short" name="end_d" value="'.$end_d.'" min="1" max="7">'; print '</td></tr>'; - - print '<tr><td>'.$langs->trans("AgendaShowBirthdayEvents").' <input type="checkbox" id="check_birthday" name="check_birthday"></td></tr>'; - print '</table>'; - print '</td>'; } // Hooks diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php index 2320b0ca556a0f3032d9d5b689bed0d9de3f24bf..eb7617b5c7e189b5b40d913b069d0a56ca1799dd 100644 --- a/htdocs/core/lib/project.lib.php +++ b/htdocs/core/lib/project.lib.php @@ -550,7 +550,7 @@ function projectLinesPerTime(&$inc, $parent, $lines, &$level, &$projectsrole, &$ print $taskstatic->getNomUrl(0); print "<br>"; for ($k = 0 ; $k < $level ; $k++) print " "; - print get_date_range($lines[$i]->date_start,$lines[$i]->date_end); + print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0); print "</td>\n"; // Planned Workload @@ -665,6 +665,9 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t { $var = !$var; $lastprojectid=$lines[$i]->fk_project; + + $projectstatic->id = $lines[$i]->fk_project; + $projectstatic->loadTimeSpent($datestart, $lines[$i]->id, $fuser->id); } // If we want all or we have a role on task, we show it @@ -673,7 +676,7 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t print "<tr ".$bc[$var].">\n"; // Project - print "<td>"; + print '<td class="nowrap">'; $projectstatic->id=$lines[$i]->fk_project; $projectstatic->ref=$lines[$i]->projectref; $projectstatic->public=$lines[$i]->public; @@ -682,7 +685,7 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t print "</td>"; // Ref - print '<td>'; + print '<td class="nowrap">'; $taskstatic->id=$lines[$i]->id; $taskstatic->ref=($lines[$i]->ref?$lines[$i]->ref:$lines[$i]->id); print $taskstatic->getNomUrl(1); @@ -696,7 +699,7 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t print $taskstatic->getNomUrl(0); print "<br>"; for ($k = 0 ; $k < $level ; $k++) print " "; - print get_date_range($lines[$i]->date_start,$lines[$i]->date_end); + print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0); print "</td>\n"; // Planned Workload @@ -711,6 +714,7 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t print '</td>'; // Time spent + /* print '<td align="right">'; if ($lines[$i]->duration) { @@ -720,6 +724,7 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t } else print '--:--'; print "</td>\n"; + */ $disabledproject=1;$disabledtask=1; //print "x".$lines[$i]->fk_project; @@ -737,27 +742,22 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t $disabledtask=1; } - // Fields to add new time - print '<td align="right">'; - print $langs->trans("FeatureNotYetAvailable"); - /* - print '<td class="nowrap" align="right">'; - $s=''; - $s.=$form->select_date('',$lines[$i]->id,0,0,2,"addtime",1,0,1,$disabledtask); - $s.=' '; - $s.=$form->select_duration($lines[$i]->id,'',$disabledtask,'text',0,1); - $s.=' <input type="submit" class="button"'.($disabledtask?' disabled="disabled"':'').' value="'.$langs->trans("Add").'">'; - print $s; - print '</td>'; - - print '<td align="right">'; - if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("YouAreNotContactOfProject")); - else if ($disabledtask) print $form->textwithpicto('',$langs->trans("TaskIsNotAffectedToYou")); - print '</td>'; - */ - - print '</td>'; - print "</tr>\n"; + //var_dump($projectstatic->weekWorkLoad); + + // Fields to show current time + $tableCell=''; $modeinput='hours'; + for ($idw = 0; $idw < 7; $idw++) + { + $dayWorkLoad = 0; + $tableCell ='<td align="center">'; + $tableCell.='<input type="text" class="center" size="2" disabled="disabled" value="'.convertSecondToTime($dayWorkLoad,'allhourmin').'">+'; + $tableCell.='<input type="text" class="center" size="2" id="task['.$inc.']['.$idw.']" name="task['.$lines[$i]->id.']['.$idw.']" value="" cols="2" maxlength="5"'; + $tableCell.=' onkeypress="return regexEvent(this,event,\'timeChar\')"'; + $tableCell.= 'onblur="regexEvent(this,event,\''.$modeinput.'\');updateTotal('.$idw.',\''.$modeinput.'\')" />'; + $tableCell.='</td>'; + print $tableCell; + } + print "</tr>\n"; } $inc++; diff --git a/htdocs/langs/en_US/commercial.lang b/htdocs/langs/en_US/commercial.lang index 390a7f837e8e54678336e7013d159c898101f0e9..7acdc7bd7e6df5d353eec33e9eb9b8fb8d0ec42f 100644 --- a/htdocs/langs/en_US/commercial.lang +++ b/htdocs/langs/en_US/commercial.lang @@ -62,7 +62,7 @@ LastProspectContactDone=Contact done DateActionPlanned=Date event planned for DateActionDone=Date event done ActionAskedBy=Event reported by -ActionAffectedTo=Event owned by +ActionAffectedTo=Event assigned to ActionDoneBy=Event done by ActionUserAsk=Reported by ErrorStatusCantBeZeroIfStarted=If field '<b>Date done</b>' is filled, action is started (or finished), so field '<b>Status</b>' can't be 0%%. diff --git a/htdocs/projet/activity/perday.php b/htdocs/projet/activity/perday.php index 6c4acb573348e2252d7d319c8442790fe91453fb..f7b37ca1ca0341607e98ec7081e63b25e7b49619 100644 --- a/htdocs/projet/activity/perday.php +++ b/htdocs/projet/activity/perday.php @@ -48,6 +48,8 @@ $socid=0; if ($user->societe_id > 0) $socid=$user->societe_id; $result = restrictedArea($user, 'projet', $projectid); +$now=dol_now(); + /* * Actions @@ -94,7 +96,7 @@ $tasksrole=$taskstatic->getUserRolesForProjectsOrTasks(0,$user,($project->id?$pr //var_dump($taskrole); -llxHeader("",$title,""); +llxHeader("",$title,"",'','','',array('/core/js/timesheet.js')); print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num); @@ -143,8 +145,17 @@ print '<td>'.$langs->trans("RefTask").'</td>'; print '<td>'.$langs->trans("LabelTask").'</td>'; print '<td align="right">'.$langs->trans("PlannedWorkload").'</td>'; print '<td align="right">'.$langs->trans("ProgressDeclared").'</td>'; -print '<td align="right">'.$langs->trans("TimeSpent").'</td>'; -print '<td colspan="2" align="right">'.$langs->trans("xxx").'</td>'; +//print '<td align="right">'.$langs->trans("TimeSpent").'</td>'; + +$tmp=dol_getdate($now); +$startdayarray=dol_get_first_day_week($tmp['mday'], $tmp['mon'], $tmp['year']); +$startday=dol_mktime(12, 0, 0, $startdayarray['first_month'], $startdayarray['first_day'], $startdayarray['first_year']); + +for($i=0;$i<7;$i++) +{ + print '<td width="7%" align="center">'.dol_print_date($startday + ($i * 3600 * 24), '%a').'<br>'.dol_print_date($startday + ($i * 3600 * 24), 'day').'</td>'; +} + print "</tr>\n"; // By default, we can edit only tasks we are assigned to @@ -154,6 +165,17 @@ if (count($tasksarray) > 0) { $j=0; projectLinesPerDay($j, 0, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask); + + print '<tr class="liste_total"> + <td class="liste_total" colspan="5" align="right">'.$langs->trans("Total").'</td> + <td class="liste_total" width="7%" align="center"><div id="totalDay[0]"> </div></td> + <td class="liste_total" width="7%" align="center"><div id="totalDay[1]"> </div></td> + <td class="liste_total" width="7%" align="center"><div id="totalDay[2]"> </div></td> + <td class="liste_total" width="7%" align="center"><div id="totalDay[3]"> </div></td> + <td class="liste_total" width="7%" align="center"><div id="totalDay[4]"> </div></td> + <td class="liste_total" width="7%" align="center"><div id="totalDay[5]"> </div></td> + <td class="liste_total" width="7%" align="center"><div id="totalDay[6]"> </div></td> + </tr>'; } else { @@ -161,8 +183,15 @@ else } print "</table>"; +print '<input type="hidden" name="timestamp" value="1425423513"/>'."\n"; +print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n"; + dol_fiche_end(); +print '<div class="center">'; +print '<input type="button" class="button" name="save" value="'.dol_escape_htmltag($langs->trans("Save")).'">'; +print '</div>'; + print '</form>'; diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 8db1313904d6877132ef0aecec9d793661745d5b..12750e00c6f8c64e808aaec0584447eda15fcb56 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -1432,5 +1432,51 @@ class Project extends CommonObject return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); } + + /** + * load time spent into this->weekWorkLoad for all day of a week and task id + * + * @param int $datestart First day of week (use dol_get_first_day to find this date) + * @param int $userid Time consumed per a particular user + * @return int <0 if OK, >0 if KO + */ + public function loadTimeSpent($datestart,$taskid,$userid=0) + { + $error=0; + + $sql = "SELECT ptt.rowid, ptt.task_duration, ptt.task_date"; + $sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time AS ptt"; + $sql.= " WHERE ptt.fk_task='".$taskid."'"; + $sql.= " AND ptt.fk_user='".$userid."'"; + $sql .= "AND (ptt.task_date >= '".$this->db->idate($datestart)."' "; + $sql .= "AND (ptt.task_date < '".$this->db->idate($datestart + 7 * 24 * 3600)."' "; + $resql=$this->db->query($sql); + if ($resql) + { + + $num = $this->db->num_rows($resql); + $i = 0; + // Loop on each record found, so each couple (project id, task id) + while ($i < $num) + { + $obj=$this->db->fetch_object($resql); + $day=$this->db->jdate($obj->task_date); + //$day=(intval(date('w',strtotime($obj->task_date)))+1)%6; + // if several tasktime in one day then only the last is used + $this->weekWorkLoad[$day] += $obj->task_duration; + $this->taskTimeId[$day]= ($obj->rowid)?($obj->rowid):0; + $i++; + } + $this->db->free($resql); + return 1; + } + else + { + $this->error="Error ".$this->db->lasterror(); + dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR); + return -1; + } + } + }