diff --git a/module/project/config/form.php b/module/project/config/form.php
index 22433ff158..c717afed7d 100644
--- a/module/project/config/form.php
+++ b/module/project/config/form.php
@@ -1,7 +1,22 @@
project->form = new stdclass();
-$config->project->form->start = array();
-$config->project->form->suspend = array();
+$config->project->form->create = array();
+$config->project->form->start = array();
+
+$config->project->form->create['parent'] = array('type' => 'int', 'required' => false, 'default' => '');
+$config->project->form->create['name'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
+$config->project->form->create['code'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
+$config->project->form->create['multiple'] = array('type' => 'string', 'required' => false, 'default' => '');
+$config->project->form->create['hasProduct'] = array('type' => 'string', 'required' => false, 'default' => '');
+$config->project->form->create['PM'] = array('type' => 'string', 'required' => false, 'default' => '');
+$config->project->form->create['budget'] = array('type' => 'string', 'required' => false, 'default' => '');
+$config->project->form->create['budgetUnit'] = array('type' => 'string', 'required' => false, 'default' => 'CNY');
+$config->project->form->create['begin'] = array('type' => 'date', 'required' => true);
+$config->project->form->create['end'] = array('type' => 'date', 'required' => true);
+$config->project->form->create['desc'] = array('type' => 'string', 'required' => false, 'default' => '');
+$config->project->form->create['acl'] = array('type' => 'string', 'required' => false, 'default' => '');
+$config->project->form->create['whitelist'] = array('type' => 'array', 'required' => false, 'default' => '');
+$config->project->form->create['auth'] = array('type' => 'array', 'required' => false, 'default' => '');
+$config->project->form->create['model'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->project->form->start['realBegan'] = array('type' => 'date', 'required' => true, 'filter' => 'trim');
-$config->project->form->suspend['realBegan'] = array('type' => 'date', 'required' => true, 'filter' => 'trim');
diff --git a/module/project/control.php b/module/project/control.php
index 470ef54cd2..7b73d21a64 100755
--- a/module/project/control.php
+++ b/module/project/control.php
@@ -277,7 +277,7 @@ class project extends control
if($objectType == 'program')
{
- $minChildBegin = $this->dao->select('`begin` as minBegin')->from(TABLE_PROGRAM)->where('id')->ne($objectID)->andWhere('deleted')->eq(0)->andWhere('path')->like("%,{$objectID},%")->orderBy('begin_asc')->fetch('tminBegin');
+ $minChildBegin = $this->dao->select('`begin` as minBegin')->from(TABLE_PROGRAM)->where('id')->ne($objectID)->andWhere('deleted')->eq(0)->andWhere('path')->like("%,{$objectID},%")->orderBy('begin_asc')->fetch('minBegin');
$maxChildEnd = $this->dao->select('`end` as maxEnd')->from(TABLE_PROGRAM)->where('id')->ne($objectID)->andWhere('deleted')->eq(0)->andWhere('path')->like("%,{$objectID},%")->andWhere('end')->ne('0000-00-00')->orderBy('end_desc')->fetch('maxEnd');
}
}
@@ -487,48 +487,25 @@ class project extends control
$this->loadModel('execution');
$this->loadModel('product');
+ $this->session->set('projectModel', $model);
+
if($model == 'kanban') unset($this->lang->project->authList['reset']);
if($_POST)
{
- $projectID = $this->project->create();
+ $postData = form::data($this->config->project->form->create);
+
+ $project = $this->projectZen->prepareCreateExtras($postData);
+
+ $projectID = $this->project->create($project, $postData);
+ $projectID = (int)$projectID;
+
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->loadModel('action')->create('project', $projectID, 'opened');
/* Link the plan stories. */
- if(!empty($_POST['hasProduct']) && !empty($_POST['plans']))
- {
- $planIdList = array();
- foreach($_POST['plans'] as $plans)
- {
- foreach($plans as $planID)
- {
- $planIdList[$planID] = $planID;
- }
- }
-
- $planStoryGroup = $this->loadModel('story')->getStoriesByPlanIdList($planIdList);
- foreach($planIdList as $planID)
- {
- $planStories = $planProducts = array();
- $planStory = isset($planStoryGroup[$planID]) ? $planStoryGroup[$planID] : array();
- if(!empty($planStory))
- {
- foreach($planStory as $id => $story)
- {
- if($story->status == 'draft' or $story->status == 'reviewing')
- {
- unset($planStory[$id]);
- continue;
- }
- $planProducts[$story->id] = $story->product;
- }
- $planStories = array_keys($planStory);
- $this->execution->linkStory($projectID, $planStories, $planProducts);
- }
- }
- }
+ if(!empty($_POST['hasProduct']) && !empty($_POST['plans'])) $this->projectZen->linkPlanStories($postData);
$message = $this->executeHooks($projectID);
if($message) $this->lang->saveSuccess = $message;
@@ -551,7 +528,7 @@ class project extends control
$parent = isset($_POST['parent']) ? $_POST['parent'] : 0;
$systemMode = $this->loadModel('setting')->getItem('owner=system&module=common§ion=global&key=mode');
if(!empty($systemMode) and $systemMode == 'light') $parent = 0;
- return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('project', 'browse', "programID=$parent&browseType=all", '', '', $projectID)));
+ return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('project', 'browse', "programID=$parent&browseType=all", '', false, $projectID)));
}
}
diff --git a/module/project/lang/de.php b/module/project/lang/de.php
index b0c53041bc..0ff816e5d1 100644
--- a/module/project/lang/de.php
+++ b/module/project/lang/de.php
@@ -64,8 +64,6 @@ $lang->project->daysGreaterProject = "Days cannot be greater than days of {$lan
$lang->project->errorHours = 'Hours/Day cannot be greater than『24』';
$lang->project->workdaysExceed = 'No more than『%s』working days';
$lang->project->teamMembersCount = ', there are %s team members.';
-$lang->project->budgetNumber = '『Budget』must be numbers.';
-$lang->project->budgetGe0 = '『Budget』must be greater than or equal to 0.';
$lang->project->allProjects = "All {$lang->projectCommon}s";
$lang->project->ignore = 'Ignore';
$lang->project->disableExecution = "{$lang->projectCommon} of disable {$lang->executionCommon}";
@@ -211,8 +209,6 @@ $lang->project->noProgram = "Independent {$lang->projectCommon}s";
$lang->project->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
-$lang->project->productNotEmpty = "Please link {$lang->productCommon}s or create {$lang->productCommon}s.";
-$lang->project->existProductName = "{$lang->productCommon} name already exists.";
$lang->project->changeProgram = "%s > Change {$lang->projectCommon}";
$lang->project->changeProgramTip = "Once the program is edited, the {$lang->productCommon} that is linked to this program will be changed. Do you want to edit it?";
$lang->project->linkedProjectsTip = "Linked {$lang->projectCommon}s are as follows";
@@ -242,6 +238,13 @@ $lang->project->tip->actived = 'The project has been activated. Re-activated
$lang->project->tip->group = "It's a Kanban project. Editing privilege group is not available.";
$lang->project->tip->whitelist = "It's a public project with open permissions. No need to edit whitelists.";
+$lang->project->error = new stdclass();
+$lang->project->error->existProductName = "{$lang->productCommon} name already exists.";
+$lang->project->error->budgetGe0 = '『Budget』must be greater than or equal to 0.';
+$lang->project->error->budgetNumber = '『Budget』must be numbers.';
+$lang->project->error->productNotEmpty = "Please link {$lang->productCommon}s or create {$lang->productCommon}s.";
+$lang->project->error->emptyBranch = 'Branch can not be empty!';
+
$lang->project->hundredMillion = 'Hundred Million';
$lang->project->unitList['CNY'] = 'RMB';
@@ -385,7 +388,6 @@ $lang->project->agileplus = 'Agile +';
$lang->project->waterfallplus = 'Waterfall +';
$lang->project->cannotCreateChild = 'It is not empty, so you cannot add a child. You can add a parent for it, and then create a child.';
$lang->project->emptyPM = 'No manager';
-$lang->project->emptyBranch = 'Branch can not be empty!';
$lang->project->cannotChangeToCat = "It is not empty, so you cannot change it to a parent.";
$lang->project->cannotCancelCat = "It has child {$lang->projectCommon}s, so you cannot unmark the parent.";
$lang->project->parentBeginEnd = "Parent begin&end date: %s ~ %s";
diff --git a/module/project/lang/en.php b/module/project/lang/en.php
index f74b059176..d411564ca9 100644
--- a/module/project/lang/en.php
+++ b/module/project/lang/en.php
@@ -64,8 +64,6 @@ $lang->project->daysGreaterProject = "Days cannot be greater than days of {$lan
$lang->project->errorHours = 'Hours/Day cannot be greater than『24』';
$lang->project->workdaysExceed = 'No more than『%s』working days';
$lang->project->teamMembersCount = ', there are %s team members.';
-$lang->project->budgetNumber = '『Budget』must be numbers.';
-$lang->project->budgetGe0 = '『Budget』must be greater than or equal to 0.';
$lang->project->allProjects = "All {$lang->projectCommon}s";
$lang->project->ignore = 'Ignore';
$lang->project->disableExecution = "{$lang->projectCommon} of disable {$lang->executionCommon}";
@@ -213,8 +211,6 @@ $lang->project->noProgram = "Independent {$lang->projectCommon}s";
$lang->project->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
-$lang->project->productNotEmpty = "Please link {$lang->productCommon}s or create {$lang->productCommon}s.";
-$lang->project->existProductName = "{$lang->productCommon} name already exists.";
$lang->project->changeProgram = "%s > Change {$lang->projectCommon}";
$lang->project->changeProgramTip = "Once the program is edited, the {$lang->productCommon} that is linked to this program will be changed. Do you want to edit it?";
$lang->project->linkedProjectsTip = "Linked {$lang->projectCommon}s are as follows";
@@ -243,6 +239,13 @@ $lang->project->tip->actived = 'The project has been activated. Re-activated
$lang->project->tip->group = "It's a Kanban project. Editing privilege group is not available.";
$lang->project->tip->whitelist = "It's a public project with open permissions. No need to edit whitelists.";
+$lang->project->error = new stdclass();
+$lang->project->error->existProductName = "{$lang->productCommon} name already exists.";
+$lang->project->error->budgetGe0 = '『Budget』must be greater than or equal to 0.';
+$lang->project->error->budgetNumber = '『Budget』must be numbers.';
+$lang->project->error->productNotEmpty = "Please link {$lang->productCommon}s or create {$lang->productCommon}s.";
+$lang->project->error->emptyBranch = 'Branch can not be empty!';
+
$lang->project->tenThousand = 'Ten Thousand';
$lang->project->hundredMillion = 'Hundred Million';
@@ -387,7 +390,6 @@ $lang->project->agileplus = 'Agile +';
$lang->project->waterfallplus = 'Waterfall +';
$lang->project->cannotCreateChild = 'It is not empty, so you cannot add a child. You can add a parent for it, and then create a child.';
$lang->project->emptyPM = 'No manager';
-$lang->project->emptyBranch = 'Branch can not be empty!';
$lang->project->cannotChangeToCat = "It is not empty, so you cannot change it to a parent.";
$lang->project->cannotCancelCat = "It has child {$lang->projectCommon}s, so you cannot unmark the parent.";
$lang->project->parentBeginEnd = "Parent begin&end date: %s ~ %s";
diff --git a/module/project/lang/fr.php b/module/project/lang/fr.php
index a569842be7..26d905b025 100644
--- a/module/project/lang/fr.php
+++ b/module/project/lang/fr.php
@@ -64,8 +64,6 @@ $lang->project->daysGreaterProject = "Days cannot be greater than days of {$lan
$lang->project->errorHours = 'Hours/Day cannot be greater than『24』';
$lang->project->workdaysExceed = 'No more than『%s』working days';
$lang->project->teamMembersCount = ', there are %s team members.';
-$lang->project->budgetNumber = '『Budget』must be numbers.';
-$lang->project->budgetGe0 = '『Budget』must be greater than or equal to 0.';
$lang->project->allProjects = "All {$lang->projectCommon}s";
$lang->project->ignore = 'Ignore';
$lang->project->disableExecution = "{$lang->projectCommon} of disable {$lang->executionCommon}";
@@ -212,8 +210,6 @@ $lang->project->noProgram = "Independent {$lang->projectCommon}s";
$lang->project->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
-$lang->project->productNotEmpty = "Please link {$lang->productCommon}s or create {$lang->productCommon}s.";
-$lang->project->existProductName = "{$lang->productCommon} name already exists.";
$lang->project->changeProgram = "%s > Change {$lang->projectCommon}";
$lang->project->changeProgramTip = "Once the program is edited, the {$lang->productCommon} that is linked to this program will be changed. Do you want to edit it?";
$lang->project->linkedProjectsTip = "Linked {$lang->projectCommon}s are as follows";
@@ -243,6 +239,13 @@ $lang->project->tip->actived = 'The project has been activated. Re-activated
$lang->project->tip->group = "It's a Kanban project. Editing privilege group is not available.";
$lang->project->tip->whitelist = "It's a public project with open permissions. No need to edit whitelists.";
+$lang->project->error = new stdclass();
+$lang->project->error->existProductName = "{$lang->productCommon} name already exists.";
+$lang->project->error->budgetGe0 = '『Budget』must be greater than or equal to 0.';
+$lang->project->error->budgetNumber = '『Budget』must be numbers.';
+$lang->project->error->productNotEmpty = "Please link {$lang->productCommon}s or create {$lang->productCommon}s.";
+$lang->project->error->emptyBranch = 'Branch can not be empty!';
+
$lang->project->hundredMillion = 'Hundred Million';
$lang->project->unitList['CNY'] = 'RMB';
@@ -385,7 +388,6 @@ $lang->project->agileplus = 'Agile +';
$lang->project->waterfallplus = 'Waterfall +';
$lang->project->cannotCreateChild = 'It is not empty, so you cannot add a child. You can add a parent for it, and then create a child.';
$lang->project->emptyPM = 'No manager';
-$lang->project->emptyBranch = 'Branch can not be empty!';
$lang->project->cannotChangeToCat = "It is not empty, so you cannot change it to a parent.";
$lang->project->cannotCancelCat = "It has child {$lang->projectCommon}s, so you cannot unmark the parent.";
$lang->project->parentBeginEnd = "Parent begin&end date: %s ~ %s";
diff --git a/module/project/lang/zh-cn.php b/module/project/lang/zh-cn.php
index 55d5612ff4..fcc469dbd2 100644
--- a/module/project/lang/zh-cn.php
+++ b/module/project/lang/zh-cn.php
@@ -64,8 +64,6 @@ $lang->project->daysGreaterProject = "可用工日不能大于{$lang->projectCo
$lang->project->errorHours = '可用工时/天不能大于『24』';
$lang->project->workdaysExceed = '可用工作日不能超过『%s』天';
$lang->project->teamMembersCount = ',团队成员共%s人。';
-$lang->project->budgetNumber = '『预算』金额必须为数字。';
-$lang->project->budgetGe0 = '『预算』金额必须大于等于0。';
$lang->project->allProjects = "所有{$lang->projectCommon}";
$lang->project->ignore = '忽略';
$lang->project->disableExecution = "不启用{$lang->executionCommon}的{$lang->projectCommon}";
@@ -212,8 +210,6 @@ $lang->project->noProgram = "无项目集归属{$lang->projectCommon}";
$lang->project->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
-$lang->project->productNotEmpty = "请关联{$lang->productCommon}或创建{$lang->productCommon}。";
-$lang->project->existProductName = "{$lang->productCommon}名称已存在。";
$lang->project->changeProgram = '%s > 修改项目集';
$lang->project->changeProgramTip = "修改项目集后,该{$lang->projectCommon}关联{$lang->productCommon}的项目集也会被修改,请确认是否修改。";
$lang->project->linkedProjectsTip = "关联的{$lang->projectCommon}如下";
@@ -234,6 +230,13 @@ $lang->project->allSummary = "本页共 %s 个{$lan
$lang->project->checkedSummary = "选中 %total% 个{$lang->projectCommon}。";
$lang->project->checkedAllSummary = "选中 %total% 个{$lang->projectCommon},未开始 %wait%,进行中 %doing%,已挂起 %suspended%,已关闭 %closed% 。";
+$lang->project->error = new stdclass();
+$lang->project->error->existProductName = "{$lang->productCommon}名称已存在。";
+$lang->project->error->budgetGe0 = '『预算』金额必须大于等于0。';
+$lang->project->error->budgetNumber = '『预算』金额必须为数字。';
+$lang->project->error->productNotEmpty = "请关联{$lang->productCommon}或创建{$lang->productCommon}。";
+$lang->project->error->emptyBranch = '分支不能为空!';
+
$lang->project->tip = new stdclass();
$lang->project->tip->closed = '该项目已是关闭状态,无须关闭。';
$lang->project->tip->notSuspend = '该项目已关闭,不可进行挂起操作。';
@@ -386,7 +389,6 @@ $lang->project->agileplus = '融合敏捷';
$lang->project->waterfallplus = '融合瀑布';
$lang->project->cannotCreateChild = "该{$lang->projectCommon}已经有实际的内容,无法直接添加子{$lang->projectCommon}。您可以为当前{$lang->projectCommon}创建一个父{$lang->projectCommon},然后在新的父{$lang->projectCommon}下面添加子{$lang->projectCommon}。";
$lang->project->emptyPM = '暂无';
-$lang->project->emptyBranch = '分支不能为空!';
$lang->project->cannotChangeToCat = "该{$lang->projectCommon}已经有实际的内容,无法修改为父{$lang->projectCommon}";
$lang->project->cannotCancelCat = "该{$lang->projectCommon}下已经有子{$lang->projectCommon},无法取消父{$lang->projectCommon}标记";
$lang->project->parentBeginEnd = "父{$lang->projectCommon}起止时间:%s ~ %s";
diff --git a/module/project/model.php b/module/project/model.php
index 888a1454ef..e2dd67d668 100644
--- a/module/project/model.php
+++ b/module/project/model.php
@@ -1,4 +1,5 @@
callFunc('name', 'trim')
- ->setDefault('status', 'wait')
- ->setIF($this->post->delta == 999, 'end', LONG_TIME)
- ->setIF($this->post->delta == 999, 'days', 0)
- ->setIF($this->post->acl == 'open', 'whitelist', '')
- ->setIF(!isset($_POST['whitelist']), 'whitelist', '')
- ->setIF(!isset($_POST['multiple']), 'multiple', '1')
- ->setDefault('openedBy', $this->app->user->account)
- ->setDefault('openedDate', helper::now())
- ->setDefault('team', $this->post->name)
- ->setDefault('lastEditedBy', $this->app->user->account)
- ->setDefault('lastEditedDate', helper::now())
- ->setDefault('days', '0')
- ->add('type', 'project')
- ->join('whitelist', ',')
- ->stripTags($this->config->project->editor->create['id'], $this->config->allowedTags)
- ->remove('uid,products,branch,plans,delta,newProduct,productName,future,contactListMenu,teamMembers')
- ->get();
- if(!isset($this->config->setCode) or $this->config->setCode == 0) unset($project->code);
-
- /* Lean mode relation defaultProgram. */
- if($this->config->systemMode == 'light') $project->parent = $this->config->global->defaultProgram;
-
- $linkedProductsCount = 0;
- if($project->hasProduct && isset($_POST['products']))
- {
- foreach($_POST['products'] as $product)
- {
- if(!empty($product)) $linkedProductsCount++;
- }
- }
-
- if($_POST['products'])
- {
- $topProgramID = $this->loadModel('program')->getTopByID($project->parent);
- $multipleProducts = $this->loadModel('product')->getMultiBranchPairs($topProgramID);
- foreach($_POST['products'] as $index => $productID)
- {
- if(isset($multipleProducts[$productID]) and empty($_POST['branch'][$index]))
- {
- dao::$errors[] = $this->lang->project->emptyBranch;
- return false;
- }
- }
- }
-
- $program = new stdClass();
- if($project->parent)
- {
- $program = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($project->parent)->fetch();
-
- /* Judge products not empty. */
- if($project->hasProduct && empty($linkedProductsCount) and !isset($_POST['newProduct']))
- {
- dao::$errors['products0'] = $this->lang->project->productNotEmpty;
- return false;
- }
- }
-
- /* Judge workdays is legitimate. */
- $workdays = helper::diffDate($project->end, $project->begin) + 1;
- if(isset($project->days) and $project->days > $workdays)
- {
- dao::$errors['days'] = sprintf($this->lang->project->workdaysExceed, $workdays);
- return false;
- }
-
- if(!empty($project->budget))
- {
- if(!is_numeric($project->budget))
- {
- dao::$errors['budget'] = sprintf($this->lang->project->budgetNumber);
- return false;
- }
- else if(is_numeric($project->budget) and ($project->budget < 0))
- {
- dao::$errors['budget'] = sprintf($this->lang->project->budgetGe0);
- return false;
- }
- else
- {
- $project->budget = round((float)$this->post->budget, 2);
- }
- }
-
- /* When select create new product, product name cannot be empty and duplicate. */
- if($project->hasProduct && isset($_POST['newProduct']))
- {
- if(empty($_POST['productName']))
- {
- $this->app->loadLang('product');
- dao::$errors['productName'] = sprintf($this->lang->error->notempty, $this->lang->product->name);
- return false;
- }
- else
- {
- $programID = isset($project->parent) ? $project->parent : 0;
- $existProductName = $this->dao->select('name')->from(TABLE_PRODUCT)->where('name')->eq($_POST['productName'])->andWhere('program')->eq($programID)->fetch('name');
- if(!empty($existProductName))
- {
- dao::$errors['productName'] = $this->lang->project->existProductName;
- return false;
- }
- }
- }
-
$requiredFields = $this->config->project->create->requiredFields;
- if($this->post->delta == 999) $requiredFields = trim(str_replace(',end,', ',', ",{$requiredFields},"), ',');
+ if($postData->rawdata->delta == 999) $requiredFields = trim(str_replace(',end,', ',', ",{$requiredFields},"), ',');
$this->lang->error->unique = $this->lang->error->repeat;
- $project = $this->loadModel('file')->processImgURL($project, $this->config->project->editor->create['id'], $this->post->uid);
+ $project = $this->loadModel('file')->processImgURL($project, $this->config->project->editor->create['id'], $postData->rawdata->uid);
$this->dao->insert(TABLE_PROJECT)->data($project)
->autoCheck()
->batchcheck($requiredFields, 'notempty')
@@ -1460,9 +1354,9 @@ class projectModel extends model
{
/* If parent not empty, link products or create products. */
$product = new stdclass();
- $product->name = $project->hasProduct && $this->post->productName ? $this->post->productName : $project->name;
+ $product->name = $project->hasProduct && $postData->rawdata->productName ? $postData->rawdata->productName : $project->name;
$product->shadow = zget($project, 'vision', 'rnd') == 'rnd' ? (int)empty($project->hasProduct) : 1;
- $product->bind = $this->post->parent ? 0 : 1;
+ $product->bind = $postData->rawdata->parent ? 0 : 1;
$product->program = $project->parent ? current(array_filter(explode(',', $program->path))) : 0;
$product->acl = $project->acl == 'open' ? 'open' : 'private';
$product->PO = $project->PM;
@@ -1510,7 +1404,7 @@ class projectModel extends model
/* Save order. */
$this->dao->update(TABLE_PROJECT)->set('`order`')->eq($projectID * 5)->where('id')->eq($projectID)->exec();
- $this->file->updateObjectID($this->post->uid, $projectID, 'project');
+ $this->file->updateObjectID($postData->rawdata->uid, $projectID, 'project');
$this->loadModel('program')->setTreePath($projectID);
/* Add project admin. */
diff --git a/module/project/test/model/create.php b/module/project/test/model/create.php
index 35e2735dc3..92c2226f82 100755
--- a/module/project/test/model/create.php
+++ b/module/project/test/model/create.php
@@ -4,55 +4,77 @@ include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/project.class.php';
su('admin');
+$program = zdTable('project');
+$program->id->range('1');
+$program->name->range('项目集一');
+$program->model->range('program');
+$program->code->range('项目集代号');
+$program->desc->range('测试项目集');
+$program->gen(1);
+
/**
title=测试 projectModel->create();
+timeout=0
cid=1
-pid=1
-创建新项目 >> 测试新增项目一
-项目名称为空时 >> 『项目名称』不能为空。
-项目的完成时间为空 >> 『计划完成』不能为空。
-项目的计划完成时间大于计划开始时间 >> 『计划完成』应当大于『2022-02-07』。
-项目的开始时间为空 >> 『计划开始』不能为空。
+- 执行projectClass模块的cr方法,参数是$normalProject, $postData,属性name @测试新增项目一
+- 执行projectClass模块的cr方法,参数是$emptyNameProject, $postData,属性name @『项目名称』不能为空。
+
+- 执行projectClass模块的cr方法,参数是$emptyEndProject, $postData,属性end @『计划完成』不能为空。
+
+- 执行projectClass模块的cr方法,参数是$beginGtEndProject, $postData,属性end @『计划完成』应当大于『2022-02-07』。
+
+- 执行projectClass模块的cr方法,参数是$emptyBeginProject, $postData,属性begin @『计划开始』不能为空。
+
+
*/
global $tester;
-$tester->app->loadConfig('execution');
-$project = new Project();
+$projectClass = new project();
-$data = array(
- 'parent' => 1,
- 'name' => '测试新增项目一',
- 'budget' => '',
- 'budgetUnit' => 'CNY',
- 'begin' => '2022-02-07',
- 'end' => '2022-03-01',
- 'desc' => '测试项目描述',
- 'acl' => 'private',
- 'whitelist' => '',
- 'PM' => '',
- 'products' => array(1)
-);
+$project = new stdclass();
+$project->parent = 0;
+$project->name = '测试新增项目一';
+$project->budget = '';
+$project->budgetUnit = 'CNY';
+$project->begin = '2022-02-07';
+$project->end = '2023-01-01';
+$project->desc = '测试项目描述';
+$project->acl = 'private';
+$project->whitelist = 'user1,user2,user3';
+$project->PM = 'admin';
+$project->type = 'project';
+$project->model = 'scrum';
+$project->multiple = 1;
+$project->hasProduct = 1;
-$normalProject = $data;
+$postData = new stdclass();
+$postData->rowdata = clone $project;
+$postData->rowdata->uid = '64dda2xc';
+$postData->rowdata->delta = 0;
+$postData->rowdata->products = array(1);
-$emptyNameProject = $data;
-$emptyNameProject['name'] = '';
+$normalProject = clone $project;
-$emptyBeginProject = $data;
-$emptyBeginProject['begin'] = '';
+$emptyNameProject = clone $project;
+$emptyNameProject->name = '';
-$emptyEndProject = $data;
-$emptyEndProject['end'] = '';
+$emptyBeginProject = clone $project;
+$emptyBeginProject->name = '测试新增项目二';
+$emptyBeginProject->begin = '';
-$beginGtEndProject = $data;
-$beginGtEndProject['end'] = '2022-01-10';
+$emptyEndProject = clone $project;
+$emptyEndProject->end = '';
+$emptyEndProject->name = '测试新增项目三';
-r($project->create($normalProject)) && p('name') && e('测试新增项目一'); // 创建新项目
-r($project->create($emptyNameProject)) && p('message[name]:0') && e('『项目名称』不能为空。'); // 项目名称为空时
-r($project->create($emptyEndProject)) && p('message[end]:0') && e('『计划完成』不能为空。'); // 项目的完成时间为空
-r($project->create($beginGtEndProject)) && p('message[end]:0') && e('『计划完成』应当大于『2022-02-07』。'); // 项目的计划完成时间大于计划开始时间
-r($project->create($emptyBeginProject)) && p('message[begin]:0') && e('『计划开始』不能为空。'); // 项目的开始时间为空
+$beginGtEndProject = clone $project;
+$beginGtEndProject->end = '2021-01-10';
+$beginGtEndProject->name = '测试新增项目四';
+r($projectClass->create($normalProject, $postData)) && p('name') && e('测试新增项目一');
+r($projectClass->create($emptyNameProject, $postData)) && p('message[name]:0') && e('『项目名称』不能为空。');
+r($projectClass->create($emptyEndProject, $postData)) && p('message[end]:0') && e('『计划完成』不能为空。');
+r($projectClass->create($beginGtEndProject, $postData)) && p('message[end]:0') && e('『计划完成』应当大于『2022-02-07』。');
+r($projectClass->create($emptyBeginProject, $postData)) && p('message[begin]:0') && e('『计划开始』不能为空。');
\ No newline at end of file
diff --git a/module/project/test/model/start.php b/module/project/test/model/start.php
index fe29a3e38f..0acb912f08 100755
--- a/module/project/test/model/start.php
+++ b/module/project/test/model/start.php
@@ -12,10 +12,10 @@ title=测试 projectModel->start();
timeout=0
cid=1
-- 执行project模块的start方法,参数是11, $data- ,属性0 @status
- @status
-- 执行project模块的start方法,参数是12, $data- ,属性0 @doing
- @doing
+- 执行project模块的start方法,参数是11, $data,属性0 @status
+
+- 执行project模块的start方法,参数是12, $data,属性0 @doing
+
- 执行project模块的start方法,参数是13, $data
- 属性name @0
- 属性status @0
diff --git a/module/project/test/project.class.php b/module/project/test/project.class.php
index 8abf7d2773..11910c81d1 100644
--- a/module/project/test/project.class.php
+++ b/module/project/test/project.class.php
@@ -40,12 +40,9 @@ class Project
* @access public
* @return void
*/
- public function create($params)
+ public function create($project, $postData)
{
- $_POST = $params;
-
- $projectID = $this->project->create();
- unset($_POST);
+ $projectID = $this->project->create($project, $postData);
if(dao::isError()) return array('message' => dao::getError());
diff --git a/module/project/zen.php b/module/project/zen.php
index b8606ca076..d4fae9afbc 100644
--- a/module/project/zen.php
+++ b/module/project/zen.php
@@ -10,8 +10,148 @@ declare(strict_types=1);
*/
class projectZen extends project
{
+ /**
+ * Append extras data to post data.
+ *
+ * @param object $postData
+ * @access protected
+ * @return int|object
+ */
+ protected function prepareCreateExtras(object $postData): object
+ {
+ $rawdata = $postData->rawdata;
+ $project = $postData->setDefault('status', 'wait')
+ ->setIF($rawdata->delta == 999, 'end', LONG_TIME)
+ ->setIF($rawdata->delta == 999, 'days', 0)
+ ->setIF($rawdata->acl == 'open', 'whitelist', '')
+ ->setIF(!isset($rawdata->whitelist), 'whitelist', '')
+ ->setIF(!isset($rawdata->multiple), 'multiple', '1')
+ ->setDefault('openedBy', $this->app->user->account)
+ ->setDefault('openedDate', helper::now())
+ ->setDefault('team', $rawdata->name)
+ ->setDefault('lastEditedBy', $this->app->user->account)
+ ->setDefault('lastEditedDate', helper::now())
+ ->setDefault('days', '0')
+ ->add('type', 'project')
+ ->join('whitelist', ',')
+ ->join('auth', ',')
+ ->stripTags($this->config->project->editor->create['id'], $this->config->allowedTags)
+ ->get();
+
+ if(!isset($this->config->setCode) or $this->config->setCode == 0) unset($project->code);
+
+ /* Lean mode relation defaultProgram. */
+ if($this->config->systemMode == 'light') $project->parent = $this->config->global->defaultProgram;
+
+ if(!$this->checkProductAndBranch($rawdata, $project)) return false;
+ if(!$this->checkDaysAndBudget($rawdata, $project)) return false;
+ if(!$this->checkProductNameUnqiue($rawdata, $project)) return false;
+
+ return $project;
+ }
+
+ private function checkProductAndBranch(object $rawdata, object $project): bool
+ {
+ $linkedProductsCount = 0;
+ if($project->hasProduct && isset($rawdata->products))
+ {
+ foreach($rawdata->products as $product)
+ {
+ if(!empty($product)) $linkedProductsCount++;
+ }
+ }
+
+ if($rawdata->products)
+ {
+ $topProgramID = $this->loadModel('program')->getTopByID($project->parent);
+ $multipleProducts = $this->loadModel('product')->getMultiBranchPairs($topProgramID);
+ foreach($rawdata->products as $index => $productID)
+ {
+ if(isset($multipleProducts[$productID]) and empty($rawdata->branch[$index]))
+ {
+ dao::$errors[] = $this->lang->project->error->emptyBranch;
+ return false;
+ }
+ }
+ }
+
+ $program = new stdClass();
+ if($project->parent)
+ {
+ $program = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($project->parent)->fetch();
+
+ /* Judge products not empty. */
+ if($project->hasProduct && empty($linkedProductsCount) and !isset($rawdata->newProduct))
+ {
+ dao::$errors['products0'] = $this->lang->project->error->productNotEmpty;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private function checkDaysAndBudget(object $rawdata, object $project): bool
+ {
+ /* Judge workdays is legitimate. */
+ $workdays = helper::diffDate($project->end, $project->begin) + 1;
+ if(isset($project->days) and $project->days > $workdays)
+ {
+ dao::$errors['days'] = sprintf($this->lang->project->workdaysExceed, $workdays);
+ return false;
+ }
+
+ if(!empty($project->budget))
+ {
+ if(!is_numeric($project->budget))
+ {
+ dao::$errors['budget'] = sprintf($this->lang->project->error->budgetNumber);
+ return false;
+ }
+ else if(is_numeric($project->budget) and ($project->budget < 0))
+ {
+ dao::$errors['budget'] = sprintf($this->lang->project->error->budgetGe0);
+ return false;
+ }
+ else
+ {
+ $project->budget = round((float)$rawdata->budget, 2);
+ }
+ }
+
+ return true;
+ }
+
+ private function checkProductNameUnqiue(object $rawdata, object $project): bool
+ {
+ /* When select create new product, product name cannot be empty and duplicate. */
+ if($project->hasProduct && isset($rawdata->newProduct))
+ {
+ if(empty($rawdata->productName))
+ {
+ $this->app->loadLang('product');
+ dao::$errors['productName'] = sprintf($this->lang->error->notempty, $this->lang->product->name);
+ return false;
+ }
+ else
+ {
+ $programID = isset($project->parent) ? $project->parent : 0;
+ $existProductName = $this->dao->select('name')->from(TABLE_PRODUCT)->where('name')->eq($rawdata->productName)->andWhere('program')->eq($programID)->fetch('name');
+ if(!empty($existProductName))
+ {
+ dao::$errors['productName'] = $this->lang->project->error->existProductName;
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
/**
* Send variables to create page.
+ *
* @param string $model
* @param int $programID
* @param int $copyProjectID
@@ -19,9 +159,10 @@ class projectZen extends project
* @access protected
* @return void
*/
- protected function buildCreateForm(string $model, int $programID, int $copyProjectID, string $extra):void
+ protected function buildCreateForm(string $model, int $programID, int $copyProjectID, string $extra): void
{
$this->loadModel('product');
+ $this->loadModel('program');
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
parse_str($extra, $output);
@@ -29,20 +170,9 @@ class projectZen extends project
if($this->app->tab == 'program' and $programID) $this->loadModel('program')->setMenu($programID);
if($this->app->tab == 'product' and !empty($output['productID'])) $this->loadModel('product')->setMenu($output['productID']);
if($this->app->tab == 'doc') unset($this->lang->doc->menu->project['subMenu']);
- $this->session->set('projectModel', $model);
- if($copyProjectID)
- {
- $copyProject = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($copyProjectID)->fetch();
- $products = $this->product->getProducts($copyProjectID);
-
- if(!$copyProject->hasProduct) $shadow = 1;
- foreach($products as $product)
- {
- $branches = implode(',', $product->branches);
- $copyProject->productPlans[$product->id] = $this->loadModel('productplan')->getPairs($product->id, $branches, 'noclosed', true);
- }
- }
+ if($copyProjectID) $copyProject = $this->copyProject((int)$copyProjectID);
+ $shadow = empty($copyProject->hasProduct) ? 1 : 0;
if($this->view->globalDisableProgram) $programID = $this->config->global->defaultProgram;
$topProgramID = $this->program->getTopByID($programID);
@@ -53,10 +183,6 @@ class projectZen extends project
$this->lang->project->subAclList = $this->lang->project->kanbanSubAclList;
}
- $sprintConcept = empty($this->config->custom->sprintConcept) ?
- $this->config->executionCommonList[$this->app->getClientLang()][0] :
- $this->config->executionCommonList[$this->app->getClientLang()][1];
-
$withProgram = $this->config->systemMode == 'ALM' ? true : false;
$allProducts = array('0' => '') + $this->program->getProductPairs($programID, 'all', 'noclosed', '', $shadow, $withProgram);
$parentProgram = $this->loadModel('program')->getByID($programID);
@@ -66,13 +192,10 @@ class projectZen extends project
$this->view->model = $model;
$this->view->pmUsers = $this->loadModel('user')->getPairs('noclosed|nodeleted|pmfirst');
$this->view->users = $this->user->getPairs('noclosed|nodeleted');
- $this->view->products = $products;
$this->view->programID = $programID;
$this->view->productID = isset($output['productID']) ? $output['productID'] : 0;
$this->view->branchID = isset($output['branchID']) ? $output['branchID'] : 0;
$this->view->allProducts = $allProducts;
- $this->view->productPlans = array('0' => '') + $productPlans;
- $this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products), 'noclosed');
$this->view->multiBranchProducts = $this->product->getMultiBranchPairs($topProgramID);
$this->view->copyProjects = $this->project->getPairsByModel($model);
$this->view->copyProjectID = $copyProjectID;
@@ -85,6 +208,72 @@ class projectZen extends project
$this->display();
}
+ /**
+ * Get copy project and send variables to create page.
+ *
+ * @param int $copyProjectID
+ * @access protected
+ * @return void
+ */
+ private function getCopyProject(int $copyProjectID): object
+ {
+ $copyProject = $this->project->getByID($copyProjectID);
+ $products = $this->product->getProducts($copyProjectID);
+
+ foreach($products as $product)
+ {
+ $branches = implode(',', $product->branches);
+ $copyProject->productPlans[$product->id] = $this->loadModel('productplan')->getPairs($product->id, $branches, 'noclosed', true);
+ }
+
+ $this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products), 'noclosed');
+ $this->view->products = $products;
+ $this->view->copyProject = $copyProject;
+
+ return $copyProject;
+ }
+
+ /**
+ * Link plan's stories after create a project.
+ *
+ * @param object $postData
+ * @access protected
+ * @return void
+ */
+ protected function linkPlanStories(object $postData)
+ {
+ $planIdList = array();
+ foreach($postData->rawdata->plans as $plans)
+ {
+ foreach($plans as $planID)
+ {
+ $planIdList[$planID] = $planID;
+ }
+ }
+
+ $planStoryGroup = $this->loadModel('story')->getStoriesByPlanIdList($planIdList);
+ foreach($planIdList as $planID)
+ {
+ $planStories = $planProducts = array();
+ $planStory = isset($planStoryGroup[$planID]) ? $planStoryGroup[$planID] : array();
+ if(!empty($planStory))
+ {
+ foreach($planStory as $id => $story)
+ {
+ if($story->status == 'draft' or $story->status == 'reviewing')
+ {
+ unset($planStory[$id]);
+ continue;
+ }
+ $planProducts[$story->id] = $story->product;
+ }
+
+ $planStories = array_keys($planStory);
+ $this->loadModel('execution')->linkStory($projectID, $planStories, $planProducts);
+ }
+ }
+ }
+
/**
* Append extras data to post data.
*