diff options
author | Frederic Guillot <fred@kanboard.net> | 2015-03-26 20:49:37 -0400 |
---|---|---|
committer | Frederic Guillot <fred@kanboard.net> | 2015-03-26 20:49:37 -0400 |
commit | d3ae8d2acb218c8e1bc50ed1b92c19016e9214ee (patch) | |
tree | 1fbf207bb2e1f681f8477f4273f084ce9c64f727 /app | |
parent | 626ad566f718e0c0f63034ecc76604d22d4b2a06 (diff) |
Display subtask estimates in the user calendar according to the timetable
Diffstat (limited to 'app')
25 files changed, 161 insertions, 5 deletions
diff --git a/app/Controller/Calendar.php b/app/Controller/Calendar.php index 6cfa2bad..49c7f56e 100644 --- a/app/Controller/Calendar.php +++ b/app/Controller/Calendar.php @@ -82,7 +82,9 @@ class Calendar extends Base $subtask_timeslots = $this->subtaskTimeTracking->getUserCalendarEvents($user_id, $start, $end); - $this->response->json(array_merge($due_tasks, $subtask_timeslots)); + $subtask_forcast = $this->config->get('subtask_forecast') == 1 ? $this->subtaskForecast->getCalendarEvents($user_id, $end) : array(); + + $this->response->json(array_merge($due_tasks, $subtask_timeslots, $subtask_forcast)); } /** diff --git a/app/Controller/Config.php b/app/Controller/Config.php index bee897be..6f3bc43c 100644 --- a/app/Controller/Config.php +++ b/app/Controller/Config.php @@ -41,7 +41,7 @@ class Config extends Base $values = $this->request->getValues(); if ($redirect === 'board') { - $values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0); + $values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0, 'subtask_forecast' => 0); } if ($this->config->save($values)) { diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php index c12e6d9b..f9fe1bab 100644 --- a/app/Locale/da_DK/translations.php +++ b/app/Locale/da_DK/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php index 3a3d145e..9898e7f3 100644 --- a/app/Locale/de_DE/translations.php +++ b/app/Locale/de_DE/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php index 00b342dd..0f576376 100644 --- a/app/Locale/es_ES/translations.php +++ b/app/Locale/es_ES/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php index d1ae2412..a5c76cd1 100644 --- a/app/Locale/fi_FI/translations.php +++ b/app/Locale/fi_FI/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php index 340d16b1..7a88669c 100644 --- a/app/Locale/fr_FR/translations.php +++ b/app/Locale/fr_FR/translations.php @@ -810,4 +810,5 @@ return array( 'Move the task to another column when assigned to a user' => 'Déplacer la tâche dans une autre colonne lorsque celle-ci est assignée à quelqu\'un', 'Move the task to another column when assignee is cleared' => 'Déplacer la tâche dans une autre colonne lorsque celle-ci n\'est plus assignée', 'Source column' => 'Colonne d\'origine', + 'Show subtask estimates in the user calendar' => 'Afficher le temps estimé des sous-tâches dans le calendrier utilisateur', ); diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php index a8d5b637..6ab3e7f4 100644 --- a/app/Locale/hu_HU/translations.php +++ b/app/Locale/hu_HU/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php index 6e704ca1..08444549 100644 --- a/app/Locale/it_IT/translations.php +++ b/app/Locale/it_IT/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php index 43834145..aa6c51f0 100644 --- a/app/Locale/ja_JP/translations.php +++ b/app/Locale/ja_JP/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php index 00ef6023..1a22bc30 100644 --- a/app/Locale/nl_NL/translations.php +++ b/app/Locale/nl_NL/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php index 2f5be941..983b42a8 100644 --- a/app/Locale/pl_PL/translations.php +++ b/app/Locale/pl_PL/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php index 6edf5d0d..b6a759ad 100644 --- a/app/Locale/pt_BR/translations.php +++ b/app/Locale/pt_BR/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php index 8f597adc..181b035c 100644 --- a/app/Locale/ru_RU/translations.php +++ b/app/Locale/ru_RU/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php index 9c7f63a8..0f7df233 100644 --- a/app/Locale/sr_Latn_RS/translations.php +++ b/app/Locale/sr_Latn_RS/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php index 212440a7..4da013bb 100644 --- a/app/Locale/sv_SE/translations.php +++ b/app/Locale/sv_SE/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php index bc94adf4..c478c9ba 100644 --- a/app/Locale/th_TH/translations.php +++ b/app/Locale/th_TH/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php index 0272a7f8..93638f89 100644 --- a/app/Locale/tr_TR/translations.php +++ b/app/Locale/tr_TR/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php index e99fedab..aa679327 100644 --- a/app/Locale/zh_CN/translations.php +++ b/app/Locale/zh_CN/translations.php @@ -808,4 +808,5 @@ return array( // 'Move the task to another column when assigned to a user' => '', // 'Move the task to another column when assignee is cleared' => '', // 'Source column' => '', + // 'Show subtask estimates in the user calendar' => '', ); diff --git a/app/Model/SubtaskForecast.php b/app/Model/SubtaskForecast.php new file mode 100644 index 00000000..5daee56b --- /dev/null +++ b/app/Model/SubtaskForecast.php @@ -0,0 +1,117 @@ +<?php + +namespace Model; + +use DateTime; +use DateInterval; + +/** + * Subtask Forecast + * + * @package model + * @author Frederic Guillot + */ +class SubtaskForecast extends Base +{ + /** + * Get not completed subtasks with an estimate sorted by postition + * + * @access public + * @param integer $user_id + * @return array + */ + public function getSubtasks($user_id) + { + return $this->db + ->table(Subtask::TABLE) + ->columns(Subtask::TABLE.'.id', Task::TABLE.'.project_id', Subtask::TABLE.'.task_id', Subtask::TABLE.'.title', Subtask::TABLE.'.time_estimated') + ->join(Task::TABLE, 'id', 'task_id') + ->asc(Task::TABLE.'.position') + ->asc(Subtask::TABLE.'.position') + ->gt(Subtask::TABLE.'.time_estimated', 0) + ->eq(Subtask::TABLE.'.user_id', $user_id) + ->findAll(); + } + + /** + * Get the start date for the forecast + * + * @access public + * @param integer $user_id + * @return array + */ + public function getStartDate($user_id) + { + $subtask = $this->db->table(Subtask::TABLE) + ->columns(Subtask::TABLE.'.time_estimated', SubtaskTimeTracking::TABLE.'.start') + ->eq(SubtaskTimeTracking::TABLE.'.user_id', $user_id) + ->eq(SubtaskTimeTracking::TABLE.'.end', 0) + ->status('status', Subtask::STATUS_INPROGRESS) + ->join(SubtaskTimeTracking::TABLE, 'subtask_id', 'id') + ->findOne(); + + if ($subtask && $subtask['time_estimated'] && $subtask['start']) { + return date('Y-m-d H:i', $subtask['start'] + $subtask['time_estimated'] * 3600); + } + + return date('Y-m-d H:i'); + } + + /** + * Get all calendar events according to the user timetable and the subtasks estimates + * + * @access public + * @param integer $user_id + * @param string $end End date of the calendar + * @return array + */ + public function getCalendarEvents($user_id, $end) + { + $events = array(); + $start_date = new DateTime($this->getStartDate($user_id)); + $timetable = $this->timetable->calculate($user_id, $start_date, new DateTime($end)); + $subtasks = $this->getSubtasks($user_id); + $total = count($subtasks); + $offset = 0; + + foreach ($timetable as $slot) { + + $interval = $this->dateParser->getHours($slot[0], $slot[1]); + $start = $slot[0]->getTimestamp(); + + if ($slot[0] < $start_date) { + continue; + } + + while ($offset < $total) { + + $event = array( + 'id' => $subtasks[$offset]['id'].'-'.$subtasks[$offset]['task_id'].'-'.$offset, + 'subtask_id' => $subtasks[$offset]['id'], + 'title' => t('#%d', $subtasks[$offset]['task_id']).' '.$subtasks[$offset]['title'], + 'url' => $this->helper->url('task', 'show', array('task_id' => $subtasks[$offset]['task_id'], 'project_id' => $subtasks[$offset]['project_id'])), + 'editable' => false, + 'start' => date('Y-m-d\TH:i:s', $start), + ); + + if ($subtasks[$offset]['time_estimated'] <= $interval) { + + $start += $subtasks[$offset]['time_estimated'] * 3600; + $interval -= $subtasks[$offset]['time_estimated']; + $offset++; + + $event['end'] = date('Y-m-d\TH:i:s', $start); + $events[] = $event; + } + else { + $subtasks[$offset]['time_estimated'] -= $interval; + $event['end'] = $slot[1]->format('Y-m-d\TH:i:s'); + $events[] = $event; + break; + } + } + } + + return $events; + } +} diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index a78ffacf..3669a647 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,13 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 54; +const VERSION = 55; + +function version_55($pdo) +{ + $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)'); + $rq->execute(array('subtask_forecast', '0')); +} function version_54($pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index 2396000f..b60e441b 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,13 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 35; +const VERSION = 36; + +function version_36($pdo) +{ + $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)'); + $rq->execute(array('subtask_forecast', '0')); +} function version_35($pdo) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index 0e0512d0..34ac2c6f 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,13 @@ use Core\Security; use PDO; use Model\Link; -const VERSION = 53; +const VERSION = 54; + +function version_54($pdo) +{ + $rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)'); + $rq->execute(array('subtask_forecast', '0')); +} function version_53($pdo) { diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index fc71ebf9..2373ab01 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -36,6 +36,7 @@ class ClassProvider implements ServiceProviderInterface 'ProjectPermission', 'Subtask', 'SubtaskExport', + 'SubtaskForecast', 'SubtaskTimeTracking', 'Swimlane', 'Task', diff --git a/app/Template/config/board.php b/app/Template/config/board.php index 57efcd08..15e2b422 100644 --- a/app/Template/config/board.php +++ b/app/Template/config/board.php @@ -28,6 +28,7 @@ <?= $this->formCheckbox('subtask_restriction', t('Allow only one subtask in progress at the same time for a user'), 1, $values['subtask_restriction'] == 1) ?> <?= $this->formCheckbox('subtask_time_tracking', t('Enable time tracking for subtasks'), 1, $values['subtask_time_tracking'] == 1) ?> + <?= $this->formCheckbox('subtask_forecast', t('Show subtask estimates in the user calendar'), 1, $values['subtask_forecast'] == 1) ?> <div class="form-actions"> <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> |