| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302 |
- <?php
- /**
- * The zen file of execution module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
- * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Shujie Tian<tianshujie@easycorp.ltd>
- * @package execution
- * @link https://www.zentao.net
- */
- class executionZen extends execution
- {
- /**
- * 展示Bug列表的相关变量。
- * Show the bug list related variables.
- *
- * @param object $execution
- * @param object $project
- * @param int $productID
- * @param string $branch
- * @param array $products
- * @param string $orderBy
- * @param string $type
- * @param string $build
- * @param int $param
- * @param array $bugs
- * @param object $pager
- * @access protected
- * @return void
- */
- protected function assignBugVars($execution, $project, $productID, $branch, $products, $orderBy, $type, $param, $build, $bugs, $pager)
- {
- $this->loadModel('product');
- $this->loadModel('tree');
- $moduleID = $type == 'bymodule' ? $param : 0;
- /* Get module tree.*/
- $extra = array('projectID' => $execution->id, 'orderBy' => $orderBy, 'type' => 'byModule', 'build' => $build, 'branchID' => $branch);
- if($execution->id and empty($productID) and count($products) > 1)
- {
- $moduleTree = $this->tree->getBugTreeMenu($execution->id, $productID, 0, array('treeModel', 'createBugLink'), $extra);
- }
- elseif(!empty($products))
- {
- $productID = empty($productID) ? reset($products)->id : $productID;
- $moduleTree = $this->tree->getTreeMenu((int)$productID, 'bug', 0, array('treeModel', 'createBugLink'), $extra + array('branchID' => $branch, 'productID' => $productID), $branch);
- }
- else
- {
- $moduleTree = array();
- }
- $tree = $moduleID ? $this->tree->getByID($moduleID) : '';
- $showModule = !empty($this->config->execution->bug->showModule) ? $this->config->execution->bug->showModule : '';
- $build = !empty($build) ? $this->loadModel('build')->getById((int)$build) : null;
- /* Assign. */
- $this->view->title = $execution->name . $this->lang->hyphen . $this->lang->execution->bug;
- $this->view->project = $project;
- $this->view->orderBy = $orderBy;
- $this->view->type = $type;
- $this->view->pager = $pager;
- $this->view->bugs = $bugs;
- $this->view->summary = $this->loadModel('bug')->summary($bugs);
- $this->view->moduleTree = $moduleTree;
- $this->view->moduleID = $moduleID;
- $this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'bug', $showModule) : array();
- $this->view->buildID = $build ? $build->id : 0;
- $this->view->productID = $productID;
- $this->view->product = $this->product->getByID($productID);
- $this->view->branchID = empty($this->view->build->branch) ? $branch : $this->view->build->branch;
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
- $this->view->param = $param;
- $this->view->defaultProduct = (empty($productID) and !empty($products)) ? current(array_keys($products)) : $productID;
- $this->view->builds = $this->loadModel('build')->getBuildPairs(array($productID));
- $this->view->projectPairs = $this->loadModel('project')->getPairsByProgram();
- $this->view->switcherObjectID = $productID;
- }
- /**
- * 展示看板的相关变量。
- * Show the variables associated with the kanban.
- *
- * @param int $executionID
- * @access protected
- * @return void
- */
- protected function assignKanbanVars($executionID)
- {
- /* Get user list. */
- $userList = array();
- $users = $this->loadModel('user')->getPairs('noletter|nodeleted');
- $avatarPairs = $this->user->getAvatarPairs('all');
- foreach($avatarPairs as $account => $avatar)
- {
- if(!isset($users[$account])) continue;
- $userList[$account]['realname'] = $users[$account];
- $userList[$account]['avatar'] = $avatar;
- }
- $userList['closed']['account'] = 'Closed';
- $userList['closed']['realname'] = 'Closed';
- $userList['closed']['avatar'] = '';
- /* Get execution linked products. */
- $productID = 0;
- $branchID = 0;
- $products = $this->loadModel('product')->getProducts($executionID);
- $productNames = array();
- if($products)
- {
- $productID = key($products);
- $branches = $this->loadModel('branch')->getPairs($productID, '', $executionID);
- if($branches) $branchID = key($branches);
- }
- foreach($products as $product) $productNames[$product->id] = $product->name;
- /* Get execution linked plans. */
- $plans = $this->execution->getPlans(array_keys($products), 'skipParent', $executionID);
- $allPlans = array();
- if(!empty($plans))
- {
- foreach($plans as $plan) $allPlans += $plan;
- }
- if(!isset($_SESSION['limitedExecutions'])) $this->execution->getLimitedExecution();
- $this->view->users = $users;
- $this->view->userList = $userList;
- $this->view->productID = $productID;
- $this->view->branchID = $branchID;
- $this->view->productNames = $productNames;
- $this->view->productNum = count($products);
- $this->view->allPlans = $allPlans;
- $this->view->isLimited = !$this->app->user->admin && strpos(",{$this->session->limitedExecutions},", ",{$executionID},") !== false;
- }
- /**
- * 展示维护产品相关变量。
- * Show the manage products related variables.
- *
- * @param object $execution
- * @access protected
- * @return void
- */
- protected function assignManageProductsVars($execution)
- {
- $branches = $this->project->getBranchesByProject($execution->id);
- $linkedProductIdList = empty($branches) ? array() : array_keys($branches);
- $allProducts = $this->loadModel('product')->getProductPairsByProject($execution->project, 'all', implode(',', $linkedProductIdList));
- $linkedProducts = $this->product->getProducts($execution->id, 'all', '', true, $linkedProductIdList);
- $linkedBranches = array();
- $executionStories = $this->project->getStoriesByProject($execution->id);
- /* If the story of the product which linked the execution, you don't allow to remove the product. */
- $unmodifiableProducts = array();
- $unmodifiableBranches = array();
- $linkedStoryIDList = array();
- $linkedBranchIdList = array();
- foreach($linkedProducts as $productID => $linkedProduct)
- {
- $linkedBranches[$productID] = array();
- if(!isset($allProducts[$productID])) $allProducts[$productID] = $linkedProduct->name;
- foreach($branches[$productID] as $branchID => $branch)
- {
- $linkedBranches[$productID][$branchID] = $branchID;
- $linkedBranchIdList[$branchID] = $branchID;
- if(!empty($executionStories[$productID][$branchID]))
- {
- array_push($unmodifiableProducts, $productID);
- array_push($unmodifiableBranches, $branchID);
- $linkedStoryIDList[$productID][$branchID] = $executionStories[$productID][$branchID]->storyIDList;
- }
- }
- }
- $this->view->title = $this->lang->execution->manageProducts . $this->lang->hyphen . $execution->name;
- $this->view->execution = $execution;
- $this->view->linkedProducts = $linkedProducts;
- $this->view->unmodifiableProducts = $unmodifiableProducts;
- $this->view->unmodifiableBranches = $unmodifiableBranches;
- $this->view->linkedBranches = $linkedBranches;
- $this->view->linkedStoryIDList = $linkedStoryIDList;
- $this->view->allProducts = $allProducts;
- $this->view->branchGroups = $this->execution->getBranchByProduct(array_keys($allProducts), $execution->project, 'ignoreNormal|noclosed', $linkedBranchIdList);
- $this->view->allBranches = $this->execution->getBranchByProduct(array_keys($allProducts), $execution->project, 'ignoreNormal');
- $this->display();
- }
- /**
- * 展示需求关联的任务、Bug、用例的数量以及统计需求信息。
- * Show the number of tasks, bugs cases linked with the stories, and statistics story information.
- *
- * @param int $executionID
- * @param array $stories
- * @param string $storyType
- * @access protected
- * @return void
- */
- protected function assignCountForStory($executionID, $stories, $storyType)
- {
- /* Get related tasks, bugs, cases count of each story. */
- $storyIdList = array();
- foreach($stories as $story)
- {
- $storyIdList[$story->id] = $story->id;
- if(empty($story->children)) continue;
- foreach($story->children as $child) $storyIdList[$child->id] = $child->id;
- }
- $this->view->stories = $stories;
- $this->view->storyTasks = $this->loadModel('task')->getStoryTaskCounts($storyIdList, $executionID);
- $this->view->storyBugs = $this->loadModel('bug')->getStoryBugCounts($storyIdList, $executionID);
- $this->view->storyCases = $this->loadModel('testcase')->getStoryCaseCounts($storyIdList);
- $this->view->summary = $this->loadModel('product')->summary($stories, 'all');
- }
- /**
- * 展示需求列表的相关变量。
- * Show the story list related variables.
- *
- * @param object $execution
- * @param array $products
- * @param int $productID
- * @param string $type
- * @param string $storyType
- * @param int $param
- * @param string $orderBy
- * @param object $pager
- * @access protected
- * @return void
- */
- protected function assignRelationForStory($execution, $products, $productID, $type, $storyType, $param, $orderBy, $pager)
- {
- $plans = $this->execution->getPlans(array_keys($products), 'skipParent|withMainPlan|unexpired|noclosed|sortedByDate', $execution->id);
- $allPlans = array();
- if(!empty($plans))
- {
- foreach($plans as $plan) $allPlans += $plan;
- }
- if($this->cookie->storyProductParam) $this->view->product = $this->loadModel('product')->getById((int)$this->cookie->storyProductParam);
- if($this->cookie->storyBranchParam)
- {
- $branchID = $this->cookie->storyBranchParam;
- if(strpos($branchID, ',') !== false) list($productID, $branchID) = explode(',', $branchID);
- $this->view->branch = $this->loadModel('branch')->getById($branchID, $productID);
- }
- $executionProductList = $this->loadModel('product')->getProducts($execution->id);
- $multiBranch = false;
- foreach($executionProductList as $executionProduct)
- {
- if($executionProduct->type != 'normal')
- {
- $multiBranch = true;
- break;
- }
- }
- $project = $this->loadModel('project')->getByID($execution->project);
- if(!($execution->type == 'stage' && in_array($execution->attribute, array('mix', 'request', 'design'))) && $project->multiple) $project->storyType = 'story';
- $productPairs = $this->loadModel('product')->getProductPairsByProject($execution->id); // Get execution's product.
- if(empty($productID)) $productID = (int)key($productPairs);
- $this->assignModuleForStory($type, $param, $storyType, $execution, $productID);
- $gradeList = $this->loadModel('story')->getGradeList('');
- $gradeGroup = array();
- foreach($gradeList as $grade) $gradeGroup[$grade->type][$grade->grade] = $grade->name;
- /* Assign. */
- $this->view->title = $execution->name . $this->lang->hyphen . $this->lang->execution->story;
- $this->view->storyType = $storyType;
- $this->view->param = $param;
- $this->view->type = $this->session->executionStoryBrowseType;
- $this->view->orderBy = $orderBy;
- $this->view->pager = $pager;
- $this->view->product = $this->product->getById($productID);
- $this->view->allPlans = $allPlans;
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
- $this->view->multiBranch = $multiBranch;
- $this->view->execution = $execution;
- $this->view->gradeMenu = $this->loadModel('story')->getGradeMenu($storyType, $project);
- $this->view->maxGradeGroup = $this->story->getMaxGradeGroup();
- $this->view->gradeGroup = $gradeGroup;
- $this->view->showGrades = isset($this->config->execution->showGrades) ? $this->config->execution->showGrades : $this->story->getDefaultShowGrades($this->view->gradeMenu);
- $this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable.
- $this->view->branchPairs = $this->loadModel('branch')->getPairs($productID, 'withClosed');
- $this->view->linkedTaskStories = $this->loadModel('story')->getIdListWithTask($execution->id);
- }
- /**
- * 展示需求列表的模块变量。
- * Show the story list module variables.
- *
- * @param string $type
- * @param int $param
- * @param string $storyType
- * @param object $execution
- * @param int $productID
- * @access protected
- * @return void
- */
- protected function assignModuleForStory($type, $param, $storyType, $execution, $productID)
- {
- $this->loadModel('tree');
- if($this->cookie->storyModuleParam) $this->view->module = $this->loadModel('tree')->getById((int)$this->cookie->storyModuleParam);
- $showModule = !empty($this->config->execution->story->showModule) ? $this->config->execution->story->showModule : '';
- $modulePairs = $showModule ? $this->tree->getModulePairs($type == 'byproduct' ? $param : 0, 'story', $showModule) : array();
- $createModuleLink = $storyType == 'story' ? 'createStoryLink' : 'createRequirementLink';
- if(!$execution->hasProduct && !$execution->multiple)
- {
- $moduleTree = $this->tree->getTreeMenu($productID, 'story', 0, array('treeModel', $createModuleLink), array('executionID' => $execution->id, 'productID' => $productID), '', "¶m=$param&storyType=$storyType");
- }
- else
- {
- $moduleTree = $this->tree->getProjectStoryTreeMenu($execution->id, 0, array('treeModel', $createModuleLink), array('storyType' => $storyType));
- }
- $this->view->moduleTree = $moduleTree;
- $this->view->modulePairs = $modulePairs;
- $this->view->moduleID = $type == 'bymodule' ? $param : 0;
- }
- /**
- * 展示任务看板的相关变量。
- * Show the task Kanban related variables.
- *
- * @param object $execution
- * @access protected
- * @return void
- */
- protected function assignTaskKanbanVars($execution)
- {
- /* Get user list. */
- $userList = array();
- $users = $this->loadModel('user')->getPairs('noletter|nodeleted');
- $avatarPairs = $this->user->getAvatarPairs('all');
- foreach($avatarPairs as $account => $avatar)
- {
- if(!isset($users[$account])) continue;
- $userList[$account]['realname'] = $users[$account];
- $userList[$account]['avatar'] = $avatar;
- }
- $userList['closed']['account'] = 'Closed';
- $userList['closed']['realname'] = 'Closed';
- $userList['closed']['avatar'] = '';
- /* Get execution linked products. */
- $productID = 0;
- $productNames = array();
- $products = $this->loadModel('product')->getProducts($execution->id);
- if($products) $productID = key($products);
- foreach($products as $product) $productNames[$product->id] = $product->name;
- $plans = $this->execution->getPlans(array_keys($products), 'skipParent|withMainPlan|unexpired|noclosed|sortedByDate', $execution->id);
- $allPlans = array();
- if(!empty($plans))
- {
- foreach($plans as $plan) $allPlans += $plan;
- }
- if(!isset($_SESSION['limitedExecutions'])) $this->execution->getLimitedExecution();
- $project = $this->project->getByID($execution->project);
- $this->view->hasFrozenStories = $this->project->hasFrozenObject($execution->project, 'SRS');
- $this->view->title = $this->lang->execution->kanban;
- $this->view->userList = $userList;
- $this->view->realnames = $users;
- $this->view->productID = $productID;
- $this->view->productNames = $productNames;
- $this->view->productNum = count($products);
- $this->view->allPlans = $allPlans;
- $this->view->hiddenPlan = $project->model !== 'scrum';
- $this->view->execution = $execution;
- $this->view->project = $project;
- $this->view->canBeChanged = common::canModify('execution', $execution);
- $this->view->isLimited = !$this->app->user->admin && strpos(",{$this->session->limitedExecutions},", ",{$execution->id},") !== false;
- }
- /**
- * 展示用例列表的相关变量。
- * Show the case list related variables.
- *
- * @param int $executionID
- * @param int $productID
- * @param string $branchID
- * @param int $moduleID
- * @param int $param
- * @param string $orderBy
- * @param string $type
- * @param object $pager
- * @access protected
- * @return void
- */
- protected function assignTestcaseVars($executionID, $productID, $branchID, $moduleID, $param, $orderBy, $type, $pager)
- {
- $this->loadModel('tree');
- /* Get cases. */
- $cases = $this->loadModel('testcase')->getExecutionCases($type, $executionID, $productID, $branchID, $moduleID, $param, $orderBy, $pager);
- $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'testcase', false);
- $cases = $this->testcase->appendData($cases, 'case');
- $cases = $this->loadModel('story')->checkNeedConfirm($cases);
- /* Get module tree.*/
- if($executionID and empty($productID))
- {
- $moduleTree = $this->tree->getCaseTreeMenu($executionID, $productID, 0, array('treeModel', 'createCaseLink'));
- }
- else
- {
- $moduleTree = $this->tree->getTreeMenu($productID, 'case', 0, array('treeModel', 'createCaseLink'), array('projectID' => $executionID, 'productID' => $productID, 'branchID' => $branchID), $branchID);
- }
- $tree = $moduleID ? $this->tree->getByID($moduleID) : '';
- $showModule = !empty($this->config->execution->testcase->showModule) ? $this->config->execution->testcase->showModule : '';
- $this->view->cases = $cases;
- $this->view->scenes = $this->testcase->getSceneMenu($productID, $moduleID);;
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
- $this->view->title = $this->lang->execution->testcase;
- $this->view->executionID = $executionID;
- $this->view->productID = $productID;
- $this->view->product = $this->loadModel('product')->getByID((int)$productID);
- $this->view->orderBy = $orderBy;
- $this->view->pager = $pager;
- $this->view->type = $type;
- $this->view->branchID = $branchID;
- $this->view->branchTagOption = $this->loadModel('branch')->getPairs($productID, 'withClosed');
- $this->view->recTotal = $pager->recTotal;
- $this->view->showBranch = $this->loadModel('branch')->showBranch($productID);
- $this->view->stories = array( 0 => '') + $this->loadModel('story')->getPairs($productID);
- $this->view->moduleTree = $moduleTree;
- $this->view->moduleID = $moduleID;
- $this->view->moduleName = $moduleID ? $tree->name : $this->lang->tree->all;
- $this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'bug', $showModule) : array();
- }
- /**
- * 展示测试单的相关变量。
- * Show the testtask related variables.
- *
- * @param array $tasks
- * @access protected
- * @return void
- */
- protected function assignTesttaskVars($tasks)
- {
- /* Compute rowspan. */
- $productGroup = array();
- $waitCount = 0;
- $testingCount = 0;
- $blockedCount = 0;
- $doneCount = 0;
- foreach($tasks as $task)
- {
- $productGroup[$task->product][] = $task;
- if($task->status == 'wait') $waitCount ++;
- if($task->status == 'doing') $testingCount ++;
- if($task->status == 'blocked') $blockedCount ++;
- if($task->status == 'done') $doneCount ++;
- if($task->build == 'trunk' || empty($task->buildName)) $task->buildName = $this->lang->trunk;
- }
- $lastProduct = '';
- foreach($tasks as $taskID => $task)
- {
- $task->rawStatus = $task->status;
- $task->status = $this->processStatus('testtask', $task);
- $task->rowspan = 0;
- if($lastProduct !== $task->product)
- {
- $lastProduct = $task->product;
- if(!empty($productGroup[$task->product])) $task->rowspan = count($productGroup[$task->product]);
- }
- }
- $this->view->waitCount = $waitCount;
- $this->view->testingCount = $testingCount;
- $this->view->blockedCount = $blockedCount;
- $this->view->doneCount = $doneCount;
- $this->view->tasks = $tasks;
- }
- /**
- * 展示执行详情的相关变量。
- * Show the view related variables.
- *
- * @param int $executionID
- * @access protected
- * @return void
- */
- protected function assignViewVars($executionID)
- {
- $this->executeHooks($executionID);
- $userPairs = array();
- $userList = array();
- $users = $this->loadModel('user')->getList('all');
- foreach($users as $user)
- {
- $userList[$user->account] = $user;
- $userPairs[$user->account] = $user->realname;
- }
- /* Get linked branches. */
- $branches = $this->project->getBranchesByProject($executionID);
- $linkedProductIdList = empty($branches) ? '' : array_keys($branches);
- $products = $this->loadModel('product')->getProducts($executionID, 'all', '', true, $linkedProductIdList, false);
- $linkedBranches = array();
- foreach($products as $product)
- {
- if(isset($product->branches))
- {
- foreach($product->branches as $branchID) $linkedBranches[$branchID] = $branchID;
- }
- }
- $this->view->users = $userPairs;
- $this->view->userList = $userList;
- $this->view->products = $products;
- $this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products), 'ignoreNormal', $linkedBranches);
- $this->view->planGroups = $this->execution->getPlans(array_keys($products));
- $this->view->actions = $this->loadModel('action')->getList('execution', $executionID);
- $this->view->dynamics = $this->loadModel('action')->getDynamic('all', 'all', 'date_desc', 50, 'all', 'all', $executionID);
- $this->view->teamMembers = $this->execution->getTeamMembers($executionID);
- $this->view->docLibs = $this->loadModel('doc')->getLibsByObject('execution', $executionID);
- $this->view->statData = $this->execution->statRelatedData($executionID);
- }
- /**
- * 构造任务分组视图数据。
- * Build task group data.
- *
- * @param string $groupBy story|status|pri|assignedTo|finishedBy|closedBy|type
- * @param array $tasks
- * @param array $users
- * @access protected
- * @return array
- */
- protected function buildGroupTasks($groupBy = 'story', $tasks = array(), $users = array())
- {
- $groupTasks = array();
- $groupByList = array();
- foreach($tasks as $task)
- {
- if($groupBy == 'story')
- {
- $groupTasks[$task->story][] = $task;
- $groupByList[$task->story] = $task->storyTitle;
- }
- elseif($groupBy == 'status')
- {
- $statusList = arrayUnion($this->lang->task->statusList, array('changed' => $this->lang->task->storyChange));
- $groupTasks[$statusList[$task->status]][] = $task;
- }
- elseif($groupBy == 'assignedTo')
- {
- if(isset($task->team))
- {
- $groupTasks = $this->buildGroupMultiTask($groupBy, $task, $users, $groupTasks);
- }
- else
- {
- $groupTasks[$task->assignedToRealName][] = $task;
- }
- }
- elseif($groupBy == 'finishedBy')
- {
- if(isset($task->team))
- {
- $task->consumed = $task->estimate = $task->left = 0;
- $groupTasks = $this->buildGroupMultiTask($groupBy, $task, $users, $groupTasks);
- }
- else
- {
- $groupTasks[$users[$task->finishedBy]][] = $task;
- }
- }
- elseif($groupBy == 'closedBy')
- {
- $groupTasks[$users[$task->closedBy]][] = $task;
- }
- elseif($groupBy == 'type')
- {
- $groupTasks[$this->lang->task->typeList[$task->type]][] = $task;
- }
- else
- {
- $groupTasks[$task->$groupBy][] = $task;
- }
- }
- /* Process closed data when group by assignedTo. */
- if($groupBy == 'assignedTo' && isset($groupTasks['Closed']))
- {
- $closedTasks = $groupTasks['Closed'];
- unset($groupTasks['Closed']);
- $groupTasks['closed'] = $closedTasks;
- }
- return array($groupTasks, $groupByList);
- }
- /**
- * 构建多人任务的分组视图数据。
- * Build group data for multiple task.
- *
- * @param string $groupBy
- * @param object $task
- * @param array $users
- * @param array $groupTasks
- * @access protected
- * @return array
- */
- protected function buildGroupMultiTask($groupBy, $task, $users, $groupTasks)
- {
- foreach($task->team as $team)
- {
- if($team->left != 0 && $groupBy == 'finishedBy')
- {
- $task->estimate += $team->estimate;
- $task->consumed += $team->consumed;
- $task->left += $team->left;
- continue;
- }
- $cloneTask = clone $task;
- $cloneTask->{$groupBy} = $team->account;
- $cloneTask->estimate = $team->estimate;
- $cloneTask->consumed = $team->consumed;
- $cloneTask->left = $team->left;
- if($team->left == 0 || $groupBy == 'finishedBy') $cloneTask->status = 'done';
- $realname = zget($users, $team->account);
- $cloneTask->assignedToRealName = $realname;
- $groupTasks[$realname][] = $cloneTask;
- }
- if($groupBy == 'finishedBy' && !empty($task->left)) $groupTasks[$users[$task->finishedBy]][] = $task;
- return $groupTasks;
- }
- /**
- * 构建需求列表的搜索表单数据。
- * Build the search form data to story list.
- *
- * @param object $execution
- * @param int $productID
- * @param array $products
- * @param int $queryID
- * @param string $actionURL
- * @access protected
- * @return void
- */
- protected function buildStorySearchForm($execution, $productID, $products, $queryID, $actionURL)
- {
- $modules = array();
- $productModules = array();
- $executionModules = $this->loadModel('tree')->getTaskTreeModules($execution->id, true);
- if($productID)
- {
- $product = $products[$productID];
- $productModules = $this->tree->getOptionMenu($productID, 'story', 0, $product->branches);
- }
- else
- {
- foreach($products as $product) $productModules += $this->tree->getOptionMenu($product->id, 'story', 0, $product->branches);
- }
- if(commonModel::isTutorialMode())
- {
- $modules = $this->loadModel('tutorial')->getModulePairs();
- }
- else
- {
- foreach($productModules as $branchID => $moduleList)
- {
- foreach($moduleList as $moduleID => $moduleName)
- {
- if($moduleID && !isset($executionModules[$moduleID])) continue;
- $modules[$moduleID] = ((count($products) >= 2 && $moduleID) ? $product->name : '') . $moduleName;
- }
- }
- }
- $branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products));
- $this->execution->buildStorySearchForm($products, $branchGroups, $modules, $queryID, $actionURL, 'executionStory', $execution);
- }
- /**
- * 将导入的Bug转为任务。
- * Change imported bugs to the tasks.
- *
- * @param object $execution
- * @param array $postData
- * @access protected
- * @return array
- */
- protected function buildTasksForImportBug($execution, $postData)
- {
- $this->loadModel('task');
- $tasks = array();
- $bugs = $this->loadModel('bug')->getByIdList(array_keys($postData));
- $showAllModule = isset($this->config->execution->task->allModule) ? $this->config->execution->task->allModule : '';
- $modules = $this->loadModel('tree')->getTaskOptionMenu($execution->id, 0, $showAllModule ? 'allModule' : '');
- $now = helper::now();
- $requiredFields = str_replace(array(',story,', ',module,'), ',', ',' . $this->config->task->create->requiredFields . ',');
- $requiredFields = trim($requiredFields, ',');
- foreach($postData as $bugID => $task)
- {
- $bug = zget($bugs, $bugID, '');
- if(empty($bug)) continue;
- unset($task->id);
- $task->bug = $bug;
- $task->project = $execution->project;
- $task->execution = $execution->id;
- $task->story = $bug->story;
- $task->storyVersion = $bug->storyVersion;
- $task->module = isset($modules[$bug->module]) ? $bug->module : 0;
- $task->fromBug = $bugID;
- $task->name = $bug->title;
- $task->type = 'devel';
- $task->consumed = 0;
- $task->status = 'wait';
- $task->openedDate = $now;
- $task->openedBy = $this->app->user->account;
- $task->estStarted = $task->estStarted ? $task->estStarted : null;
- $task->deadline = $task->deadline ? $task->deadline : null;
- if($task->estimate !== '') $task->left = $task->estimate;
- if(!empty($task->assignedTo)) $task->assignedDate = $now;
- /* Check task required fields. */
- foreach(explode(',', $requiredFields) as $field)
- {
- if(empty($field)) continue;
- if(!isset($task->$field)) continue;
- if(!empty($task->$field)) continue;
- dao::$errors["{$field}[{$bugID}]"] = 'ID: ' . $bugID . sprintf($this->lang->error->notempty, $this->lang->task->$field);
- return false;
- }
- if(!preg_match("/^[0-9]+(.[0-9]+)?$/", (string)$task->estimate) and !empty($task->estimate))
- {
- dao::$errors["{$field}[{$bugID}]"] = 'ID: ' . $bugID . $this->lang->task->error->estimateNumber;
- return false;
- }
- if(!helper::isZeroDate($task->deadline) && $task->estStarted > $task->deadline)
- {
- dao::$errors["deadline[{$bugID}]"] = 'ID: ' . $bugID . $this->lang->task->error->deadlineSmall;
- return false;
- }
- if(!empty($this->config->limitTaskDate))
- {
- $this->task->checkEstStartedAndDeadline($execution->id, (string)$task->estStarted, (string)$task->deadline);
- if(dao::isError()) return false;
- }
- $tasks[$bugID] = $task;
- }
- return $tasks;
- }
- /**
- * 构建导入Bug的搜索表单数据。
- * Build the search form data to import the Bug.
- *
- * @param object $execution
- * @param int $queryID
- * @param array $products
- * @param array $executions
- * @param array $projects
- * @access protected
- * @return void
- */
- protected function buildImportBugSearchForm($execution, $queryID, $products, $executions, $projects)
- {
- $project = $this->loadModel('project')->getByID($execution->project);
- $this->config->bug->search['actionURL'] = $this->createLink('execution', 'importBug', "executionID=$execution->id&browseType=bySearch¶m=myQueryID");
- $this->config->bug->search['queryID'] = $queryID;
- if(!empty($products))
- {
- $this->config->bug->search['params']['product']['values'] = array(''=>'') + $products + array('all'=>$this->lang->execution->aboveAllProduct);
- }
- else
- {
- $this->config->bug->search['params']['product']['values'] = array(''=>'');
- }
- if(!$execution->multiple)
- {
- unset($this->config->bug->search['fields']['execution'], $this->config->bug->search['params']['execution']);
- }
- else
- {
- $this->config->bug->search['params']['execution']['values'] = array(''=>'') + $executions + array('all'=>$this->lang->execution->aboveAllExecution);
- }
- $this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairs(array_keys($products));
- $this->config->bug->search['module'] = 'importBug';
- $this->config->bug->search['params']['confirmed']['values'] = $this->lang->bug->confirmedList;
- $this->loadModel('tree');
- $bugModules = array();
- foreach($products as $productID => $productName)
- {
- $productModules = $this->tree->getOptionMenu($productID, 'bug', 0, 'all');
- foreach($productModules as $moduleID => $moduleName)
- {
- if(empty($moduleID))
- {
- $bugModules[$moduleID] = $moduleName;
- continue;
- }
- $bugModules[$moduleID] = $productName . $moduleName;
- }
- }
- $this->config->bug->search['params']['module']['values'] = $bugModules;
- $this->config->bug->search['params']['project']['values'] = $projects;
- $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs(array_keys($products), 'all', 'withbranch|releasetag');
- unset($this->config->bug->search['fields']['resolvedBy']);
- unset($this->config->bug->search['fields']['closedBy']);
- unset($this->config->bug->search['fields']['status']);
- unset($this->config->bug->search['fields']['toTask']);
- unset($this->config->bug->search['fields']['toStory']);
- unset($this->config->bug->search['fields']['resolution']);
- unset($this->config->bug->search['fields']['resolvedBuild']);
- unset($this->config->bug->search['fields']['resolvedDate']);
- unset($this->config->bug->search['fields']['closedDate']);
- unset($this->config->bug->search['fields']['branch']);
- if(empty($execution->multiple) && empty($execution->hasProduct)) unset($this->config->bug->search['fields']['plan']);
- if(empty($project->hasProduct))
- {
- unset($this->config->bug->search['fields']['product']);
- if($project->model !== 'scrum') unset($this->config->bug->search['fields']['plan']);
- }
- unset($this->config->bug->search['params']['resolvedBy']);
- unset($this->config->bug->search['params']['closedBy']);
- unset($this->config->bug->search['params']['status']);
- unset($this->config->bug->search['params']['toTask']);
- unset($this->config->bug->search['params']['toStory']);
- unset($this->config->bug->search['params']['resolution']);
- unset($this->config->bug->search['params']['resolvedBuild']);
- unset($this->config->bug->search['params']['resolvedDate']);
- unset($this->config->bug->search['params']['closedDate']);
- unset($this->config->bug->search['params']['branch']);
- $this->loadModel('search')->setSearchParams($this->config->bug->search);
- }
- /**
- * 检查创建的表单数据。
- * Check the form data for create.
- *
- * @access protected
- * @return bool
- */
- protected function checkPostForCreate()
- {
- if(empty($_POST['project']))
- {
- dao::$errors['project'] = $this->lang->execution->projectNotEmpty;
- return false;
- }
- $projectID = (int)$_POST['project'];
- $project = $this->loadModel('project')->fetchByID($projectID);
- $this->execution->checkBeginAndEndDate($projectID, $_POST['begin'], $_POST['end'], isset($_POST['parent']) ? (int)$this->post->parent : $projectID);
- if(dao::isError()) return false;
- /* Judge workdays is legitimate. */
- $workdays = helper::diffDate($_POST['end'], $_POST['begin']) + 1;
- if(isset($_POST['days']) && $_POST['days'] > $workdays)
- {
- dao::$errors['days'] = sprintf($this->lang->project->workdaysExceed, $workdays);
- return false;
- }
- if(!empty($_POST['products']))
- {
- $_POST['products'] = array_filter($_POST['products']);
- $this->app->loadLang('project');
- $multipleProducts = $this->loadModel('product')->getMultiBranchPairs();
- foreach($_POST['products'] as $index => $productID)
- {
- if(empty($_POST['branch'][$index])) continue;
- $branches = implode(',', $_POST['branch'][$index]);
- if(isset($multipleProducts[$productID]) && $branches == '')
- {
- dao::$errors["branch[{$index}][]"] = $this->lang->project->error->emptyBranch;
- return false;
- }
- }
- }
- /* Determine whether to add a sprint or a stage according to the model of the execution. */
- if($project->model == 'waterfall' || $project->model == 'waterfallplus')
- {
- if(empty($_POST['products'])) dao::$errors['products[0]'] = $this->lang->project->errorNoProducts;
- if(dao::isError()) return false;
- if(isset($this->config->setPercent) && $this->config->setPercent == 1)
- {
- $this->execution->checkWorkload('create', (int)$this->post->percent, $project);
- if(dao::isError()) return false;
- }
- }
- return true;
- }
- /**
- * 构造创建执行的数据。
- * Build the data for create execution.
- *
- * @access protected
- * @return object|false
- */
- protected function buildExecutionForCreate()
- {
- $now = helper::now();
- $project = $this->loadModel('project')->fetchByID((int)$_POST['project']);
- $type = 'sprint';
- if($project) $type = zget($this->config->execution->modelList, $project->model, 'sprint');
- $fields = $this->config->execution->form->create;
- foreach(explode(',', trim($this->config->execution->create->requiredFields, ',')) as $field) $fields[$field]['required'] = true;
- if(!isset($_POST['code'])) $fields['code']['required'] = false;
- if(!isset($_POST['percent'])) $fields['percent']['required'] = false;
- $this->config->execution->create->requiredFields = implode(',', array_keys(array_filter(array_map(function($config){return $config['required'] == true;}, $fields))));
- $this->correctErrorLang();
- $execution = form::data($fields)
- ->setDefault('openedBy', $this->app->user->account)
- ->setDefault('openedDate', $now)
- ->setDefault('lastEditedBy', $this->app->user->account)
- ->setDefault('lastEditedDate', $now)
- ->setDefault('type', $type)
- ->setDefault('team', $this->post->name)
- ->setDefault('parent', $this->post->project)
- ->setDefault('isTpl', $project->isTpl)
- ->setIF($this->post->parent, 'parent', $this->post->parent)
- ->setIF($this->post->heightType == 'auto', 'displayCards', 0)
- ->setIF($this->post->acl == 'open', 'whitelist', '')
- ->setIF($this->post->type, 'type', $this->post->type)
- ->get();
- if(!empty($execution->parent) && ($execution->project == $execution->parent)) $execution->hasProduct = $project->hasProduct;
- if(!empty($execution->parent) && empty($execution->attribute))
- {
- /* 子阶段与父阶段同类型。 */
- $parent = $this->execution->fetchByID((int)$execution->parent);
- $execution->attribute = $parent->attribute;
- }
- if($this->post->heightType == 'custom' && !$this->loadModel('kanban')->checkDisplayCards($execution->displayCards)) return false;
- if(!$this->checkPostForCreate()) return false;
- /* Set planDuration and realDuration. */
- if(in_array($this->config->edition, array('max', 'ipd')))
- {
- $execution->planDuration = $this->loadModel('programplan')->getDuration($execution->begin, $execution->end);
- if(!empty($execution->realBegan) && !empty($execution->realEnd)) $execution->realDuration = $this->programplan->getDuration($execution->realBegan, $execution->realEnd);
- }
- return $this->loadModel('file')->processImgURL($execution, $this->config->execution->editor->create['id'], $this->post->uid);
- }
- /**
- * 检查累积流图的日期。
- * Check Cumulative flow diagram date.
- *
- * @param string $begin
- * @param string $end
- * @param string $minDate
- * @param string $maxDate
- * @access protected
- * @return bool
- */
- protected function checkCFDDate($begin, $end, $minDate, $maxDate)
- {
- $dateError = array();
- if(empty($begin)) $dateError[] = sprintf($this->lang->error->notempty, $this->lang->execution->charts->cfd->begin);
- if(empty($end)) $dateError[] = sprintf($this->lang->error->notempty, $this->lang->execution->charts->cfd->end);
- if(empty($dateError))
- {
- if($begin < $minDate) $dateError[] = sprintf($this->lang->error->gt, $this->lang->execution->charts->cfd->begin, $minDate);
- if($begin > $maxDate) $dateError[] = sprintf($this->lang->error->lt, $this->lang->execution->charts->cfd->begin, $maxDate);
- if($end < $minDate) $dateError[] = sprintf($this->lang->error->gt, $this->lang->execution->charts->cfd->end, $minDate);
- if($end > $maxDate) $dateError[] = sprintf($this->lang->error->lt, $this->lang->execution->charts->cfd->end, $maxDate);
- }
- foreach($dateError as $index => $error)
- {
- dao::$errors = str_replace(array('。', '.'), array('', ''), $error);
- return false;
- }
- if($begin >= $end)
- {
- dao::$errors = $this->lang->execution->charts->cfd->errorBegin;
- return false;
- }
- if(date("Y-m-d", strtotime("-3 months", strtotime($end))) > $begin)
- {
- dao::$errors = $this->lang->execution->charts->cfd->errorDateRange;
- return false;
- }
- return true;
- }
- /**
- * 处理版本列表展示数据。
- * Process build list display data.
- *
- * @param array $buildList
- * @param int $executionID
- * @access protected
- * @return object[]
- */
- protected function processBuildListData($buildList, $executionID = 0)
- {
- $this->loadModel('build');
- $productIdList = array();
- foreach($buildList as $build) $productIdList[$build->product] = $build->product;
- /* Get branch name. */
- $showBranch = false;
- $branchGroups = $this->loadModel('branch')->getByProducts($productIdList);
- $builds = array();
- foreach($buildList as $build)
- {
- $build->branchName = '';
- if(isset($branchGroups[$build->product]))
- {
- $showBranch = true;
- $branchPairs = $branchGroups[$build->product];
- foreach(explode(',', trim($build->branch, ',')) as $branchID)
- {
- if(isset($branchPairs[$branchID])) $build->branchName .= "{$branchPairs[$branchID]},";
- }
- $build->branchName = trim($build->branchName, ',');
- }
- if($build->scmPath && $build->filePath)
- {
- $build->rowspan = 2;
- $buildInfo = clone $build;
- $buildInfo->pathType = 'scmPath';
- $buildInfo->path = $build->scmPath;
- $builds[] = $buildInfo;
- $buildInfo = clone $build;
- $buildInfo->pathType = 'filePath';
- $buildInfo->path = $build->filePath;
- $builds[] = $buildInfo;
- }
- else
- {
- $build->pathType = empty($build->scmPath) ? 'filePath' : 'scmPath';
- $build->path = empty($build->scmPath) ? $build->filePath : $build->scmPath;
- $builds[] = $build;
- }
- if(!$build->system) $build->system = '';
- }
- if(!$showBranch) unset($this->config->build->dtable->fieldList['branch']);
- unset($this->config->build->dtable->fieldList['execution']);
- return $builds;
- }
- /**
- * 构建产品下拉选择数据。
- * Build product drop-down select data.
- *
- * @param int $executionID
- * @param int $productID
- * @param object[] $products
- * @access protected
- * @return array
- */
- protected function buildProductSwitcher($executionID, $productID, $products)
- {
- $productOption = array();
- $branchOption = array();
- $programIdList = array();
- if(count($products) > 1) $productOption[0] = $this->lang->product->all;
- foreach($products as $productData) $programIdList[$productData->program] = $productData->program;
- $programPairs = $this->loadModel('program')->getPairsByList($programIdList);
- $linePairs = $this->loadModel('product')->getLinePairs($programIdList);
- foreach($products as $productData)
- {
- $programName = isset($programPairs[$productData->program]) ? $programPairs[$productData->program] . ' / ' : '';
- $lineName = isset($linePairs[$productData->line]) ? $linePairs[$productData->line] . ' / ' : '';
- $productOption[$productData->id] = $programName . $lineName . $productData->name;
- }
- $product = $this->product->getById((int)$productID);
- if($product and $product->type != 'normal')
- {
- /* Display status of branch. */
- $branches = $this->loadModel('branch')->getList($productID, $executionID, 'all');
- foreach($branches as $branchInfo)
- {
- $branchOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
- }
- }
- return array($productOption, $branchOption);
- }
- /**
- * 构建执行团队成员信息。
- * Build execution team member information.
- *
- * @param array $currentMembers
- * @param array $members2Import
- * @param array $deptUsers
- * @param int $days
- * @access protected
- * @return array
- */
- protected function buildMembers($currentMembers, $members2Import, $deptUsers, $days)
- {
- $teamMembers = array();
- foreach($currentMembers as $account => $member)
- {
- $member->memberType = 'default';
- $teamMembers[$account] = $member;
- }
- foreach($members2Import as $account => $member2Import)
- {
- $member2Import->memberType = 'import';
- $member2Import->days = $days;
- $member2Import->limited = 'no';
- $teamMembers[$account] = $member2Import;
- }
- $roles = $this->loadModel('user')->getUserRoles(array_keys($deptUsers));
- foreach($deptUsers as $deptAccount => $userName)
- {
- if(isset($currentMembers[$deptAccount]) || isset($members2Import[$deptAccount])) continue;
- $deptMember = new stdclass();
- $deptMember->memberType = 'dept';
- $deptMember->account = $deptAccount;
- $deptMember->role = zget($roles, $deptAccount, '');
- $deptMember->days = $days;
- $deptMember->hours = $this->config->execution->defaultWorkhours;
- $deptMember->limited = 'no';
- $teamMembers[$deptAccount] = $deptMember;
- }
- for($j = 0; $j < 5; $j ++)
- {
- $newMember = new stdclass();
- $newMember->memberType = 'add';
- $newMember->account = '';
- $newMember->role = '';
- $newMember->days = $days;
- $newMember->hours = $this->config->execution->defaultWorkhours;
- $newMember->limited = 'no';
- $teamMembers[] = $newMember;
- }
- return $teamMembers;
- }
- /**
- * 构造待更新的团队成员数据。
- * Construct the team member data to be updated.
- *
- * @param object $execution
- * @access protected
- * @return array
- */
- protected function buildMembersForManageMembers($execution)
- {
- $members = form::batchData()->get();
- $oldMemberDays = $this->dao->select('`account`, `days`')->from(TABLE_TEAM)->where('root')->eq($execution->id)->andWhere('type')->eq('execution')->fetchPairs('account', 'days');
- foreach($members as $rowIndex => $member)
- {
- $member->root = $execution->id;
- if($member->hours > 24) dao::$errors["hours[$rowIndex]"] = $this->lang->execution->errorHours;
- if(!empty($execution->days))
- {
- if(isset($oldMemberDays[$member->account]) && $member->days == $oldMemberDays[$member->account]) continue;
- if($member->days > $execution->days) dao::$errors["days[$rowIndex]"] = sprintf($this->lang->execution->daysGreaterProject, $execution->days);
- }
- }
- return $members;
- }
- /**
- * 根据过滤规则,筛选任务分组数据。
- * Filter task group data based on the filter rules.
- *
- * @param array $groupTasks
- * @param string $groupBy
- * @param string $filter
- * @param int $allCount
- * @param array $tasks
- * @access protected
- * @return array
- */
- protected function filterGroupTasks($groupTasks, $groupBy, $filter, $allCount, $tasks)
- {
- if($filter == 'all') return array($groupTasks, $allCount);
- if($groupBy == 'story' && $filter == 'linked' && isset($groupTasks[0]))
- {
- $allCount -= count($groupTasks[0]);
- unset($groupTasks[0]);
- }
- elseif($groupBy == 'pri' && $filter == 'noset')
- {
- foreach($groupTasks as $pri => $tasks)
- {
- if($pri)
- {
- $allCount -= count($tasks);
- unset($groupTasks[$pri]);
- }
- }
- }
- elseif($groupBy == 'assignedTo' && $filter == 'undone')
- {
- $multiTaskCount = array();
- foreach($groupTasks as $assignedTo => $tasks)
- {
- foreach($tasks as $i => $task)
- {
- if($task->status != 'wait' && $task->status != 'doing')
- {
- if($task->mode == 'multi' && !isset($multiTaskCount[$task->id]))
- {
- $multiTaskCount[$task->id] = true;
- $allCount -= 1;
- }
- elseif($task->mode != 'multi')
- {
- $allCount -= 1;
- }
- unset($groupTasks[$assignedTo][$i]);
- }
- }
- }
- }
- elseif(($groupBy == 'finishedBy' || $groupBy == 'closedBy') && isset($tasks['']))
- {
- $allCount -= count($tasks['']);
- unset($tasks['']);
- }
- return array($groupTasks, $allCount);
- }
- /**
- * 设置最近五次执行。
- * Set the recent five executions.
- *
- * @param int $executionID
- * @access protected
- * @return void
- */
- protected function setRecentExecutions($executionID)
- {
- if($this->session->multiple)
- {
- $recentExecutions = isset($this->config->execution->recentExecutions) ? explode(',', $this->config->execution->recentExecutions) : array();
- array_unshift($recentExecutions, $executionID);
- $recentExecutions = array_slice(array_unique($recentExecutions), 0, 5);
- $recentExecutions = implode(',', $recentExecutions);
- $this->loadModel('setting');
- if(empty($this->config->execution->recentExecutions) || $this->config->execution->recentExecutions != $recentExecutions) $this->setting->updateItem($this->app->user->account . 'common.execution.recentExecutions', $recentExecutions);
- if(empty($this->config->execution->lastExecution) || $this->config->execution->lastExecution != $executionID) $this->setting->updateItem($this->app->user->account . 'common.execution.lastExecution', $executionID);
- }
- }
- /**
- * 设置任务页面的Cookie和Session。
- * Set task page storage.
- *
- * @access protected
- * @return void
- * @param int $executionID
- * @param string $orderBy
- * @param string $browseType
- * @param int $param
- */
- protected function setTaskPageStorage($executionID, $orderBy, $browseType, $param = 0)
- {
- helper::setcookie('preExecutionID', (string)$executionID);
- helper::setcookie('executionTaskOrder', $orderBy);
- if($this->cookie->preExecutionID != $executionID)
- {
- helper::setcookie('moduleBrowseParam', '0');
- helper::setcookie('productBrowseParam', '0');
- }
- if($browseType == 'bymodule')
- {
- helper::setcookie('moduleBrowseParam', (string)$param);
- helper::setcookie('productBrowseParam', '0');
- }
- elseif($browseType == 'byproduct')
- {
- helper::setcookie('moduleBrowseParam', '0');
- helper::setcookie('productBrowseParam', (string)$param);
- }
- else
- {
- $this->session->set('taskBrowseType', $browseType);
- }
- if($browseType == 'bymodule' && $this->session->taskBrowseType == 'bysearch') $this->session->set('taskBrowseType', 'unclosed');
- }
- /**
- * 构建执行看板的数据。
- * Build the data to execution Kanban.
- *
- * @param array $projectIdList
- * @param array $executions
- * @access protected
- * @return void
- */
- protected function buildExecutionKanbanData($projectIdList, $executions)
- {
- $projectCount = 0;
- $statusCount = array();
- $myExecutions = array();
- $kanbanGroup = array();
- $teams = $this->execution->getMembersByIdList(toIntArray($this->app->user->view->sprints));
- foreach($projectIdList as $projectID)
- {
- foreach(array_keys($this->lang->execution->statusList) as $status)
- {
- if(!isset($statusCount[$status])) $statusCount[$status] = 0;
- foreach($executions as $execution)
- {
- if($execution->status == $status)
- {
- if(isset($teams[$execution->id][$this->app->user->account])) $myExecutions[$status][$execution->id] = $execution;
- if($execution->project == $projectID) $kanbanGroup[$projectID][$status][$execution->id] = $execution;
- }
- }
- $statusCount[$status] += isset($kanbanGroup[$projectID][$status]) ? count($kanbanGroup[$projectID][$status]) : 0;
- /* Max 2 closed executions. */
- if($status == 'closed')
- {
- list($myExecutions, $kanbanGroup) = $this->processExecutionKanbanData($myExecutions, $kanbanGroup, $projectID, $status);
- }
- }
- if(empty($kanbanGroup[$projectID])) continue;
- $projectCount ++;
- }
- return array($projectCount, $statusCount, $myExecutions, $kanbanGroup);
- }
- /**
- * 获取可以导入到执行中的Bug。
- *
- * @param int $executionID
- * @param array $productIdList
- * @param string $browseType
- * @param int $queryID
- * @param object $pager
- * @access protected
- * @return array
- */
- protected function getImportBugs($executionID, $productIdList, $browseType, $queryID, $pager)
- {
- $this->loadModel('bug');
- $bugs = array();
- if($browseType != "bysearch")
- {
- $bugs = $this->bug->getActiveAndPostponedBugs($productIdList, $executionID, $pager);
- }
- else
- {
- if($queryID)
- {
- $query = $this->loadModel('search')->getQuery($queryID);
- if($query)
- {
- $this->session->set('importBugQuery', $query->sql);
- $this->session->set('importBugForm', $query->form);
- }
- else
- {
- $this->session->set('importBugQuery', ' 1 = 1');
- }
- }
- else
- {
- if($this->session->importBugQuery === false) $this->session->set('importBugQuery', ' 1 = 1');
- }
- $bugQuery = str_replace("`product` = 'all'", "`product`" . helper::dbIN($productIdList), $this->session->importBugQuery); // Search all execution.
- $bugs = $this->execution->getSearchBugs($productIdList, $executionID, $bugQuery, 'id_desc', $pager);
- }
- return $bugs;
- }
- /**
- * 获取打印看板的数据。
- * Get printed kanban data.
- *
- * @param int $executionID
- * @param array $stories
- * @access protected
- * @return array
- */
- protected function getPrintKanbanData($executionID, $stories)
- {
- $kanbanTasks = $this->execution->getKanbanTasks($executionID, "id");
- $kanbanBugs = $this->loadModel('bug')->getExecutionBugs($executionID);
- $users = array();
- $taskAndBugs = array();
- foreach($kanbanTasks as $task)
- {
- $status = $task->status;
- $users[] = $task->assignedTo;
- $taskAndBugs[$status]["task{$task->id}"] = $task;
- }
- foreach($kanbanBugs as $bug)
- {
- $status = $bug->status;
- $status = $status == 'active' ? 'wait' : ($status == 'resolved' ? ($bug->resolution == 'postponed' ? 'cancel' : 'done') : $status);
- $users[] = $bug->assignedTo;
- $taskAndBugs[$status]["bug{$bug->id}"] = $bug;
- }
- $dataList = array();
- $contents = array('story', 'wait', 'doing', 'done', 'cancel');
- foreach($contents as $content)
- {
- if($content != 'story' and !isset($taskAndBugs[$content])) continue;
- $dataList[$content] = $content == 'story' ? $stories : $taskAndBugs[$content];
- }
- return array($dataList, $users);
- }
- /**
- * 处理执行看板数据。
- * Process execution kanban data.
- *
- * @param array $myExecutions
- * @param array $kanbanGroup
- * @param int $projectID
- * @param string $status
- * @access protected
- * @return array
- */
- protected function processExecutionKanbanData($myExecutions, $kanbanGroup, $projectID, $status)
- {
- if(isset($myExecutions[$status]) and count($myExecutions[$status]) > 2)
- {
- foreach($myExecutions[$status] as $executionID => $execution)
- {
- unset($myExecutions[$status][$executionID]);
- $myExecutions[$status][$execution->closedDate] = $execution;
- }
- krsort($myExecutions[$status]);
- $myExecutions[$status] = array_slice($myExecutions[$status], 0, 2, true);
- }
- if(isset($kanbanGroup[$projectID][$status]) and count($kanbanGroup[$projectID][$status]) > 2)
- {
- foreach($kanbanGroup[$projectID][$status] as $executionID => $execution)
- {
- unset($kanbanGroup[$projectID][$status][$executionID]);
- $kanbanGroup[$projectID][$status][$execution->closedDate] = $execution;
- }
- krsort($kanbanGroup[$projectID][$status]);
- $kanbanGroup[$projectID][$status] = array_slice($kanbanGroup[$projectID][$status], 0, 2);
- }
- return array($myExecutions, $kanbanGroup);
- }
- /**
- * 处理打印的看板数据。
- * Process printed Kanban data.
- *
- * @param int $executionID
- * @param array $dataList
- * @access protected
- * @return array
- */
- protected function processPrintKanbanData($executionID, $dataList)
- {
- $prevKanbans = $this->execution->getPrevKanban($executionID);
- foreach($dataList as $type => $data)
- {
- if(isset($prevKanbans[$type]))
- {
- $prevData = $prevKanbans[$type];
- foreach($prevData as $id)
- {
- if(isset($data[$id])) unset($dataList[$type][$id]);
- }
- }
- }
- return $dataList;
- }
- /**
- * Check if the product has multiple branch and check if the execution has a product with multiple branch.
- *
- * @param int $productID
- * @param int $executionID
- * @return bool
- */
- protected function hasMultipleBranch($productID, $executionID)
- {
- /* Check if the product is multiple branch. */
- $multiBranchProduct = false;
- if($productID)
- {
- $product = $this->loadModel('product')->getByID($productID);
- if($product->type != 'normal') $multiBranchProduct = true;
- }
- else
- {
- $executionProductList = $this->loadModel('product')->getProducts($executionID);
- foreach($executionProductList as $executionProduct)
- {
- if($executionProduct->type != 'normal')
- {
- $multiBranchProduct = true;
- break;
- }
- }
- }
- return $multiBranchProduct;
- }
- /**
- * 通过模块,方法和类型生成执行的链接。
- * Generate the link of execution by module, method and type.
- *
- * @param string $module
- * @param string $method
- * @param string $type
- * @access protected
- * @return string
- */
- protected function getLink($module, $method, $type = '')
- {
- $executionModules = array('task', 'testcase', 'build', 'bug', 'case', 'testtask', 'testreport', 'doc');
- if(in_array($module, array('task', 'testcase', 'story', 'testtask')) && in_array($method, array('view', 'edit', 'batchedit', 'create', 'batchcreate', 'report', 'batchrun', 'groupcase'))) $method = $module;
- if(in_array($module, $executionModules) && in_array($method, array('view', 'edit', 'create'))) $method = $module;
- if(in_array($module, array_merge($executionModules, array('story', 'product')))) $module = 'execution';
- if($module == 'execution' && $method == 'create') return '';
- if($this->config->edition != 'open')
- {
- $flow = $this->loadModel('workflow')->getByModule($module);
- if(!empty($flow) && in_array($flow->app, array('scrum', 'waterfall', 'kanbanProject'))) $flow->app = 'project';
- if(!empty($flow) && $flow->buildin == '0') return helper::createLink('flow', 'ajaxSwitchBelong', "objectID=%s&moduleName=$module") . "#app=$flow->app";
- }
- $link = helper::createLink($module, $method, "executionID=%s");
- if($module == 'execution' && ($method == 'index' || $method == 'all'))
- {
- $link = helper::createLink($module, 'task', "executionID=%s");
- }
- elseif($module == 'execution' && $method == 'storyview')
- {
- $link = helper::createLink($module, 'story', "executionID=%s");
- }
- elseif($module == 'execution' && in_array($method, array('kanban', 'cfd')))
- {
- $link = helper::createLink($module, 'view', "executionID=%s");
- }
- elseif($module == 'execution' && $method == 'autoschedule')
- {
- $link = helper::createLink('task', 'autoSchedule', "executionID=%s");
- }
- elseif($module == 'bug' && $method == 'create' && $this->app->tab == 'execution')
- {
- $link = helper::createLink($module, $method, "productID=0&branch=0&executionID=%s");
- }
- elseif(in_array($module, array('bug', 'case', 'testtask', 'testreport')) && strpos(',view,edit,', ",$method,") !== false)
- {
- $link = helper::createLink('execution', $module, "executionID=%s");
- }
- elseif($module == 'repo' && $method == 'review')
- {
- $link = helper::createLink('repo', 'review', "repoID=0&browseType=all&executionID=%s") . '#app=execution';
- }
- elseif($module == 'repo')
- {
- $link = helper::createLink('repo', 'browse', "repoID=0&branchID=&executionID=%s");
- }
- elseif($module == 'mr')
- {
- $link = helper::createLink('mr', 'browse', "repoID=0&mode=status¶m=opened&objectID=%s") . '#app=execution';
- }
- elseif($module == 'doc')
- {
- $link = helper::createLink('doc', $method, "type=execution&objectID=%s&from=execution");
- }
- elseif($module == 'pssp')
- {
- $link = helper::createLink($module, 'browse', "projectID=%s") . "#app={$this->app->tab}";
- }
- elseif(in_array($module, array('issue', 'risk', 'opportunity', 'auditplan', 'nc', 'meeting')))
- {
- $link = helper::createLink($module, 'browse', "executionID=%s&from=execution");
- }
- elseif(($module == 'testreport' && $method == 'create') || ($module == 'execution' && $method == 'cases'))
- {
- $link = helper::createLink('execution', 'testtask', "executionID=%s");
- }
- elseif($method == 'zerocase')
- {
- $link = helper::createLink('execution', 'testcase', "executionID=%s");
- }
- elseif($method == 'createrelation')
- {
- $link = helper::createLink('execution', 'relation', "executionID=%s");
- }
- elseif($module == 'project' && $method == 'deliverablechecklist')
- {
- $link = helper::createLink('project', 'deliverableChecklist', "projectID=%s") . "#app={$this->app->tab}";
- }
- if($type != '') $link .= "&type=$type";
- return $link;
- }
- /**
- * 设置cookie和session。
- * Set the cookie and session.
- *
- * @param string $executionID
- * @param string $type all|byModule|byProduct|byBranch|bySearch
- * @param string $param
- * @param string $orderBy
- * @access protected
- * @return int
- */
- protected function setStorageForStory($executionID, $type, $param, $orderBy)
- {
- $productID = 0;
- if($this->cookie->storyPreExecutionID != $executionID)
- {
- $_COOKIE['storyModuleParam'] = $_COOKIE['storyProductParam'] = $_COOKIE['storyBranchParam'] = 0;
- helper::setcookie('storyModuleParam', '0');
- helper::setcookie('storyProductParam', '0');
- helper::setcookie('storyBranchParam', '0');
- }
- if($type == 'bymodule')
- {
- $module = $this->loadModel('tree')->getByID((int)$param);
- $productID = isset($module->root) ? $module->root : 0;
- helper::setcookie('storyModuleParam', $param);
- helper::setcookie('storyProductParam', '0');
- helper::setcookie('storyBranchParam', '0');
- }
- elseif($type == 'byproduct')
- {
- $productID = $param;
- helper::setcookie('storyModuleParam', '0');
- helper::setcookie('storyProductParam', $param);
- helper::setcookie('storyBranchParam', '0');
- }
- elseif($type == 'bybranch')
- {
- helper::setcookie('storyModuleParam', '0');
- helper::setcookie('storyProductParam', '0');
- helper::setcookie('storyBranchParam', $param);
- }
- $this->session->set('executionStoryBrowseType', $type);
- $this->session->set('storyBrowseType', $type, 'execution');
- $uri = $this->app->getURI(true);
- $this->session->set('storyList', $uri, $this->app->tab);
- $this->session->set('executionStoryList', $uri, 'execution');
- helper::setcookie('executionStoryOrder', $orderBy);
- helper::setcookie('storyPreExecutionID', $executionID);
- if($this->app->tab == 'project' && $this->cookie->storyProductParam != $productID) helper::setcookie('storyProductParam', '0');
- return (int)$productID;
- }
- /**
- * Set the more link of user and return users with echo role.
- *
- * @param mixed $execution
- * @return array
- */
- protected function setUserMoreLink($execution = null)
- {
- $appendPo = $appendPm = $appendQd = $appendRd = array();
- if(is_array($execution))
- {
- $appendPo = $appendPm = $appendQd = $appendRd = array();
- foreach($execution as $item)
- {
- $appendPo[$item->PO] = $item->PO;
- $appendPm[$item->PM] = $item->PM;
- $appendQd[$item->QD] = $item->QD;
- $appendRd[$item->RD] = $item->RD;
- }
- }
- elseif(is_object($execution))
- {
- $appendPo[$execution->PO] = $execution->PO;
- $appendPm[$execution->PM] = $execution->PM;
- $appendQd[$execution->QD] = $execution->QD;
- $appendRd[$execution->RD] = $execution->RD;
- }
- $this->loadModel('user');
- $pmUsers = $this->user->getPairs('noclosed|nodeleted|pmfirst', $appendPm, $this->config->maxCount);
- if(!empty($this->config->user->moreLink)) $this->config->moreLinks["PM"] = $this->config->user->moreLink;
- $poUsers = $this->user->getPairs('noclosed|nodeleted|pofirst', $appendPo, $this->config->maxCount);
- if(!empty($this->config->user->moreLink)) $this->config->moreLinks["PO"] = $this->config->user->moreLink;
- $qdUsers = $this->user->getPairs('noclosed|nodeleted|qdfirst', $appendQd, $this->config->maxCount);
- if(!empty($this->config->user->moreLink)) $this->config->moreLinks["QD"] = $this->config->user->moreLink;
- $rdUsers = $this->user->getPairs('noclosed|nodeleted|devfirst', $appendRd, $this->config->maxCount);
- if(!empty($this->config->user->moreLink)) $this->config->moreLinks["RD"] = $this->config->user->moreLink;
- return array($pmUsers, $poUsers, $qdUsers, $rdUsers);
- }
- /**
- * 初始化创建执行的字段。
- * Init execution fields for create.
- *
- * @param int $projectID
- * @param array $output
- * @access protected
- * @return object
- */
- protected function initFieldsForCreate($projectID, $output = array())
- {
- $execution = new stdclass();
- $execution->project = $projectID;
- $execution->type = zget($output, 'type', 'sprint');
- $execution->name = '';
- $execution->code = '';
- $execution->team = '';
- $execution->acl = 'private';
- $execution->whitelist = '';
- $this->view->execution = $execution;
- return $execution;
- }
- /**
- * 通过复制执行ID设置字段值。
- * Set execution fields by copy execution id.
- *
- * @param object $fields
- * @param int $copyExecutionID
- * @access protected
- * @return object
- */
- protected function setFieldsByCopyExecution($fields, $copyExecutionID)
- {
- if(empty($copyExecutionID)) return $fields;
- $copyExecution = $this->execution->fetchByID($copyExecutionID);
- $fields->project = (int)$copyExecution->project;
- $fields->type = $copyExecution->type;
- $fields->name = $copyExecution->name;
- $fields->code = $copyExecution->code;
- $fields->team = $copyExecution->team;
- $fields->acl = $copyExecution->acl;
- $fields->whitelist = $copyExecution->whitelist;
- $this->view->execution = $copyExecution;
- return $fields;
- }
- /**
- * 获取已关联的产品。
- * Get can link products.
- *
- * @param int $copyExecutionID
- * @param int $planID
- * @param object|null $project
- * @access protected
- * @return array
- */
- protected function getLinkedProducts($copyExecutionID, $planID, $project)
- {
- $products = array();
- if($copyExecutionID) $products = $this->loadModel('product')->getProducts($copyExecutionID);
- if($planID)
- {
- $plan = $this->loadModel('productplan')->fetchByID($planID);
- if($plan->begin == $this->config->productplan->future) $plan->begin = '';
- if($plan->end == $this->config->productplan->future) $plan->end = '';
- $products = $this->dao->select('t1.id, t1.name, t1.type, t2.branch')->from(TABLE_PRODUCT)->alias('t1')
- ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id = t2.product')
- ->where('t1.id')->eq($plan->product)
- ->fetchAll('id');
- $this->view->plan = $plan;
- }
- if(isset($project->hasProduct) && empty($project->hasProduct))
- {
- $product = $this->loadModel('product')->getShadowProductByProject($project->id);
- $products = array($product->id => $product->name);
- }
- return $products;
- }
- /**
- * 获取已关联的分支。
- * Set linked branches.
- *
- * @param array $products
- * @param int $copyExecutionID
- * @param int $planID
- * @param object|null $project
- * @access protected
- * @return void
- */
- protected function setLinkedBranches($products, $copyExecutionID, $planID, $project)
- {
- $projectID = empty($project) ? 0 : $project->id;
- if(!empty($copyExecutionID))
- {
- $branches = $this->project->getBranchesByProject($copyExecutionID);
- $plans = $this->loadModel('productplan')->getGroupByProduct(array_keys($products), 'skipparent|unexpired');
- $branchGroups = $this->execution->getBranchByProduct(array_keys($products), $projectID);
- }
- if(!empty($project) and $project->stageBy == 'project')
- {
- $products = $this->loadModel('product')->getProducts($project->id);
- $branches = $this->project->getBranchesByProject($projectID);
- $plans = $this->loadModel('productplan')->getGroupByProduct(array_keys($products), 'skipparent|unexpired');
- }
- if($products and isset($branches))
- {
- $linkedBranches = array();
- foreach($products as $productIndex => $product)
- {
- $productPlans[$productIndex] = array();
- foreach($branches[$productIndex] as $branchID => $branch)
- {
- $linkedBranches[$productIndex][$branchID] = $branchID;
- if(isset($plans[$productIndex][$branchID]))
- {
- foreach($plans[$productIndex][$branchID] as $plan) $productPlans[$productIndex][$branchID][$plan->id] = $plan->title;
- }
- }
- }
- $this->view->productPlans = $productPlans;
- $this->view->linkedBranches = $linkedBranches;
- }
- if(!empty($planID))
- {
- $plan = $this->loadModel('productplan')->fetchByID($planID);
- $productPlan = $this->productplan->getPairs($plan->product, $plan->branch, 'unexpired|withMainPlan', true);
- $linkedBranches = array();
- $linkedBranches[$plan->product][$plan->branch] = $plan->branch;
- $this->view->linkedBranches = $linkedBranches;
- }
- $this->view->productPlan = isset($productPlan) ? $productPlan : array();
- $this->view->branchGroups = isset($branchGroups) ? $branchGroups : $this->execution->getBranchByProduct(array_keys($products), $projectID);
- if(isset($project->hasProduct) and empty($project->hasProduct))
- {
- $shadowProduct = $this->loadModel('product')->getShadowProductByProject($project->id);
- $this->view->productPlan = $this->loadModel('productplan')->getPairs($shadowProduct->id ?? 0, '0,0', 'noclosed,unexpired', true);
- }
- }
- /**
- * 根据项目获取可关联的产品。
- * Get all products for create.
- *
- * @param object|null $project
- * @access protected
- * @return void
- */
- protected function getAllProductsForCreate($project)
- {
- if(empty($project)) return array();
- $allProducts = $this->loadModel('product')->getProductPairsByProject($project->id, 'noclosed');
- if(!empty($project->hasProduct)) $allProducts = array(0 => '') + $allProducts;
- return $allProducts;
- }
- /**
- * 设置可复制的执行。
- * Set copy projects.
- *
- * @param object|null $project
- * @access protected
- * @return void
- */
- protected function setCopyProjects($project)
- {
- $parentProject = 0;
- $projectModel = '';
- if($project)
- {
- $parentProject = $project->parent;
- $projectModel = $project->model;
- if($projectModel == 'agileplus') $projectModel = array('scrum', 'agileplus');
- if($projectModel == 'waterfallplus') $projectModel = array('waterfall', 'waterfallplus');
- }
- $copyProjects = $this->loadModel('project')->getPairsByProgram($parentProject, 'noclosed', false, 'order_asc', '', $projectModel, 'multiple');
- $copyProjectID = empty($project) ? key($copyProjects) : $project->id;
- $this->view->copyProjects = $copyProjects;
- $this->view->copyProjectID = $copyProjectID;
- $this->view->copyExecutions = empty($copyProjectID) ? array() : $this->execution->getList($copyProjectID, 'all', 'all', 0, 0, 0, null, false);
- }
- /**
- * 修正executionCommon公共语言项。
- * Correct execution common lang.
- *
- * @param object $project
- * @param string $type
- * @access protected
- * @return bool
- */
- protected function correctExecutionCommonLang($project, $type)
- {
- if(empty($project)) return false;
- if($project->model == 'kanban')
- {
- global $lang;
- $executionLang = $lang->execution->common;
- $executionCommonLang = $lang->executionCommon;
- $lang->executionCommon = $lang->execution->kanban;
- $lang->execution->common = $lang->execution->kanban;
- include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
- $lang->execution->common = $executionLang;
- $lang->executionCommon = $executionCommonLang;
- $lang->execution->typeList['sprint'] = $executionCommonLang;
- }
- elseif($project->model == 'waterfall' || $project->model == 'waterfallplus')
- {
- $this->app->loadLang('stage');
- global $lang;
- $lang->executionCommon = $lang->execution->stage;
- include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
- }
- if(isset($project->hasProduct) and empty($project->hasProduct)) $this->lang->execution->PO = $this->lang->common->story . $this->lang->execution->owner;
- return true;
- }
- /**
- * 修正错误提示语言。
- * Correct error lang.
- *
- * @access protected
- * @return void
- */
- protected function correctErrorLang()
- {
- $this->lang->execution->team = $this->lang->execution->teamName;
- $this->lang->error->unique = $this->lang->error->repeat;
- /* Redefines the language entries for the fields in the project table. */
- foreach(explode(',', $this->config->execution->create->requiredFields) as $field)
- {
- if(isset($this->lang->execution->$field)) $this->lang->project->$field = $this->lang->execution->$field;
- }
- /* Replace required language. */
- if($this->app->tab == 'project')
- {
- $this->lang->project->name = $this->lang->execution->name;
- $this->lang->project->code = $this->lang->execution->code;
- }
- else
- {
- $this->lang->project->name = $this->lang->execution->execName;
- $this->lang->project->code = $this->lang->execution->execCode;
- }
- }
- /**
- * 创建执行后,显示提示页面。
- * Display after created.
- *
- * @param int $projectID
- * @param int $executionID
- * @param int $planID
- * @param string $confirm
- * @access protected
- * @return void
- */
- protected function displayAfterCreated($projectID, $executionID, $planID, $confirm = 'no')
- {
- $execution = $this->execution->fetchByID($executionID);
- if(!empty($planID) and $execution->lifetime != 'ops')
- {
- if($confirm == 'yes')
- {
- $this->execution->linkStories($executionID);
- }
- else
- {
- $executionProductList = $this->loadModel('product')->getProducts($executionID);
- $multiBranchProduct = false;
- array_map(function($executionProduct) use(&$multiBranchProduct){if($executionProduct->type != 'normal') $multiBranchProduct = true;}, $executionProductList);
- $storyType = '';
- $project = $this->loadModel('project')->fetchByID($projectID);
- if($project)
- {
- $this->loadModel('story');
- foreach(explode(',', $project->storyType) as $type) $storyType .= $this->lang->story->typeList[$type] . ', ';
- }
- if(empty($storyType)) $storyType = $this->lang->story->common;
- $importPlanStoryTips = sprintf($multiBranchProduct ? $this->lang->execution->importBranchPlanStory : $this->lang->execution->importPlanStory, trim($storyType, ', '));
- if($execution->type == 'stage') $importPlanStoryTips = str_replace($this->lang->executionCommon, $this->lang->execution->stage, $importPlanStoryTips);
- $confirmURL = inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=$planID&confirm=yes");
- $cancelURL = inlink('create', "projectID=$projectID&executionID=$executionID");
- return $this->send(array('result' => 'success', 'open' => array('confirm' => $importPlanStoryTips, 'url' => $confirmURL, 'canceled' => $cancelURL)));
- }
- }
- if(!empty($projectID) and $execution->type == 'kanban' and $this->app->tab == 'project') return $this->send(array('result' => 'success', 'load' => $this->createLink('project', 'index', "projectID=$projectID")));
- if(!empty($projectID) and $execution->type == 'kanban') return $this->send(array('result' => 'success', 'load' => inlink('kanban', "executionID=$executionID")));
- $this->view->title = $this->lang->execution->tips;
- $this->view->executionID = $executionID;
- $this->view->execution = $this->execution->fetchByID($executionID);
- $this->display('execution', 'tips');
- }
- /**
- * 更新迭代关联的计划。
- * Update linked plans.
- *
- * @param int $executionID
- * @param string $newPlans
- * @param string $confirm
- * @return void
- */
- protected function updateLinkedPlans($executionID, $newPlans = '', $confirm = 'no')
- {
- $projectID = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->fetch('project');
- if(!empty($newPlans) and $confirm == 'yes')
- {
- $newPlans = explode(',', $newPlans);
- $this->loadModel('productplan')->linkProject($executionID, $newPlans);
- $this->productplan->linkProject($projectID, $newPlans);
- return $this->send(array('result' => 'success', 'load' => inlink('view', "executionID=$executionID")));
- }
- elseif(!empty($newPlans))
- {
- $executionProductList = $this->loadModel('product')->getProducts($executionID); /* 无论是迭代ID还是项目ID都会查到一个与之对应的产品。*/
- $multiBranchProduct = false;
- foreach($executionProductList as $executionProduct)
- {
- if($executionProduct->type != 'normal')
- {
- $multiBranchProduct = true;
- break;
- }
- }
- $storyType = '';
- $project = $this->loadModel('project')->fetchByID($projectID);
- if($project)
- {
- $this->loadModel('story');
- foreach(explode(',', $project->storyType) as $type) $storyType .= $this->lang->story->typeList[$type] . ', ';
- }
- if(empty($storyType)) $storyType = $this->lang->story->common;
- $linkPlanMsg = sprintf($multiBranchProduct ? $this->lang->execution->importBranchEditPlanStory : $this->lang->execution->importEditPlanStory, trim($storyType, ', '));
- $confirmURL = inlink('edit', "executionID=$executionID&action=edit&extra=&newPlans=$newPlans&confirm=yes");
- $cancelURL = inlink('view', "executionID=$executionID");
- return $this->send(array('result' => 'success', 'load' => array('confirm' => $linkPlanMsg, 'confirmed' => $confirmURL, 'canceled' => $cancelURL)));
- }
- }
- /**
- * Check if the execution can be linked to plan stories.
- *
- * @param int $executionID
- * @param array $oldPlans
- * @return void
- */
- protected function checkLinkPlan($executionID, $oldPlans)
- {
- $oldPlans = explode(',', implode(',' ,$oldPlans));
- $newPlans = array();
- if(isset($_POST['plans']))
- {
- foreach((array)$_POST['plans'] as $plans)
- {
- foreach($plans as $planID)
- {
- if(array_search($planID, $oldPlans) === false) $newPlans[$planID] = $planID;
- }
- }
- }
- $newPlans = array_filter($newPlans);
- if(!empty($newPlans))
- {
- $newPlans = implode(',', $newPlans);
- return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('edit', "executionID=$executionID&action=edit&extra=&newPlans=$newPlans&confirm=no")));
- }
- }
- /**
- * 获取执行关联的对象,如关联的产品、分支、需求等。
- * Get linked objects of this execution.
- *
- * @param object $execution
- * @return object
- */
- protected function getLinkedObjects($execution)
- {
- $this->loadModel('project');
- $this->loadModel('product');
- $this->loadModel('productplan');
- $branches = $this->project->getBranchesByProject($execution->id);
- $linkedProductIdList = empty($branches) ? '' : array_keys($branches);
- $allProducts = $this->product->getProducts($execution->project, 'noclosed', '', false, $linkedProductIdList);
- $productPlans = $linkedBranches = $linkedBranchList = array();
- $linkedProducts = $this->product->getProducts($execution->id, 'all', '', true, $linkedProductIdList, false);
- $plans = $this->productplan->getGroupByProduct(array_keys($linkedProducts), 'skipparent|unexpired');
- $executionStories = $this->project->getStoriesByProject($execution->id);
- /* If the story of the product which linked the execution, you don't allow to remove the product. */
- $unmodifiableProducts = $unmodifiableBranches = $linkedStoryIDList = array();
- foreach($linkedProducts as $productID => $linkedProduct)
- {
- if(!isset($allProducts[$productID])) $allProducts[$productID] = $linkedProduct->deleted ? $linkedProduct->name . "({$this->lang->product->deleted})" : $linkedProduct->name;
- $productPlans[$productID] = array();
- foreach($branches[$productID] as $branchID => $branch)
- {
- if(isset($plans[$productID][$branchID]))
- {
- foreach($plans[$productID][$branchID] as $plan) $productPlans[$productID][$branchID][$plan->id] = $plan->title;
- }
- $linkedBranchList[$branchID] = $branchID;
- $linkedBranches[$productID][$branchID] = $branchID;
- if($branchID != BRANCH_MAIN && isset($plans[$productID][BRANCH_MAIN]))
- {
- foreach($plans[$productID][BRANCH_MAIN] as $plan) $productPlans[$productID][BRANCH_MAIN][$plan->id] = $plan->title;
- }
- if(!empty($executionStories[$productID][$branchID]))
- {
- array_push($unmodifiableProducts, $productID);
- array_push($unmodifiableBranches, $branchID);
- $linkedStoryIDList[$productID][$branchID] = $executionStories[$productID][$branchID]->storyIDList;
- }
- }
- if(!empty($linkedProduct->plans))
- {
- foreach($linkedProduct->plans as $linkedPlans)
- {
- $planList = explode(',', $linkedPlans);
- $planList = array_filter($planList);
- foreach($planList as $planID)
- {
- if(isset($plans[$productID][$planID])) continue;
- $productPlans[$productID][$branchID][$planID] = '';
- }
- }
- }
- }
- $productPlan = array();
- if(!empty($planID))
- {
- $plan = $this->productplan->fetchByID((int)$planID);
- $productPlan = $this->productplan->getPairs($plan->product, $plan->branch, 'unexpired|withMainPlan', true);
- }
- $productPlansOrder = array();
- foreach($productPlans as $productID => $branchPlans)
- {
- foreach($branchPlans as $branchID => $plans)
- {
- $orderPlans = $this->loadModel('productplan')->getByIDList(array_keys($plans));
- $orderPlans = $this->productplan->relationBranch($orderPlans);
- $orderPlansMap = array_keys($orderPlans);
- foreach($orderPlansMap as $planMapID)
- {
- if(empty($plans[$planMapID])) $productPlans[$productID][$branchID][$planMapID] = $orderPlans[$planMapID]->title;
- $productPlansOrder[$productID][$branchID][$planMapID] = $productPlans[$productID][$branchID][$planMapID];
- }
- }
- }
- $linkedObjects = new stdclass();
- $linkedObjects->currentPlan = !empty($planID) ? $planID : 0;
- $linkedObjects->productPlan = $productPlan;
- $linkedObjects->allProducts = $allProducts;
- $linkedObjects->linkedProducts = $linkedProducts;
- $linkedObjects->productPlans = array_filter($productPlansOrder);
- $linkedObjects->linkedBranches = $linkedBranches;
- $linkedObjects->linkedBranchList = $linkedBranchList;
- $linkedObjects->linkedStoryIDList = $linkedStoryIDList;
- $linkedObjects->unmodifiableProducts = $unmodifiableProducts;
- $linkedObjects->unmodifiableBranches = $unmodifiableBranches;
- return $linkedObjects;
- }
- /**
- * 获取创建执行后的跳转地址。
- * Get location after create.
- *
- * @param int $projectID
- * @param int $executionID
- * @param string $model
- * @access protected
- * @return string
- */
- protected function getAfterCreateLocation($projectID, $executionID, $model = '')
- {
- if($this->app->tab == 'doc') return $this->createLink('doc', 'projectSpace', "objectID=$executionID");
- if(!empty($_POST['plans'])) return inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=1&confirm=no");
- if(!empty($projectID) and $model == 'kanban')
- {
- if($this->app->tab == 'project') return $this->config->vision != 'lite' ? $this->createLink('project', 'index', "projectID=$projectID") : $this->createLink('project', 'execution', "status=all&projectID=$projectID");
- return inlink('kanban', "executionID=$executionID");
- }
- $execution = $this->execution->fetchByID($executionID);
- if(!empty($execution->isTpl)) return inlink('task', "executionID=$executionID");
- return inlink('create', "projectID=$projectID&executionID=$executionID");
- }
- }
|