- createLink('bug', 'batchEdit');
- $misc = $canBatchEdit ? "onclick=\"setFormAction('$actionLink')\"" : "disabled='disabled'";
- echo html::commonButton($lang->edit, $misc);
- ?>
{$pager->recTotal}";
- echo "
";
if($app->rawMethod == 'work') echo html::a(inlink($app->rawMethod, "mode=testtask&type=wait"), "
", '', "class='btn btn-link'");
if($app->rawMethod == 'contribute') echo html::a(inlink($app->rawMethod, "mode=testtask&type=done"), "
" . ($type == 'assigntome' ? $recTotalLabel : ''), '', "class='btn btn-link" . ($type == 'assigntome' ? ' btn-active-text' : '') . "'");
echo html::a(inlink($app->rawMethod, "mode=$mode&type=openedbyme"), "
" . ($type == 'openedbyme' ? $recTotalLabel : ''), '', "class='btn btn-link" . ($type == 'openedbyme' ? ' btn-active-text' : '') . "'");
?>
diff --git a/module/my/view/testtask.html.php b/module/my/view/testtask.html.php
index df96280270..54b0bd2f7b 100644
--- a/module/my/view/testtask.html.php
+++ b/module/my/view/testtask.html.php
@@ -17,11 +17,9 @@
{$pager->recTotal}";
- echo "
{$lang->testtask->common}: ";
if($app->rawMethod == 'work') echo html::a(inlink($app->rawMethod, "mode=$mode&type=wait"), "
{$lang->testtask->wait}" . ($type == 'wait' ? $recTotalLabel : ''), '', "class='btn btn-link" . ($type == 'wait' ? ' btn-active-text' : '') . "'");
if($app->rawMethod == 'contribute') echo html::a(inlink($app->rawMethod, "mode=$mode&type=done"), "
{$lang->testtask->done}" . ($type == 'done' ? $recTotalLabel : ''), '', "class='btn btn-link" . ($type == 'done' ? ' btn-active-text' : '') . "'");
echo "
";
- echo "
{$lang->testcase->common}: ";
echo html::a(inlink($app->rawMethod, "mode=testcase&type=assigntome"), "
{$lang->testcase->assignToMe}", '', "class='btn btn-link'");
echo html::a(inlink($app->rawMethod, "mode=testcase&type=openedbyme"), "
{$lang->testcase->openedByMe}", '', "class='btn btn-link'");
?>
diff --git a/module/product/control.php b/module/product/control.php
index 38755aa949..429cbbce88 100644
--- a/module/product/control.php
+++ b/module/product/control.php
@@ -246,10 +246,11 @@ class product extends control
/**
* Create a product.
*
+ * @param int $programID
* @access public
* @return void
*/
- public function create()
+ public function create($programID = 0)
{
$this->lang->product->switcherMenu = $this->product->getSwitcher();
@@ -265,6 +266,15 @@ class product extends control
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locate));
}
+ if($programID)
+ {
+ $this->app->rawModule = 'program';
+ $this->app->rawMethod = 'pgmproduct';
+ $this->lang->navGroup->program = 'program';
+ $this->loadModel('program')->setPGMViewMenu($programID);
+ $this->lang->program->switcherMenu = $this->program->getPGMCommonAction() . $this->program->getPGMSwitcher($programID, true);
+ }
+
$this->loadModel('user');
$poUsers = $this->user->getPairs('nodeleted|pofirst|noclosed', '', $this->config->maxCount);
if(!empty($this->config->user->moreLink)) $this->config->moreLinks["PO"] = $this->config->user->moreLink;
diff --git a/module/product/model.php b/module/product/model.php
index b0f0a02479..dc25b7bd0c 100644
--- a/module/product/model.php
+++ b/module/product/model.php
@@ -1102,10 +1102,18 @@ class productModel extends model
->page($pager)
->fetchAll('id');
- $stories = $this->dao->select('product, status, count(status) AS count')
+ $stories = $this->dao->select('product, status, type, count(status) AS count')
->from(TABLE_STORY)
->where('deleted')->eq(0)
- ->andWhere('type')->eq($storyType)
+ ->andWhere('type')->eq('story')
+ ->andWhere('product')->in($productKeys)
+ ->groupBy('product, status')
+ ->fetchGroup('product', 'status');
+
+ $requirements = $this->dao->select('product, status, type, count(status) AS count')
+ ->from(TABLE_STORY)
+ ->where('deleted')->eq(0)
+ ->andWhere('type')->eq('requirement')
->andWhere('product')->in($productKeys)
->groupBy('product, status')
->fetchGroup('product', 'status');
@@ -1114,7 +1122,8 @@ class productModel extends model
$emptyStory = array_keys($this->lang->story->statusList);
foreach($productKeys as $productID)
{
- if(!isset($stories[$productID])) $stories[$productID] = $emptyStory;
+ if(!isset($stories[$productID])) $stories[$productID] = $emptyStory;
+ if(!isset($requirements[$productID])) $requirements[$productID] = $emptyStory;
}
/* Padding the stories to sure all status have records. */
@@ -1126,6 +1135,16 @@ class productModel extends model
}
$stories[$key] = $story;
}
+ foreach($requirements as $key => $requirement)
+ {
+ foreach(array_keys($this->lang->story->statusList) as $status)
+ {
+ $requirement[$status] = isset($requirement[$status]) ? $requirement[$status]->count : 0;
+ }
+ $requirements[$key] = $requirement;
+ }
+
+ if($storyType == 'requirement') $stories = $requirements;
$plans = $this->dao->select('product, count(*) AS count')
->from(TABLE_PRODUCTPLAN)
@@ -1157,6 +1176,14 @@ class productModel extends model
->groupBy('product')
->fetchPairs();
+ $closedBugs = $this->dao->select('product,count(*) AS count')
+ ->from(TABLE_BUG)
+ ->where('deleted')->eq(0)
+ ->andwhere('status')->eq('closed')
+ ->andWhere('product')->in($productKeys)
+ ->groupBy('product')
+ ->fetchPairs();
+
$assignToNull = $this->dao->select('product,count(*) AS count')
->from(TABLE_BUG)
->where('deleted')->eq(0)
@@ -1180,12 +1207,14 @@ class productModel extends model
$stats = array();
foreach($products as $key => $product)
{
- $product->stories = $stories[$product->id];
- $product->plans = isset($plans[$product->id]) ? $plans[$product->id] : 0;
- $product->releases = isset($releases[$product->id]) ? $releases[$product->id] : 0;
+ $product->stories = $stories[$product->id];
+ $product->requirements = $requirements[$product->id];
+ $product->plans = isset($plans[$product->id]) ? $plans[$product->id] : 0;
+ $product->releases = isset($releases[$product->id]) ? $releases[$product->id] : 0;
$product->bugs = isset($bugs[$product->id]) ? $bugs[$product->id] : 0;
$product->unResolved = isset($unResolved[$product->id]) ? $unResolved[$product->id] : 0;
+ $product->closedBugs = isset($closedBugs[$product->id]) ? $closedBugs[$product->id] : 0;
$product->assignToNull = isset($assignToNull[$product->id]) ? $assignToNull[$product->id] : 0;
$stats[] = $product;
}
diff --git a/module/program/css/pgmproduct.css b/module/program/css/pgmproduct.css
new file mode 100644
index 0000000000..40b83f5765
--- /dev/null
+++ b/module/program/css/pgmproduct.css
@@ -0,0 +1 @@
+.main-table thead>tr:first-of-type>th {border-left: 1px solid #ddd;}
diff --git a/module/program/lang/de.php b/module/program/lang/de.php
index 65000e8eee..0201d502a6 100644
--- a/module/program/lang/de.php
+++ b/module/program/lang/de.php
@@ -197,6 +197,7 @@ $lang->program->unlinkStakeholder = 'Unlink Stakeholder';
$lang->program->importStakeholder = 'Import program';
$lang->program->PGMManageMembers = 'Program Team';
$lang->program->PGMParentBudget = "Parent program budget:%s";
+$lang->program->beyondParentBudget = 'The remaining budget has been exceeded.';
$lang->program->PGMBeginLetterParent = "Parent begin date: %s, begin date should be >= parent begin date.";
$lang->program->PGMEndGreaterParent = "Parent end date: %s, end date should be <= parent end date.";
$lang->program->PGMBeginGreateChild = "Child earliest begin: %s, parent begin date <= child earliest begin date.";
diff --git a/module/program/lang/en.php b/module/program/lang/en.php
index 9784092c5f..c2fa5dde62 100644
--- a/module/program/lang/en.php
+++ b/module/program/lang/en.php
@@ -197,6 +197,7 @@ $lang->program->unlinkStakeholder = 'Unlink Stakeholder';
$lang->program->importStakeholder = 'Import program';
$lang->program->PGMManageMembers = 'Program Team';
$lang->program->PGMParentBudget = "Parent program budget:%s";
+$lang->program->beyondParentBudget = 'The remaining budget has been exceeded.';
$lang->program->PGMBeginLetterParent = "Parent begin date: %s, begin date should be >= parent begin date.";
$lang->program->PGMEndGreaterParent = "Parent end date: %s, end date should be <= parent end date.";
$lang->program->PGMBeginGreateChild = "Child earliest begin: %s, parent begin date <= child earliest begin date.";
diff --git a/module/program/lang/fr.php b/module/program/lang/fr.php
index 65000e8eee..0201d502a6 100644
--- a/module/program/lang/fr.php
+++ b/module/program/lang/fr.php
@@ -197,6 +197,7 @@ $lang->program->unlinkStakeholder = 'Unlink Stakeholder';
$lang->program->importStakeholder = 'Import program';
$lang->program->PGMManageMembers = 'Program Team';
$lang->program->PGMParentBudget = "Parent program budget:%s";
+$lang->program->beyondParentBudget = 'The remaining budget has been exceeded.';
$lang->program->PGMBeginLetterParent = "Parent begin date: %s, begin date should be >= parent begin date.";
$lang->program->PGMEndGreaterParent = "Parent end date: %s, end date should be <= parent end date.";
$lang->program->PGMBeginGreateChild = "Child earliest begin: %s, parent begin date <= child earliest begin date.";
diff --git a/module/program/lang/vi.php b/module/program/lang/vi.php
index 65000e8eee..0201d502a6 100644
--- a/module/program/lang/vi.php
+++ b/module/program/lang/vi.php
@@ -197,6 +197,7 @@ $lang->program->unlinkStakeholder = 'Unlink Stakeholder';
$lang->program->importStakeholder = 'Import program';
$lang->program->PGMManageMembers = 'Program Team';
$lang->program->PGMParentBudget = "Parent program budget:%s";
+$lang->program->beyondParentBudget = 'The remaining budget has been exceeded.';
$lang->program->PGMBeginLetterParent = "Parent begin date: %s, begin date should be >= parent begin date.";
$lang->program->PGMEndGreaterParent = "Parent end date: %s, end date should be <= parent end date.";
$lang->program->PGMBeginGreateChild = "Child earliest begin: %s, parent begin date <= child earliest begin date.";
diff --git a/module/program/lang/zh-cn.php b/module/program/lang/zh-cn.php
index 7ac3081275..990188cb9b 100644
--- a/module/program/lang/zh-cn.php
+++ b/module/program/lang/zh-cn.php
@@ -197,6 +197,7 @@ $lang->program->unlinkStakeholder = '移除干系人';
$lang->program->importStakeholder = '从父项目集导入';
$lang->program->PGMManageMembers = '项目集团队';
$lang->program->PGMParentBudget = "父项目集预算:%s";
+$lang->program->beyondParentBudget = '已超出剩余预算';
$lang->program->PGMBeginLetterParent = "父项目集的开始日期:%s,开始日期不能小于父项目集的开始日期";
$lang->program->PGMEndGreaterParent = "父项目集的完成日期:%s,完成日期不能大于父项目集的完成日期";
$lang->program->PGMBeginGreateChild = "子项目集的最小开始日期:%s,父项目集的开始日期不能大于子项目集的最小开始日期";
diff --git a/module/program/lang/zh-tw.php b/module/program/lang/zh-tw.php
index 95bba62aae..c598cf31cb 100644
--- a/module/program/lang/zh-tw.php
+++ b/module/program/lang/zh-tw.php
@@ -200,6 +200,7 @@ $lang->program->unlinkStakeholder = '移除干係人';
$lang->program->importStakeholder = '從父項目集導入';
$lang->program->PGMManageMembers = '項目集團隊';
$lang->program->PGMParentBudget = "父項目集預算:%s";
+$lang->program->beyondParentBudget = '已超出剩餘預算';
$lang->program->PGMBeginLetterParent = "父項目集的開始日期:%s,開始日期不能小於父項目集的開始日期";
$lang->program->PGMEndGreaterParent = "父項目集的完成日期:%s,完成日期不能大於父項目集的完成日期";
$lang->program->PGMBeginGreateChild = "子項目集的最小開始日期:%s,父項目集的開始日期不能大於子項目集的最小開始日期";
diff --git a/module/program/model.php b/module/program/model.php
index f6556906bf..409f1429a2 100644
--- a/module/program/model.php
+++ b/module/program/model.php
@@ -143,6 +143,18 @@ class programModel extends model
/* When parent set end then child program cannot set longTime. */
if(empty($program->end) and $this->post->delta == 999 and $parentProgram->end != '0000-00-00') dao::$errors['end'] = sprintf($this->lang->program->PGMEndGreaterParent, $parentProgram->end);
+ /* The budget of a child program cannot beyond the remaining budget of the parent program. */
+ if(isset($program->budget) and $parentProgram->budget != 0)
+ {
+ $childGrade = $parentProgram->grade + 1;
+ $childSumBudget = $this->dao->select("sum(budget) as sumBudget")->from(TABLE_PROJECT)
+ ->where('path')->like("%{$program->parent}%")
+ ->andWhere('grade')->eq($childGrade)
+ ->fetch('sumBudget');
+
+ if($program->budget > $parentProgram->budget - $childSumBudget) dao::$errors['budget'] = $this->lang->program->beyondParentBudget;
+ }
+
if(dao::isError()) return false;
}
}
diff --git a/module/program/view/pgmproduct.html.php b/module/program/view/pgmproduct.html.php
index 657e178cfd..eed27ae13e 100644
--- a/module/program/view/pgmproduct.html.php
+++ b/module/program/view/pgmproduct.html.php
@@ -32,7 +32,7 @@
id&browseType=$browseType&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?>
- |
+ |
@@ -40,43 +40,60 @@
idAB);?>
|
- product->name);?> |
- product->activeStories;?> |
- product->changedStories;?> |
- product->draftStories;?> |
- product->closedStories;?> |
- product->plans;?> |
- product->releases;?> |
- product->unResolvedBugs;?> |
- product->assignToNullBugs;?> |
+ product->name);?> |
+ story->requirement;?> |
+ story->story;?> |
+ bug->common;?> |
+ product->release;?> |
+ product->plan;?> |
- product->updateOrder);?> |
+ product->updateOrder);?> |
+
+ | story->activate;?> |
+ story->close;?> |
+ story->draft;?> |
+ story->completeRate;?> |
+ story->activate;?> |
+ story->close;?> |
+ story->draft;?> |
+ story->completeRate;?> |
+ bug->activate;?> |
+ bug->close;?> |
+
-
- |
-
- id => sprintf('%03d', $product->id)));?>
-
- id);?>
+ stories['active'] + $product->stories['closed'] + $product->stories['draft'] + $product->stories['changed'];
+ $totalRequirements = $product->requirements['active'] + $product->requirements['closed'] + $product->requirements['draft'] + $product->requirements['changed'];
+ ?>
+ |
+ |
+
+ id => sprintf('%03d', $product->id)));?>
+
+ id);?>
+
+ |
+ createLink('product', 'browse', 'product=' . $product->id), $product->name);?> |
+ requirements['active'];?> |
+ requirements['closed'];?> |
+ requirements['draft'];?> |
+ requirements['closed'] / $totalRequirements, 3) * 100;?>% |
+ stories['active'];?> |
+ stories['closed'];?> |
+ stories['draft'];?> |
+ stories['closed'] / $totalStories, 3) * 100;?>% |
+ unResolved;?> |
+ closedBugs;?> |
+ releases;?> |
+ plans;?> |
+
+ |
-
- createLink('product', 'browse', 'product=' . $product->id), $product->name);?> |
- stories['active'];?> |
- stories['changed'];?> |
- stories['draft'];?> |
- stories['closed'];?> |
- plans;?> |
- releases;?> |
- unResolved;?> |
- assignToNull;?> |
-
- |
-
-
+