* Move methods from execution to project.
This commit is contained in:
@@ -1129,155 +1129,6 @@ class executionModel extends model
|
||||
return $executions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project stats.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $status
|
||||
* @param int $productID
|
||||
* @param int $itemCounts
|
||||
* @param string $orderBy
|
||||
* @param object $pager
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getStats($projectID = 0, $status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'id_asc', $pager = null)
|
||||
{
|
||||
if(empty($productID))
|
||||
{
|
||||
$executions = $this->dao->select('*')->from(TABLE_EXECUTION)
|
||||
->where('project')->eq($projectID)
|
||||
->beginIF($status == 'undone')->andWhere('status')->notIN('done,closed')->fi()
|
||||
->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->eq($status)->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
->andWhere('deleted')->eq('0')
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
}
|
||||
else
|
||||
{
|
||||
$executions = $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution=t2.id')
|
||||
->where('t1.product')->eq($productID)
|
||||
->beginIF($projectID)->andWhere('t2.project')->eq($projectID)->fi()
|
||||
->beginIF($status == 'undone')->andWhere('t2.status')->notIN('done,closed')->fi()
|
||||
->beginIF($status != 'all' and $status != 'undone')->andWhere('t2.status')->eq($status)->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->sprints)->fi()
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
$hours = array();
|
||||
$emptyHour = array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0);
|
||||
|
||||
/* Get all tasks and compute totalEstimate, totalConsumed, totalLeft, progress according to them. */
|
||||
$tasks = $this->dao->select('id, execution, estimate, consumed, `left`, status, closedReason')
|
||||
->from(TABLE_TASK)
|
||||
->where('execution')->in(array_keys($executions))
|
||||
->andWhere('parent')->lt(1)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchGroup('execution', 'id');
|
||||
|
||||
/* Compute totalEstimate, totalConsumed, totalLeft. */
|
||||
foreach($tasks as $executionID => $executionTasks)
|
||||
{
|
||||
$hour = (object)$emptyHour;
|
||||
foreach($executionTasks as $task)
|
||||
{
|
||||
if($task->status != 'cancel')
|
||||
{
|
||||
$hour->totalEstimate += $task->estimate;
|
||||
$hour->totalConsumed += $task->consumed;
|
||||
}
|
||||
if($task->status != 'cancel' and $task->status != 'closed') $hour->totalLeft += $task->left;
|
||||
}
|
||||
$hours[$executionID] = $hour;
|
||||
}
|
||||
|
||||
/* Compute totalReal and progress. */
|
||||
foreach($hours as $hour)
|
||||
{
|
||||
$hour->totalEstimate = round($hour->totalEstimate, 1) ;
|
||||
$hour->totalConsumed = round($hour->totalConsumed, 1);
|
||||
$hour->totalLeft = round($hour->totalLeft, 1);
|
||||
$hour->totalReal = $hour->totalConsumed + $hour->totalLeft;
|
||||
$hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 3) * 100 : 0;
|
||||
}
|
||||
|
||||
/* Get burndown charts datas. */
|
||||
$burns = $this->dao->select('execution, date AS name, `left` AS value')
|
||||
->from(TABLE_BURN)
|
||||
->where('execution')->in(array_keys($executions))
|
||||
->andWhere('task')->eq(0)
|
||||
->orderBy('date desc')
|
||||
->fetchGroup('execution', 'name');
|
||||
|
||||
foreach($burns as $executionID => $executionBurns)
|
||||
{
|
||||
/* If executionBurns > $itemCounts, split it, else call processBurnData() to pad burns. */
|
||||
$begin = $executions[$executionID]->begin;
|
||||
$end = $executions[$executionID]->end;
|
||||
if(helper::isZeroDate($begin)) $begin = $executions[$executionID]->openedDate;
|
||||
$executionBurns = $this->processBurnData($executionBurns, $itemCounts, $begin, $end);
|
||||
|
||||
/* Shorter names. */
|
||||
foreach($executionBurns as $executionBurn)
|
||||
{
|
||||
$executionBurn->name = substr($executionBurn->name, 5);
|
||||
unset($executionBurn->execution);
|
||||
}
|
||||
|
||||
ksort($executionBurns);
|
||||
$burns[$executionID] = $executionBurns;
|
||||
}
|
||||
|
||||
/* Process executions. */
|
||||
$parents = array();
|
||||
$children = array();
|
||||
foreach($executions as $key => $execution)
|
||||
{
|
||||
/* Process the end time. */
|
||||
$execution->end = date(DT_DATE1, strtotime($execution->end));
|
||||
|
||||
/* Judge whether the execution is delayed. */
|
||||
if($execution->status != 'done' and $execution->status != 'closed' and $execution->status != 'suspended')
|
||||
{
|
||||
$delay = helper::diffDate(helper::today(), $execution->end);
|
||||
if($delay > 0) $execution->delay = $delay;
|
||||
}
|
||||
|
||||
/* Process the burns. */
|
||||
$execution->burns = array();
|
||||
$burnData = isset($burns[$execution->id]) ? $burns[$execution->id] : array();
|
||||
foreach($burnData as $data) $execution->burns[] = $data->value;
|
||||
|
||||
/* Process the hours. */
|
||||
$execution->hours = isset($hours[$execution->id]) ? $hours[$execution->id] : (object)$emptyHour;
|
||||
|
||||
$execution->children = array();
|
||||
$execution->grade == 1 ? $parents[$execution->id] = $execution : $children[$execution->parent][] = $execution;
|
||||
}
|
||||
|
||||
/* In the case of the waterfall model, calculate the sub-stage. */
|
||||
$execution = $this->loadModel('execution')->getById($this->session->project);
|
||||
if($execution and $execution->model == 'waterfall')
|
||||
{
|
||||
foreach($parents as $id => $execution)
|
||||
{
|
||||
$execution->children = isset($children[$id]) ? $children[$id] : array();
|
||||
unset($children[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
$orphan = array();
|
||||
foreach($children as $child) $orphan = array_merge($child, $orphan);
|
||||
|
||||
return array_merge($parents, $orphan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the link from module,method,extra
|
||||
*
|
||||
|
||||
@@ -875,4 +875,18 @@ class programModel extends model
|
||||
}
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get budget unit list.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getBudgetUnitList()
|
||||
{
|
||||
$budgetUnitList = array();
|
||||
foreach(explode(',', $this->config->project->unitList) as $unit) $budgetUnitList[$unit] = zget($this->lang->project->unitList, $unit, '');
|
||||
|
||||
return $budgetUnitList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<?php if(isset($this->config->maxVersion)):?>
|
||||
<?php common::printLink('project', 'createGuide', "programID=0&from=PGM", '<i class="icon icon-plus"></i>' . $lang->project->create, '', 'class="btn btn-primary" data-toggle="modal" data-target="#guideDialog"');?>
|
||||
<?php elseif($this->config->systemMode == 'new'):?>
|
||||
<?php common::printLink('project', 'create', "mode=scrum&programID=0&from=PGM", '<i class="icon icon-plus"></i>' . $lang->project->create, '', 'class="btn btn-primary"');?>
|
||||
<?php common::printLink('project', 'create', "mode=scrum&programID=0&from=program", '<i class="icon icon-plus"></i>' . $lang->project->create, '', 'class="btn btn-primary"');?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+21
-22
@@ -322,10 +322,10 @@ class project extends control
|
||||
$this->view->users = $this->user->getPairs('noclosed|nodeleted');
|
||||
$this->view->copyProjects = $this->project->getPairsByModel();
|
||||
$this->view->products = $products;
|
||||
$this->view->allProducts = array('0' => '') + $this->project->getPGMProductPairs($projectID);
|
||||
$this->view->allProducts = array('0' => '') + $this->program->getProductPairs($programID);
|
||||
$this->view->productPlans = array('0' => '') + $productPlans;
|
||||
$this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products));
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->programID = $programID;
|
||||
$this->view->model = $model;
|
||||
$this->view->name = $name;
|
||||
$this->view->code = $code;
|
||||
@@ -335,7 +335,7 @@ class project extends control
|
||||
$this->view->whitelist = $whitelist;
|
||||
$this->view->copyProjectID = $copyProjectID;
|
||||
$this->view->from = $from;
|
||||
$this->view->projectList = $this->project->getParentPairs();
|
||||
$this->view->programList = $this->program->getParentPairs();
|
||||
$this->view->parentProgram = $parentProgram;
|
||||
$this->view->URSRPairs = $this->loadModel('custom')->getURSRPairs();
|
||||
$this->view->availableBudget = $this->program->getBudgetLeft($parentProgram);
|
||||
@@ -438,7 +438,7 @@ class project extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchEdit($from = 'prjbrowse', $projectID = 0)
|
||||
public function batchEdit($from = 'browse', $projectID = 0)
|
||||
{
|
||||
$this->loadModel('action');
|
||||
|
||||
@@ -526,11 +526,11 @@ class project extends control
|
||||
* Project browse groups.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $projectID
|
||||
* @param int $programID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function group($projectID = 0, $projectID = 0)
|
||||
public function group($projectID = 0, $programID = 0)
|
||||
{
|
||||
$this->lang->navGroup->project = 'project';
|
||||
$this->lang->project->menu = $this->lang->scrum->setMenu;
|
||||
@@ -548,7 +548,7 @@ class project extends control
|
||||
$this->view->position = $position;
|
||||
$this->view->groups = $groups;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->programID = $programID;
|
||||
$this->view->groupUsers = $groupUsers;
|
||||
|
||||
$this->display();
|
||||
@@ -558,11 +558,10 @@ class project extends control
|
||||
* Project create a group.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createGroup($projectID = 0, $projectID = 0)
|
||||
public function createGroup($projectID = 0)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -583,7 +582,7 @@ class project extends control
|
||||
*
|
||||
* @param int $groupID
|
||||
* @param int $projectID
|
||||
* @param int $projectID
|
||||
* @param int $programID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -1076,17 +1075,17 @@ class project extends control
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $deptID
|
||||
* @param int $projectID
|
||||
* @param int $programID
|
||||
* @param int $from
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function addWhitelist($projectID = 0, $deptID = 0, $projectID = 0, $from = 'project')
|
||||
public function addWhitelist($projectID = 0, $deptID = 0, $programID = 0, $from = 'project')
|
||||
{
|
||||
/* Navigation stay in project when enter from project list. */
|
||||
$this->adjustNavigation($from, $projectID);
|
||||
|
||||
echo $this->fetch('personnel', 'addWhitelist', "objectID=$projectID&dept=$deptID&objectType=project&module=project&projectID=$projectID&from=$from");
|
||||
echo $this->fetch('personnel', 'addWhitelist', "objectID=$projectID&dept=$deptID&objectType=project&module=project&programID=$programID&from=$from");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1106,12 +1105,12 @@ class project extends control
|
||||
* Manage products.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $projectID
|
||||
* @param int $programID
|
||||
* @param string $from project|program|programproject
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function manageProducts($projectID, $projectID = 0, $from = 'project')
|
||||
public function manageProducts($projectID, $programID = 0, $from = 'project')
|
||||
{
|
||||
/* Navigation stay in project when enter from project list. */
|
||||
$this->adjustNavigation($from, $projectID);
|
||||
@@ -1135,7 +1134,7 @@ class project extends control
|
||||
if($diffProducts) $this->loadModel('action')->create('project', $projectID, 'Managed', '', !empty($_POST['products']) ? join(',', $_POST['products']) : '');
|
||||
|
||||
$locateLink = $this->session->projectBrowse ? $this->session->projectBrowse : inLink('manageProducts', "projectID=$projectID");
|
||||
if($from == 'program') $locateLink = inLink('PGMBrowse');
|
||||
if($from == 'program') $locateLink = $this->createLink('program', 'browse');
|
||||
if($from == 'programproject') $locateLink = $this->session->programProject ? $this->session->programProject : inLink('programProject', "projectID=$projectID");
|
||||
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locateLink));
|
||||
}
|
||||
@@ -1177,17 +1176,17 @@ class project extends control
|
||||
/**
|
||||
* AJAX: Check products.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $programID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxCheckProduct($projectID, $projectID)
|
||||
public function ajaxCheckProduct($programID, $projectID)
|
||||
{
|
||||
/* Set vars. */
|
||||
$project = $this->project->getByID($projectID);
|
||||
$oldTopPGM = $this->project->getTopPGMByID($project->parent);
|
||||
$newTopPGM = $this->project->getTopPGMByID($projectID);
|
||||
$oldTopPGM = $this->loadModel('program')->getTopByID($project->parent);
|
||||
$newTopPGM = $this->program->getTopByID($programID);
|
||||
|
||||
if($oldTopPGM == $newTopPGM) die();
|
||||
|
||||
@@ -1220,8 +1219,8 @@ class project extends control
|
||||
*/
|
||||
public function adjustNavigation($from = '', $projectID = 0)
|
||||
{
|
||||
if($from == 'prjbrowse') $this->lang->project->menu = $this->lang->project->menu;
|
||||
if($from == 'pgmbrowse') $this->lang->navGroup->project = 'project';
|
||||
if($from == 'browse') $this->lang->project->menu = $this->lang->project->menu;
|
||||
if($from == 'program') $this->lang->navGroup->project = 'project';
|
||||
|
||||
if($from == 'project')
|
||||
{
|
||||
|
||||
+230
-2
@@ -170,9 +170,9 @@ class projectModel extends model
|
||||
*/
|
||||
public function getMainAction($module, $method)
|
||||
{
|
||||
$link = html::a(helper::createLink('project', 'prjbrowse'), "<i class='icon icon-list'></i>", '', "style='border: none;'");
|
||||
$link = html::a(helper::createLink('project', 'browse'), "<i class='icon icon-list'></i>", '', "style='border: none;'");
|
||||
$html = "<p style='padding-top:5px;'>" . $link . "</p>";
|
||||
return common::hasPriv('project', 'prjbrowse') ? $html : '';
|
||||
return common::hasPriv('project', 'browse') ? $html : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1148,4 +1148,232 @@ class projectModel extends model
|
||||
echo '</td>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update products of a project.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param array $products
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function updateProducts($projectID, $products = '')
|
||||
{
|
||||
$this->loadModel('user');
|
||||
$products = isset($_POST['products']) ? $_POST['products'] : $products;
|
||||
$oldProjectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->eq((int)$projectID)->fetchGroup('product', 'branch');
|
||||
$this->dao->delete()->from(TABLE_PROJECTPRODUCT)->where('project')->eq((int)$projectID)->exec();
|
||||
$members = array_keys($this->getTeamMembers($projectID));
|
||||
if(empty($products))
|
||||
{
|
||||
$this->user->updateUserView(array_keys($oldProjectProducts), 'product', $members);
|
||||
return true;
|
||||
}
|
||||
|
||||
$branches = isset($_POST['branch']) ? $_POST['branch'] : array();
|
||||
$plans = isset($_POST['plans']) ? $_POST['plans'] : array();;
|
||||
|
||||
$existedProducts = array();
|
||||
foreach($products as $i => $productID)
|
||||
{
|
||||
if(empty($productID)) continue;
|
||||
if(isset($existedProducts[$productID])) continue;
|
||||
|
||||
$oldPlan = 0;
|
||||
$branch = isset($branches[$i]) ? $branches[$i] : 0;
|
||||
if(isset($oldProjectProducts[$productID][$branch]))
|
||||
{
|
||||
$oldProjectProduct = $oldProjectProducts[$productID][$branch];
|
||||
$oldPlan = $oldProjectProduct->plan;
|
||||
}
|
||||
|
||||
$data = new stdclass();
|
||||
$data->project = $executionID;
|
||||
$data->product = $productID;
|
||||
$data->branch = $branch;
|
||||
$data->plan = isset($plans[$productID]) ? $plans[$productID] : $oldPlan;
|
||||
$this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec();
|
||||
$existedProducts[$productID] = true;
|
||||
}
|
||||
|
||||
/* Delete the execution linked products that is not linked with the execution. */
|
||||
$executions = $this->dao->select('id')->from(TABLE_EXECUTION)->where('execution')->eq((int)$executionID)->fetchPairs('id');
|
||||
$this->dao->delete()->from(TABLE_PROJECTPRODUCT)->where('execution')->in($executions)->andWhere('product')->notin($products)->exec();
|
||||
|
||||
$oldProductKeys = array_keys($oldProjectProducts);
|
||||
$needUpdate = array_merge(array_diff($oldProductKeys, $products), array_diff($products, $oldProductKeys));
|
||||
if($needUpdate) $this->user->updateUserView($needUpdate, 'product', $members);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get team members.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getTeamMembers($projectID)
|
||||
{
|
||||
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getTeamMembers();
|
||||
|
||||
$project = $this->getByID($projectID);
|
||||
$type = $this->config->systemMode == 'new' ? $project->type : 'project';
|
||||
if(empty($project)) return array();
|
||||
|
||||
return $this->dao->select("t1.*, t1.hours * t1.days AS totalHours, t2.id as userID, if(t2.deleted='0', t2.realname, t1.account) as realname")->from(TABLE_TEAM)->alias('t1')
|
||||
->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account')
|
||||
->where('t1.root')->eq((int)$projectID)
|
||||
->andWhere('t1.type')->eq($type)
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->fetchAll('account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project stats.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $status
|
||||
* @param int $productID
|
||||
* @param int $itemCounts
|
||||
* @param string $orderBy
|
||||
* @param object $pager
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getStats($projectID = 0, $status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'id_asc', $pager = null)
|
||||
{
|
||||
if(empty($productID))
|
||||
{
|
||||
$executions = $this->dao->select('*')->from(TABLE_EXECUTION)
|
||||
->where('project')->eq($projectID)
|
||||
->beginIF($status == 'undone')->andWhere('status')->notIN('done,closed')->fi()
|
||||
->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->eq($status)->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
->andWhere('deleted')->eq('0')
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
}
|
||||
else
|
||||
{
|
||||
$executions = $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution=t2.id')
|
||||
->where('t1.product')->eq($productID)
|
||||
->beginIF($projectID)->andWhere('t2.project')->eq($projectID)->fi()
|
||||
->beginIF($status == 'undone')->andWhere('t2.status')->notIN('done,closed')->fi()
|
||||
->beginIF($status != 'all' and $status != 'undone')->andWhere('t2.status')->eq($status)->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->sprints)->fi()
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
$hours = array();
|
||||
$emptyHour = array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0);
|
||||
|
||||
/* Get all tasks and compute totalEstimate, totalConsumed, totalLeft, progress according to them. */
|
||||
$tasks = $this->dao->select('id, execution, estimate, consumed, `left`, status, closedReason')
|
||||
->from(TABLE_TASK)
|
||||
->where('execution')->in(array_keys($executions))
|
||||
->andWhere('parent')->lt(1)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchGroup('execution', 'id');
|
||||
|
||||
/* Compute totalEstimate, totalConsumed, totalLeft. */
|
||||
foreach($tasks as $executionID => $executionTasks)
|
||||
{
|
||||
$hour = (object)$emptyHour;
|
||||
foreach($executionTasks as $task)
|
||||
{
|
||||
if($task->status != 'cancel')
|
||||
{
|
||||
$hour->totalEstimate += $task->estimate;
|
||||
$hour->totalConsumed += $task->consumed;
|
||||
}
|
||||
if($task->status != 'cancel' and $task->status != 'closed') $hour->totalLeft += $task->left;
|
||||
}
|
||||
$hours[$executionID] = $hour;
|
||||
}
|
||||
|
||||
/* Compute totalReal and progress. */
|
||||
foreach($hours as $hour)
|
||||
{
|
||||
$hour->totalEstimate = round($hour->totalEstimate, 1) ;
|
||||
$hour->totalConsumed = round($hour->totalConsumed, 1);
|
||||
$hour->totalLeft = round($hour->totalLeft, 1);
|
||||
$hour->totalReal = $hour->totalConsumed + $hour->totalLeft;
|
||||
$hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 3) * 100 : 0;
|
||||
}
|
||||
|
||||
/* Get burndown charts datas. */
|
||||
$burns = $this->dao->select('execution, date AS name, `left` AS value')
|
||||
->from(TABLE_BURN)
|
||||
->where('execution')->in(array_keys($executions))
|
||||
->andWhere('task')->eq(0)
|
||||
->orderBy('date desc')
|
||||
->fetchGroup('execution', 'name');
|
||||
|
||||
foreach($burns as $executionID => $executionBurns)
|
||||
{
|
||||
/* If executionBurns > $itemCounts, split it, else call processBurnData() to pad burns. */
|
||||
$begin = $executions[$executionID]->begin;
|
||||
$end = $executions[$executionID]->end;
|
||||
if(helper::isZeroDate($begin)) $begin = $executions[$executionID]->openedDate;
|
||||
$executionBurns = $this->processBurnData($executionBurns, $itemCounts, $begin, $end);
|
||||
|
||||
/* Shorter names. */
|
||||
foreach($executionBurns as $executionBurn)
|
||||
{
|
||||
$executionBurn->name = substr($executionBurn->name, 5);
|
||||
unset($executionBurn->execution);
|
||||
}
|
||||
|
||||
ksort($executionBurns);
|
||||
$burns[$executionID] = $executionBurns;
|
||||
}
|
||||
|
||||
/* Process executions. */
|
||||
$parents = array();
|
||||
$children = array();
|
||||
foreach($executions as $key => $execution)
|
||||
{
|
||||
/* Process the end time. */
|
||||
$execution->end = date(DT_DATE1, strtotime($execution->end));
|
||||
|
||||
/* Judge whether the execution is delayed. */
|
||||
if($execution->status != 'done' and $execution->status != 'closed' and $execution->status != 'suspended')
|
||||
{
|
||||
$delay = helper::diffDate(helper::today(), $execution->end);
|
||||
if($delay > 0) $execution->delay = $delay;
|
||||
}
|
||||
|
||||
/* Process the burns. */
|
||||
$execution->burns = array();
|
||||
$burnData = isset($burns[$execution->id]) ? $burns[$execution->id] : array();
|
||||
foreach($burnData as $data) $execution->burns[] = $data->value;
|
||||
|
||||
/* Process the hours. */
|
||||
$execution->hours = isset($hours[$execution->id]) ? $hours[$execution->id] : (object)$emptyHour;
|
||||
|
||||
$execution->children = array();
|
||||
$execution->grade == 1 ? $parents[$execution->id] = $execution : $children[$execution->parent][] = $execution;
|
||||
}
|
||||
|
||||
/* In the case of the waterfall model, calculate the sub-stage. */
|
||||
$execution = $this->loadModel('execution')->getById($this->session->project);
|
||||
if($execution and $execution->model == 'waterfall')
|
||||
{
|
||||
foreach($parents as $id => $execution)
|
||||
{
|
||||
$execution->children = isset($children[$id]) ? $children[$id] : array();
|
||||
unset($children[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
$orphan = array();
|
||||
foreach($children as $child) $orphan = array_merge($child, $orphan);
|
||||
|
||||
return array_merge($parents, $orphan);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th class='w-120px'><?php echo $lang->project->parent;?></th>
|
||||
<td><?php echo html::select('parent', $projectList, $projectID, "class='form-control chosen' onchange='setParentProgram(this.value)'");?></td>
|
||||
<td><?php echo html::select('parent', $programList, $programID, "class='form-control chosen' onchange='setParentProgram(this.value)'");?></td>
|
||||
<td>
|
||||
<icon class='icon icon-help' data-toggle='popover' data-trigger='focus hover' data-placement='right' data-tip-class='text-muted popover-sm' data-content="<?php echo $lang->program->tips;?>"></icon>
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user