Move analytic logic to separate classes
This commit is contained in:
50
app/Analytic/EstimatedTimeComparisonAnalytic.php
Normal file
50
app/Analytic/EstimatedTimeComparisonAnalytic.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Analytic;
|
||||||
|
|
||||||
|
use Kanboard\Core\Base;
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimated/Spent Time Comparison
|
||||||
|
*
|
||||||
|
* @package analytic
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class EstimatedTimeComparisonAnalytic extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Build report
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function build($project_id)
|
||||||
|
{
|
||||||
|
$rows = $this->db->table(Task::TABLE)
|
||||||
|
->columns('SUM(time_estimated) AS time_estimated', 'SUM(time_spent) AS time_spent', 'is_active')
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->groupBy('is_active')
|
||||||
|
->findAll();
|
||||||
|
|
||||||
|
$metrics = array(
|
||||||
|
'open' => array(
|
||||||
|
'time_spent' => 0,
|
||||||
|
'time_estimated' => 0,
|
||||||
|
),
|
||||||
|
'closed' => array(
|
||||||
|
'time_spent' => 0,
|
||||||
|
'time_estimated' => 0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$key = $row['is_active'] == Task::STATUS_OPEN ? 'open' : 'closed';
|
||||||
|
$metrics[$key]['time_spent'] = $row['time_spent'];
|
||||||
|
$metrics[$key]['time_estimated'] = $row['time_estimated'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $metrics;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
app/Analytic/TaskDistributionAnalytic.php
Normal file
48
app/Analytic/TaskDistributionAnalytic.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Analytic;
|
||||||
|
|
||||||
|
use Kanboard\Core\Base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task Distribution
|
||||||
|
*
|
||||||
|
* @package analytic
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskDistributionAnalytic extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Build report
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function build($project_id)
|
||||||
|
{
|
||||||
|
$metrics = array();
|
||||||
|
$total = 0;
|
||||||
|
$columns = $this->board->getColumns($project_id);
|
||||||
|
|
||||||
|
foreach ($columns as $column) {
|
||||||
|
$nb_tasks = $this->taskFinder->countByColumnId($project_id, $column['id']);
|
||||||
|
$total += $nb_tasks;
|
||||||
|
|
||||||
|
$metrics[] = array(
|
||||||
|
'column_title' => $column['title'],
|
||||||
|
'nb_tasks' => $nb_tasks,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($total === 0) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($metrics as &$metric) {
|
||||||
|
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $metrics;
|
||||||
|
}
|
||||||
|
}
|
||||||
56
app/Analytic/UserDistributionAnalytic.php
Normal file
56
app/Analytic/UserDistributionAnalytic.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Analytic;
|
||||||
|
|
||||||
|
use Kanboard\Core\Base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Distribution
|
||||||
|
*
|
||||||
|
* @package analytic
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class UserDistributionAnalytic extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Build Report
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function build($project_id)
|
||||||
|
{
|
||||||
|
$metrics = array();
|
||||||
|
$total = 0;
|
||||||
|
$tasks = $this->taskFinder->getAll($project_id);
|
||||||
|
$users = $this->projectUserRole->getAssignableUsersList($project_id);
|
||||||
|
|
||||||
|
foreach ($tasks as $task) {
|
||||||
|
$user = isset($users[$task['owner_id']]) ? $users[$task['owner_id']] : $users[0];
|
||||||
|
$total++;
|
||||||
|
|
||||||
|
if (! isset($metrics[$user])) {
|
||||||
|
$metrics[$user] = array(
|
||||||
|
'nb_tasks' => 0,
|
||||||
|
'percentage' => 0,
|
||||||
|
'user' => $user,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$metrics[$user]['nb_tasks']++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($total === 0) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($metrics as &$metric) {
|
||||||
|
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($metrics);
|
||||||
|
|
||||||
|
return array_values($metrics);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,7 +88,7 @@ class Analytic extends Base
|
|||||||
|
|
||||||
$this->response->html($this->layout('analytic/tasks', array(
|
$this->response->html($this->layout('analytic/tasks', array(
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'metrics' => $this->projectAnalytic->getTaskRepartition($project['id']),
|
'metrics' => $this->taskDistributionAnalytic->build($project['id']),
|
||||||
'title' => t('Task repartition for "%s"', $project['name']),
|
'title' => t('Task repartition for "%s"', $project['name']),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ class Analytic extends Base
|
|||||||
|
|
||||||
$this->response->html($this->layout('analytic/users', array(
|
$this->response->html($this->layout('analytic/users', array(
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'metrics' => $this->projectAnalytic->getUserRepartition($project['id']),
|
'metrics' => $this->userDistributionAnalytic->build($project['id']),
|
||||||
'title' => t('User repartition for "%s"', $project['name']),
|
'title' => t('User repartition for "%s"', $project['name']),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ class Analytic extends Base
|
|||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProject();
|
||||||
$params = $this->getProjectFilters('analytic', 'compareHours');
|
$params = $this->getProjectFilters('analytic', 'compareHours');
|
||||||
$query = $this->taskFilter->search('status:all')->filterByProject($params['project']['id'])->getQuery();
|
$query = $this->taskFilter->create()->filterByProject($params['project']['id'])->getQuery();
|
||||||
|
|
||||||
$paginator = $this->paginator
|
$paginator = $this->paginator
|
||||||
->setUrl('analytic', 'compareHours', array('project_id' => $project['id']))
|
->setUrl('analytic', 'compareHours', array('project_id' => $project['id']))
|
||||||
@@ -186,12 +186,10 @@ class Analytic extends Base
|
|||||||
->setQuery($query)
|
->setQuery($query)
|
||||||
->calculate();
|
->calculate();
|
||||||
|
|
||||||
$stats = $this->projectAnalytic->getHoursByStatus($project['id']);
|
|
||||||
|
|
||||||
$this->response->html($this->layout('analytic/compare_hours', array(
|
$this->response->html($this->layout('analytic/compare_hours', array(
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'paginator' => $paginator,
|
'paginator' => $paginator,
|
||||||
'metrics' => $stats,
|
'metrics' => $this->estimatedTimeComparisonAnalytic->build($project['id']),
|
||||||
'title' => t('Compare hours for "%s"', $project['name']),
|
'title' => t('Compare hours for "%s"', $project['name']),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ use Pimple\Container;
|
|||||||
* @package core
|
* @package core
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*
|
*
|
||||||
|
* @property \Kanboard\Analytic\TaskDistributionAnalytic $taskDistributionAnalytic
|
||||||
|
* @property \Kanboard\Analytic\UserDistributionAnalytic $userDistributionAnalytic
|
||||||
|
* @property \Kanboard\Analytic\EstimatedTimeComparisonAnalytic $estimatedTimeComparisonAnalytic
|
||||||
* @property \Kanboard\Core\Action\ActionManager $actionManager
|
* @property \Kanboard\Core\Action\ActionManager $actionManager
|
||||||
* @property \Kanboard\Core\Cache\MemoryCache $memoryCache
|
* @property \Kanboard\Core\Cache\MemoryCache $memoryCache
|
||||||
* @property \Kanboard\Core\Event\EventManager $eventManager
|
* @property \Kanboard\Core\Event\EventManager $eventManager
|
||||||
|
|||||||
@@ -10,82 +10,6 @@ namespace Kanboard\Model;
|
|||||||
*/
|
*/
|
||||||
class ProjectAnalytic extends Base
|
class ProjectAnalytic extends Base
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Get tasks repartition
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getTaskRepartition($project_id)
|
|
||||||
{
|
|
||||||
$metrics = array();
|
|
||||||
$total = 0;
|
|
||||||
$columns = $this->board->getColumns($project_id);
|
|
||||||
|
|
||||||
foreach ($columns as $column) {
|
|
||||||
$nb_tasks = $this->taskFinder->countByColumnId($project_id, $column['id']);
|
|
||||||
$total += $nb_tasks;
|
|
||||||
|
|
||||||
$metrics[] = array(
|
|
||||||
'column_title' => $column['title'],
|
|
||||||
'nb_tasks' => $nb_tasks,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($total === 0) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($metrics as &$metric) {
|
|
||||||
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $metrics;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get users repartition
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getUserRepartition($project_id)
|
|
||||||
{
|
|
||||||
$metrics = array();
|
|
||||||
$total = 0;
|
|
||||||
$tasks = $this->taskFinder->getAll($project_id);
|
|
||||||
$users = $this->projectUserRole->getAssignableUsersList($project_id);
|
|
||||||
|
|
||||||
foreach ($tasks as $task) {
|
|
||||||
$user = isset($users[$task['owner_id']]) ? $users[$task['owner_id']] : $users[0];
|
|
||||||
$total++;
|
|
||||||
|
|
||||||
if (! isset($metrics[$user])) {
|
|
||||||
$metrics[$user] = array(
|
|
||||||
'nb_tasks' => 0,
|
|
||||||
'percentage' => 0,
|
|
||||||
'user' => $user,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$metrics[$user]['nb_tasks']++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($total === 0) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($metrics as &$metric) {
|
|
||||||
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
ksort($metrics);
|
|
||||||
|
|
||||||
return array_values($metrics);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the average lead and cycle time
|
* Get the average lead and cycle time
|
||||||
*
|
*
|
||||||
@@ -179,49 +103,4 @@ class ProjectAnalytic extends Base
|
|||||||
|
|
||||||
return $stats;
|
return $stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the time spent and estimated into each status
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getHoursByStatus($project_id)
|
|
||||||
{
|
|
||||||
$stats = array();
|
|
||||||
|
|
||||||
// Get the times related to each task
|
|
||||||
$tasks = $this->db
|
|
||||||
->table(Task::TABLE)
|
|
||||||
->columns('id', 'time_estimated', 'time_spent', 'is_active')
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->desc('id')
|
|
||||||
->limit(1000)
|
|
||||||
->findAll();
|
|
||||||
|
|
||||||
// Init values
|
|
||||||
$stats['closed'] = array(
|
|
||||||
'time_spent' => 0,
|
|
||||||
'time_estimated' => 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
$stats['open'] = array(
|
|
||||||
'time_spent' => 0,
|
|
||||||
'time_estimated' => 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add times spent and estimated to each status
|
|
||||||
foreach ($tasks as &$task) {
|
|
||||||
if ($task['is_active']) {
|
|
||||||
$stats['open']['time_estimated'] += $task['time_estimated'];
|
|
||||||
$stats['open']['time_spent'] += $task['time_spent'];
|
|
||||||
} else {
|
|
||||||
$stats['closed']['time_estimated'] += $task['time_estimated'];
|
|
||||||
$stats['closed']['time_spent'] += $task['time_spent'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $stats;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ use Kanboard\Core\Http\Client as HttpClient;
|
|||||||
class ClassProvider implements ServiceProviderInterface
|
class ClassProvider implements ServiceProviderInterface
|
||||||
{
|
{
|
||||||
private $classes = array(
|
private $classes = array(
|
||||||
|
'Analytic' => array(
|
||||||
|
'TaskDistributionAnalytic',
|
||||||
|
'UserDistributionAnalytic',
|
||||||
|
'EstimatedTimeComparisonAnalytic',
|
||||||
|
),
|
||||||
'Model' => array(
|
'Model' => array(
|
||||||
'Action',
|
'Action',
|
||||||
'ActionParameter',
|
'ActionParameter',
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
<div class="listing">
|
<div class="listing">
|
||||||
<ul>
|
<ul>
|
||||||
<li><?= t('Estimated hours: ').'<strong>'.$this->e($metrics['open']['time_estimated']+$metrics['open']['time_estimated']) ?></strong></li>
|
<li><?= t('Estimated hours: ').'<strong>'.$this->e($metrics['open']['time_estimated'] + $metrics['closed']['time_estimated']) ?></strong></li>
|
||||||
<li><?= t('Actual hours: ').'<strong>'.$this->e($metrics['open']['time_spent']+$metrics['closed']['time_spent']) ?></strong></li>
|
<li><?= t('Actual hours: ').'<strong>'.$this->e($metrics['open']['time_spent'] + $metrics['closed']['time_spent']) ?></strong></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -13,7 +13,12 @@
|
|||||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<section id="analytic-compare-hours">
|
<section id="analytic-compare-hours">
|
||||||
<div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS)?>' data-label-spent="<?= t('Hours Spent') ?>" data-label-estimated="<?= t('Hours Estimated') ?>"></div>
|
<div id="chart"
|
||||||
|
data-metrics='<?= json_encode($metrics, JSON_HEX_APOS)?>'
|
||||||
|
data-label-spent="<?= t('Hours Spent') ?>"
|
||||||
|
data-label-estimated="<?= t('Hours Estimated') ?>"
|
||||||
|
data-label-closed="<?= t('Closed') ?>"
|
||||||
|
data-label-open="<?= t('Open') ?>"></div>
|
||||||
|
|
||||||
<?php if ($paginator->isEmpty()): ?>
|
<?php if ($paginator->isEmpty()): ?>
|
||||||
<p class="alert"><?= t('No tasks found.') ?></p>
|
<p class="alert"><?= t('No tasks found.') ?></p>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,14 +4,16 @@ function CompareHoursColumnChart(app) {
|
|||||||
|
|
||||||
CompareHoursColumnChart.prototype.execute = function() {
|
CompareHoursColumnChart.prototype.execute = function() {
|
||||||
var metrics = $("#chart").data("metrics");
|
var metrics = $("#chart").data("metrics");
|
||||||
|
var labelOpen = $("#chart").data("label-open");
|
||||||
|
var labelClosed = $("#chart").data("label-closed");
|
||||||
var spent = [$("#chart").data("label-spent")];
|
var spent = [$("#chart").data("label-spent")];
|
||||||
var estimated = [$("#chart").data("label-estimated")];
|
var estimated = [$("#chart").data("label-estimated")];
|
||||||
var categories = [];
|
var categories = [];
|
||||||
|
|
||||||
for (var status in metrics) {
|
for (var status in metrics) {
|
||||||
spent.push(parseInt(metrics[status].time_spent));
|
spent.push(parseFloat(metrics[status].time_spent));
|
||||||
estimated.push(parseInt(metrics[status].time_estimated));
|
estimated.push(parseFloat(metrics[status].time_estimated));
|
||||||
categories.push(status);
|
categories.push(status == 'open' ? labelOpen : labelClosed);
|
||||||
}
|
}
|
||||||
|
|
||||||
c3.generate({
|
c3.generate({
|
||||||
|
|||||||
99
tests/units/Analytic/EstimatedTimeComparisonAnalyticTest.php
Normal file
99
tests/units/Analytic/EstimatedTimeComparisonAnalyticTest.php
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/../Base.php';
|
||||||
|
|
||||||
|
use Kanboard\Model\TaskCreation;
|
||||||
|
use Kanboard\Model\Project;
|
||||||
|
use Kanboard\Analytic\EstimatedTimeComparisonAnalytic;
|
||||||
|
|
||||||
|
class EstimatedTimeComparisonAnalyticTest extends Base
|
||||||
|
{
|
||||||
|
public function testBuild()
|
||||||
|
{
|
||||||
|
$taskCreationModel = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$estimatedTimeComparisonAnalytic = new EstimatedTimeComparisonAnalytic($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
|
||||||
|
$this->assertEquals(2, $projectModel->create(array('name' => 'test1')));
|
||||||
|
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_estimated' => 5.5)));
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_estimated' => 1.75)));
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_estimated' => 1.25, 'is_active' => 0)));
|
||||||
|
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_spent' => 8.25)));
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_spent' => 0.25)));
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_spent' => 0.5, 'is_active' => 0)));
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
'open' => array(
|
||||||
|
'time_spent' => 8.5,
|
||||||
|
'time_estimated' => 7.25,
|
||||||
|
),
|
||||||
|
'closed' => array(
|
||||||
|
'time_spent' => 0.5,
|
||||||
|
'time_estimated' => 1.25,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $estimatedTimeComparisonAnalytic->build(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildWithNoClosedTask()
|
||||||
|
{
|
||||||
|
$taskCreationModel = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$estimatedTimeComparisonAnalytic = new EstimatedTimeComparisonAnalytic($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
|
||||||
|
$this->assertEquals(2, $projectModel->create(array('name' => 'test1')));
|
||||||
|
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_estimated' => 5.5)));
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_estimated' => 1.75)));
|
||||||
|
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_spent' => 8.25)));
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_spent' => 0.25)));
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
'open' => array(
|
||||||
|
'time_spent' => 8.5,
|
||||||
|
'time_estimated' => 7.25,
|
||||||
|
),
|
||||||
|
'closed' => array(
|
||||||
|
'time_spent' => 0,
|
||||||
|
'time_estimated' => 0,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $estimatedTimeComparisonAnalytic->build(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildWithOnlyClosedTask()
|
||||||
|
{
|
||||||
|
$taskCreationModel = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$estimatedTimeComparisonAnalytic = new EstimatedTimeComparisonAnalytic($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
|
||||||
|
$this->assertEquals(2, $projectModel->create(array('name' => 'test1')));
|
||||||
|
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_estimated' => 5.5, 'is_active' => 0)));
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_estimated' => 1.75, 'is_active' => 0)));
|
||||||
|
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_spent' => 8.25, 'is_active' => 0)));
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'time_spent' => 0.25, 'is_active' => 0)));
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
'closed' => array(
|
||||||
|
'time_spent' => 8.5,
|
||||||
|
'time_estimated' => 7.25,
|
||||||
|
),
|
||||||
|
'open' => array(
|
||||||
|
'time_spent' => 0,
|
||||||
|
'time_estimated' => 0,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $estimatedTimeComparisonAnalytic->build(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
62
tests/units/Analytic/TaskDistributionAnalyticTest.php
Normal file
62
tests/units/Analytic/TaskDistributionAnalyticTest.php
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/../Base.php';
|
||||||
|
|
||||||
|
use Kanboard\Model\TaskCreation;
|
||||||
|
use Kanboard\Model\Project;
|
||||||
|
use Kanboard\Analytic\TaskDistributionAnalytic;
|
||||||
|
|
||||||
|
class TaskDistributionAnalyticTest extends Base
|
||||||
|
{
|
||||||
|
public function testBuild()
|
||||||
|
{
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$taskDistributionModel = new TaskDistributionAnalytic($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
|
||||||
|
$this->assertEquals(2, $projectModel->create(array('name' => 'test1')));
|
||||||
|
|
||||||
|
$this->createTasks(1, 20, 1);
|
||||||
|
$this->createTasks(2, 30, 1);
|
||||||
|
$this->createTasks(3, 40, 1);
|
||||||
|
$this->createTasks(4, 10, 1);
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
array(
|
||||||
|
'column_title' => 'Backlog',
|
||||||
|
'nb_tasks' => 20,
|
||||||
|
'percentage' => 20.0,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'column_title' => 'Ready',
|
||||||
|
'nb_tasks' => 30,
|
||||||
|
'percentage' => 30.0,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'column_title' => 'Work in progress',
|
||||||
|
'nb_tasks' => 40,
|
||||||
|
'percentage' => 40.0,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'column_title' => 'Done',
|
||||||
|
'nb_tasks' => 10,
|
||||||
|
'percentage' => 10.0,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $taskDistributionModel->build(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createTasks($column_id, $nb_active, $nb_inactive)
|
||||||
|
{
|
||||||
|
$taskCreationModel = new TaskCreation($this->container);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $nb_active; $i++) {
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'column_id' => $column_id, 'is_active' => 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < $nb_inactive; $i++) {
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'column_id' => $column_id, 'is_active' => 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
tests/units/Analytic/UserDistributionAnalyticTest.php
Normal file
83
tests/units/Analytic/UserDistributionAnalyticTest.php
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/../Base.php';
|
||||||
|
|
||||||
|
use Kanboard\Model\TaskCreation;
|
||||||
|
use Kanboard\Model\Project;
|
||||||
|
use Kanboard\Model\ProjectUserRole;
|
||||||
|
use Kanboard\Model\User;
|
||||||
|
use Kanboard\Analytic\UserDistributionAnalytic;
|
||||||
|
use Kanboard\Core\Security\Role;
|
||||||
|
|
||||||
|
class UserDistributionAnalyticTest extends Base
|
||||||
|
{
|
||||||
|
public function testBuild()
|
||||||
|
{
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectUserRoleModel = new ProjectUserRole($this->container);
|
||||||
|
$userModel = new User($this->container);
|
||||||
|
$userDistributionModel = new UserDistributionAnalytic($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
|
||||||
|
$this->assertEquals(2, $projectModel->create(array('name' => 'test1')));
|
||||||
|
|
||||||
|
$this->assertEquals(2, $userModel->create(array('username' => 'user1')));
|
||||||
|
$this->assertEquals(3, $userModel->create(array('username' => 'user2')));
|
||||||
|
$this->assertEquals(4, $userModel->create(array('username' => 'user3')));
|
||||||
|
$this->assertEquals(5, $userModel->create(array('username' => 'user4')));
|
||||||
|
|
||||||
|
$this->assertTrue($projectUserRoleModel->addUser(1, 2, Role::PROJECT_MEMBER));
|
||||||
|
$this->assertTrue($projectUserRoleModel->addUser(1, 3, Role::PROJECT_MEMBER));
|
||||||
|
$this->assertTrue($projectUserRoleModel->addUser(1, 4, Role::PROJECT_MEMBER));
|
||||||
|
$this->assertTrue($projectUserRoleModel->addUser(1, 5, Role::PROJECT_MEMBER));
|
||||||
|
|
||||||
|
$this->createTasks(0, 10, 1);
|
||||||
|
$this->createTasks(2, 30, 1);
|
||||||
|
$this->createTasks(3, 40, 1);
|
||||||
|
$this->createTasks(4, 10, 1);
|
||||||
|
$this->createTasks(5, 10, 1);
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
array(
|
||||||
|
'user' => 'Unassigned',
|
||||||
|
'nb_tasks' => 10,
|
||||||
|
'percentage' => 10.0,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'user' => 'user1',
|
||||||
|
'nb_tasks' => 30,
|
||||||
|
'percentage' => 30.0,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'user' => 'user2',
|
||||||
|
'nb_tasks' => 40,
|
||||||
|
'percentage' => 40.0,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'user' => 'user3',
|
||||||
|
'nb_tasks' => 10,
|
||||||
|
'percentage' => 10.0,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'user' => 'user4',
|
||||||
|
'nb_tasks' => 10,
|
||||||
|
'percentage' => 10.0,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $userDistributionModel->build(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createTasks($user_id, $nb_active, $nb_inactive)
|
||||||
|
{
|
||||||
|
$taskCreationModel = new TaskCreation($this->container);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $nb_active; $i++) {
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'owner_id' => $user_id, 'is_active' => 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < $nb_inactive; $i++) {
|
||||||
|
$this->assertNotFalse($taskCreationModel->create(array('project_id' => 1, 'title' => 'test', 'owner_id' => $user_id, 'is_active' => 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user