Merge branch 'master' into 'master_xieqiyu_67691'
# Conflicts: # db/update17.6.sql
This commit is contained in:
@@ -14,3 +14,4 @@ CREATE TABLE `zt_taskteam` (
|
||||
ALTER TABLE `zt_taskestimate` ADD `order` tinyint unsigned NULL DEFAULT '0';
|
||||
ALTER TABLE `zt_effort` ADD `order` tinyint unsigned NOT NULL DEFAULT '0' AFTER `end`;
|
||||
ALTER TABLE `zt_storyspec` ADD `files` text NOT NULL AFTER `verify`;
|
||||
ALTER TABLE `zt_block` CHANGE `block` `block` varchar(30) COLLATE 'utf8_general_ci' NOT NULL AFTER `source`;
|
||||
+1
-1
@@ -218,7 +218,7 @@ CREATE TABLE IF NOT EXISTS `zt_block` (
|
||||
`type` char(30) NOT NULL,
|
||||
`title` varchar(100) NOT NULL,
|
||||
`source` varchar(20) NOT NULL,
|
||||
`block` varchar(20) NOT NULL,
|
||||
`block` varchar(30) NOT NULL,
|
||||
`params` text NOT NULL,
|
||||
`order` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`grid` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
|
||||
@@ -935,8 +935,9 @@ class block extends control
|
||||
$current = zget($weeks, $monday, '');
|
||||
$current = substr($current, 0, -11) . substr($current, -6);
|
||||
|
||||
$project->pv = $this->weekly->getPV($projectID, $today);
|
||||
$project->ev = $this->weekly->getEV($projectID, $today);
|
||||
$PVEV = $this->weekly->getPVEV($projectID, $today);
|
||||
$project->pv = $PVEV['PV'];
|
||||
$project->ev = $PVEV['EV'];
|
||||
$project->ac = $this->weekly->getAC($projectID, $today);
|
||||
$project->sv = $this->weekly->getSV($project->ev, $project->pv);
|
||||
$project->cv = $this->weekly->getCV($project->ev, $project->ac);
|
||||
@@ -1200,8 +1201,9 @@ class block extends control
|
||||
|
||||
$this->weekly->save($this->session->project, $date);
|
||||
|
||||
$this->view->pv = (float)$this->weekly->getPV($this->session->project, $today);
|
||||
$this->view->ev = (float)$this->weekly->getEV($this->session->project, $today);
|
||||
$PVEV = $this->weekly->getPVEV($this->session->project, $today);
|
||||
$this->view->pv = (float)$PVEV['PV'];
|
||||
$this->view->ev = (float)$PVEV['EV'];
|
||||
$this->view->ac = (float)$this->weekly->getAC($this->session->project, $today);
|
||||
$this->view->sv = $this->weekly->getSV($this->view->ev, $this->view->pv);
|
||||
$this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac);
|
||||
@@ -1210,6 +1212,28 @@ class block extends control
|
||||
$this->view->progress = !empty($this->view->pv) ? floor($this->view->ac / $this->view->pv * 1000) / 1000 * 100 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print waterfall general report block.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function printWaterfallGeneralReportBlock()
|
||||
{
|
||||
$this->app->loadLang('programplan');
|
||||
$this->loadModel('project');
|
||||
$this->loadModel('weekly');
|
||||
|
||||
$PVEV = $this->project->getWaterfallPVEV($this->session->project);
|
||||
$this->view->pv = (float)$PVEV['PV'];
|
||||
$this->view->ev = (float)$PVEV['EV'];
|
||||
$this->view->ac = (float)$this->project->getWaterfallAC($this->session->project);
|
||||
$this->view->sv = $this->weekly->getSV($this->view->ev, $this->view->pv);
|
||||
$this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac);
|
||||
|
||||
$this->view->progress = !empty($this->view->pv) ? floor($this->view->ac / $this->view->pv * 1000) / 1000 * 100 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print waterfall gantt block.
|
||||
*
|
||||
|
||||
+13
-2
@@ -656,18 +656,29 @@ class blockModel extends model
|
||||
* Get waterfall project report pararms.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
* @return bool
|
||||
*/
|
||||
public function getWaterfallReportParams()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get waterfall general report params.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function getWaterfallGeneralReportParams()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project estimate pararms.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
* @return bool
|
||||
*/
|
||||
public function getWaterfallEstimateParams()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<style>
|
||||
.block-waterfallgeneralreport .col-left {width: 25%; text-align: center;}
|
||||
.block-waterfallgeneralreport .col-right {width: 87%;}
|
||||
.block-waterfallgeneralreport .panel-body {padding-top: 0;}
|
||||
.block-waterfallgeneralreport .table-row {margin-bottom: 20px;}
|
||||
<?php if(common::checkNotCN()):?>
|
||||
.block-waterfallgeneralreport .stage {position: absolute; top: 14px; left: 140px;}
|
||||
<?php else:?>
|
||||
.block-waterfallgeneralreport .stage {position: absolute; top: 14px; left: 90px;}
|
||||
<?php endif;?>
|
||||
.block-waterfallgeneralreport .col-right .tiles {padding: 10px 0 0 16px;}
|
||||
.block-waterfallgeneralreport .col-right .tile {width: 20%;}
|
||||
.block-waterfallgeneralreport .col-right .tile .tile-title {font-weight: 700;}
|
||||
.block-waterfallgeneralreport .progress {position: absolute; left: 45px; top: 90px; right: 40px;}
|
||||
.block-waterfallgeneralreport .progress-num {font-size: 20px; font-weight: 700;}
|
||||
.block-waterfallgeneralreport .col-right .tile-amount {font-size: 20px;}
|
||||
</style>
|
||||
|
||||
<div class="panel-body conatiner-fluid">
|
||||
<div class='table-row'>
|
||||
<div class="col col-left hide-in-sm">
|
||||
<h4><?php echo $lang->project->progress;?></h4>
|
||||
<span class='progress-num'><?php echo $progress . '%';?></span>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="<?php echo $progress;?>" aria-valuemin="0" aria-valuemax="100" style="width: <?php echo $progress;?>%">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-right'>
|
||||
<div class='row tiles'>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'PV(' . $lang->programplan->end . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $pv == 0 ? 0 : $pv;?></div>
|
||||
</div>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'EV(' . $lang->programplan->realEnd . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $ev == 0 ? 0 : $ev;?></div>
|
||||
</div>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'AC(' . $lang->programplan->ac . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $ac == 0 ? 0 : $ac;?></div>
|
||||
</div>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'SV(' . $lang->programplan->sv . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $sv . '%';?></div>
|
||||
</div>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'CV(' . $lang->programplan->cv . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $cv . '%';?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,6 +153,7 @@ class my extends control
|
||||
$riskCount = 0;
|
||||
$reviewCount = 0;
|
||||
$ncCount = 0;
|
||||
$qaCount = 0;
|
||||
$meetingCount = 0;
|
||||
$isMax = $this->config->edition == 'max' ? 1 : 0;
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ $config->product->all->search['fields']['createdDate'] = $lang->product->created
|
||||
$config->product->all->search['fields']['createdBy'] = $lang->product->createdBy;
|
||||
|
||||
$config->product->all->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
$config->product->all->search['params']['code'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
if(!isset($config->setCode) or $config->setCode == 1) $config->product->all->search['params']['code'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
$config->product->all->search['params']['id'] = array('operator' => '=', 'control' => 'input', 'values' => '');
|
||||
if($config->systemMode == 'new') $config->product->all->search['params']['program'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
$config->product->all->search['params']['line'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
|
||||
@@ -415,6 +415,55 @@ class projectModel extends model
|
||||
return is_numeric($projectIDList) ? (empty($progressList) ? 0 : $progressList[$projectIDList]) : $progressList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get waterfall general PV and EV.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getWaterfallPVEV($projectID)
|
||||
{
|
||||
$executions = $this->dao->select('id,begin,end,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($projectID)->fetchAll('id');
|
||||
$stmt = $this->dao->select('id,status,estimate,consumed,`left`,closedReason')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere("parent")->ge(0)->andWhere("deleted")->eq(0)->query();
|
||||
|
||||
$PV = 0;
|
||||
$EV = 0;
|
||||
while($task = $stmt->fetch())
|
||||
{
|
||||
$PV += $task->estimate;
|
||||
if($task->status == 'done' or $task->closedReason == 'done')
|
||||
{
|
||||
$EV += $task->estimate;
|
||||
}
|
||||
else
|
||||
{
|
||||
$task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100;
|
||||
$EV += round($task->estimate * $task->progress / 100, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return array('PV' => sprintf("%.2f", $PV), 'EV' => sprintf("%.2f", $EV));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get waterfall general AC
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getWaterfallAC($projectID)
|
||||
{
|
||||
$executions = $this->dao->select('id,begin,end,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($projectID)->fetchAll('id');
|
||||
$taskIdList = $this->dao->select('id')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere("parent")->ge(0)->andWhere("deleted")->eq(0)->fetchPairs('id', 'id');
|
||||
|
||||
$AC = $this->dao->select('sum(consumed) as consumed')->from(TABLE_EFFORT)->where('objectType')->eq('task')->andWhere('objectID')->in($taskIdList)->andWhere('deleted')->eq('0')->fetch('consumed');
|
||||
if(is_null($AC)) $AC = 0;
|
||||
|
||||
return sprintf("%.2f", $AC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project workhour info.
|
||||
*
|
||||
|
||||
@@ -48,6 +48,7 @@ foreach($efforts as $effort)
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($allEfforts[$order] as $effort):?>
|
||||
<?php if($effort->account != $this->app->user->account) continue;?>
|
||||
<tr class="text-center">
|
||||
<td><?php echo $effort->date;?></td>
|
||||
<td><?php echo zget($users, $effort->account);?></td>
|
||||
|
||||
@@ -74,10 +74,10 @@
|
||||
<div class="alert with-icon">
|
||||
<i class="icon-exclamation-sign"></i>
|
||||
<div class="content">
|
||||
<?php if($task->assignedTo != $app->user->account and $task->mode == 'linear'):?>
|
||||
<p><?php echo sprintf($lang->task->deniedNotice, '<strong>' . $task->assignedToRealName . '</strong>', $lang->task->logEfforts);?></p>
|
||||
<?php elseif(!isset($task->members[$app->user->account])):?>
|
||||
<?php if(!isset($task->members[$app->user->account])):?>
|
||||
<p><?php echo sprintf($lang->task->deniedNotice, '<strong>' . $lang->task->teamMember . '</strong>', $lang->task->logEfforts);?></p>
|
||||
<?php elseif($task->assignedTo != $app->user->account and $task->mode == 'linear'):?>
|
||||
<p><?php echo sprintf($lang->task->deniedNotice, '<strong>' . $task->assignedToRealName . '</strong>', $lang->task->logEfforts);?></p>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -49,7 +49,7 @@ $lang->testreport->legendCase = 'CasTests associés';
|
||||
$lang->testreport->legendLegacyBugs = 'Bugs Restants';
|
||||
$lang->testreport->legendReport = 'Rapport';
|
||||
$lang->testreport->legendComment = 'Résumé';
|
||||
$lang->testreport->legendMore = 'Plus...';
|
||||
$lang->testreport->legendMore = 'Plus';
|
||||
$lang->testreport->date = 'Date';
|
||||
|
||||
$lang->testreport->bugSeverityGroups = 'Distribution Sévérité de Bug';
|
||||
|
||||
@@ -7308,7 +7308,7 @@ class upgradeModel extends model
|
||||
|
||||
$this->dao->insert(TABLE_TASKTEAM)->data($oldTeam)->exec();
|
||||
|
||||
$this->dao->update(TABLE_TASKESTIMATE)->set('`order`')->eq($order)->where('task')->($oldTeam->task)->andWhere('account')->eq($oldTeam->account)->exec();
|
||||
$this->dao->update(TABLE_TASKESTIMATE)->set('`order`')->eq($order)->where('task')->eq($oldTeam->task)->andWhere('account')->eq($oldTeam->account)->exec();
|
||||
$this->dao->update(TABLE_EFFORT)->set('`order`')->eq($order)->where('objectType')->eq('task')->andWhere('objectID')->eq($oldTeam->task)->andWhere('account')->eq($oldTeam->account)->exec();
|
||||
$order ++;
|
||||
}
|
||||
|
||||
@@ -54,8 +54,9 @@ class weekly extends control
|
||||
|
||||
$this->view->title = $this->lang->weekly->common;
|
||||
|
||||
$this->view->pv = $this->weekly->getPV($projectID, $date);
|
||||
$this->view->ev = $this->weekly->getEV($projectID, $date);
|
||||
$PVEV = $this->weekly->getPVEV($projectID, $date);
|
||||
$this->view->pv = $PVEV['PV'];
|
||||
$this->view->ev = $PVEV['EV'];
|
||||
$this->view->ac = $this->weekly->getAC($projectID, $date);
|
||||
$this->view->sv = $this->weekly->getSV($this->view->ev, $this->view->pv);
|
||||
$this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac);
|
||||
|
||||
+21
-61
@@ -121,8 +121,9 @@ class weeklyModel extends model
|
||||
->exec();
|
||||
|
||||
$report = new stdclass;
|
||||
$report->pv = $this->getPV($project, $date);
|
||||
$report->ev = $this->getEV($project, $date);
|
||||
$PVEV = $this->getPVEV($project, $date);
|
||||
$report->pv = $PVEV['PV'];
|
||||
$report->ev = $PVEV['EV'];
|
||||
$report->ac = $this->getAC($project, $date);
|
||||
$report->sv = $this->getSV($report->ev, $report->pv);
|
||||
$report->cv = $this->getCV($report->ev, $report->ac);
|
||||
@@ -369,17 +370,17 @@ class weeklyModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* GetPV
|
||||
* Get PV and EV
|
||||
*
|
||||
* @param int $project
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return int
|
||||
* @return array
|
||||
*/
|
||||
public function getPV($projectID, $date = '')
|
||||
public function getPVEV($projectID, $date = '')
|
||||
{
|
||||
$report = $this->getFromDB($projectID, $date);
|
||||
if(!empty($report)) return $report->pv;
|
||||
if(!empty($report)) return array('PV' => $report->pv, 'EV' => $report->ev);
|
||||
|
||||
if(!$date) $date = date('Y-m-d');
|
||||
$monday = $this->getThisMonday($date);
|
||||
@@ -397,6 +398,8 @@ class weeklyModel extends model
|
||||
->fetchAll('id');
|
||||
|
||||
$PV = 0;
|
||||
$EV = 0;
|
||||
$this->loadModel('holiday');
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if(helper::isZeroDate($task->estStarted)) $task->estStarted = date('Y-m-d', strtotime($task->openedDate));
|
||||
@@ -407,74 +410,36 @@ class weeklyModel extends model
|
||||
if(helper::isZeroDate($task->finishedDate)) $task->deadline = date('Y-m-d', strtotime($task->finishedDate));
|
||||
}
|
||||
|
||||
$fullDays = $this->loadModel('holiday')->getActualWorkingDays($task->estStarted, $task->deadline);
|
||||
$fullDays = $this->holiday->getActualWorkingDays($task->estStarted, $task->deadline);
|
||||
if($task->estStarted < $monday and $task->deadline >= $nextMonday)
|
||||
{
|
||||
$weekActualDays = $workdays;
|
||||
}
|
||||
elseif($task->estStarted >= $monday and $task->estStarted < $nextMonday)
|
||||
{
|
||||
$weekActualDays = $this->loadModel('holiday')->getActualWorkingDays($task->estStarted, $task->deadline >= $nextMonday ? $sunday : $task->deadline);
|
||||
$weekActualDays = $this->holiday->getActualWorkingDays($task->estStarted, $task->deadline >= $nextMonday ? $sunday : $task->deadline);
|
||||
}
|
||||
elseif($task->deadline >= $monday and $task->deadline < $nextMonday)
|
||||
{
|
||||
$weekActualDays = $this->loadModel('holiday')->getActualWorkingDays($monday, $task->deadline);
|
||||
$weekActualDays = $this->holiday->getActualWorkingDays($monday, $task->deadline);
|
||||
}
|
||||
|
||||
if(empty($fullDays) or empty($weekActualDays) or empty($task->estimate)) continue;
|
||||
$PV += round(count($weekActualDays) / count($fullDays) * $task->estimate, 2);
|
||||
}
|
||||
$thisPV = round(count($weekActualDays) / count($fullDays) * $task->estimate, 2);
|
||||
|
||||
return sprintf("%.2f",$PV);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get EV data.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getEV($projectID, $date = '')
|
||||
{
|
||||
$report = $this->getFromDB($projectID, $date);
|
||||
if(!empty($report)) return $report->ev;
|
||||
|
||||
$executions = $this->loadModel('execution')->getList($projectID);
|
||||
$executionIdList = array_keys($executions);
|
||||
|
||||
if(!$date) $date = date('Y-m-d');
|
||||
$monday = $this->getThisMonday($date);
|
||||
$sunday = $this->getThisSunday($date);
|
||||
$lastDay = $this->getLastDay($date);
|
||||
$nextMonday = date('Y-m-d', strtotime($sunday) + 24 * 3600);
|
||||
|
||||
$tasks = $this->dao->select('*')
|
||||
->from(TABLE_TASK)
|
||||
->where('execution')->in($executionIdList)
|
||||
->andWhere('consumed')->gt(0)
|
||||
->andWhere("((estStarted >= '$monday' AND estStarted < '$nextMonday') OR (deadline >= '$monday' AND deadline < '$nextMonday') OR (estStarted < '$monday' AND deadline > '$nextMonday'))")
|
||||
->andWhere("parent")->ge(0)
|
||||
->andWhere("deleted")->eq(0)
|
||||
->andWhere('status')->ne('cancel')
|
||||
->query();
|
||||
|
||||
$EV = 0;
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->status == 'done' or $task->closedReason == 'done')
|
||||
{
|
||||
$EV += $task->estimate;
|
||||
$EV += $thisPV;
|
||||
}
|
||||
else
|
||||
{
|
||||
$task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100;
|
||||
$EV += $task->estimate * $task->progress / 100;
|
||||
$EV += round($thisPV * $task->progress / 100, 2);
|
||||
}
|
||||
$PV += $thisPV;
|
||||
}
|
||||
|
||||
return sprintf("%.2f", $EV);
|
||||
return array('PV' => sprintf("%.2f", $PV), 'EV' => sprintf("%.2f", $EV));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,15 +457,10 @@ class weeklyModel extends model
|
||||
|
||||
if(!$date) $date = date('Y-m-d');
|
||||
|
||||
$monday = $this->getThisMonday($date);
|
||||
$nextMonday = date('Y-m-d', strtotime($monday) + (7 * 24 * 3600));
|
||||
$executions = $this->dao->select('id,begin,end,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($project)->fetchAll('id');
|
||||
$executionIdList = array_keys($executions);
|
||||
$taskIdList = $this->dao->select('id')->from(TABLE_TASK)
|
||||
->where('execution')->in($executionIdList)
|
||||
->andWhere("parent")->ge(0)
|
||||
->andWhere("deleted")->eq(0)
|
||||
->fetchPairs();
|
||||
$monday = $this->getThisMonday($date);
|
||||
$nextMonday = date('Y-m-d', strtotime($monday) + (7 * 24 * 3600));
|
||||
$executions = $this->dao->select('id,begin,end,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($project)->fetchAll('id');
|
||||
$taskIdList = $this->dao->select('id')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere("parent")->ge(0)->andWhere("deleted")->eq(0)->fetchPairs();
|
||||
|
||||
$AC = $this->dao->select('sum(consumed) as consumed')
|
||||
->from(TABLE_EFFORT)
|
||||
|
||||
Reference in New Issue
Block a user