diff --git a/db/update18.8.sql b/db/update18.8.sql index a11b288cad..067f31616f 100644 --- a/db/update18.8.sql +++ b/db/update18.8.sql @@ -1 +1,3 @@ ALTER TABLE `zt_mr` ADD executionID mediumint(8) unsigned NOT NULL DEFAULT 0 AFTER `jobID`; +ALTER TABLE `zt_testtask` ADD COLUMN `members` text NULL; +UPDATE `zt_solutions` SET `deleted` = '0' WHERE `deleted` = ''; diff --git a/lib/base/dao/dao.class.php b/lib/base/dao/dao.class.php index 476746283f..1b6dde94dd 100644 --- a/lib/base/dao/dao.class.php +++ b/lib/base/dao/dao.class.php @@ -1578,6 +1578,24 @@ class baseSQL */ public $conditionIsTrue = false; + /** + * 条件层级。 + * The condition level. + * + * @var bool + * @access public; + */ + public $conditionLevel = 0; + + /** + * 条件结果,beginIF 中表达式的结果会存储到这个数组中。 + * Store the result of the expression. + * + * @var bool + * @access public; + */ + public $conditionResults = array(); + /** * WHERE条件嵌套小括号标记。 * If in mark or not. @@ -1889,7 +1907,9 @@ class baseSQL public function beginIF($condition) { $this->inCondition = true; - $this->conditionIsTrue = $condition; + $this->conditionLevel += 1; + $this->conditionResults[$this->conditionLevel] = $condition; + $this->conditionIsTrue = !in_array(false, $this->conditionResults); return $this; } @@ -1902,6 +1922,14 @@ class baseSQL */ public function fi() { + unset($this->conditionResults[$this->conditionLevel]); + $this->conditionLevel -= 1; + if($this->conditionLevel > 0) + { + $this->conditionIsTrue = !in_array(false, $this->conditionResults); + return $this; + } + $this->inCondition = false; $this->conditionIsTrue = false; return $this; diff --git a/module/block/control.php b/module/block/control.php index b91a1fa924..943a9e19dc 100755 --- a/module/block/control.php +++ b/module/block/control.php @@ -980,12 +980,14 @@ class block extends control $this->app->loadLang('story'); $this->app->loadLang('bug'); + $this->loadModel('program')->refreshStats(); + /* Set project status and count. */ $status = isset($this->params->type) ? $this->params->type : 'all'; $count = isset($this->params->count) ? (int)$this->params->count : 15; /* Get projects. */ - $projects = $this->project->getOverviewList('byStatus', $status, 'order_asc', $count, ''); + $projects = $this->project->getOverviewList('byStatus', $status, 'order_asc', $count, ''); if(empty($projects)) { $this->view->projects = $projects; @@ -1031,7 +1033,6 @@ class block extends control $project->cv = $this->weekly->getCV($project->ev, $project->ac); $left = (float)$this->weekly->getLeft($project->id, $today); - $project->progress = ($project->ac + $left) ? floor($project->ac / ($project->ac + $left) * 1000) / 1000 * 100 : 0; $project->progress = $project->progress > 100 ? 100 : $project->progress; $project->current = $current; } @@ -1282,6 +1283,9 @@ class block extends control public function printWaterfallReportBlock() { $this->app->loadLang('programplan'); + + $this->loadModel('program')->refreshStats(); + $project = $this->loadModel('project')->getByID($this->session->project); $today = helper::today(); $date = date('Ymd', strtotime('this week Monday')); @@ -1298,9 +1302,8 @@ class block extends control $this->view->sv = $this->weekly->getSV($this->view->ev, $this->view->pv); $this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac); - $left = (float)$this->weekly->getLeft($this->session->project, $today); - $progress = ($this->view->ac + $left) ? floor($this->view->ac / ($this->view->ac + $left) * 1000) / 1000 * 100 : 0; - $this->view->progress = $progress > 100 ? 100 : $progress; + $left = (float)$this->weekly->getLeft($this->session->project, $today); + $this->view->progress = $project->progress > 100 ? 100 : $project->progress; $this->view->current = $current; } diff --git a/module/block/view/recentprojectblock.html.php b/module/block/view/recentprojectblock.html.php index cd3e14a250..c61426f361 100644 --- a/module/block/view/recentprojectblock.html.php +++ b/module/block/view/recentprojectblock.html.php @@ -101,7 +101,7 @@
createLink('execution', 'task', "executionID={$project->id}"), $project->name);?>
-
+
progress;?>%
diff --git a/module/caselib/control.php b/module/caselib/control.php index 8b2b5da1bc..c07ca9560d 100644 --- a/module/caselib/control.php +++ b/module/caselib/control.php @@ -529,16 +529,16 @@ class caselib extends control $columnKey[] = $fields[$title]; } - if(count($columnKey) != count($header) or $this->post->encode != 'utf-8') + if(count($columnKey) <= 3 or $this->post->encode != 'utf-8') { - $fc = file_get_contents($fileName); $encode = $this->post->encode != "utf-8" ? $this->post->encode : 'gbk'; + $fc = file_get_contents($fileName); $fc = helper::convertEncoding($fc, $encode, 'utf-8'); file_put_contents($fileName, $fc); $rows = $this->file->parseCSV($fileName); $columnKey = array(); - $header = array(); + $header = array(); foreach($rows[0] as $i => $rowValue) { if(empty($rowValue)) break; @@ -550,7 +550,7 @@ class caselib extends control if(!isset($fields[$title])) continue; $columnKey[] = $fields[$title]; } - if(count($columnKey) != count($header)) return print(js::alert($this->lang->testcase->errorEncode)); + if(count($columnKey) == 0) return print(js::alert($this->lang->testcase->errorEncode)); } $this->session->set('fileImport', $fileName); diff --git a/module/caselib/view/showimport.html.php b/module/caselib/view/showimport.html.php index 46170f0fa3..882b0d9154 100644 --- a/module/caselib/view/showimport.html.php +++ b/module/caselib/view/showimport.html.php @@ -29,13 +29,14 @@ $(function() testcase->id?> - testcase->title?> - testcase->module?> - testcase->pri?> - testcase->type?> - testcase->stage?> - testcase->keywords?> - testcase->precondition?> + ' id='title'> testcase->title?> + ' id='module'> testcase->module?> + ' id='pri'> testcase->pri?> + ' id='type'> testcase->type?> + ' id='stage'> testcase->stage?> + ' id='keywords'> testcase->keywords?> + ' id='precondition'>testcase->precondition?> + col-content'> diff --git a/module/common/model.php b/module/common/model.php index 3b907be598..e6f62503cd 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -585,7 +585,7 @@ class commonModel extends model echo "
  • {$lang->switchTo}
  • "; foreach($userVisions as $vision) { - echo ($currentVision == $vision ? '
  • ' : '
  • ') . html::a(helper::createLink('my', 'ajaxSwitchVision', "vision=$vision"), $lang->visionList[$vision], '', "data-type='ajax'") . '
  • '; + if(isset($lang->visionList[$vision])) echo ($currentVision == $vision ? '
  • ' : '
  • ') . html::a(helper::createLink('my', 'ajaxSwitchVision', "vision=$vision"), $lang->visionList[$vision], '', "data-type='ajax'") . '
  • '; } echo ''; diff --git a/module/common/view/kanban.html.php b/module/common/view/kanban.html.php index 04818b6019..bd94badc4c 100644 --- a/module/common/view/kanban.html.php +++ b/module/common/view/kanban.html.php @@ -197,7 +197,7 @@ function renderProjectItem(item, $item) { $progress = $('
    ').appendTo($item); } - var progress = Math.max(0, Math.min(100, Math.round(item.hours && !Array.isArray(item.hours) ? Math.round(item.hours.progress || 0) : 0))); + var progress = Math.max(0, Math.min(100, Math.round(item.progress ? Math.round(item.progress || 0) : 0))); $progress.find('span').text(progress); $progress.css('background-position-x', -Math.ceil(progress / 2) * 24); $item.addClass('has-progress'); diff --git a/module/doc/css/edit.css b/module/doc/css/edit.css index cc929ee0b3..c9b8ab7575 100644 --- a/module/doc/css/edit.css +++ b/module/doc/css/edit.css @@ -38,5 +38,5 @@ body {overflow: hidden;} #whiteListBox .input-group:last-child {margin-top: 10px;} #mainContent .main-header h2 {width: 90%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;} .fullscreen-save, .markdown-fullscreen-save {position: fixed; top: 10px; right: 30px; z-index: 999999;} - .modal-header .fullscreen-save, .markdown-fullscreen-save {top: 5px; right: 60px;} +#dataform .table tr:last-child {position: fixed; top: 47px;} diff --git a/module/execution/control.php b/module/execution/control.php index 1ea98145fb..462a63c023 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -591,6 +591,9 @@ class execution extends control $executions = $this->execution->getPairs(0, 'all', 'nocode'); $this->execution->setMenu($executionID); + $execution = $this->execution->getByID($executionID); + $project = $this->loadModel('project')->getByID($execution->project); + /* Load pager. */ $this->app->loadClass('pager', $static = true); $pager = new pager($recTotal, $recPerPage, $pageID); @@ -613,13 +616,18 @@ class execution extends control ->leftJoin(TABLE_EXECUTION)->alias('t2') ->on('t1.project = t2.id') ->where('t1.product')->in(array_keys($products)) + ->andWhere('t2.type')->in('sprint,stage,kanban') ->fetchPairs('project'); + + $projects = $this->loadModel('product')->getProjectPairsByProductIDList(array_keys($products)); } else { $executionName = $executions[$executionID]; unset($executions); $executions[$executionID] = $executionName; + + $projects[$project->id] = $project->name; } /* Get bugs.*/ @@ -651,9 +659,6 @@ class execution extends control $bugs = $this->execution->getSearchBugs($products, $executionID, $bugQuery, $pager, 'id_desc'); } - $execution = $this->execution->getByID($executionID); - $project = $this->loadModel('project')->getByID($execution->project); - /* Build the search form. */ $this->config->bug->search['actionURL'] = $this->createLink('execution', 'importBug', "executionID=$executionID&browseType=bySearch¶m=myQueryID"); $this->config->bug->search['queryID'] = $queryID; @@ -687,6 +692,8 @@ class execution extends control } $this->config->bug->search['params']['module']['values'] = $bugModules; + $this->config->bug->search['params']['project']['values'] = array('' => '') + $projects; + unset($this->config->bug->search['fields']['resolvedBy']); unset($this->config->bug->search['fields']['closedBy']); unset($this->config->bug->search['fields']['status']); diff --git a/module/execution/js/task.js b/module/execution/js/task.js index ac3b39baf0..76b796ad2d 100644 --- a/module/execution/js/task.js +++ b/module/execution/js/task.js @@ -93,6 +93,8 @@ function setStatistics() const task = element.getRowInfo(id).data; + if(task.isParent == true) return true; + totalEstimate += Number(task.estimateNum); totalConsumed += Number(task.consumedNum); if(task.statusCode != 'cancel' && task.statusCode != 'closed') totalLeft += Number(task.leftNum); diff --git a/module/execution/model.php b/module/execution/model.php index 6655b4fd8e..2f95610f47 100755 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -2665,6 +2665,19 @@ class executionModel extends model return $execution; } + /** + * Get execution by build id. + * + * @param int $buildID + * @access public + * @return object + */ + public function getByBuild($buildID) + { + $build = $this->loadModel('build')->getById($buildID); + return $this->getById($build->execution); + } + /** * Get the default managers for a execution from it's related products. * diff --git a/module/file/control.php b/module/file/control.php index 1c206247ca..9b150245c3 100755 --- a/module/file/control.php +++ b/module/file/control.php @@ -149,7 +149,7 @@ class file extends control /* Judge the mode, down or open. */ $mode = 'down'; - $fileTypes = 'txt|jpg|jpeg|gif|png|bmp|xml|html'; + $fileTypes = 'txt|jpg|jpeg|gif|png|bmp|xml|html|mp4'; if(stripos($fileTypes, $file->extension) !== false && $mouse == 'left') $mode = 'open'; if($file->extension == 'txt') { @@ -164,11 +164,11 @@ class file extends control /* If the mode is open, locate directly. */ if($mode == 'open') { - if(stripos('txt|jpg|jpeg|gif|png|bmp', $file->extension) !== false) + if(stripos('txt|jpg|jpeg|gif|png|bmp|mp4', $file->extension) !== false) { $this->view->file = $file; $this->view->charset = $this->get->charset ? $this->get->charset : $this->config->charset; - $this->view->fileType = ($file->extension == 'txt') ? 'txt' : 'image'; + $this->view->fileType = $file->extension == 'txt' ? 'txt' : ($file->extension == 'mp4' ? 'video' : 'image'); $this->display(); } else diff --git a/module/file/lang/de.php b/module/file/lang/de.php index 8b0f3820d7..b404172b62 100755 --- a/module/file/lang/de.php +++ b/module/file/lang/de.php @@ -38,6 +38,7 @@ $lang->file->beginUpload = 'Upload'; $lang->file->uploadSuccess = 'Hochgeladen!'; $lang->file->batchExport = 'Export in batches'; $lang->file->downloadFile = 'Download'; +$lang->file->playFailed = 'Video preview failed, please contact admin'; $lang->file->pathname = 'Pfadname'; $lang->file->title = 'Titel'; diff --git a/module/file/lang/en.php b/module/file/lang/en.php index c3aa59cb27..5f9f14173d 100755 --- a/module/file/lang/en.php +++ b/module/file/lang/en.php @@ -38,6 +38,7 @@ $lang->file->beginUpload = 'Click to Upload'; $lang->file->uploadSuccess = 'Uploaded!'; $lang->file->batchExport = 'Export in batches'; $lang->file->downloadFile = 'Download'; +$lang->file->playFailed = 'Video preview failed, please contact admin'; $lang->file->pathname = 'Path Name'; $lang->file->title = 'Title'; diff --git a/module/file/lang/fr.php b/module/file/lang/fr.php index 706179a526..47899858ab 100755 --- a/module/file/lang/fr.php +++ b/module/file/lang/fr.php @@ -38,6 +38,7 @@ $lang->file->beginUpload = 'Clic pour Charger'; $lang->file->uploadSuccess = 'Chargé !'; $lang->file->batchExport = 'Export in batches'; $lang->file->downloadFile = 'Download'; +$lang->file->playFailed = 'Video preview failed, please contact admin'; $lang->file->pathname = 'Nom Chemin'; $lang->file->title = 'Titre'; diff --git a/module/file/lang/vi.php b/module/file/lang/vi.php index a36bee1dc4..f6ff7eddd3 100755 --- a/module/file/lang/vi.php +++ b/module/file/lang/vi.php @@ -33,6 +33,7 @@ $lang->file->addFile = 'Thêm'; $lang->file->beginUpload = 'Click to Upload'; $lang->file->uploadSuccess = 'Uploaded!'; $lang->file->batchExport = 'Export in batches'; +$lang->file->playFailed = 'Video preview failed, please contact admin'; $lang->file->pathname = 'Path tên'; $lang->file->title = 'Tiêu đề'; diff --git a/module/file/lang/zh-cn.php b/module/file/lang/zh-cn.php index b9b3e55a80..c48b87b899 100755 --- a/module/file/lang/zh-cn.php +++ b/module/file/lang/zh-cn.php @@ -38,6 +38,7 @@ $lang->file->beginUpload = '开始上传'; $lang->file->uploadSuccess = '上传成功'; $lang->file->batchExport = '分批导出'; $lang->file->downloadFile = '下载'; +$lang->file->playFailed = '视频预览失败,请联系管理员'; $lang->file->pathname = '路径'; $lang->file->title = '标题'; diff --git a/module/file/view/download.html.php b/module/file/view/download.html.php index ddc0719240..439e3532fc 100644 --- a/module/file/view/download.html.php +++ b/module/file/view/download.html.php @@ -1,8 +1,9 @@ id);?> + +
    @@ -47,14 +53,19 @@

    -
    +
    recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?> - + multiple);?> '> @@ -67,12 +78,6 @@ - $productTasks):?> @@ -80,7 +85,7 @@ status == 'doing') $testingCount ++;?> status == 'blocked') $blockedCount ++;?> status == 'done') $doneCount ++;?> - > + data-status='status;?>'>
    '>testtask->product);?> + +
    + +
    + idAB);?>
    testtask->name);?>
    '> @@ -88,7 +93,11 @@ + + id => sprintf('%03d', $task->id)));?> + id);?> + createLink('testtask', 'cases', "taskID=$task->id"), $task->name, '', "data-app='project'");?> @@ -139,10 +148,22 @@
    +testtask->allSummary, $total, $waitCount, $testingCount, $blockedCount, $doneCount));?> +testtask->checkedAllSummary);?> diff --git a/module/project/view/view.html.php b/module/project/view/view.html.php index 1b81b56971..62aa2bcbf1 100644 --- a/module/project/view/view.html.php +++ b/module/project/view/view.html.php @@ -204,10 +204,9 @@ - model == 'waterfall' ? $this->project->getWaterfallProgress($project->id) : (((float)$workhour->totalConsumed + (float)$workhour->totalLeft) ? floor($workhour->totalConsumed / ((float)$workhour->totalConsumed + (float)$workhour->totalLeft) * 1000) / 1000 * 100 : 0);?> - project->progress;?> percent;?>   + project->progress;?> progress . $lang->percent;?>  
    -
    +
    diff --git a/module/task/config.php b/module/task/config.php index f4ca4b895a..4df61a3465 100644 --- a/module/task/config.php +++ b/module/task/config.php @@ -263,7 +263,7 @@ $config->task->datatable->fieldList['mailto']['required'] = 'no'; $config->task->datatable->fieldList['module']['title'] = 'module'; $config->task->datatable->fieldList['module']['control'] = 'select'; -$config->task->datatable->fieldList['module']['dataSource'] = array('module' => 'tree', 'method' => 'getTaskOptionMenu', 'params' => '$executionID'); +$config->task->datatable->fieldList['module']['dataSource'] = array('module' => 'tree', 'method' => 'getAllModulePairs'); $config->task->datatable->fieldList['module']['display'] = false; $config->task->datatable->fieldList['execution']['title'] = 'execution'; diff --git a/module/testcase/control.php b/module/testcase/control.php index 00e6d7886c..4bb553cfec 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -226,7 +226,7 @@ class testcase extends control $this->config->testcase->search['onMenuBar'] = 'yes'; $searchProducts = $this->product->getPairs('', 0, '', 'all'); - $this->testcase->buildSearchForm($productID, $searchProducts, $queryID, $actionURL, $projectID); + $this->testcase->buildSearchForm($productID, $searchProducts, $queryID, $actionURL, $projectID, 0, $branch); $showModule = !empty($this->config->datatable->testcaseBrowse->showModule) ? $this->config->datatable->testcaseBrowse->showModule : ''; diff --git a/module/testcase/lang/de.php b/module/testcase/lang/de.php index 334ea2933e..5d023e005f 100644 --- a/module/testcase/lang/de.php +++ b/module/testcase/lang/de.php @@ -246,6 +246,7 @@ $lang->testcase->mustChooseResult = 'Prüfungsergebnis wird benötigt.'; $lang->testcase->noModule = '
    Es existieren keine Module
    Jetzt verwalten
    '; $lang->testcase->noCase = 'Keine Fälle. '; $lang->testcase->importedCases = 'The case with ID%s has been imported in the same module and has been ignored.'; +$lang->testcase->importedFromLib = '%s items imported successfully: %s.'; $lang->testcase->searchStories = 'Story suchen'; $lang->testcase->selectLib = 'Bibliothek wählen'; diff --git a/module/testcase/lang/en.php b/module/testcase/lang/en.php index e3179dc8da..5189effcb4 100644 --- a/module/testcase/lang/en.php +++ b/module/testcase/lang/en.php @@ -246,6 +246,7 @@ $lang->testcase->mustChooseResult = 'Review result is required.'; $lang->testcase->noModule = '
    You have no modules.
    Manage it now.
    '; $lang->testcase->noCase = 'No cases yet. '; $lang->testcase->importedCases = 'The case with ID%s has been imported in the same module and has been ignored.'; +$lang->testcase->importedFromLib = '%s items imported successfully: %s.'; $lang->testcase->searchStories = 'Enter to search for stories'; $lang->testcase->selectLib = 'Select Library'; diff --git a/module/testcase/lang/fr.php b/module/testcase/lang/fr.php index 9296750827..295f603f0c 100644 --- a/module/testcase/lang/fr.php +++ b/module/testcase/lang/fr.php @@ -246,6 +246,7 @@ $lang->testcase->mustChooseResult = 'La Validation du résultat est nécessaire. $lang->testcase->noModule = "
    Vous n'avez aucun modules.
    Gérer les modules maintenant.
    "; $lang->testcase->noCase = "Aucun CasTest pour l'instant. "; $lang->testcase->importedCases = 'Le cas d\'utilisation avec l\'ID %s est déjà importé dans le même module, il est donc ignoré.'; +$lang->testcase->importedFromLib = '%s items imported successfully: %s.'; $lang->testcase->searchStories = 'Rechercher des stories'; $lang->testcase->selectLib = 'Sélectionner Library'; diff --git a/module/testcase/lang/zh-cn.php b/module/testcase/lang/zh-cn.php index 617d57b7e9..b2ffbfdc3f 100644 --- a/module/testcase/lang/zh-cn.php +++ b/module/testcase/lang/zh-cn.php @@ -246,6 +246,7 @@ $lang->testcase->mustChooseResult = '必须选择评审结果'; $lang->testcase->noModule = '
    您现在还没有模块信息
    请维护测试模块
    '; $lang->testcase->noCase = '暂时没有用例。'; $lang->testcase->importedCases = 'ID为 %s 的用例在相同模块已经导入,已忽略。'; +$lang->testcase->importedFromLib = '导入成功%s项:%s。'; $lang->testcase->searchStories = "键入来搜索{$lang->SRCommon}"; $lang->testcase->selectLib = '请选择库'; diff --git a/module/testcase/model.php b/module/testcase/model.php index 8c81cbc16b..ec51f37081 100644 --- a/module/testcase/model.php +++ b/module/testcase/model.php @@ -1930,10 +1930,11 @@ class testcaseModel extends model $caseModules[$branch] = $this->loadModel('testsuite')->getCanImportModules($productID, $libID, $branch); } - $libCases = $this->dao->select('*')->from(TABLE_CASE)->where('deleted')->eq(0)->andWhere('id')->in($data->caseIdList)->fetchAll('id'); - $libSteps = $this->dao->select('*')->from(TABLE_CASESTEP)->where('`case`')->in($data->caseIdList)->orderBy('id')->fetchGroup('case'); - $libFiles = $this->dao->select('*')->from(TABLE_FILE)->where('objectID')->in($data->caseIdList)->andWhere('objectType')->eq('testcase')->fetchGroup('objectID', 'id'); - $imported = ''; + $libCases = $this->dao->select('*')->from(TABLE_CASE)->where('deleted')->eq(0)->andWhere('id')->in($data->caseIdList)->fetchAll('id'); + $libSteps = $this->dao->select('*')->from(TABLE_CASESTEP)->where('`case`')->in($data->caseIdList)->orderBy('id')->fetchGroup('case'); + $libFiles = $this->dao->select('*')->from(TABLE_FILE)->where('objectID')->in($data->caseIdList)->andWhere('objectType')->eq('testcase')->fetchGroup('objectID', 'id'); + $hasImported = ''; + $importedCases = array(); foreach($libCases as $libCaseID => $case) { $case->fromCaseID = $case->id; @@ -1946,7 +1947,7 @@ class testcaseModel extends model $branch = isset($case->branch) ? $case->branch : 0; if(empty($caseModules[$branch][$case->fromCaseID][$case->module])) { - $imported .= "$case->fromCaseID,"; + $hasImported .= "$case->fromCaseID,"; continue; } @@ -1991,12 +1992,18 @@ class testcaseModel extends model unset($file->id); $this->dao->insert(TABLE_FILE)->data($file)->exec(); } + + $importedCases[] = $libCaseID; + $this->loadModel('action')->create('case', $caseID, 'fromlib', '', $case->lib); } - if(!empty($imported)) + + if(!empty($importedCases)) print(js::alert(sprintf($this->lang->testcase->importedFromLib, count($importedCases), implode(',', $importedCases)))); + + if(!empty($hasImported)) { - $imported = trim($imported, ','); - return print(js::error(sprintf($this->lang->testcase->importedCases, $imported))); + $hasImported = trim($hasImported, ','); + return print(js::error(sprintf($this->lang->testcase->importedCases, $hasImported))); } } diff --git a/module/testreport/control.php b/module/testreport/control.php index c20b6eae13..46fb975195 100644 --- a/module/testreport/control.php +++ b/module/testreport/control.php @@ -302,9 +302,13 @@ class testreport extends control list($bugInfo, $bugSummary) = $this->testreport->getBug4Report($tasks, $productIdList, $begin, $end, $builds); + $members = $this->dao->select('DISTINCT lastRunner')->from(TABLE_TESTRUN)->where('task')->in(array_keys($tasks))->fetchPairs('lastRunner', 'lastRunner'); + $taskMembers = explode(',', $task->members); + $members = array_merge($members, $taskMembers); + $this->view->begin = $begin; $this->view->end = $end; - $this->view->members = $this->dao->select('DISTINCT lastRunner')->from(TABLE_TESTRUN)->where('task')->in(array_keys($tasks))->fetchPairs('lastRunner', 'lastRunner'); + $this->view->members = $members; $this->view->owner = $owner; $this->view->stories = $stories; diff --git a/module/testtask/control.php b/module/testtask/control.php index 7c3b95386d..e9b93a151f 100644 --- a/module/testtask/control.php +++ b/module/testtask/control.php @@ -1660,4 +1660,17 @@ class testtask extends control $result = $this->dao->select('*')->from(TABLE_TESTRESULT)->where('id')->eq((int)$resultID)->fetch(); $this->send(array('result' => 'success', 'message' => '', 'data' => $result)); } + + /** + * AJAX: Get executionID by buildID. + * + * @param int $buildID + * @access public + * @return int + */ + public function ajaxGetExecutionByBuild($buildID) + { + $execution = $this->loadModel('execution')->getByBuild($buildID); + return print($execution ? $execution->id : 0); + } } diff --git a/module/testtask/js/create.js b/module/testtask/js/create.js index 80909db538..baf25c5dec 100755 --- a/module/testtask/js/create.js +++ b/module/testtask/js/create.js @@ -32,6 +32,17 @@ function loadExecutions(productID) }); } +$('#mainContent').on('change', '#build', function() +{ + var buildID = $(this).val(); + link = createLink('testtask', 'ajaxGetExecutionByBuild', 'buildID=' + buildID); + $.get(link, function(data) + { + $('#execution').val(data); + $("#execution").trigger("chosen:updated"); + }); +}) + /* If the mouse hover over the manage contacts button, give tip. */ $(function() { diff --git a/module/testtask/js/edit.js b/module/testtask/js/edit.js index 2e8300669a..86d4e2630e 100755 --- a/module/testtask/js/edit.js +++ b/module/testtask/js/edit.js @@ -3,3 +3,14 @@ $(function() adjustPriBoxWidth(); if(config.onlybody) $('#ownerAndPriBox .picker-selection').css('width', '123px'); }) + +$('#mainContent').on('change', '#build', function() +{ + var buildID = $(this).val(); + link = createLink('testtask', 'ajaxGetExecutionByBuild', 'buildID=' + buildID); + $.get(link, function(data) + { + $('#execution').val(data); + $("#execution").trigger("chosen:updated"); + }); +}) diff --git a/module/testtask/lang/de.php b/module/testtask/lang/de.php index 64d2980176..ff4225f2ad 100644 --- a/module/testtask/lang/de.php +++ b/module/testtask/lang/de.php @@ -58,6 +58,7 @@ $lang->testtask->run = 'Test Run ID'; $lang->testtask->job = 'Job'; $lang->testtask->compile = 'Compile'; $lang->testtask->duration = 'Duration'; +$lang->testtask->myInvolved = 'Involved'; $lang->testtask->viewAction = "View Request"; $lang->testtask->casesAction = 'Browse Cases List'; @@ -76,6 +77,7 @@ $lang->testtask->execution = $lang->execution->common; $lang->testtask->type = 'Typ'; $lang->testtask->build = 'Build'; $lang->testtask->owner = 'Besitzer'; +$lang->testtask->members = 'Participant'; $lang->testtask->executor = 'Executor'; $lang->testtask->execTime = 'Exec Time'; $lang->testtask->pri = 'Priorität'; @@ -202,6 +204,7 @@ $lang->testtask->report->options->width = 500; $lang->testtask->report->options->height = 140; $lang->testtask->featureBar['browse']['totalStatus'] = $lang->testtask->totalStatus; +$lang->testtask->featureBar['browse']['myinvolved'] = $lang->testtask->myInvolved; $lang->testtask->featureBar['browse']['wait'] = $lang->testtask->wait; $lang->testtask->featureBar['browse']['doing'] = $lang->testtask->testing; $lang->testtask->featureBar['browse']['blocked'] = $lang->testtask->blocked; diff --git a/module/testtask/lang/en.php b/module/testtask/lang/en.php index 979ee97f18..19c48df28e 100644 --- a/module/testtask/lang/en.php +++ b/module/testtask/lang/en.php @@ -58,6 +58,7 @@ $lang->testtask->run = 'Test Run ID'; $lang->testtask->job = 'Job'; $lang->testtask->compile = 'Compile'; $lang->testtask->duration = 'Duration'; +$lang->testtask->myInvolved = 'Involved'; $lang->testtask->viewAction = "View Request"; $lang->testtask->casesAction = 'Browse Cases List'; @@ -76,6 +77,7 @@ $lang->testtask->execution = $lang->execution->common; $lang->testtask->type = 'Type'; $lang->testtask->build = 'Build'; $lang->testtask->owner = 'Owner'; +$lang->testtask->members = 'Participant'; $lang->testtask->executor = 'Executor'; $lang->testtask->execTime = 'Exec Time'; $lang->testtask->pri = 'Priority'; @@ -202,6 +204,7 @@ $lang->testtask->report->options->width = 500; $lang->testtask->report->options->height = 140; $lang->testtask->featureBar['browse']['totalStatus'] = $lang->testtask->totalStatus; +$lang->testtask->featureBar['browse']['myinvolved'] = $lang->testtask->myInvolved; $lang->testtask->featureBar['browse']['wait'] = $lang->testtask->wait; $lang->testtask->featureBar['browse']['doing'] = $lang->testtask->testing; $lang->testtask->featureBar['browse']['blocked'] = $lang->testtask->blocked; diff --git a/module/testtask/lang/fr.php b/module/testtask/lang/fr.php index 49f5ebca35..f3f747fa3a 100644 --- a/module/testtask/lang/fr.php +++ b/module/testtask/lang/fr.php @@ -58,6 +58,7 @@ $lang->testtask->run = 'Test Run ID'; $lang->testtask->job = 'Job'; $lang->testtask->compile = 'Compile'; $lang->testtask->duration = 'Duration'; +$lang->testtask->myInvolved = 'Involved'; $lang->testtask->viewAction = "View Request"; $lang->testtask->casesAction = 'Browse Cases List'; @@ -76,6 +77,7 @@ $lang->testtask->execution = $lang->execution->common; $lang->testtask->type = 'Type'; $lang->testtask->build = 'Build'; $lang->testtask->owner = 'Owner'; +$lang->testtask->members = 'Participant'; $lang->testtask->executor = 'Executeur'; $lang->testtask->execTime = 'Durée Exec'; $lang->testtask->pri = 'Priorité'; @@ -202,6 +204,7 @@ $lang->testtask->report->options->width = 500; $lang->testtask->report->options->height = 140; $lang->testtask->featureBar['browse']['totalStatus'] = $lang->testtask->totalStatus; +$lang->testtask->featureBar['browse']['myinvolved'] = $lang->testtask->myInvolved; $lang->testtask->featureBar['browse']['wait'] = $lang->testtask->wait; $lang->testtask->featureBar['browse']['doing'] = $lang->testtask->testing; $lang->testtask->featureBar['browse']['blocked'] = $lang->testtask->blocked; diff --git a/module/testtask/lang/zh-cn.php b/module/testtask/lang/zh-cn.php index cb9163b533..a020a18c8b 100644 --- a/module/testtask/lang/zh-cn.php +++ b/module/testtask/lang/zh-cn.php @@ -58,6 +58,7 @@ $lang->testtask->run = '执行编号'; $lang->testtask->job = '构建任务'; $lang->testtask->compile = '构建'; $lang->testtask->duration = '持续时间'; +$lang->testtask->myInvolved = '由我参与'; $lang->testtask->viewAction = "测试单概况"; $lang->testtask->casesAction = '浏览用例列表'; @@ -76,6 +77,7 @@ $lang->testtask->execution = '所属' . $lang->execution->common; $lang->testtask->type = '测试类型'; $lang->testtask->build = '版本'; $lang->testtask->owner = '负责人'; +$lang->testtask->members = '参与人'; $lang->testtask->executor = '执行人'; $lang->testtask->execTime = '执行时间'; $lang->testtask->pri = '优先级'; @@ -202,6 +204,7 @@ $lang->testtask->report->options->width = 500; $lang->testtask->report->options->height = 140; $lang->testtask->featureBar['browse']['totalStatus'] = $lang->testtask->totalStatus; +$lang->testtask->featureBar['browse']['myinvolved'] = $lang->testtask->myInvolved; $lang->testtask->featureBar['browse']['wait'] = $lang->testtask->wait; $lang->testtask->featureBar['browse']['doing'] = $lang->testtask->testing; $lang->testtask->featureBar['browse']['blocked'] = $lang->testtask->blocked; diff --git a/module/testtask/model.php b/module/testtask/model.php index 31de537a02..f448e04ade 100755 --- a/module/testtask/model.php +++ b/module/testtask/model.php @@ -20,7 +20,7 @@ class testtaskModel extends model * @access public * @return void */ - function create($projectID = 0) + public function create($projectID = 0) { if($this->post->execution) { @@ -28,16 +28,25 @@ class testtaskModel extends model $projectID = $execution->project; } + if($this->post->build && empty($projectID)) + { + $build = $this->loadModel('build')->getById($this->post->build); + $projectID = $build->project; + } + $task = fixer::input('post') ->setDefault('build', '') ->setDefault('project', $projectID) ->setDefault('createdBy', $this->app->user->account) ->setDefault('createdDate', helper::now()) + ->setDefault('members', '') ->stripTags($this->config->testtask->editor->create['id'], $this->config->allowedTags) ->join('mailto', ',') ->join('type', ',') + ->join('members', ',') ->remove('files,labels,uid,contactListMenu') ->get(); + $task->members = trim($task->members, ','); $task = $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->create['id'], $this->post->uid); $this->dao->insert(TABLE_TESTTASK)->data($task) @@ -87,8 +96,9 @@ class testtaskModel extends model ->beginIF(!$this->app->user->admin)->andWhere('t1.execution')->in("0,{$this->app->user->view->sprints}")->fi() ->beginIF($scopeAndStatus[0] == 'local')->andWhere('t1.product')->eq((int)$productID)->fi() ->beginIF($scopeAndStatus[0] == 'all')->andWhere('t1.product')->in($products)->fi() + ->beginIF(strtolower($scopeAndStatus[1]) == 'myinvolved')->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.members)")->fi() ->beginIF(strtolower($scopeAndStatus[1]) == 'totalstatus')->andWhere('t1.status')->in('blocked,doing,wait,done')->fi() - ->beginIF(!in_array(strtolower($scopeAndStatus[1]), array('totalstatus', 'review'), true))->andWhere('t1.status')->eq($scopeAndStatus[1])->fi() + ->beginIF(!in_array(strtolower($scopeAndStatus[1]), array('totalstatus', 'review', 'myinvolved'), true))->andWhere('t1.status')->eq($scopeAndStatus[1])->fi() ->beginIF($branch !== 'all')->andWhere("CONCAT(',', t4.branch, ',')")->like("%,$branch,%")->fi() ->beginIF($beginTime)->andWhere('t1.begin')->ge($beginTime)->fi() ->beginIF($endTime)->andWhere('t1.end')->le($endTime)->fi() @@ -105,6 +115,7 @@ class testtaskModel extends model ->orderBy($orderBy) ->page($pager) ->fetchAll('id'); + foreach($tasks as $taskID => $task) { if($task->multiple) @@ -773,15 +784,26 @@ class testtaskModel extends model ->setDefault('type', '') ->setDefault('mailto', '') ->setDefault('deleteFiles', array()) + ->setDefault('members', '') ->stripTags($this->config->testtask->editor->edit['id'], $this->config->allowedTags) ->join('mailto', ',') ->join('type', ',') + ->join('members', ',') ->remove('files,labels,uid,comment,contactListMenu') ->get(); + $task->members = trim($task->members, ','); /* Fix bug #35419. */ - $execution = $this->loadModel('execution')->getByID($task->execution); - $task->project = $execution->project; + $execution = $this->loadModel('execution')->getByID($task->execution); + if(!$execution) + { + $build = $this->loadModel('build')->getById($task->build); + $task->project = $build->project; + } + else + { + $task->project = $execution->project; + } $task = $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->edit['id'], $this->post->uid); @@ -1777,7 +1799,7 @@ class testtaskModel extends model public function getToAndCcList($testtask) { /* Set toList and ccList. */ - $toList = $testtask->owner; + $toList = $testtask->owner . ',' . $testtask->members . ','; $ccList = str_replace(' ', '', trim($testtask->mailto, ',')); if(empty($toList)) @@ -1795,6 +1817,7 @@ class testtaskModel extends model $ccList = substr($ccList, $commaPos + 1); } } + return array($toList, $ccList); } diff --git a/module/testtask/view/browse.html.php b/module/testtask/view/browse.html.php index c9c1186c84..44d8af388b 100644 --- a/module/testtask/view/browse.html.php +++ b/module/testtask/view/browse.html.php @@ -78,6 +78,7 @@ $status = strtolower($status); testtask->execution);?> statusAB);?> testtask->owner);?> + testtask->members);?> testtask->begin);?> testtask->end);?> owner);?> + + members) as $member) $members[] = zget($users, $member);?> + + begin?> end?> " . $this->loadModel('flow')->getFieldValue($extendField, $task) . "";?> diff --git a/module/testtask/view/create.html.php b/module/testtask/view/create.html.php index 2360aecfa9..6c47bc9d5a 100644 --- a/module/testtask/view/create.html.php +++ b/module/testtask/view/create.html.php @@ -73,6 +73,10 @@
    + + testtask->members;?> + + testtask->begin;?> diff --git a/module/testtask/view/edit.html.php b/module/testtask/view/edit.html.php index 670e466275..d138517023 100644 --- a/module/testtask/view/edit.html.php +++ b/module/testtask/view/edit.html.php @@ -56,6 +56,12 @@ + + testtask->members;?> + + members, "class='form-control picker-select' multiple");?> + + testtask->begin;?> diff --git a/module/transfer/control.php b/module/transfer/control.php index c6e3f0b892..51f45e797d 100755 --- a/module/transfer/control.php +++ b/module/transfer/control.php @@ -152,6 +152,11 @@ class transfer extends control { $filter = ''; if($model == 'task') $filter = 'estimate'; + if($model == 'bug') + { + $this->loadModel('bug'); + $this->config->bug->datatable->fieldList['execution']['dataSource'] = array('module' => 'product', 'method' =>'getAllExecutionPairsByProduct', 'params' => '$productID&$branch'); + } if($model == 'story' and $this->session->storyType == 'requirement') $this->loadModel('story')->replaceUserRequirementLang(); $this->loadModel($model); @@ -198,6 +203,7 @@ class transfer extends control { $this->loadModel($model); $fields = $this->config->$model->templateFields; + if($model == 'bug') $this->config->bug->datatable->fieldList['execution']['dataSource'] = array('module' => 'product', 'method' =>'getAllExecutionPairsByProduct', 'params' => '$productID&$branch'); if($this->config->edition != 'open') { diff --git a/module/upgrade/model.php b/module/upgrade/model.php index a62cc027f0..d5dc7b36db 100644 --- a/module/upgrade/model.php +++ b/module/upgrade/model.php @@ -707,6 +707,11 @@ class upgradeModel extends model $this->processHistoryDataForMetric(); $this->loadModel('metric')->updateMetricDate(); break; + case '18_8': + /* Upgrade members for testtask. */ + $this->upgradeTesttaskMembers(); + $this->loadModel('program')->refreshStats(true); + break; } $this->deletePatch(); @@ -9878,4 +9883,23 @@ class upgradeModel extends model } $this->dao->commit(); } + + /** + * Upgrade testtask members. + * + * @access public + * @return void + */ + public function upgradeTesttaskMembers() + { + $memberGroup = $this->dao->select('task,lastRunner')->from(TABLE_TESTRUN) + ->where('lastRunner')->ne('') + ->fetchGroup('task', 'lastRunner'); + + foreach($memberGroup as $taskID => $members) + { + $members = implode(',', array_keys($members)); + $this->dao->update(TABLE_TESTTASK)->set('members')->eq($members)->where('id')->eq($taskID)->exec(); + } + } } diff --git a/module/weekly/lang/de.php b/module/weekly/lang/de.php index 459e38dc3c..940594866d 100644 --- a/module/weekly/lang/de.php +++ b/module/weekly/lang/de.php @@ -90,15 +90,15 @@ EOD; $lang->weekly->blockHelpNotice = <<Progress this week Calculation method: -
    1) Progress of this week=total consumed man hours/(total consumed man hours+remaining man hours) +
    1) Project progress = consumed task hours / (consumed task hours + remaining task hours) * 100%

    Statistical range:

    -1) The total consumed man hours include task, demand, bug, use case, version, test sheet, problem, risk, document and review time -
    2) To avoid repeated calculation, the task only contains child tasks, not parent tasks -
    3) Including deleted tasks, requirements, bugs, use cases, versions, test sheets, problems, risks, documents, and consumed man hours in reviews -
    4) This includes the work hours consumed by deleted tasks, requirements, bugs, use cases, versions, test sheets, and documents -
    5) Including work hours consumed by cancelled tasks, problems and risks -
    6) Exclude remaining work on canceled tasks -
    7) Exclude remaining work for deleted tasks in progress +1) Only the working hour consumption data of the task is counted +
    2) To avoid repeated calculation, the task working hours only include child tasks, not parent tasks +
    3) Including the working hours consumed by canceled tasks +
    4) Excluding the working hours consumed in deleted tasks +
    5) Excluding the working hours consumed in deleted tasks in progress +
    6) Excluding the remaining working hours of canceled tasks +
    7) Excluding the remaining working hours of deleted tasks in progress

    PV Planned Value

    Calculation method:
    1) The estimated start date and end date of the task are within the range of the start and end dates of this week, and the estimated work hours are accumulated diff --git a/module/weekly/lang/en.php b/module/weekly/lang/en.php index 459e38dc3c..940594866d 100644 --- a/module/weekly/lang/en.php +++ b/module/weekly/lang/en.php @@ -90,15 +90,15 @@ EOD; $lang->weekly->blockHelpNotice = <<Progress this week Calculation method: -
    1) Progress of this week=total consumed man hours/(total consumed man hours+remaining man hours) +
    1) Project progress = consumed task hours / (consumed task hours + remaining task hours) * 100%

    Statistical range:

    -1) The total consumed man hours include task, demand, bug, use case, version, test sheet, problem, risk, document and review time -
    2) To avoid repeated calculation, the task only contains child tasks, not parent tasks -
    3) Including deleted tasks, requirements, bugs, use cases, versions, test sheets, problems, risks, documents, and consumed man hours in reviews -
    4) This includes the work hours consumed by deleted tasks, requirements, bugs, use cases, versions, test sheets, and documents -
    5) Including work hours consumed by cancelled tasks, problems and risks -
    6) Exclude remaining work on canceled tasks -
    7) Exclude remaining work for deleted tasks in progress +1) Only the working hour consumption data of the task is counted +
    2) To avoid repeated calculation, the task working hours only include child tasks, not parent tasks +
    3) Including the working hours consumed by canceled tasks +
    4) Excluding the working hours consumed in deleted tasks +
    5) Excluding the working hours consumed in deleted tasks in progress +
    6) Excluding the remaining working hours of canceled tasks +
    7) Excluding the remaining working hours of deleted tasks in progress

    PV Planned Value

    Calculation method:
    1) The estimated start date and end date of the task are within the range of the start and end dates of this week, and the estimated work hours are accumulated diff --git a/module/weekly/lang/fr.php b/module/weekly/lang/fr.php index 459e38dc3c..940594866d 100644 --- a/module/weekly/lang/fr.php +++ b/module/weekly/lang/fr.php @@ -90,15 +90,15 @@ EOD; $lang->weekly->blockHelpNotice = <<Progress this week Calculation method: -
    1) Progress of this week=total consumed man hours/(total consumed man hours+remaining man hours) +
    1) Project progress = consumed task hours / (consumed task hours + remaining task hours) * 100%

    Statistical range:

    -1) The total consumed man hours include task, demand, bug, use case, version, test sheet, problem, risk, document and review time -
    2) To avoid repeated calculation, the task only contains child tasks, not parent tasks -
    3) Including deleted tasks, requirements, bugs, use cases, versions, test sheets, problems, risks, documents, and consumed man hours in reviews -
    4) This includes the work hours consumed by deleted tasks, requirements, bugs, use cases, versions, test sheets, and documents -
    5) Including work hours consumed by cancelled tasks, problems and risks -
    6) Exclude remaining work on canceled tasks -
    7) Exclude remaining work for deleted tasks in progress +1) Only the working hour consumption data of the task is counted +
    2) To avoid repeated calculation, the task working hours only include child tasks, not parent tasks +
    3) Including the working hours consumed by canceled tasks +
    4) Excluding the working hours consumed in deleted tasks +
    5) Excluding the working hours consumed in deleted tasks in progress +
    6) Excluding the remaining working hours of canceled tasks +
    7) Excluding the remaining working hours of deleted tasks in progress

    PV Planned Value

    Calculation method:
    1) The estimated start date and end date of the task are within the range of the start and end dates of this week, and the estimated work hours are accumulated diff --git a/module/weekly/lang/zh-cn.php b/module/weekly/lang/zh-cn.php index a5508a2bc4..aabc2de79d 100644 --- a/module/weekly/lang/zh-cn.php +++ b/module/weekly/lang/zh-cn.php @@ -90,13 +90,13 @@ EOD; $lang->weekly->blockHelpNotice = <<本周进度 计算方式: -
    1)本周进度=总消耗工时/(总消耗工时+剩余工时) +
    1)项目进度=已消耗任务工时 /(已消耗任务工时 + 剩余任务工时)*100%

    统计范围:

    -1)总消耗的工时包括任务、需求、Bug、用例、版本、测试单、问题、风险、文档、评审的耗时 -
    2)为避免重复计算,任务只包含子任务,不包括父任务 -
    3)包括已删除任务、需求、Bug、用例、版本、测试单、问题、风险、文档、评审中已消耗的工时 -
    4)包括已删除执行中任务、需求、Bug、用例、版本、测试单、文档已消耗的工时 -
    5)包括已取消任务、问题、风险已消耗的工时 +1)只统计任务的工时消耗数据。 +
    2)为避免重复计算,任务工时只包含子任务,不包括父任务 +
    3)包括已取消任务消耗的工时 +
    4)不包括已删除任务中消耗的工时 +
    5)不包括已删除执行中任务消耗的工时
    6)不包括已取消任务的剩余工时
    7)不包括已删除执行中任务的剩余工时

    PV 计划完成的工作