* Resolve confilict.
This commit is contained in:
+16
-16
@@ -57,10 +57,10 @@ class product extends control
|
||||
if($locate == 'yes') $this->locate($this->createLink($this->moduleName, 'browse'));
|
||||
|
||||
if($this->app->getViewType() != 'mhtml') unset($this->lang->product->menu->index);
|
||||
$productID = $this->productZen->saveVisitState($productID, $this->products);
|
||||
$productID = $this->product->saveVisitState($productID, $this->products);
|
||||
$branch = (int)$this->cookie->preBranch;
|
||||
|
||||
if($this->app->viewType == 'mhtml') $this->productZen->setMenu($productID, $branch);
|
||||
if($this->app->viewType == 'mhtml') $this->product->setMenu($productID, $branch);
|
||||
|
||||
if(common::hasPriv('product', 'create')) $this->lang->TRActions = html::a($this->createLink('product', 'create'), "<i class='icon icon-sm icon-plus'></i> " . $this->lang->product->create, '', "class='btn btn-primary'");
|
||||
|
||||
@@ -123,7 +123,7 @@ class product extends control
|
||||
$pageID = (int)$pageID;
|
||||
$projectID = (int)$projectID;
|
||||
|
||||
$productID = $this->app->tab != 'project' ? $this->saveVisitState($productID, $this->products) : $productID;
|
||||
$productID = $this->app->tab != 'project' ? $this->product->saveVisitState($productID, $this->products) : $productID;
|
||||
$product = $this->product->getById($productID);
|
||||
|
||||
if($product && !isset($this->products[$product->id])) $this->products[$product->id] = $product->name;
|
||||
@@ -150,7 +150,7 @@ class product extends control
|
||||
$this->session->set('storyList', $this->app->getURI(true), 'product');
|
||||
$this->session->set('productList', $this->app->getURI(true), 'product');
|
||||
|
||||
$this->productZen->setMenu($productID, $branch, 0, '', "storyType=$storyType");
|
||||
$this->product->setMenu($productID, $branch, 0, '', "storyType=$storyType");
|
||||
}
|
||||
|
||||
/* Lower browse type. */
|
||||
@@ -435,7 +435,7 @@ class product extends control
|
||||
$this->productZen->setEditMenu($productID, $programID);
|
||||
|
||||
$product = $this->product->getByID($productID);
|
||||
$productID = $this->productZen->saveVisitState($productID, $this->products);
|
||||
$productID = $this->product->saveVisitState($productID, $this->products);
|
||||
|
||||
$this->productZen->buildEditForm($product);
|
||||
}
|
||||
@@ -567,7 +567,7 @@ class product extends control
|
||||
return print(js::reload('parent.parent'));
|
||||
}
|
||||
|
||||
$this->productZen->setMenu($productID);
|
||||
$this->product->setMenu($productID);
|
||||
|
||||
$this->view->product = $product;
|
||||
$this->view->title = $this->view->product->name . $this->lang->colon .$this->lang->close;
|
||||
@@ -596,7 +596,7 @@ class product extends control
|
||||
}
|
||||
|
||||
$product->desc = $this->loadModel('file')->setImgSize($product->desc);
|
||||
$this->productZen->setMenu($productID);
|
||||
$this->product->setMenu($productID);
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
@@ -655,7 +655,7 @@ class product extends control
|
||||
*/
|
||||
public function roadmap($productID, $branch = 'all')
|
||||
{
|
||||
$this->productZen->setMenu($productID, $branch);
|
||||
$this->product->setMenu($productID, $branch);
|
||||
|
||||
$this->session->set('releaseList', $this->app->getURI(true), 'product');
|
||||
$this->session->set('productPlanList', $this->app->getURI(true), 'product');
|
||||
@@ -701,7 +701,7 @@ class product extends control
|
||||
$this->session->set('caseList', $uri, 'qa');
|
||||
$this->session->set('testtaskList', $uri, 'qa');
|
||||
|
||||
$this->productZen->setMenu($productID, 0, 0, '', $type);
|
||||
$this->product->setMenu($productID, 0, 0, '', $type);
|
||||
|
||||
/* Append id for secend sort. */
|
||||
$orderBy = $direction == 'next' ? 'date_desc' : 'date_asc';
|
||||
@@ -757,12 +757,12 @@ class product extends control
|
||||
$this->session->set('productPlanList', $uri, 'product');
|
||||
$this->session->set('releaseList', $uri, 'product');
|
||||
|
||||
$productID = $this->productZen->saveVisitState($productID, $this->products);
|
||||
$productID = $this->product->saveVisitState($productID, $this->products);
|
||||
$product = $this->product->getStatByID($productID);
|
||||
if(!$product) return print(js::locate('product', 'all'));
|
||||
|
||||
$product->desc = $this->loadModel('file')->setImgSize($product->desc);
|
||||
$this->productZen->setMenu($productID);
|
||||
$this->product->setMenu($productID);
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
@@ -989,7 +989,7 @@ class product extends control
|
||||
*/
|
||||
public function whitelist($productID = 0, $module = 'product', $objectType = 'product', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
{
|
||||
$this->productZen->setMenu($productID, 0);
|
||||
$this->product->setMenu($productID, 0);
|
||||
$this->lang->modulePageNav = '';
|
||||
|
||||
echo $this->fetch('personnel', 'whitelist', "objectID=$productID&module=product&browseType=$objectType&orderBy=$orderBy&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID");
|
||||
@@ -1007,7 +1007,7 @@ class product extends control
|
||||
*/
|
||||
public function addWhitelist($productID = 0, $deptID = 0, $copyID = 0)
|
||||
{
|
||||
$this->productZen->setMenu($productID);
|
||||
$this->product->setMenu($productID);
|
||||
$this->lang->modulePageNav = '';
|
||||
|
||||
echo $this->fetch('personnel', 'addWhitelist', "objectID=$productID&dept=$deptID©ID=$copyID&objectType=product&module=product");
|
||||
@@ -1132,9 +1132,9 @@ class product extends control
|
||||
if(!$projectID)
|
||||
{
|
||||
$products = $this->product->getPairs();
|
||||
$productID = $this->productZen->saveVisitState($productID, $products);
|
||||
$this->product->products = $this->productZen->saveVisitState($productID, $products);
|
||||
$this->productZen->setMenu($productID, $branch);
|
||||
$productID = $this->product->saveVisitState($productID, $products);
|
||||
$this->product->products = $this->product->saveVisitState($productID, $products);
|
||||
$this->product->setMenu($productID, $branch);
|
||||
}
|
||||
|
||||
/* Save session. */
|
||||
|
||||
+129
-3
@@ -1162,7 +1162,6 @@ class productModel extends model
|
||||
if(empty($projects)) return array();
|
||||
|
||||
$projectKeys = array_keys($projects);
|
||||
$stats = array();
|
||||
|
||||
/* Get all tasks and compute totalEstimate, totalConsumed, totalLeft, progress according to them. */
|
||||
$tasks = $this->dao->select('id, project, estimate, consumed, `left`, status, closedReason')
|
||||
@@ -1181,8 +1180,7 @@ class productModel extends model
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->fetchGroup('root', 'account');
|
||||
|
||||
$stats = $this->program->appendStatToProjects($projects, 'hours,teamCount', array('hours' => $hours, 'teams' => $teams));
|
||||
return $stats;
|
||||
return $this->program->appendStatToProjects($projects, 'hours,teamCount', array('hours' => $hours, 'teams' => $teams));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2231,4 +2229,132 @@ class productModel extends model
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把访问的产品ID等状态信息保存到session和cookie中。
|
||||
* Save the product id user last visited to session and cookie.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param array $products
|
||||
* @access protected
|
||||
* @return int
|
||||
*/
|
||||
protected function saveVisitState(int $productID, array $products): int
|
||||
{
|
||||
if(defined('TUTORIAL')) return $productID;
|
||||
|
||||
$productID = $this->getAccessableProductID($productID, $products);
|
||||
|
||||
$this->session->set('product', $productID, $this->app->tab);
|
||||
|
||||
setcookie('preProductID', (string)$productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
/* If preProductID changed, then reset preBranch. */
|
||||
if($this->cookie->preProductID != $this->session->product)
|
||||
{
|
||||
$this->cookie->set('preBranch', 0);
|
||||
setcookie('preBranch', '0', $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
}
|
||||
|
||||
return $productID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可访问的产品ID。
|
||||
* Get accessable product ID.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param array $products
|
||||
* @access protected
|
||||
* @return int
|
||||
*/
|
||||
protected function getAccessableProductID(int $productID, array $products): int
|
||||
{
|
||||
if(empty($productID))
|
||||
{
|
||||
if($this->cookie->preProductID and isset($products[$this->cookie->preProductID])) $productID = $this->cookie->preProductID;
|
||||
if(empty($this->session->product)) $productID = (int)key($products);
|
||||
}
|
||||
|
||||
/* 产品ID已经被删除,不存在于产品列表中。*/
|
||||
/* Product ID does not exsit in products list, it may be deleted. */
|
||||
if(!isset($products[$productID]))
|
||||
{
|
||||
/* Confirm if product exist. */
|
||||
$product = $this->product->getById($productID);
|
||||
if(empty($product) or $product->deleted == 1) $productID = (int)key($products);
|
||||
/* If product is invisable for curren user, then response access denied message. */
|
||||
if($productID && strpos(",{$this->app->user->view->products},", ",{$productID},") === false)
|
||||
{
|
||||
$productID = (int)key($products);
|
||||
$this->accessDenied($this->lang->product->accessDenied);
|
||||
}
|
||||
}
|
||||
|
||||
return $productID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出访问被拒绝提示信息。
|
||||
* Show accessDenied response.
|
||||
*
|
||||
* @param string $tips
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
public function accessDenied($tips)
|
||||
{
|
||||
if(defined('TUTORIAL')) return true;
|
||||
|
||||
echo js::alert($tips);
|
||||
|
||||
if(!$this->server->http_referer) return print(js::locate(helper::createLink('product', 'index')));
|
||||
|
||||
$loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login";
|
||||
if(strpos($this->server->http_referer, $loginLink) !== false) return print(js::locate(helper::createLink('product', 'index')));
|
||||
|
||||
echo js::locate('back');
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置导航菜单。
|
||||
* Set menu.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int|string $branch
|
||||
* @param int $module
|
||||
* @param string $moduleType
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setMenu($productID = 0, $branch = '', $module = 0, $moduleType = '', $extra = ''): void
|
||||
{
|
||||
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL'))
|
||||
{
|
||||
$this->accessDenied($this->lang->product->accessDenied);
|
||||
return;
|
||||
}
|
||||
|
||||
$product = $this->getByID($productID);
|
||||
|
||||
$params = array('branch' => $branch);
|
||||
common::setMenuVars('product', $productID, $params);
|
||||
if(!$product) return;
|
||||
|
||||
$this->lang->switcherMenu = $this->getSwitcher($productID, $extra, $branch);
|
||||
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
unset($this->lang->product->menu->settings['subMenu']->branch);
|
||||
}
|
||||
else
|
||||
{
|
||||
$branchLink = $this->lang->product->menu->settings['subMenu']->branch['link'];
|
||||
$this->lang->product->menu->settings['subMenu']->branch['link'] = str_replace('@branch@', $this->lang->product->branchName[$product->type], $branchLink);
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
}
|
||||
|
||||
if(strpos($extra, 'requirement') !== false) unset($this->lang->product->moreSelects['willclose']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,132 +596,4 @@ class productZen extends product
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把访问的产品ID等状态信息保存到session和cookie中。
|
||||
* Save the product id user last visited to session and cookie.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param array $products
|
||||
* @access protected
|
||||
* @return int
|
||||
*/
|
||||
protected function saveVisitState(int $productID, array $products): int
|
||||
{
|
||||
if(defined('TUTORIAL')) return $productID;
|
||||
|
||||
$productID = $this->getAccessableProductID($productID, $products);
|
||||
|
||||
$this->session->set('product', $productID, $this->app->tab);
|
||||
|
||||
setcookie('preProductID', (string)$productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
/* If preProductID changed, then reset preBranch. */
|
||||
if($this->cookie->preProductID != $this->session->product)
|
||||
{
|
||||
$this->cookie->set('preBranch', 0);
|
||||
setcookie('preBranch', '0', $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
}
|
||||
|
||||
return $productID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可访问的产品ID。
|
||||
* Get accessable product ID.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param array $products
|
||||
* @access protected
|
||||
* @return int
|
||||
*/
|
||||
protected function getAccessableProductID(int $productID, array $products): int
|
||||
{
|
||||
if(empty($productID))
|
||||
{
|
||||
if($this->cookie->preProductID and isset($products[$this->cookie->preProductID])) $productID = $this->cookie->preProductID;
|
||||
if(empty($this->session->product)) $productID = (int)key($products);
|
||||
}
|
||||
|
||||
/* 产品ID已经被删除,不存在于产品列表中。*/
|
||||
/* Product ID does not exsit in products list, it may be deleted. */
|
||||
if(!isset($products[$productID]))
|
||||
{
|
||||
/* Confirm if product exist. */
|
||||
$product = $this->product->getById($productID);
|
||||
if(empty($product) or $product->deleted == 1) $productID = (int)key($products);
|
||||
/* If product is invisable for curren user, then response access denied message. */
|
||||
if($productID && strpos(",{$this->app->user->view->products},", ",{$productID},") === false)
|
||||
{
|
||||
$productID = (int)key($products);
|
||||
$this->accessDenied($this->lang->product->accessDenied);
|
||||
}
|
||||
}
|
||||
|
||||
return $productID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出访问被拒绝提示信息。
|
||||
* Show accessDenied response.
|
||||
*
|
||||
* @param string $tips
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
public function accessDenied($tips)
|
||||
{
|
||||
if(defined('TUTORIAL')) return true;
|
||||
|
||||
echo(js::alert($tips));
|
||||
|
||||
if(!$this->server->http_referer) return print(js::locate(helper::createLink('product', 'index')));
|
||||
|
||||
$loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login";
|
||||
if(strpos($this->server->http_referer, $loginLink) !== false) return print(js::locate(helper::createLink('product', 'index')));
|
||||
|
||||
echo js::locate('back');
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置导航菜单。
|
||||
* Set menu.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int|string $branch
|
||||
* @param int $module
|
||||
* @param string $moduleType
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setMenu($productID = 0, $branch = '', $module = 0, $moduleType = '', $extra = ''): void
|
||||
{
|
||||
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL'))
|
||||
{
|
||||
$this->accessDenied($this->lang->product->accessDenied);
|
||||
return;
|
||||
}
|
||||
|
||||
$product = $this->product->getByID($productID);
|
||||
|
||||
$params = array('branch' => $branch);
|
||||
common::setMenuVars('product', $productID, $params);
|
||||
if(!$product) return;
|
||||
|
||||
$this->lang->switcherMenu = $this->product->getSwitcher($productID, $extra, $branch);
|
||||
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
unset($this->lang->product->menu->settings['subMenu']->branch);
|
||||
}
|
||||
else
|
||||
{
|
||||
$branchLink = $this->lang->product->menu->settings['subMenu']->branch['link'];
|
||||
$this->lang->product->menu->settings['subMenu']->branch['link'] = str_replace('@branch@', $this->lang->product->branchName[$product->type], $branchLink);
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
}
|
||||
|
||||
if(strpos($extra, 'requirement') !== false) unset($this->lang->product->moreSelects['willclose']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
helper::import(dirname(__FILE__) . 'config/form.php');
|
||||
|
||||
$config->programplan->create = new stdclass();
|
||||
$config->programplan->edit = new stdclass();
|
||||
$config->programplan->create->requiredFields = 'name,begin,end';
|
||||
|
||||
@@ -14,3 +14,11 @@ $config->programplan->edit->form['realBegan'] = array('required' => false, 'type
|
||||
$config->programplan->edit->form['realEnd'] = array('required' => false, 'type' => 'string', 'default' => '0000-00-00');
|
||||
$config->programplan->edit->form['output'] = array('required' => false, 'type' => 'array', 'default' => array());
|
||||
|
||||
$config->programplan->ajaxCustom = new stdClass();
|
||||
$config->programplan->ajaxCustom->form = array();
|
||||
$config->programplan->ajaxCustom->form['type'] = array('required' => true, 'type' => 'string');
|
||||
$config->programplan->ajaxCustom->form['name'] = array('required' => true, 'type' => 'string');
|
||||
$config->programplan->ajaxCustom->form['status'] = array('required' => true, 'type' => 'string');
|
||||
$config->programplan->ajaxCustom->form['pri'] = array('required' => true, 'type' => 'int');
|
||||
$config->programplan->ajaxCustom->form['date'] = array('required' => false, 'type' => 'string', 'default' => helper::today());
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ class programplan extends control
|
||||
if($_POST)
|
||||
{
|
||||
$formData = form::data($this->config->programplan->create->form);
|
||||
$this->programplan->create($formData, $projectID, $this->productID, $planID);
|
||||
$this->programplan->create($formData, $projectID, $productID, $planID);
|
||||
if(dao::isError())
|
||||
{
|
||||
$errors = dao::getError();
|
||||
@@ -173,7 +173,7 @@ class programplan extends control
|
||||
$this->view->position[] = $this->lang->programplan->create;
|
||||
|
||||
$executions = !empty($planID) ? $this->loadModel('execution')->getChildExecutions($planID, 'order_asc') : array();
|
||||
$plans = $this->programplan->getStage($planID ? $planID : $projectID, $this->productID, 'parent', 'order_asc');
|
||||
$plans = $this->programplan->getStage($planID ? $planID : $projectID, $productID, 'parent', 'order_asc');
|
||||
if(!empty($planID) and !empty($plans) and $project->model == 'waterfallplus')
|
||||
{
|
||||
$executionType = 'stage';
|
||||
@@ -266,6 +266,7 @@ class programplan extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过ajax请求保存自定义设置。
|
||||
* Save custom settings via ajax.
|
||||
*
|
||||
* @access public
|
||||
@@ -279,34 +280,18 @@ class programplan extends control
|
||||
$this->loadModel('datatable');
|
||||
$this->loadModel('setting');
|
||||
|
||||
$stageCustom = $this->setting->getItem("owner=$owner&module=$module§ion=browse&key=stageCustom");
|
||||
$ganttFields = $this->setting->getItem("owner=$owner&module=$module§ion=ganttCustom&key=ganttFields");
|
||||
$zooming = $this->setting->getItem("owner=$owner&module=$module§ion=ganttCustom&key=zooming");
|
||||
|
||||
if($_POST)
|
||||
{
|
||||
$data = fixer::input('post')->get();
|
||||
$zooming = empty($data->zooming) ? '' : $data->zooming;
|
||||
$stageCustom = empty($data->stageCustom) ? '' : implode(',', $data->stageCustom);
|
||||
$ganttFields = empty($data->ganttFields) ? '' : implode(',', $data->ganttFields);
|
||||
|
||||
$this->setting->setItem("$owner.$module.browse.stageCustom", $stageCustom);
|
||||
$this->setting->setItem("$owner.$module.ganttCustom.ganttFields", $ganttFields);
|
||||
$this->setting->setItem("$owner.$module.ganttCustom.zooming", $zooming);
|
||||
$formData = form::data($this->config->product->form->create);
|
||||
$this->programplanZen->beforeAjaxCustom($formData, $owner, $module);
|
||||
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
|
||||
}
|
||||
|
||||
/* Set Custom. */
|
||||
foreach(explode(',', $this->config->programplan->custom->customGanttFields) as $field) $customFields[$field] = $this->lang->programplan->ganttCustom[$field];
|
||||
|
||||
$this->view->zooming = $zooming;
|
||||
$this->view->customFields = $customFields;
|
||||
$this->view->showFields = $this->config->programplan->ganttCustom->ganttFields;
|
||||
$this->view->ganttFields = $ganttFields;
|
||||
$this->view->stageCustom = $stageCustom;
|
||||
|
||||
$this->display();
|
||||
|
||||
$this->programplanZen->buildAjaxCustomView($owner, $module, $customFields);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -767,12 +767,14 @@ class programplanModel extends model
|
||||
$plans[] = $plan;
|
||||
}
|
||||
|
||||
/* Set dao error and return false if the programplan has no name. */
|
||||
if(empty($plans))
|
||||
{
|
||||
dao::$errors['message'][] = sprintf($this->lang->error->notempty, $this->lang->programplan->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check every plan is valid. */
|
||||
$totalPercent = 0;
|
||||
$milestone = 0;
|
||||
foreach($plans as $index => $plan)
|
||||
@@ -861,7 +863,7 @@ class programplanModel extends model
|
||||
{
|
||||
$orderIndex = empty($orders) ? 0 : count($orders);
|
||||
$lastID = $this->dao->select('id')->from(TABLE_EXECUTION)->orderBy('id_desc')->fetch('id');
|
||||
for($i = $orderIndex; $i < count($datas); $i ++)
|
||||
for($i = $orderIndex; $i < count($plans); $i ++)
|
||||
{
|
||||
$lastID ++;
|
||||
$orders[$i] = $lastID * 5;
|
||||
@@ -881,33 +883,29 @@ class programplanModel extends model
|
||||
$linkProducts = array_keys($productList);
|
||||
foreach($linkProducts as $index => $productID) $linkBranches[$index] = $productList[$productID]->branches;
|
||||
}
|
||||
$this->post->set('products', $linkProducts);
|
||||
$this->post->set('branch', $linkBranches);
|
||||
|
||||
foreach($datas as $data)
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
/* Set planDuration and realDuration. */
|
||||
if($this->config->edition == 'max')
|
||||
{
|
||||
$data->planDuration = $this->getDuration($data->begin, $data->end);
|
||||
$data->realDuration = $this->getDuration($data->realBegan, $data->realEnd);
|
||||
$plan->planDuration = $this->getDuration($plan->begin, $plan->end);
|
||||
$plan->realDuration = $this->getDuration($plan->realBegan, $plan->realEnd);
|
||||
}
|
||||
|
||||
$projectChanged = false;
|
||||
$data->days = helper::diffDate($data->end, $data->begin) + 1;
|
||||
$data->order = current($orders);
|
||||
$plan->days = helper::diffDate($plan->end, $plan->begin) + 1;
|
||||
$plan->order = current($orders);
|
||||
|
||||
|
||||
if($data->id)
|
||||
if($plan->id)
|
||||
{
|
||||
$stageID = $data->id;
|
||||
unset($data->id, $data->type);
|
||||
$stageID = $plan->id;
|
||||
unset($plan->id, $plan->type);
|
||||
|
||||
$oldStage = $this->getByID($stageID);
|
||||
$planChanged = ($oldStage->name != $data->name || $oldStage->milestone != $data->milestone || $oldStage->begin != $data->begin || $oldStage->end != $data->end);
|
||||
$planChanged = ($oldStage->name != $plan->name || $oldStage->milestone != $plan->milestone || $oldStage->begin != $plan->begin || $oldStage->end != $plan->end);
|
||||
|
||||
if($planChanged) $data->version = $oldStage->version + 1;
|
||||
$this->dao->update(TABLE_PROJECT)->data($data)
|
||||
if($planChanged) $plan->version = $oldStage->version + 1;
|
||||
$this->dao->update(TABLE_PROJECT)->data($plan)
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->programplan->edit->requiredFields, 'notempty')
|
||||
->checkIF($plan->percent != '' and $setPercent, 'percent', 'float')
|
||||
@@ -915,56 +913,56 @@ class programplanModel extends model
|
||||
->exec();
|
||||
|
||||
/* Add PM to stage teams and project teams. */
|
||||
if(!empty($data->PM))
|
||||
if(!empty($plan->PM))
|
||||
{
|
||||
$team = $this->user->getTeamMemberPairs($stageID, 'execution');
|
||||
if(isset($team[$data->PM])) continue;
|
||||
if(isset($team[$plan->PM])) continue;
|
||||
|
||||
$roles = $this->user->getUserRoles($data->PM);
|
||||
$roles = $this->user->getUserRoles($plan->PM);
|
||||
$member = new stdclass();
|
||||
$member->root = $stageID;
|
||||
$member->account = $data->PM;
|
||||
$member->role = zget($roles, $data->PM, '');
|
||||
$member->account = $plan->PM;
|
||||
$member->role = zget($roles, $plan->PM, '');
|
||||
$member->join = $now;
|
||||
$member->type = 'execution';
|
||||
$member->days = $data->days;
|
||||
$member->days = $plan->days;
|
||||
$member->hours = $this->config->execution->defaultWorkhours;
|
||||
$this->dao->insert(TABLE_TEAM)->data($member)->exec();
|
||||
$this->execution->addProjectMembers($data->project, array($data->PM => $member));
|
||||
$this->execution->addProjectMembers($plan->project, array($plan->PM => $member));
|
||||
}
|
||||
|
||||
if($data->acl != 'open') $this->user->updateUserView($stageID, 'sprint');
|
||||
if($plan->acl != 'open') $this->user->updateUserView($stageID, 'sprint');
|
||||
|
||||
/* Record version change information. */
|
||||
if($planChanged)
|
||||
{
|
||||
$spec = new stdclass();
|
||||
$spec->project = $stageID;
|
||||
$spec->version = $data->version;
|
||||
$spec->name = $data->name;
|
||||
$spec->milestone = $data->milestone;
|
||||
$spec->begin = $data->begin;
|
||||
$spec->end = $data->end;
|
||||
$spec->version = $plan->version;
|
||||
$spec->name = $plan->name;
|
||||
$spec->milestone = $plan->milestone;
|
||||
$spec->begin = $plan->begin;
|
||||
$spec->end = $plan->end;
|
||||
$this->dao->insert(TABLE_PROJECTSPEC)->data($spec)->exec();
|
||||
}
|
||||
|
||||
$changes = common::createChanges($oldStage, $data);
|
||||
$changes = common::createChanges($oldStage, $plan);
|
||||
$actionID = $this->action->create('execution', $stageID, 'edited');
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($data->id);
|
||||
$data->status = 'wait';
|
||||
$data->division = $project->division;
|
||||
$data->version = 1;
|
||||
$data->parentVersion = $data->parent == 0 ? 0 : $this->dao->findByID($data->parent)->from(TABLE_PROJECT)->fetch('version');
|
||||
$data->team = substr($data->name,0, 30);
|
||||
$data->openedBy = $account;
|
||||
$data->openedDate = $now;
|
||||
$data->openedVersion = $this->config->version;
|
||||
if(!isset($data->acl)) $data->acl = $this->dao->findByID($data->parent)->from(TABLE_PROJECT)->fetch('acl');
|
||||
$this->dao->insert(TABLE_PROJECT)->data($data)
|
||||
unset($plan->id);
|
||||
$plan->status = 'wait';
|
||||
$plan->division = $project->division;
|
||||
$plan->version = 1;
|
||||
$plan->parentVersion = $plan->parent == 0 ? 0 : $this->dao->findByID($plan->parent)->from(TABLE_PROJECT)->fetch('version');
|
||||
$plan->team = substr($plan->name,0, 30);
|
||||
$plan->openedBy = $account;
|
||||
$plan->openedDate = $now;
|
||||
$plan->openedVersion = $this->config->version;
|
||||
if(!isset($plan->acl)) $plan->acl = $this->dao->findByID($plan->parent)->from(TABLE_PROJECT)->fetch('acl');
|
||||
$this->dao->insert(TABLE_PROJECT)->data($plan)
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->programplan->create->requiredFields, 'notempty')
|
||||
->checkIF($plan->percent != '' and $setPercent, 'percent', 'float')
|
||||
@@ -973,13 +971,13 @@ class programplanModel extends model
|
||||
if(!dao::isError())
|
||||
{
|
||||
$stageID = $this->dao->lastInsertID();
|
||||
if($data->type == 'kanban')
|
||||
if($plan->type == 'kanban')
|
||||
{
|
||||
$execution = $this->execution->getByID($stageID);
|
||||
$this->loadModel('kanban')->createRDKanban($execution);
|
||||
}
|
||||
|
||||
if($data->acl != 'open') $this->user->updateUserView($stageID, 'sprint');
|
||||
if($plan->acl != 'open') $this->user->updateUserView($stageID, 'sprint');
|
||||
|
||||
/* Create doc lib. */
|
||||
$lib = new stdclass();
|
||||
@@ -995,7 +993,7 @@ class programplanModel extends model
|
||||
|
||||
/* Add creators and PM to stage teams and project teams. */
|
||||
$teamMembers = array();
|
||||
$members = array($this->app->user->account, $data->PM);
|
||||
$members = array($this->app->user->account, $plan->PM);
|
||||
$roles = $this->user->getUserRoles(array_values($members));
|
||||
$team = $this->user->getTeamMemberPairs($stageID, 'execution');
|
||||
foreach($members as $teamMember)
|
||||
@@ -1008,29 +1006,29 @@ class programplanModel extends model
|
||||
$member->role = zget($roles, $teamMember, '');
|
||||
$member->join = $now;
|
||||
$member->type = 'execution';
|
||||
$member->days = $data->days;
|
||||
$member->days = $plan->days;
|
||||
$member->hours = $this->config->execution->defaultWorkhours;
|
||||
$this->dao->insert(TABLE_TEAM)->data($member)->exec();
|
||||
$teamMembers[$teamMember] = $member;
|
||||
}
|
||||
$this->execution->addProjectMembers($data->project, $teamMembers);
|
||||
$this->execution->addProjectMembers($plan->project, $teamMembers);
|
||||
|
||||
$this->setTreePath($stageID);
|
||||
if($data->acl != 'open') $this->user->updateUserView($stageID, 'sprint');
|
||||
if($plan->acl != 'open') $this->user->updateUserView($stageID, 'sprint');
|
||||
|
||||
/* Record version change information. */
|
||||
$spec = new stdclass();
|
||||
$spec->project = $stageID;
|
||||
$spec->version = $data->version;
|
||||
$spec->name = $data->name;
|
||||
$spec->milestone = $data->milestone;
|
||||
$spec->begin = $data->begin;
|
||||
$spec->end = $data->end;
|
||||
$spec->version = $plan->version;
|
||||
$spec->name = $plan->name;
|
||||
$spec->milestone = $plan->milestone;
|
||||
$spec->begin = $plan->begin;
|
||||
$spec->end = $plan->end;
|
||||
$this->dao->insert(TABLE_PROJECTSPEC)->data($spec)->exec();
|
||||
|
||||
if($project->hasProduct)
|
||||
if($project->hasProduct and !empty($linkProducts))
|
||||
{
|
||||
$this->action->create('execution', $stageID, 'opened', '', join(',', $_POST['products']));
|
||||
$this->action->create('execution', $stageID, 'opened', '', implode(',', $linkProducts));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -73,6 +73,54 @@ class programplanZen extends programplan
|
||||
$this->view->isTopStage = $this->programplan->checkTopStage($plan->id);
|
||||
$this->view->isLeafStage = $this->programplan->checkLeafStage($plan->id);
|
||||
$this->view->PMUsers = $this->loadModel('user')->getPairs('noclosed|nodeleted|pmfirst', $plan->PM);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理请求数据
|
||||
* Processing request data.
|
||||
*
|
||||
* @param object $formData
|
||||
* @param string $owner
|
||||
* @param string $module
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function beforeAjaxCustom(object $formData, string $owner, string $module): object
|
||||
{
|
||||
$data = $formData->get();
|
||||
|
||||
$zooming = empty($data->zooming) ? '' : $data->zooming;
|
||||
$stageCustom = empty($data->stageCustom) ? '' : implode(',', $data->stageCustom);
|
||||
$ganttFields = empty($data->ganttFields) ? '' : implode(',', $data->ganttFields);
|
||||
|
||||
$this->setting->setItem("$owner.$module.browse.stageCustom", $stageCustom);
|
||||
$this->setting->setItem("$owner.$module.ganttCustom.ganttFields", $ganttFields);
|
||||
$this->setting->setItem("$owner.$module.ganttCustom.zooming", $zooming);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成自定义设置视图。
|
||||
* Build custom setting view form data.
|
||||
*
|
||||
* @param string $owner
|
||||
* @param string $module
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function buildAjaxCustomView(string $owner, string $module, array $customFields)
|
||||
{
|
||||
$stageCustom = $this->setting->getItem("owner=$owner&module=$module§ion=browse&key=stageCustom");
|
||||
$ganttFields = $this->setting->getItem("owner=$owner&module=$module§ion=ganttCustom&key=ganttFields");
|
||||
$zooming = $this->setting->getItem("owner=$owner&module=$module§ion=ganttCustom&key=zooming");
|
||||
|
||||
$this->view->zooming = $zooming;
|
||||
$this->view->customFields = $customFields;
|
||||
$this->view->showFields = $this->config->programplan->ganttCustom->ganttFields;
|
||||
$this->view->ganttFields = $ganttFields;
|
||||
$this->view->stageCustom = $stageCustom;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-16
@@ -123,7 +123,7 @@ class todoModel extends model
|
||||
{
|
||||
$oldTodo = $oldTodos[$todoID];
|
||||
if(in_array($todo->type, $this->config->todo->moduleList)) $oldTodo->name = '';
|
||||
$this->updateTodoDataByID($todoID, $todo);
|
||||
$this->todoTao->updateRow($todoID, $todo);
|
||||
|
||||
if($oldTodo->status != 'done' and $todo->status == 'done') $this->loadModel('action')->create('todo', $todoID, 'finished', '', 'done');
|
||||
|
||||
@@ -538,7 +538,7 @@ class todoModel extends model
|
||||
*/
|
||||
public function getTodosByIdList(array $todoIdList): array
|
||||
{
|
||||
return $this->todoTao->fetchRows($todoIdList);
|
||||
return $this->dao->select('*')->from(TABLE_TODO)->where('id')->in(array_values($todoIdList))->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -553,20 +553,6 @@ class todoModel extends model
|
||||
return $this->dao->select('*')->from(TABLE_TODO)->where('cycle')->eq(1)->andWhere('deleted')->eq(0)->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据待办ID更新待办数据。
|
||||
* Update todo data by id.
|
||||
*
|
||||
* @param int $todoID
|
||||
* @param object $todo
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function updateTodoDataByID(int $todoID, object $todo): bool
|
||||
{
|
||||
return $this->todoTao->updateRow($todoID, $todo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据待办类型获取优先级。
|
||||
* Get pri by todo type.
|
||||
|
||||
@@ -11,13 +11,13 @@ title=测试 todoModel->create();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 执行todoTest模块的createTest方法,参数是$todoWithoutName, $formData @0
|
||||
- 执行todoTest模块的createTest方法,参数是$todoWithoutName @0
|
||||
|
||||
- 执行todoTest模块的createTest方法,参数是$todoInvalidEnd, $formData @0
|
||||
- 执行todoTest模块的createTest方法,参数是$todoInvalidObjectID @0
|
||||
|
||||
- 执行todoTest模块的createTest方法,参数是$todo, $formData @2
|
||||
- 执行todoTest模块的createTest方法,参数是$todo @6
|
||||
|
||||
- 执行todoTest模块的createTest方法,参数是$todoWithCycle, $formData @3
|
||||
- 执行todoTest模块的createTest方法,参数是$todoWithCycle @7
|
||||
|
||||
*/
|
||||
|
||||
@@ -27,10 +27,6 @@ $tester->loadModel('todo');
|
||||
zdTable('todo')->config('create')->gen(5);
|
||||
$today = date('Y-m-d');
|
||||
|
||||
$formData = new stdClass;
|
||||
$formData->rawdata = new stdclass;
|
||||
$formData->rawdata->uid = '';
|
||||
|
||||
$todo = new stdclass;
|
||||
$todo->name = 'TODO Create Test';
|
||||
$todo->account = 'admin';
|
||||
@@ -45,19 +41,20 @@ $todo->assignedDate = $today;
|
||||
$todoWithoutName = clone $todo;
|
||||
$todoWithoutName->name = '';
|
||||
|
||||
$todoInvalidEnd = clone $todo;
|
||||
$todoInvalidEnd->name = 'todoInvalidDate';
|
||||
$todoInvalidEnd->begin = '1000';
|
||||
$todoInvalidEnd->end = '0800';
|
||||
$todoInvalidObjectID = clone $todo;
|
||||
$randModuleKey = array_rand($tester->config->todo->moduleList, 1);
|
||||
$todoInvalidObjectID->name = 'todoInvalidObjectID';
|
||||
$todoInvalidObjectID->type = $tester->config->todo->moduleList[$randModuleKey];
|
||||
$todoInvalidObjectID->objectID = 0;
|
||||
|
||||
$todoWithCycle = clone $todo;
|
||||
$todoWithCycle->type = 'cycle';
|
||||
$todoWithCycle->cycle = 1;
|
||||
$todoWithCycle->config = array('day' => 1, 'specify' => array('month' => 0, 'day' => 1), 'type' => 'day', 'beforeDays' => 1, 'end' => '');
|
||||
$todoWithCycle->config = json_encode(array('day' => 1, 'specify' => array('month' => 0, 'day' => 1), 'type' => 'day', 'beforeDays' => 1, 'end' => ''));
|
||||
$todoWithCycle->objectID = 0;
|
||||
|
||||
$todoTest = new todoTest();
|
||||
r($todoTest->createTest($todoWithoutName, $formData)) && p() && e('0');
|
||||
r($todoTest->createTest($todoInvalidEnd, $formData)) && p() && e('0');
|
||||
r($todoTest->createTest($todo, $formData)) && p() && e('6');
|
||||
r($todoTest->createTest($todoWithCycle, $formData)) && p() && e('7');
|
||||
r($todoTest->createTest($todoWithoutName)) && p() && e('0');
|
||||
r($todoTest->createTest($todoInvalidObjectID)) && p() && e('0');
|
||||
r($todoTest->createTest($todo)) && p() && e('6');
|
||||
r($todoTest->createTest($todoWithCycle)) && p() && e('7');
|
||||
|
||||
@@ -13,13 +13,12 @@ class todoTest
|
||||
* Test create a todo.
|
||||
*
|
||||
* @param object $todoData
|
||||
* @param object $formData
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function createTest($todoData, $formData)
|
||||
public function createTest($todoData)
|
||||
{
|
||||
$objectID = $this->objectModel->create($todoData, $formData);
|
||||
$objectID = $this->objectModel->create($todoData);
|
||||
|
||||
return $objectID ?: 0;
|
||||
}
|
||||
@@ -86,7 +85,7 @@ class todoTest
|
||||
*/
|
||||
public function batchUpdateTest(array $todos, int $todoID)
|
||||
{
|
||||
$todoIDList = array($todoID => $todoID);
|
||||
$todoIDList = array($todoID);
|
||||
$changes = $this->objectModel->batchUpdate($todos, $todoIDList);
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
|
||||
Reference in New Issue
Block a user