Add lead and cycle time for projects
This commit is contained in:
@@ -7,13 +7,13 @@ use Symfony\Component\Console\Input\InputArgument;
|
|||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
class ProjectDailySummaryExport extends Base
|
class ProjectDailyColumnStatsExport extends Base
|
||||||
{
|
{
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
->setName('export:daily-project-summary')
|
->setName('export:daily-project-column-stats')
|
||||||
->setDescription('Daily project summary CSV export (number of tasks per column and per day)')
|
->setDescription('Daily project column stats CSV export (number of tasks per column and per day)')
|
||||||
->addArgument('project_id', InputArgument::REQUIRED, 'Project id')
|
->addArgument('project_id', InputArgument::REQUIRED, 'Project id')
|
||||||
->addArgument('start_date', InputArgument::REQUIRED, 'Start date (YYYY-MM-DD)')
|
->addArgument('start_date', InputArgument::REQUIRED, 'Start date (YYYY-MM-DD)')
|
||||||
->addArgument('end_date', InputArgument::REQUIRED, 'End date (YYYY-MM-DD)');
|
->addArgument('end_date', InputArgument::REQUIRED, 'End date (YYYY-MM-DD)');
|
||||||
@@ -21,7 +21,7 @@ class ProjectDailySummaryExport extends Base
|
|||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$data = $this->projectDailySummary->getAggregatedMetrics(
|
$data = $this->projectDailyColumnStats->getAggregatedMetrics(
|
||||||
$input->getArgument('project_id'),
|
$input->getArgument('project_id'),
|
||||||
$input->getArgument('start_date'),
|
$input->getArgument('start_date'),
|
||||||
$input->getArgument('end_date')
|
$input->getArgument('end_date')
|
||||||
@@ -6,13 +6,13 @@ use Model\Project;
|
|||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
class ProjectDailySummaryCalculation extends Base
|
class ProjectDailyStatsCalculation extends Base
|
||||||
{
|
{
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
->setName('projects:daily-summary')
|
->setName('projects:daily-stats')
|
||||||
->setDescription('Calculate daily summary data for all projects');
|
->setDescription('Calculate daily statistics for all projects');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
@@ -21,7 +21,8 @@ class ProjectDailySummaryCalculation extends Base
|
|||||||
|
|
||||||
foreach ($projects as $project) {
|
foreach ($projects as $project) {
|
||||||
$output->writeln('Run calculation for '.$project['name']);
|
$output->writeln('Run calculation for '.$project['name']);
|
||||||
$this->projectDailySummary->updateTotals($project['id'], date('Y-m-d'));
|
$this->projectDailyColumnStats->updateTotals($project['id'], date('Y-m-d'));
|
||||||
|
$this->projectDailyStats->updateTotals($project['id'], date('Y-m-d'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,40 @@ class Analytic extends Base
|
|||||||
return $this->template->layout('analytic/layout', $params);
|
return $this->template->layout('analytic/layout', $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show average Lead and Cycle time
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function leadAndCycleTime()
|
||||||
|
{
|
||||||
|
$project = $this->getProject();
|
||||||
|
$values = $this->request->getValues();
|
||||||
|
|
||||||
|
$this->projectDailyStats->updateTotals($project['id'], date('Y-m-d'));
|
||||||
|
|
||||||
|
$from = $this->request->getStringParam('from', date('Y-m-d', strtotime('-1week')));
|
||||||
|
$to = $this->request->getStringParam('to', date('Y-m-d'));
|
||||||
|
|
||||||
|
if (! empty($values)) {
|
||||||
|
$from = $values['from'];
|
||||||
|
$to = $values['to'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->html($this->layout('analytic/lead_cycle_time', array(
|
||||||
|
'values' => array(
|
||||||
|
'from' => $from,
|
||||||
|
'to' => $to,
|
||||||
|
),
|
||||||
|
'project' => $project,
|
||||||
|
'average' => $this->projectAnalytic->getAverageLeadAndCycleTime($project['id']),
|
||||||
|
'metrics' => $this->projectDailyStats->getRawMetrics($project['id'], $from, $to),
|
||||||
|
'date_format' => $this->config->get('application_date_format'),
|
||||||
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
|
'title' => t('Lead and Cycle time for "%s"', $project['name']),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show average time spent by column
|
* Show average time spent by column
|
||||||
*
|
*
|
||||||
@@ -104,6 +138,8 @@ class Analytic extends Base
|
|||||||
$project = $this->getProject();
|
$project = $this->getProject();
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
|
|
||||||
|
$this->projectDailyColumnStats->updateTotals($project['id'], date('Y-m-d'));
|
||||||
|
|
||||||
$from = $this->request->getStringParam('from', date('Y-m-d', strtotime('-1week')));
|
$from = $this->request->getStringParam('from', date('Y-m-d', strtotime('-1week')));
|
||||||
$to = $this->request->getStringParam('to', date('Y-m-d'));
|
$to = $this->request->getStringParam('to', date('Y-m-d'));
|
||||||
|
|
||||||
@@ -112,7 +148,7 @@ class Analytic extends Base
|
|||||||
$to = $values['to'];
|
$to = $values['to'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$display_graph = $this->projectDailySummary->countDays($project['id'], $from, $to) >= 2;
|
$display_graph = $this->projectDailyColumnStats->countDays($project['id'], $from, $to) >= 2;
|
||||||
|
|
||||||
$this->response->html($this->layout($template, array(
|
$this->response->html($this->layout($template, array(
|
||||||
'values' => array(
|
'values' => array(
|
||||||
@@ -120,7 +156,7 @@ class Analytic extends Base
|
|||||||
'to' => $to,
|
'to' => $to,
|
||||||
),
|
),
|
||||||
'display_graph' => $display_graph,
|
'display_graph' => $display_graph,
|
||||||
'metrics' => $display_graph ? $this->projectDailySummary->getAggregatedMetrics($project['id'], $from, $to, $column) : array(),
|
'metrics' => $display_graph ? $this->projectDailyColumnStats->getAggregatedMetrics($project['id'], $from, $to, $column) : array(),
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'date_format' => $this->config->get('application_date_format'),
|
'date_format' => $this->config->get('application_date_format'),
|
||||||
'date_formats' => $this->dateParser->getAvailableFormats(),
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class Export extends Base
|
|||||||
*/
|
*/
|
||||||
public function summary()
|
public function summary()
|
||||||
{
|
{
|
||||||
$this->common('projectDailySummary', 'getAggregatedMetrics', t('Summary'), 'summary', t('Daily project summary export'));
|
$this->common('ProjectDailyColumnStats', 'getAggregatedMetrics', t('Summary'), 'summary', t('Daily project summary export'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ use Pimple\Container;
|
|||||||
* @property \Model\ProjectActivity $projectActivity
|
* @property \Model\ProjectActivity $projectActivity
|
||||||
* @property \Model\ProjectAnalytic $projectAnalytic
|
* @property \Model\ProjectAnalytic $projectAnalytic
|
||||||
* @property \Model\ProjectDuplication $projectDuplication
|
* @property \Model\ProjectDuplication $projectDuplication
|
||||||
* @property \Model\ProjectDailySummary $projectDailySummary
|
* @property \Model\ProjectDailyColumnStats $projectDailyColumnStats
|
||||||
|
* @property \Model\ProjectDailyStats $projectDailyStats
|
||||||
* @property \Model\ProjectIntegration $projectIntegration
|
* @property \Model\ProjectIntegration $projectIntegration
|
||||||
* @property \Model\ProjectPermission $projectPermission
|
* @property \Model\ProjectPermission $projectPermission
|
||||||
* @property \Model\Subtask $subtask
|
* @property \Model\Subtask $subtask
|
||||||
|
|||||||
@@ -88,6 +88,43 @@ class ProjectAnalytic extends Base
|
|||||||
return array_values($metrics);
|
return array_values($metrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the average lead and cycle time
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAverageLeadAndCycleTime($project_id)
|
||||||
|
{
|
||||||
|
$stats = array(
|
||||||
|
'count' => 0,
|
||||||
|
'total_lead_time' => 0,
|
||||||
|
'total_cycle_time' => 0,
|
||||||
|
'avg_lead_time' => 0,
|
||||||
|
'avg_cycle_time' => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
$tasks = $this->db
|
||||||
|
->table(Task::TABLE)
|
||||||
|
->columns('date_completed', 'date_creation', 'date_started')
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->desc('id')
|
||||||
|
->limit(1000)
|
||||||
|
->findAll();
|
||||||
|
|
||||||
|
foreach ($tasks as &$task) {
|
||||||
|
$stats['count']++;
|
||||||
|
$stats['total_lead_time'] += ($task['date_completed'] ?: time()) - $task['date_creation'];
|
||||||
|
$stats['total_cycle_time'] += empty($task['date_started']) ? 0 : ($task['date_completed'] ?: time()) - $task['date_started'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$stats['avg_lead_time'] = (int) ($stats['total_lead_time'] / $stats['count']);
|
||||||
|
$stats['avg_cycle_time'] = (int) ($stats['total_cycle_time'] / $stats['count']);
|
||||||
|
|
||||||
|
return $stats;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the average time spent into each column
|
* Get the average time spent into each column
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,22 +3,22 @@
|
|||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project daily summary
|
* Project Daily Column Stats
|
||||||
*
|
*
|
||||||
* @package model
|
* @package model
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
class ProjectDailySummary extends Base
|
class ProjectDailyColumnStats extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* SQL table name
|
* SQL table name
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const TABLE = 'project_daily_summaries';
|
const TABLE = 'project_daily_column_stats';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update daily totals for the project
|
* Update daily totals for the project and foreach column
|
||||||
*
|
*
|
||||||
* "total" is the number open of tasks in the column
|
* "total" is the number open of tasks in the column
|
||||||
* "score" is the sum of tasks score in the column
|
* "score" is the sum of tasks score in the column
|
||||||
@@ -38,7 +38,7 @@ class ProjectDailySummary extends Base
|
|||||||
|
|
||||||
// This call will fail if the record already exists
|
// This call will fail if the record already exists
|
||||||
// (cross database driver hack for INSERT..ON DUPLICATE KEY UPDATE)
|
// (cross database driver hack for INSERT..ON DUPLICATE KEY UPDATE)
|
||||||
$db->table(ProjectDailySummary::TABLE)->insert(array(
|
$db->table(ProjectDailyColumnStats::TABLE)->insert(array(
|
||||||
'day' => $date,
|
'day' => $date,
|
||||||
'project_id' => $project_id,
|
'project_id' => $project_id,
|
||||||
'column_id' => $column_id,
|
'column_id' => $column_id,
|
||||||
@@ -46,7 +46,7 @@ class ProjectDailySummary extends Base
|
|||||||
'score' => 0,
|
'score' => 0,
|
||||||
));
|
));
|
||||||
|
|
||||||
$db->table(ProjectDailySummary::TABLE)
|
$db->table(ProjectDailyColumnStats::TABLE)
|
||||||
->eq('project_id', $project_id)
|
->eq('project_id', $project_id)
|
||||||
->eq('column_id', $column_id)
|
->eq('column_id', $column_id)
|
||||||
->eq('day', $date)
|
->eq('day', $date)
|
||||||
@@ -95,19 +95,19 @@ class ProjectDailySummary extends Base
|
|||||||
*/
|
*/
|
||||||
public function getRawMetrics($project_id, $from, $to)
|
public function getRawMetrics($project_id, $from, $to)
|
||||||
{
|
{
|
||||||
return $this->db->table(ProjectDailySummary::TABLE)
|
return $this->db->table(ProjectDailyColumnStats::TABLE)
|
||||||
->columns(
|
->columns(
|
||||||
ProjectDailySummary::TABLE.'.column_id',
|
ProjectDailyColumnStats::TABLE.'.column_id',
|
||||||
ProjectDailySummary::TABLE.'.day',
|
ProjectDailyColumnStats::TABLE.'.day',
|
||||||
ProjectDailySummary::TABLE.'.total',
|
ProjectDailyColumnStats::TABLE.'.total',
|
||||||
ProjectDailySummary::TABLE.'.score',
|
ProjectDailyColumnStats::TABLE.'.score',
|
||||||
Board::TABLE.'.title AS column_title'
|
Board::TABLE.'.title AS column_title'
|
||||||
)
|
)
|
||||||
->join(Board::TABLE, 'id', 'column_id')
|
->join(Board::TABLE, 'id', 'column_id')
|
||||||
->eq(ProjectDailySummary::TABLE.'.project_id', $project_id)
|
->eq(ProjectDailyColumnStats::TABLE.'.project_id', $project_id)
|
||||||
->gte('day', $from)
|
->gte('day', $from)
|
||||||
->lte('day', $to)
|
->lte('day', $to)
|
||||||
->asc(ProjectDailySummary::TABLE.'.day')
|
->asc(ProjectDailyColumnStats::TABLE.'.day')
|
||||||
->findAll();
|
->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,17 +122,17 @@ class ProjectDailySummary extends Base
|
|||||||
*/
|
*/
|
||||||
public function getRawMetricsByDay($project_id, $from, $to)
|
public function getRawMetricsByDay($project_id, $from, $to)
|
||||||
{
|
{
|
||||||
return $this->db->table(ProjectDailySummary::TABLE)
|
return $this->db->table(ProjectDailyColumnStats::TABLE)
|
||||||
->columns(
|
->columns(
|
||||||
ProjectDailySummary::TABLE.'.day',
|
ProjectDailyColumnStats::TABLE.'.day',
|
||||||
'SUM('.ProjectDailySummary::TABLE.'.total) AS total',
|
'SUM('.ProjectDailyColumnStats::TABLE.'.total) AS total',
|
||||||
'SUM('.ProjectDailySummary::TABLE.'.score) AS score'
|
'SUM('.ProjectDailyColumnStats::TABLE.'.score) AS score'
|
||||||
)
|
)
|
||||||
->eq(ProjectDailySummary::TABLE.'.project_id', $project_id)
|
->eq(ProjectDailyColumnStats::TABLE.'.project_id', $project_id)
|
||||||
->gte('day', $from)
|
->gte('day', $from)
|
||||||
->lte('day', $to)
|
->lte('day', $to)
|
||||||
->asc(ProjectDailySummary::TABLE.'.day')
|
->asc(ProjectDailyColumnStats::TABLE.'.day')
|
||||||
->groupBy(ProjectDailySummary::TABLE.'.day')
|
->groupBy(ProjectDailyColumnStats::TABLE.'.day')
|
||||||
->findAll();
|
->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ class ProjectDailySummary extends Base
|
|||||||
$aggregates = array();
|
$aggregates = array();
|
||||||
|
|
||||||
// Fetch metrics for the project
|
// Fetch metrics for the project
|
||||||
$records = $this->db->table(ProjectDailySummary::TABLE)
|
$records = $this->db->table(ProjectDailyColumnStats::TABLE)
|
||||||
->eq('project_id', $project_id)
|
->eq('project_id', $project_id)
|
||||||
->gte('day', $from)
|
->gte('day', $from)
|
||||||
->lte('day', $to)
|
->lte('day', $to)
|
||||||
72
app/Model/ProjectDailyStats.php
Normal file
72
app/Model/ProjectDailyStats.php
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project Daily Stats
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectDailyStats extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* SQL table name
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const TABLE = 'project_daily_stats';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update daily totals for the project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param string $date Record date (YYYY-MM-DD)
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function updateTotals($project_id, $date)
|
||||||
|
{
|
||||||
|
$lead_cycle_time = $this->projectAnalytic->getAverageLeadAndCycleTime($project_id);
|
||||||
|
|
||||||
|
return $this->db->transaction(function($db) use ($project_id, $date, $lead_cycle_time) {
|
||||||
|
|
||||||
|
// This call will fail if the record already exists
|
||||||
|
// (cross database driver hack for INSERT..ON DUPLICATE KEY UPDATE)
|
||||||
|
$db->table(ProjectDailyStats::TABLE)->insert(array(
|
||||||
|
'day' => $date,
|
||||||
|
'project_id' => $project_id,
|
||||||
|
'avg_lead_time' => 0,
|
||||||
|
'avg_cycle_time' => 0,
|
||||||
|
));
|
||||||
|
|
||||||
|
$db->table(ProjectDailyStats::TABLE)
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->eq('day', $date)
|
||||||
|
->update(array(
|
||||||
|
'avg_lead_time' => $lead_cycle_time['avg_lead_time'],
|
||||||
|
'avg_cycle_time' => $lead_cycle_time['avg_cycle_time'],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get raw metrics for the project within a data range
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param string $from Start date (ISO format YYYY-MM-DD)
|
||||||
|
* @param string $to End date
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getRawMetrics($project_id, $from, $to)
|
||||||
|
{
|
||||||
|
return $this->db->table(self::TABLE)
|
||||||
|
->columns('day', 'avg_lead_time', 'avg_cycle_time')
|
||||||
|
->eq(self::TABLE.'.project_id', $project_id)
|
||||||
|
->gte('day', $from)
|
||||||
|
->lte('day', $to)
|
||||||
|
->asc(self::TABLE.'.day')
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,26 @@ use PDO;
|
|||||||
use Core\Security;
|
use Core\Security;
|
||||||
use Model\Link;
|
use Model\Link;
|
||||||
|
|
||||||
const VERSION = 78;
|
const VERSION = 79;
|
||||||
|
|
||||||
|
function version_79($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE project_daily_stats (
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
day CHAR(10) NOT NULL,
|
||||||
|
project_id INT NOT NULL,
|
||||||
|
avg_lead_time INT NOT NULL DEFAULT 0,
|
||||||
|
avg_cycle_time INT NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY(id),
|
||||||
|
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB CHARSET=utf8
|
||||||
|
");
|
||||||
|
|
||||||
|
$pdo->exec('CREATE UNIQUE INDEX project_daily_stats_idx ON project_daily_stats(day, project_id)');
|
||||||
|
|
||||||
|
$pdo->exec('RENAME TABLE project_daily_summaries TO project_daily_column_stats');
|
||||||
|
}
|
||||||
|
|
||||||
function version_78($pdo)
|
function version_78($pdo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,25 @@ use PDO;
|
|||||||
use Core\Security;
|
use Core\Security;
|
||||||
use Model\Link;
|
use Model\Link;
|
||||||
|
|
||||||
const VERSION = 58;
|
const VERSION = 59;
|
||||||
|
|
||||||
|
function version_59($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE project_daily_stats (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
day CHAR(10) NOT NULL,
|
||||||
|
project_id INTEGER NOT NULL,
|
||||||
|
avg_lead_time INTEGER NOT NULL DEFAULT 0,
|
||||||
|
avg_cycle_time INTEGER NOT NULL DEFAULT 0,
|
||||||
|
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
$pdo->exec('CREATE UNIQUE INDEX project_daily_stats_idx ON project_daily_stats(day, project_id)');
|
||||||
|
|
||||||
|
$pdo->exec('ALTER TABLE project_daily_summaries RENAME TO project_daily_column_stats');
|
||||||
|
}
|
||||||
|
|
||||||
function version_58($pdo)
|
function version_58($pdo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,25 @@ use Core\Security;
|
|||||||
use PDO;
|
use PDO;
|
||||||
use Model\Link;
|
use Model\Link;
|
||||||
|
|
||||||
const VERSION = 74;
|
const VERSION = 75;
|
||||||
|
|
||||||
|
function version_75($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE project_daily_stats (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
day TEXT NOT NULL,
|
||||||
|
project_id INTEGER NOT NULL,
|
||||||
|
avg_lead_time INTEGER NOT NULL DEFAULT 0,
|
||||||
|
avg_cycle_time INTEGER NOT NULL DEFAULT 0,
|
||||||
|
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
$pdo->exec('CREATE UNIQUE INDEX project_daily_stats_idx ON project_daily_stats(day, project_id)');
|
||||||
|
|
||||||
|
$pdo->exec('ALTER TABLE project_daily_summaries RENAME TO project_daily_column_stats');
|
||||||
|
}
|
||||||
|
|
||||||
function version_74($pdo)
|
function version_74($pdo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ class ClassProvider implements ServiceProviderInterface
|
|||||||
'ProjectActivity',
|
'ProjectActivity',
|
||||||
'ProjectAnalytic',
|
'ProjectAnalytic',
|
||||||
'ProjectDuplication',
|
'ProjectDuplication',
|
||||||
'ProjectDailySummary',
|
'ProjectDailyColumnStats',
|
||||||
|
'ProjectDailyStats',
|
||||||
'ProjectIntegration',
|
'ProjectIntegration',
|
||||||
'ProjectPermission',
|
'ProjectPermission',
|
||||||
'Subtask',
|
'Subtask',
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ class ProjectDailySummarySubscriber extends \Core\Base implements EventSubscribe
|
|||||||
public function execute(TaskEvent $event)
|
public function execute(TaskEvent $event)
|
||||||
{
|
{
|
||||||
if (isset($event['project_id'])) {
|
if (isset($event['project_id'])) {
|
||||||
$this->projectDailySummary->updateTotals($event['project_id'], date('Y-m-d'));
|
$this->projectDailyColumnStats->updateTotals($event['project_id'], date('Y-m-d'));
|
||||||
|
$this->projectDailyStats->updateTotals($event['project_id'], date('Y-m-d'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
42
app/Template/analytic/lead_cycle_time.php
Normal file
42
app/Template/analytic/lead_cycle_time.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('Average Lead and Cycle time') ?></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="listing">
|
||||||
|
<ul>
|
||||||
|
<li><?= t('Average lead time: ').'<strong>'.$this->dt->duration($average['avg_lead_time']) ?></strong></li>
|
||||||
|
<li><?= t('Average cycle time: ').'<strong>'.$this->dt->duration($average['avg_cycle_time']) ?></strong></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (empty($metrics)): ?>
|
||||||
|
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||||
|
<?php else: ?>
|
||||||
|
<section id="analytic-lead-cycle-time">
|
||||||
|
|
||||||
|
<div id="chart" data-metrics='<?= json_encode($metrics) ?>' data-label-cycle="<?= t('Cycle Time') ?>" data-label-lead="<?= t('Lead Time') ?>"></div>
|
||||||
|
|
||||||
|
<form method="post" class="form-inline" action="<?= $this->url->href('analytic', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
||||||
|
|
||||||
|
<?= $this->form->csrf() ?>
|
||||||
|
|
||||||
|
<div class="form-inline-group">
|
||||||
|
<?= $this->form->label(t('Start Date'), 'from') ?>
|
||||||
|
<?= $this->form->text('from', $values, array(), array('required', 'placeholder="'.$this->text->in($date_format, $date_formats).'"'), 'form-date') ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-inline-group">
|
||||||
|
<?= $this->form->label(t('End Date'), 'to') ?>
|
||||||
|
<?= $this->form->text('to', $values, array(), array('required', 'placeholder="'.$this->text->in($date_format, $date_formats).'"'), 'form-date') ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-inline-group">
|
||||||
|
<input type="submit" value="<?= t('Execute') ?>" class="btn btn-blue"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="alert alert-info">
|
||||||
|
<?= t('This chart show the average lead and cycle time for the last %d tasks over the time.', 1000) ?>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
<?php endif ?>
|
||||||
@@ -16,5 +16,8 @@
|
|||||||
<li>
|
<li>
|
||||||
<?= $this->url->link(t('Average time into each column'), 'analytic', 'averageTimeByColumn', array('project_id' => $project['id'])) ?>
|
<?= $this->url->link(t('Average time into each column'), 'analytic', 'averageTimeByColumn', array('project_id' => $project['id'])) ?>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<?= $this->url->link(t('Lead and cycle time'), 'analytic', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
File diff suppressed because one or more lines are too long
@@ -243,6 +243,51 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw lead and cycle time for the project
|
||||||
|
function drawLeadAndCycleTime()
|
||||||
|
{
|
||||||
|
var metrics = $("#chart").data("metrics");
|
||||||
|
var cycle = [$("#chart").data("label-cycle")];
|
||||||
|
var lead = [$("#chart").data("label-lead")];
|
||||||
|
var categories = [];
|
||||||
|
|
||||||
|
var types = {};
|
||||||
|
types[$("#chart").data("label-cycle")] = 'area';
|
||||||
|
types[$("#chart").data("label-lead")] = 'area-spline';
|
||||||
|
|
||||||
|
var colors = {};
|
||||||
|
colors[$("#chart").data("label-lead")] = '#afb42b';
|
||||||
|
colors[$("#chart").data("label-cycle")] = '#4e342e';
|
||||||
|
|
||||||
|
for (var i = 0; i < metrics.length; i++) {
|
||||||
|
cycle.push(parseInt(metrics[i].avg_cycle_time));
|
||||||
|
lead.push(parseInt(metrics[i].avg_lead_time));
|
||||||
|
categories.push(metrics[i].day);
|
||||||
|
}
|
||||||
|
|
||||||
|
c3.generate({
|
||||||
|
data: {
|
||||||
|
columns: [
|
||||||
|
lead,
|
||||||
|
cycle
|
||||||
|
],
|
||||||
|
types: types,
|
||||||
|
colors: colors
|
||||||
|
},
|
||||||
|
axis: {
|
||||||
|
x: {
|
||||||
|
type: 'category',
|
||||||
|
categories: categories
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
tick: {
|
||||||
|
format: formatDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function formatDuration(d)
|
function formatDuration(d)
|
||||||
{
|
{
|
||||||
if (d >= 86400) {
|
if (d >= 86400) {
|
||||||
@@ -281,6 +326,9 @@
|
|||||||
else if (Kanboard.Exists("analytic-task-time-column")) {
|
else if (Kanboard.Exists("analytic-task-time-column")) {
|
||||||
drawTaskTimeColumn();
|
drawTaskTimeColumn();
|
||||||
}
|
}
|
||||||
|
else if (Kanboard.Exists("analytic-lead-cycle-time")) {
|
||||||
|
drawLeadAndCycleTime();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"eluceo/ical": "*",
|
"eluceo/ical": "*",
|
||||||
"erusev/parsedown" : "1.5.3",
|
"erusev/parsedown" : "1.5.3",
|
||||||
"fabiang/xmpp" : "0.6.1",
|
"fabiang/xmpp" : "0.6.1",
|
||||||
"fguillot/json-rpc" : "dev-master",
|
"fguillot/json-rpc" : "1.0.0",
|
||||||
"fguillot/picodb" : "1.0.0",
|
"fguillot/picodb" : "1.0.0",
|
||||||
"fguillot/simpleLogger" : "0.0.2",
|
"fguillot/simpleLogger" : "0.0.2",
|
||||||
"fguillot/simple-validator" : "0.0.3",
|
"fguillot/simple-validator" : "0.0.3",
|
||||||
|
|||||||
13
composer.lock
generated
13
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "1ef3f084b6c8651977b1bbc84d86cb69",
|
"hash": "0048471872ea99cd30c53c0398c7d9f2",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "christian-riesen/base32",
|
"name": "christian-riesen/base32",
|
||||||
@@ -260,16 +260,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fguillot/json-rpc",
|
"name": "fguillot/json-rpc",
|
||||||
"version": "dev-master",
|
"version": "v1.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/fguillot/JsonRPC.git",
|
"url": "https://github.com/fguillot/JsonRPC.git",
|
||||||
"reference": "ac3ddcf8f74777d72b8044d6d128f41aabe292f2"
|
"reference": "5a11f1414780a200f09b78d20ab72b5cee4faa95"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/ac3ddcf8f74777d72b8044d6d128f41aabe292f2",
|
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/5a11f1414780a200f09b78d20ab72b5cee4faa95",
|
||||||
"reference": "ac3ddcf8f74777d72b8044d6d128f41aabe292f2",
|
"reference": "5a11f1414780a200f09b78d20ab72b5cee4faa95",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -292,7 +292,7 @@
|
|||||||
],
|
],
|
||||||
"description": "Simple Json-RPC client/server library that just works",
|
"description": "Simple Json-RPC client/server library that just works",
|
||||||
"homepage": "https://github.com/fguillot/JsonRPC",
|
"homepage": "https://github.com/fguillot/JsonRPC",
|
||||||
"time": "2015-07-01 19:26:37"
|
"time": "2015-07-01 19:50:31"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fguillot/picodb",
|
"name": "fguillot/picodb",
|
||||||
@@ -819,7 +819,6 @@
|
|||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": {
|
"stability-flags": {
|
||||||
"fguillot/json-rpc": 20,
|
|
||||||
"swiftmailer/swiftmailer": 0,
|
"swiftmailer/swiftmailer": 0,
|
||||||
"symfony/console": 0
|
"symfony/console": 0
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,6 +37,6 @@ Kanboard use the complexity or story point to generate this diagram.
|
|||||||
Don't forget to run the daily job for stats calculation
|
Don't forget to run the daily job for stats calculation
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
To generate accurate analytics data, you should run the daily cronjob **project daily summaries** just before midnight.
|
To generate accurate analytics data, you should run the daily cronjob **project daily statistics** just before midnight.
|
||||||
|
|
||||||
[Read the documentation about Kanboard CLI](http://kanboard.net/documentation/cli)
|
[Read the documentation about Kanboard CLI](cli.markdown)
|
||||||
|
|||||||
@@ -13,36 +13,35 @@ Usage
|
|||||||
- Run the command `./kanboard`
|
- Run the command `./kanboard`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ ./kanboard
|
|
||||||
Kanboard version master
|
Kanboard version master
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
command [options] [arguments]
|
command [options] [arguments]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--help (-h) Display this help message
|
-h, --help Display this help message
|
||||||
--quiet (-q) Do not output any message
|
-q, --quiet Do not output any message
|
||||||
--verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
|
-V, --version Display this application version
|
||||||
--version (-V) Display this application version
|
--ansi Force ANSI output
|
||||||
--ansi Force ANSI output
|
--no-ansi Disable ANSI output
|
||||||
--no-ansi Disable ANSI output
|
-n, --no-interaction Do not ask any interactive question
|
||||||
--no-interaction (-n) Do not ask any interactive question
|
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
|
||||||
|
|
||||||
Available commands:
|
Available commands:
|
||||||
help Displays help for a command
|
help Displays help for a command
|
||||||
list Lists commands
|
list Lists commands
|
||||||
export
|
export
|
||||||
export:daily-project-summary Daily project summary CSV export (number of tasks per column and per day)
|
export:daily-project-column-stats Daily project column stats CSV export (number of tasks per column and per day)
|
||||||
export:subtasks Subtasks CSV export
|
export:subtasks Subtasks CSV export
|
||||||
export:tasks Tasks CSV export
|
export:tasks Tasks CSV export
|
||||||
export:transitions Task transitions CSV export
|
export:transitions Task transitions CSV export
|
||||||
locale
|
locale
|
||||||
locale:compare Compare application translations with the fr_FR locale
|
locale:compare Compare application translations with the fr_FR locale
|
||||||
locale:sync Synchronize all translations based on the fr_FR locale
|
locale:sync Synchronize all translations based on the fr_FR locale
|
||||||
notification
|
notification
|
||||||
notification:overdue-tasks Send notifications for overdue tasks
|
notification:overdue-tasks Send notifications for overdue tasks
|
||||||
projects
|
projects
|
||||||
projects:daily-summary Calculate daily summary data for all projects
|
projects:daily-stats Calculate daily statistics for all projects
|
||||||
```
|
```
|
||||||
|
|
||||||
Available commands
|
Available commands
|
||||||
@@ -97,13 +96,13 @@ Example:
|
|||||||
The exported data will be printed on the standard output:
|
The exported data will be printed on the standard output:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./kanboard export:daily-project-summary <project_id> <start_date> <end_date>
|
./kanboard export:daily-project-column-stats <project_id> <start_date> <end_date>
|
||||||
```
|
```
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./kanboard export:daily-project-summary 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
|
./kanboard export:daily-project-column-stats 1 2014-10-01 2014-11-30 > /tmp/my_custom_export.csv
|
||||||
```
|
```
|
||||||
|
|
||||||
### Send notifications for overdue tasks
|
### Send notifications for overdue tasks
|
||||||
@@ -133,12 +132,12 @@ Cronjob example:
|
|||||||
0 8 * * * cd /path/to/kanboard && ./kanboard notification:overdue-tasks >/dev/null 2>&1
|
0 8 * * * cd /path/to/kanboard && ./kanboard notification:overdue-tasks >/dev/null 2>&1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run daily project summaries calculation
|
### Run daily project stats calculation
|
||||||
|
|
||||||
You can add a background task that calculate the daily project summaries everyday:
|
You can add a background task to calculate the project statistics everyday:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ ./kanboard projects:daily-summary
|
$ ./kanboard projects:daily-stats
|
||||||
Run calculation for Project #0
|
Run calculation for Project #0
|
||||||
Run calculation for Project #1
|
Run calculation for Project #1
|
||||||
Run calculation for Project #10
|
Run calculation for Project #10
|
||||||
|
|||||||
4
kanboard
4
kanboard
@@ -12,8 +12,8 @@ $application = new Application('Kanboard', APP_VERSION);
|
|||||||
$application->add(new Console\TaskOverdueNotification($container));
|
$application->add(new Console\TaskOverdueNotification($container));
|
||||||
$application->add(new Console\SubtaskExport($container));
|
$application->add(new Console\SubtaskExport($container));
|
||||||
$application->add(new Console\TaskExport($container));
|
$application->add(new Console\TaskExport($container));
|
||||||
$application->add(new Console\ProjectDailySummaryCalculation($container));
|
$application->add(new Console\ProjectDailyStatsCalculation($container));
|
||||||
$application->add(new Console\ProjectDailySummaryExport($container));
|
$application->add(new Console\ProjectDailyColumnStatsExport($container));
|
||||||
$application->add(new Console\TransitionExport($container));
|
$application->add(new Console\TransitionExport($container));
|
||||||
$application->add(new Console\LocaleSync($container));
|
$application->add(new Console\LocaleSync($container));
|
||||||
$application->add(new Console\LocaleComparator($container));
|
$application->add(new Console\LocaleComparator($container));
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
require __DIR__.'/../app/common.php';
|
require __DIR__.'/../app/common.php';
|
||||||
|
|
||||||
use Model\ProjectDailySummary;
|
use Model\ProjectDailyColumnStats;
|
||||||
use Model\TaskCreation;
|
use Model\TaskCreation;
|
||||||
use Model\TaskStatus;
|
use Model\TaskStatus;
|
||||||
|
|
||||||
$pds = new ProjectDailySummary($container);
|
$pds = new ProjectDailyColumnStats($container);
|
||||||
$taskCreation = new TaskCreation($container);
|
$taskCreation = new TaskCreation($container);
|
||||||
$taskStatus = new TaskStatus($container);
|
$taskStatus = new TaskStatus($container);
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
require __DIR__.'/../app/common.php';
|
require __DIR__.'/../app/common.php';
|
||||||
|
|
||||||
use Model\ProjectDailySummary;
|
use Model\ProjectDailyColumnStats;
|
||||||
use Model\TaskCreation;
|
use Model\TaskCreation;
|
||||||
use Model\TaskPosition;
|
use Model\TaskPosition;
|
||||||
|
|
||||||
$pds = new ProjectDailySummary($container);
|
$pds = new ProjectDailyColumnStats($container);
|
||||||
$taskCreation = new TaskCreation($container);
|
$taskCreation = new TaskCreation($container);
|
||||||
$taskPosition = new TaskPosition($container);
|
$taskPosition = new TaskPosition($container);
|
||||||
|
|
||||||
|
|||||||
70
scripts/create-sample-lead-time.php
Executable file
70
scripts/create-sample-lead-time.php
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require __DIR__.'/../app/common.php';
|
||||||
|
|
||||||
|
use Model\Project;
|
||||||
|
use Model\ProjectDailyStats;
|
||||||
|
|
||||||
|
$p = new Project($container);
|
||||||
|
$pds = new ProjectDailyStats($container);
|
||||||
|
|
||||||
|
$p->create(array('name' => 'Test Lead/Cycle time'));
|
||||||
|
|
||||||
|
$container['db']->table('tasks')->insert(array(
|
||||||
|
'title' => 'Lead time = 4d | Cycle time = 3d',
|
||||||
|
'date_creation' => strtotime('-7 days'),
|
||||||
|
'date_started' => strtotime('-6 days'),
|
||||||
|
'date_completed' => strtotime('-3 days'),
|
||||||
|
'is_active' => 0,
|
||||||
|
'project_id' => 1,
|
||||||
|
'column_id' => 1,
|
||||||
|
));
|
||||||
|
|
||||||
|
$container['db']->table('tasks')->insert(array(
|
||||||
|
'title' => 'Lead time = 1d | Cycle time = 1d',
|
||||||
|
'date_creation' => strtotime('-7 days'),
|
||||||
|
'date_started' => strtotime('-7 days'),
|
||||||
|
'date_completed' => strtotime('-6 days'),
|
||||||
|
'is_active' => 0,
|
||||||
|
'project_id' => 1,
|
||||||
|
'column_id' => 1,
|
||||||
|
));
|
||||||
|
|
||||||
|
$pds->updateTotals(1, date('Y-m-d', strtotime('-6 days')));
|
||||||
|
|
||||||
|
$container['db']->table('tasks')->insert(array(
|
||||||
|
'title' => 'Lead time = 7d | Cycle time = 5d',
|
||||||
|
'date_creation' => strtotime('-7 days'),
|
||||||
|
'date_started' => strtotime('-5 days'),
|
||||||
|
'date_completed' => strtotime('today'),
|
||||||
|
'is_active' => 0,
|
||||||
|
'project_id' => 1,
|
||||||
|
'column_id' => 1,
|
||||||
|
));
|
||||||
|
|
||||||
|
$pds->updateTotals(1, date('Y-m-d', strtotime('-5 days')));
|
||||||
|
|
||||||
|
$container['db']->table('tasks')->insert(array(
|
||||||
|
'title' => 'Lead time = 1d | Cycle time = 0',
|
||||||
|
'date_creation' => strtotime('-3 days'),
|
||||||
|
'date_started' => 0,
|
||||||
|
'date_completed' => 0,
|
||||||
|
'is_active' => 0,
|
||||||
|
'project_id' => 1,
|
||||||
|
'column_id' => 1,
|
||||||
|
));
|
||||||
|
|
||||||
|
$pds->updateTotals(1, date('Y-m-d', strtotime('-4 days')));
|
||||||
|
|
||||||
|
$container['db']->table('tasks')->insert(array(
|
||||||
|
'title' => 'Lead time = 1d | Cycle time = 1d',
|
||||||
|
'date_creation' => strtotime('-3 days'),
|
||||||
|
'date_started' => strtotime('-3 days'),
|
||||||
|
'date_completed' => 0,
|
||||||
|
'is_active' => 0,
|
||||||
|
'project_id' => 1,
|
||||||
|
'column_id' => 1,
|
||||||
|
));
|
||||||
|
|
||||||
|
$pds->updateTotals(1, date('Y-m-d', strtotime('-3 days')));
|
||||||
@@ -3,17 +3,17 @@
|
|||||||
require_once __DIR__.'/Base.php';
|
require_once __DIR__.'/Base.php';
|
||||||
|
|
||||||
use Model\Project;
|
use Model\Project;
|
||||||
use Model\ProjectDailySummary;
|
use Model\ProjectDailyColumnStats;
|
||||||
use Model\Task;
|
use Model\Task;
|
||||||
use Model\TaskCreation;
|
use Model\TaskCreation;
|
||||||
use Model\TaskStatus;
|
use Model\TaskStatus;
|
||||||
|
|
||||||
class ProjectDailySummaryTest extends Base
|
class ProjectDailyColumnStatsTest extends Base
|
||||||
{
|
{
|
||||||
public function testUpdateTotals()
|
public function testUpdateTotals()
|
||||||
{
|
{
|
||||||
$p = new Project($this->container);
|
$p = new Project($this->container);
|
||||||
$pds = new ProjectDailySummary($this->container);
|
$pds = new ProjectDailyColumnStats($this->container);
|
||||||
$tc = new TaskCreation($this->container);
|
$tc = new TaskCreation($this->container);
|
||||||
$ts = new TaskStatus($this->container);
|
$ts = new TaskStatus($this->container);
|
||||||
|
|
||||||
Reference in New Issue
Block a user