/** * Called by the Event Queue processor to process a reminder * on a task. * @access public * @param string $module Module name (not used) * @param string $type Type of event (not used) * @param integer $id ID of task being reminded * @param integer $owner Originator of event * @param mixed $args event-specific arguments. * @return mixed true, dequeue event, false, event stays in queue. * -1, event is destroyed. */ public function remind($module, $type, $id, $owner, &$args) { global $locale_char_set, $AppUI; $q = new DBQuery(); $df = $AppUI->getPref('SHDATEFORMAT'); $tf = $AppUI->getPref('TIMEFORMAT'); // If we don't have preferences set for these, use ISO defaults. if (!$df) { $df = '%Y-%m-%d'; } if (!$tf) { $tf = '%H:%m'; } $df .= ' ' . $tf; // At this stage we won't have an object yet if (!$this->load($id)) { return -1; // No point it trying again later. } $this->htmlDecode(); // Only remind on working days. $today = new CDate(); if (!$today->isWorkingDay()) { return true; } // Check if the task is completed if ($this->task_percent_complete == 100) { return -1; } // Grab the assignee list $q->addTable('user_tasks', 'ut'); $q->addJoin('users', 'u', 'u.user_id = ut.user_id', 'inner'); $q->addJoin('contacts', 'c', 'c.contact_id = u.user_contact', 'inner'); $q->addQuery('c.contact_id, contact_first_name, contact_last_name, contact_email'); $q->addWhere('ut.task_id = ' . (int) $id); $contacts = $q->loadHashList('contact_id'); $q->clear(); // Now we also check the owner of the task, as we will need // to notify them as well. $owner_is_not_assignee = false; $q->addTable('users', 'u'); $q->addJoin('contacts', 'c', 'c.contact_id = u.user_contact', 'inner'); $q->addQuery('c.contact_id, contact_first_name, contact_last_name, contact_email'); $q->addWhere('u.user_id = ' . (int) $this->task_owner); if ($q->exec(ADODB_FETCH_NUM)) { list($owner_contact, $owner_first_name, $owner_last_name, $owner_email) = $q->fetchRow(); if (!isset($contacts[$owner_contact])) { $owner_is_not_assignee = true; $contacts[$owner_contact] = array('contact_id' => $owner_contact, 'contact_first_name' => $owner_first_name, 'contact_last_name' => $owner_last_name, 'contact_email' => $owner_email); } } $q->clear(); // build the subject line, based on how soon the // task will be overdue. $starts = new CDate($this->task_start_date); $expires = new CDate($this->task_end_date); $now = new CDate(); $diff = $expires->dateDiff($now); $diff *= CDate::compare($expires, $now); $prefix = $AppUI->_('Task Due', UI_OUTPUT_RAW); if ($diff == 0) { $msg = $AppUI->_('TODAY', UI_OUTPUT_RAW); } elseif ($diff == 1) { $msg = $AppUI->_('TOMORROW', UI_OUTPUT_RAW); } elseif ($diff < 0) { $msg = $AppUI->_(array('OVERDUE', abs($diff), 'DAYS')); $prefix = $AppUI->_('Task', UI_OUTPUT_RAW); } else { $msg = $AppUI->_(array($diff, 'DAYS')); } $q->addTable('projects'); $q->addQuery('project_name'); $q->addWhere('project_id = ' . (int) $this->task_project); $project_name = htmlspecialchars_decode($q->loadResult()); $q->clear(); $subject = $prefix . ' ' . $msg . ' ' . $this->task_name . '::' . $project_name; $body = $AppUI->_('Task Due', UI_OUTPUT_RAW) . ': ' . $msg . "\n" . $AppUI->_('Project', UI_OUTPUT_RAW) . ': ' . $project_name . "\n" . $AppUI->_('Task', UI_OUTPUT_RAW) . ': ' . $this->task_name . "\n" . $AppUI->_('Start Date', UI_OUTPUT_RAW) . ': ' . $starts->format($df) . "\n" . $AppUI->_('Finish Date', UI_OUTPUT_RAW) . ': ' . $expires->format($df) . "\n" . $AppUI->_('URL', UI_OUTPUT_RAW) . ': ' . W2P_BASE_URL . '/index.php?m=tasks&a=view&task_id=' . $this->task_id . '&reminded=1' . "\n\n" . $AppUI->_('Resources', UI_OUTPUT_RAW) . ":\n"; foreach ($contacts as $contact) { if ($owner_is_not_assignee || $contact['contact_id'] != $owner_contact) { $body .= $contact['contact_first_name'] . ' ' . $contact['contact_last_name'] . ' <' . $contact['contact_email'] . ">\n"; } } $body .= "\n" . $AppUI->_('Description', UI_OUTPUT_RAW) . ":\n" . $this->task_description . "\n"; $mail = new Mail(); $mail->Subject($subject, $locale_char_set); $mail->Body($body, $locale_char_set); foreach ($contacts as $contact) { if ($mail->ValidEmail($contact['contact_email'])) { $mail->To($contact['contact_email'], true); $mail->Send(); } } return true; }
/** * Injects a reminder event into the event queue. * Repeat interval is one day, repeat count * and days to trigger before event overdue is * set in the system config. */ function addReminder() { $day = 86400; if (!dPgetConfig('task_reminder_control')) { return; } if (!$this->task_end_date) { // No end date, can't do anything. return $this->clearReminder(true); // Also no point if it is changed to null } if ($this->task_percent_complete >= 100) { return $this->clearReminder(true); } $eq = new EventQueue(); $pre_charge = dPgetConfig('task_reminder_days_before', 1); $repeat = dPgetConfig('task_reminder_repeat', 100); /* * If we don't need any arguments (and we don't) then we set this to null. * We can't just put null in the call to add as it is passed by reference. */ $args = null; // Find if we have a reminder on this task already $old_reminders = $eq->find('tasks', 'remind', $this->task_id); if (count($old_reminders)) { /* * It shouldn't be possible to have more than one reminder, * but if we do, we may as well clean them up now. */ foreach ($old_reminders as $old_id => $old_data) { $eq->remove($old_id); } } // Find the end date of this task, then subtract the required number of days. $date = new CDate($this->task_end_date); $today = new CDate(date('Y-m-d')); if (CDate::compare($date, $today) < 0) { $start_day = time(); } else { $start_day = $date->getDate(DATE_FORMAT_UNIXTIME); $start_day -= $day * $pre_charge; } $eq->add(array($this, 'remind'), $args, 'tasks', false, $this->task_id, 'remind', $start_day, $day, $repeat); }
$d_start = new CDate(); $d_end = new CDate(); for ($i = 0; $i < count(@$gantt_arr); $i++) { $a = $gantt_arr[$i][0]; $start = substr($a['task_start_date'], 0, 10); $end = substr($a['task_end_date'], 0, 10); $d_start->Date($start); $d_end->Date($end); if ($i == 0) { $min_d_start = $d_start; $max_d_end = $d_end; } else { if (CDate::compare($min_d_start, $d_start) > 0) { $min_d_start = $d_start; } if (CDate::compare($max_d_end, $d_end) < 0) { $max_d_end = $d_end; } } } } // check day_diff and modify Headers $day_diff = $max_d_end->dateDiff($min_d_start); // new scale display for gantt //////////////////////////////////////////////////////////////////// if ($day_diff > 1096) { //more than 3 years, show only the year scale $graph->ShowHeaders(GANTT_HYEAR); $graph->scale->year->grid->Show(); $graph->scale->year->grid->SetStyle(longdashed); $graph->scale->year->grid->SetColor('lightgray'); } else {
$del = dPgetParam($_POST, 'del', 0); // bind the POST parameter to the object record if (!$obj->bind($_POST)) { $AppUI->setMsg($obj->getError(), UI_MSG_ERROR); $AppUI->redirect(); } // configure the date and times to insert into the db table if ($obj->event_start_date) { $start_date = new CDate($obj->event_start_date . $_POST['start_time']); $obj->event_start_date = $start_date->format(FMT_DATETIME_MYSQL); } if ($obj->event_end_date) { $end_date = new CDate($obj->event_end_date . $_POST['end_time']); $obj->event_end_date = $end_date->format(FMT_DATETIME_MYSQL); } if (!$del && $start_date->compare($start_date, $end_date) >= 0) { $AppUI->setMsg("Start-Date >= End-Date, please correct", UI_MSG_ERROR); $AppUI->redirect(); exit; } // prepare (and translate) the module name ready for the suffix $AppUI->setMsg('Event'); $do_redirect = true; require_once $AppUI->getSystemClass("CustomFields"); if ($del) { if (!$obj->canDelete($msg)) { $AppUI->setMsg($msg, UI_MSG_ERROR); $AppUI->redirect(); } if ($msg = $obj->delete()) { $AppUI->setMsg($msg, UI_MSG_ERROR);
function displayTask($list, $task, $level, $display_week_hours, $fromPeriod, $toPeriod, $user_id, $canEditINA) { global $AppUI, $df, $durnTypes, $log_userfilter_users, $priority, $system_users, $z, $zi, $x, $userAlloc; $zi++; $users = $task->task_assigned_users; $task->userPriority = $task->getUserSpecificTaskPriority($user_id); $projects = $task->getProject(); $tmp = "<tr>"; $tmp .= "<td align=\"center\" nowrap=\"nowrap\">"; $tmp .= "<input type=\"checkbox\" name=\"selected_task[{$task->task_id}]\" value=\"{$task->task_id}\"/>"; $tmp .= "</td>"; /*ina */ $tmp .= "<td>"; for ($i = 0; $i < $level; $i++) { $tmp .= " "; } if ($task->task_milestone == true) { $tmp .= "<B>"; } if ($level >= 1) { $tmp .= dPshowImage(dPfindImage('corner-dots.gif', 'tasks'), 16, 12, 'Subtask') . " "; } $tmp .= "<a href='?m=tasks&a=view&task_id={$task->task_id}'>" . $task->task_name . "</a>"; if ($task->task_milestone == true) { $tmp .= "</B>"; } if ($task->task_priority < 0) { $tmp .= " (<img src=\"./images/icons/priority-" . -$task->task_priority . ".gif\" width=13 height=16>)"; } elseif ($task->task_priority > 0) { $tmp .= " (<img src=\"./images/icons/priority+" . $task->task_priority . ".gif\" width=13 height=16>)"; } $tmp .= "</td>"; $tmp .= "<td align=\"center\">"; $tmp .= "<a href='?m=projects&a=view&project_id={$task->task_project}' style='background-color:#" . @$projects["project_color_identifier"] . "; color:" . bestColor(@$projects['project_color_identifier']) . "'>" . $projects['project_short_name'] . "</a>"; $tmp .= "</td>"; $tmp .= "<td align=\"center\" nowrap=\"nowrap\">"; $tmp .= $task->task_duration . " " . $AppUI->_($durnTypes[$task->task_duration_type]); $tmp .= "</td>"; $tmp .= "<td align=\"center\" nowrap=\"nowrap\">"; $dt = new CDate($task->task_start_date); $tmp .= $dt->format($df); $tmp .= "   </td>"; $tmp .= "<td align=\"center\" nowrap=\"nowrap\">"; $ed = new CDate($task->task_end_date); $now = new CDate(); $dt = $now->dateDiff($ed); $sgn = $now->compare($ed, $now); $tmp .= $dt * $sgn; $tmp .= "</td>"; if ($display_week_hours) { $tmp .= displayWeeks($list, $task, $level, $fromPeriod, $toPeriod); } $tmp .= "<td>"; $sep = $us = ""; foreach ($users as $row) { if ($row["user_id"]) { if ($canEditINA) { $us .= "<a href='?m=admin&a=viewuser&user_id={$row['0']}'>" . $sep . $row['contact_last_name'] . " \n \t(" . $row['perc_assignment'] . "%)</a>"; } else { $us .= $sep . $row['contact_last_name'] . " (" . $row['perc_assignment'] . "%)"; } /*ina*/ $sep = ", "; } } $tmp .= $us; $tmp .= "</td>"; // create the list of possible assignees if ($zi == 1) { // selectbox may not have a size smaller than 2, use 5 here as minimum $zz = $z < 5 ? 5 : $z * 1.5; if (sizeof($users) >= 7) { $zz = $zz * 2; } $zm1 = $z - 2; if ($zm1 == 0) { $zm1 = 1; } $assUser = $userAlloc[$user_id]['userFC']; if ($user_id == 0) { // need to handle orphaned tasks different from tasks with existing assignees $zm1++; } if ($canEditINA) { $tmp .= "<td valign=\"top\" align=\"center\" nowrap=\"nowrap\" rowspan=\"{$zm1}\">"; $tmp .= '<select name="add_users" style="width:200px" size="' . ($zz - 1) . '" class="text" multiple="multiple" ondblclick="javascript:chAssignment(' . $user_id . ', 0, false)">'; foreach ($userAlloc as $v => $u) { $tmp .= "\n\t<option value=\"" . $u['user_id'] . "\">" . dPformSafe($u['userFC']) . "</option>"; } $tmp .= '</select>'; //$tmp.= arraySelect( $user_list, 'add_users', 'class="text" STYLE="width: 200px" size="'.($zz-1).'" multiple="multiple"',NULL ); $tmp .= "</td>"; } } $tmp .= "</tr>\n"; return $tmp; }
/** * Sub-function to collect tasks within a period * * @param Date the starting date of the period * @param Date the ending date of the period * @param array by-ref an array of links to append new items to * @param int the length to truncate entries by * @param int the company id to filter by * @author Andrew Eddie <*****@*****.**> */ function getTaskLinks($startPeriod, $endPeriod, &$links, $strMaxLen, $company_id = 0) { global $a, $AppUI, $dPconfig; $tasks = CTask::getTasksForPeriod($startPeriod, $endPeriod, $company_id, $AppUI->user_id, true); $durnTypes = dPgetSysVal('TaskDurationType'); $link = array(); $sid = 3600 * 24; // assemble the links for the tasks foreach ($tasks as $row) { // the link $link['href'] = '?m=tasks&a=view&task_id=' . $row['task_id']; $link['alt'] = $row['project_name'] . ":\n" . $row['task_name']; // the link text if (mb_strlen($row['task_name']) > $strMaxLen) { $row['task_name'] = mb_substr($row['task_name'], 0, $strMaxLen) . '...'; } $link['text'] = $row['task_name']; $link['style'] = 'color:' . bestColor($row['color']) . ';background-color:#' . $row['color']; // determine which day(s) to display the task $start = new CDate($row['task_start_date']); $end = $row['task_end_date'] ? new CDate($row['task_end_date']) : null; $durn = $row['task_duration']; $durnType = $row['task_duration_type']; if (($start->after($startPeriod) || $start->equals($startPeriod)) && ($start->before($endPeriod) || $start->equals($endPeriod))) { $temp = $link; $temp['alt'] = 'START [' . $row['task_duration'] . ' ' . $AppUI->_($durnTypes[$row['task_duration_type']]) . "]\n" . $link['alt']; if ($a != 'day_view') { $temp['text'] = dPshowImage(dPfindImage('block-start-16.png')) . $temp['text']; } $links[$start->format(FMT_TIMESTAMP_DATE)][] = $temp; } if ($end && $start->before($end) && ($end->after($startPeriod) || $end->equals($startPeriod)) || ($end->before($endPeriod) || $end->equals($endPeriod))) { $temp = $link; $temp['alt'] = "FINISH\n" . $link['alt']; if ($a != 'day_view') { $temp['text'] .= dPshowImage(dPfindImage('block-end-16.png')); } $links[$end->format(FMT_TIMESTAMP_DATE)][] = $temp; } // convert duration to days if ($durnType < 24.0) { if ($durn > $dPconfig['daily_working_hours']) { $durn /= $dPconfig['daily_working_hours']; } else { $durn = 0.0; } } else { $durn *= $durnType / 24.0; } // fill in between start and finish based on duration // notes: // start date is not in a future month, must be this or past month // start date is counted as one days work // business days are not taken into account $target = $start; $target->addSeconds($durn * $sid); if (CDate::compare($target, $startPeriod) < 0) { continue; } if (CDate::compare($start, $startPeriod) > 0) { $temp = $start; $temp->addSeconds($sid); } else { $temp = $startPeriod; } // Optimised for speed, AJD. while (CDate::compare($endPeriod, $temp) > 0 && CDate::compare($target, $temp) > 0 && ($end == null || $temp->before($end))) { $links[$temp->format(FMT_TIMESTAMP_DATE)][] = $link; $temp->addSeconds($sid); } } }
/** Import tasks from another project * * @param int Project ID of the tasks come from. * @return bool **/ public function importTasks($from_project_id) { global $AppUI; // Load the original $origProject = new CProject(); $origProject->load($from_project_id); $q = new DBQuery(); $q->addTable('tasks'); $q->addQuery('task_id'); $q->addWhere('task_project =' . (int) $from_project_id); $tasks = array_flip($q->loadColumn()); $q->clear(); $origDate = new CDate($origProject->project_start_date); $destDate = new CDate($this->project_start_date); $timeOffset = $origDate->dateDiff($destDate); if ($origDate->compare($origDate, $destDate) > 0) { $timeOffset = -1 * $timeOffset; } // Dependencies array $deps = array(); // Copy each task into this project and get their deps foreach ($tasks as $orig => $void) { $objTask = new CTask(); $objTask->load($orig); $destTask = $objTask->copy($this->project_id); $tasks[$orig] = $destTask; $deps[$orig] = $objTask->getDependencies(); } // Fix record integrity foreach ($tasks as $old_id => $newTask) { // Fix parent Task // This task had a parent task, adjust it to new parent task_id if ($newTask->task_id != $newTask->task_parent) { $newTask->task_parent = $tasks[$newTask->task_parent]->task_id; } // Fix task start date from project start date offset $origDate->setDate($newTask->task_start_date); $origDate->addDays($timeOffset); $destDate = $origDate; $newTask->task_start_date = $destDate->format(FMT_DATETIME_MYSQL); // Fix task end date from start date + work duration if (!empty($newTask->task_end_date) && $newTask->task_end_date != '0000-00-00 00:00:00') { $origDate->setDate($newTask->task_end_date); $origDate->addDays($timeOffset); $destDate = $origDate; $newTask->task_end_date = $destDate->format(FMT_DATETIME_MYSQL); } // Dependencies if (!empty($deps[$old_id])) { $oldDeps = explode(',', $deps[$old_id]); // New dependencies array $newDeps = array(); foreach ($oldDeps as $dep) { $newDeps[] = $tasks[$dep]->task_id; } // Update the new task dependencies $csList = implode(',', $newDeps); $newTask->updateDependencies($csList); } // end of update dependencies $newTask->store($AppUI); } // end Fix record integrity }