diff --git a/module/common/lang/common.php b/module/common/lang/common.php index cfeeb76a0d..9a3dd66d0d 100644 --- a/module/common/lang/common.php +++ b/module/common/lang/common.php @@ -43,6 +43,7 @@ $lang->group = new stdclass(); $lang->user = new stdclass(); $lang->screen = new stdclass(); $lang->report = new stdclass(); +$lang->pivot = new stdclass(); $lang->repo = new stdclass(); $lang->jenkins = new stdclass(); $lang->gitlab = new stdclass(); diff --git a/module/common/lang/de.php b/module/common/lang/de.php index 0c916d800e..75cf6cbc3c 100644 --- a/module/common/lang/de.php +++ b/module/common/lang/de.php @@ -176,6 +176,7 @@ $lang->repo->common = 'Code'; $lang->repo->codeRepo = 'Code Repo'; $lang->screen->common = 'Screen'; $lang->report->common = 'BI'; +$lang->pivot->common = 'Pivot Table'; $lang->system->common = 'System'; $lang->admin->common = 'Admin'; $lang->story->common = 'Story'; @@ -294,7 +295,6 @@ $lang->project->report = 'Report'; $lang->report->weekly = 'Weekly'; $lang->report->annual = 'Annual Summary'; -$lang->report->pivotTable = 'Pivot Table'; $lang->report->notice = new stdclass(); $lang->report->notice->help = 'Hinweis: Berichte wurde auf Basis der Suche generiert. Bitte suchen Sie in der Liste bevor Sie einen Bericht generieren.'; diff --git a/module/common/lang/en.php b/module/common/lang/en.php index 715782f579..99c8212fa3 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -176,6 +176,7 @@ $lang->repo->common = 'Code'; $lang->repo->codeRepo = 'Code Repo'; $lang->screen->common = 'Screen'; $lang->report->common = 'BI'; +$lang->pivot->common = 'Pivot Table'; $lang->system->common = 'System'; $lang->admin->common = 'Admin'; $lang->story->common = 'Story'; @@ -294,7 +295,6 @@ $lang->project->report = 'Report'; $lang->report->weekly = 'Weekly'; $lang->report->annual = 'Annual Summary'; -$lang->report->pivotTable = 'Pivot Table'; $lang->report->notice = new stdclass(); $lang->report->notice->help = 'Note: The report is generated on the results of browsing the list. Click, e.g. AssignedToMe, then click Create Report to generate a report based on AssignedToMe list.'; diff --git a/module/common/lang/fr.php b/module/common/lang/fr.php index 502a64a84c..25ba46a032 100644 --- a/module/common/lang/fr.php +++ b/module/common/lang/fr.php @@ -176,6 +176,7 @@ $lang->repo->common = 'Code'; $lang->repo->codeRepo = 'Code Repo'; $lang->screen->common = 'Screen'; $lang->report->common = 'BI'; +$lang->pivot->common = 'Pivot Table'; $lang->system->common = 'System'; $lang->admin->common = 'Admin'; $lang->story->common = 'Story'; @@ -294,7 +295,6 @@ $lang->project->report = 'Report'; $lang->report->weekly = 'Weekly'; $lang->report->annual = 'Annual Summary'; -$lang->report->pivotTable = 'Pivot Table'; $lang->report->notice = new stdclass(); $lang->report->notice->help = 'Note : Le rapport est généré à partir des résultats de la liste consultée. Par exemple, cliquez sur AssignedToMe, puis Générer Rapport pour obtenir un rapport basé sur la liste de ce qui vous est assigné.'; diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php index 9a9d25e8bd..d985267f1b 100644 --- a/module/common/lang/menu.php +++ b/module/common/lang/menu.php @@ -539,26 +539,24 @@ $lang->doc->menu->api['subMenu']->index = array('link' => "{$lang->doc->apiDoc} $lang->doc->menu->api['subMenu']->struct = array('link' => "{$lang->doc->apiStruct}|api|struct|libID=%s", 'alias' => 'createstruct,editstruct'); /* Report menu.*/ -$lang->report->menu = new stdclass(); -$lang->report->menu->screen = array('link' => "{$lang->screen->common}|screen|browse"); -$lang->report->menu->pivotTable = array('link' => "{$lang->report->pivotTable}|report|productsummary", 'alias' => 'projectdeviation,bugcreate,workload,bugassign'); +$lang->report->menu = new stdclass(); +$lang->report->menu->screen = array('link' => "{$lang->screen->common}|screen|browse"); +$lang->report->menu->pivot = array('link' => "{$lang->pivot->common}|pivot|preview"); /* Report menu order. */ $lang->report->menuOrder[5] = 'screen'; -$lang->report->menuOrder[10] = 'pivotTable'; +$lang->report->menuOrder[10] = 'pivot'; -/* -$lang->report->menu->pivotTable['subMenu'] = new stdclass(); -$lang->report->menu->pivotTable['subMenu']->product = array('link' => "{$lang->product->common}|report|productsummary"); -$lang->report->menu->pivotTable['subMenu']->project = array('link' => "{$lang->project->common}|report|projectdeviation"); -$lang->report->menu->pivotTable['subMenu']->test = array('link' => "{$lang->qa->common}|report|bugcreate", 'alias' => 'bugassign'); -$lang->report->menu->pivotTable['subMenu']->staff = array('link' => "{$lang->system->common}|report|workload"); +$lang->report->menu->pivot['subMenu'] = new stdclass(); +$lang->report->menu->pivot['subMenu']->product = array('link' => "{$lang->product->common}|pivot|preview|diemsnion=&group=product"); +$lang->report->menu->pivot['subMenu']->project = array('link' => "{$lang->project->common}|pivot|preview|dimension=&group=project"); +$lang->report->menu->pivot['subMenu']->test = array('link' => "{$lang->qa->common}|pivot|preview|dimension=&group=test"); +$lang->report->menu->pivot['subMenu']->staff = array('link' => "{$lang->system->common}|pivot|preview|dimension=&group=staff"); -$lang->report->menu->pivotTable['menuOrder'][5] = 'product'; -$lang->report->menu->pivotTable['menuOrder'][10] = 'project'; -$lang->report->menu->pivotTable['menuOrder'][15] = 'test'; -$lang->report->menu->pivotTable['menuOrder'][20] = 'staff'; - */ +$lang->report->menu->pivot['menuOrder'][5] = 'product'; +$lang->report->menu->pivot['menuOrder'][10] = 'project'; +$lang->report->menu->pivot['menuOrder'][15] = 'test'; +$lang->report->menu->pivot['menuOrder'][20] = 'staff'; /* Company menu.*/ $lang->company->menu = new stdclass(); diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 4f8b53fb0a..bbd59e3d0f 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -176,6 +176,7 @@ $lang->repo->common = '代码'; $lang->repo->codeRepo = '代码库'; $lang->screen->common = '大屏'; $lang->report->common = 'BI'; +$lang->pivot->common = '透视表'; $lang->system->common = '组织'; $lang->admin->common = '后台'; $lang->story->common = $lang->SRCommon; @@ -294,7 +295,6 @@ $lang->project->report = '报告'; $lang->report->weekly = '周报'; $lang->report->annual = '年度总结'; -$lang->report->pivotTable = '透视表'; $lang->report->notice = new stdclass(); $lang->report->notice->help = '注:统计报表的数据来源于列表页面的检索结果,生成统计报表前请先在列表页面进行检索。比如列表页面我们检索的是%tab%,那么报表就是基于之前检索的%tab%的结果集进行统计。'; diff --git a/module/pivot/config.php b/module/pivot/config.php new file mode 100644 index 0000000000..225c0e235f --- /dev/null +++ b/module/pivot/config.php @@ -0,0 +1,2 @@ +pivot = new stdclass(); diff --git a/module/pivot/control.php b/module/pivot/control.php new file mode 100644 index 0000000000..c6624c78e2 --- /dev/null +++ b/module/pivot/control.php @@ -0,0 +1,202 @@ + + * @package pivot + * @version $Id: control.php 4622 2013-03-28 01:09:02Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +class pivot extends control +{ + /** + * The index of pivot, goto project deviation. + * + * @access public + * @return void + */ + public function index() + { + $this->locate(inlink('preview')); + } + + /** + * Preview a pivot. + * + * @param int $dimension + * @param string $group + * @param string $module + * @param string $method + * @param string $params + * @access public + * @return void + */ + public function preview($dimension = 0, $group = '', $module = 'pivot', $method = '', $params = '') + { + $this->prepare4Preview($dimension, $group, $module, $method, $params); + $this->display(); + } + + /** + * Project deviation pivot. + * + * @access public + * @return void + */ + public function projectDeviation($begin = 0, $end = 0) + { + $this->session->set('executionList', $this->app->getURI(true), 'execution'); + + $begin = date('Y-m-d', ($begin ? strtotime($begin) : time() - (date('j') - 1) * 24 * 3600)); + $end = date('Y-m-d', ($end ? strtotime($end) : time() + (date('t') - date('j')) * 24 * 3600)); + + $this->view->title = $this->lang->pivot->projectDeviation; + $this->view->position[] = $this->lang->pivot->projectDeviation; + + $this->view->executions = $this->pivot->getExecutions($begin, $end); + $this->view->begin = $begin; + $this->view->end = $end; + $this->view->submenu = 'project'; + $this->display(); + } + + /** + * Product information pivot. + * + * @params string $conditions + * @access public + * @return void + */ + public function productSummary($conditions = '') + { + $this->app->loadLang('story'); + $this->app->loadLang('product'); + $this->app->loadLang('productplan'); + $this->session->set('productList', $this->app->getURI(true), 'product'); + + $this->view->title = $this->lang->pivot->productSummary; + $this->view->position[] = $this->lang->pivot->productSummary; + $this->view->products = $this->pivot->getProducts($conditions); + $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); + $this->view->submenu = 'product'; + $this->view->conditions = $conditions; + $this->display(); + } + + /** + * Bug create pivot. + * + * @param int $begin + * @param int $end + * @param int $product + * @param int $execution + * @access public + * @return void + */ + public function bugCreate($begin = 0, $end = 0, $product = 0, $execution = 0) + { + $this->app->loadLang('bug'); + $begin = $begin == 0 ? date('Y-m-d', strtotime('last month', strtotime(date('Y-m',time()) . '-01 00:00:01'))) : date('Y-m-d', strtotime($begin)); + $end = $end == 0 ? date('Y-m-d', strtotime('now')) : $end = date('Y-m-d', strtotime($end)); + + $this->view->title = $this->lang->pivot->bugCreate; + $this->view->position[] = $this->lang->pivot->bugCreate; + $this->view->begin = $begin; + $this->view->end = $end; + $this->view->bugs = $this->pivot->getBugs($begin, $end, $product, $execution); + $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); + $this->view->executions = array('' => '') + $this->pivot->getProjectExecutions(); + $this->view->products = array('' => '') + $this->loadModel('product')->getPairs('', 0, '', 'all'); + $this->view->execution = $execution; + $this->view->product = $product; + $this->view->submenu = 'test'; + $this->display(); + } + + /** + * Bug assign pivot. + * + * @access public + * @return void + */ + public function bugAssign() + { + $this->session->set('productList', $this->app->getURI(true), 'product'); + + $this->view->title = $this->lang->pivot->bugAssign; + $this->view->position[] = $this->lang->pivot->bugAssign; + $this->view->submenu = 'test'; + $this->view->assigns = $this->pivot->getBugAssign(); + $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); + $this->display(); + } + + /** + * Workload pivot. + * + * @param string $begin + * @param string $end + * @param int $days + * @param int $workday + * @param int $dept + * @param int $assign + * + * @access public + * @return void + */ + public function workload($begin = '', $end = '', $days = 0, $workday = 0, $dept = 0, $assign = 'assign') + { + if($_POST) + { + $data = fixer::input('post')->get(); + $begin = $data->begin; + $end = $data->end; + $dept = $data->dept; + $days = $data->days; + $assign = $data->assign; + $workday = $data->workday; + } + + $this->app->loadConfig('execution'); + $this->session->set('executionList', $this->app->getURI(true), 'execution'); + + $begin = $begin ? strtotime($begin) : time(); + $end = $end ? strtotime($end) : time() + (7 * 24 * 3600); + $end += 24 * 3600; + $beginWeekDay = date('w', $begin); + $begin = date('Y-m-d', $begin); + $end = date('Y-m-d', $end); + + if(empty($workday))$workday = $this->config->execution->defaultWorkhours; + $diffDays = helper::diffDate($end, $begin); + if($days > $diffDays) $days = $diffDays; + if(empty($days)) + { + $weekDay = $beginWeekDay; + $days = $diffDays; + for($i = 0; $i < $diffDays; $i++,$weekDay++) + { + $weekDay = $weekDay % 7; + if(($this->config->execution->weekend == 2 and $weekDay == 6) or $weekDay == 0) $days --; + } + } + + $this->view->title = $this->lang->pivot->workload; + $this->view->position[] = $this->lang->pivot->workload; + + $this->view->workload = $this->pivot->getWorkload($dept, $assign); + $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); + $this->view->depts = $this->loadModel('dept')->getOptionMenu(); + $this->view->begin = $begin; + $this->view->end = date('Y-m-d', strtotime($end) - 24 * 3600); + $this->view->days = $days; + $this->view->workday = $workday; + $this->view->dept = $dept; + $this->view->assign = $assign; + $this->view->allHour = $days * $workday; + $this->view->submenu = 'staff'; + $this->display(); + } +} diff --git a/module/pivot/css/bugcreate.css b/module/pivot/css/bugcreate.css new file mode 100644 index 0000000000..46f45e44f6 --- /dev/null +++ b/module/pivot/css/bugcreate.css @@ -0,0 +1,5 @@ +#begin {min-width: 85px;} +#end {min-width: 85px;} +#bug th {font-size: 12px;} +#bug th:nth-child(7) {width: 87px;} +#bug th:nth-child(10) {width: 100px;} diff --git a/module/pivot/css/common.css b/module/pivot/css/common.css new file mode 100644 index 0000000000..d9e4869e84 --- /dev/null +++ b/module/pivot/css/common.css @@ -0,0 +1,38 @@ +.choose-date span, .dp-choose-date {display: block; float: left; margin: 0 10px;} +.dp-applied {float: left;} +.choose-date span {line-height: 20px;} +.date {width: 80px;} +ul li {list-style: none;} + +.side-col {padding-right: 20px; width: 15%;} +#sidebar>.cell {width: 100%;} +#productList p {margin: 2px 0;} +.table-bordered, .outer.with-side .main, .outer.with-side > form > .table, .outer.with-side > .table {border: none;} + +#report-list.list-group {margin-bottom: 0;} +#report-list .list-group-item {padding: 8px 15px; border-left: none; border-right: none;} +#report-list .list-group-item:first-child {border-top: 1px;} +#report-list .list-group-item:last-child {border-bottom: 1px;} +#report-list .list-group-item.active {background: none; color: #333;} +.proversion a {color: #81511C;} + +.main > .input-group {margin-bottom: 10px;} +.main > .input-group > .datepicker-wrapper {display: table-cell;} +.main > .input-group > .datepicker-wrapper > .form-control {padding: 5px 10px; height: 30px;} +.main > .input-group > .datepicker-wrapper:before {top: 4px;} +.main > .input-group > .datepicker-wrapper + .input-group-addon {border-left: none; border-right: none;} + +td .deviation {padding-left: 20px; text-align: left;} +.up {color: red; padding-right: 2px;} +.down {color: green; padding-right: 2px;} +.zero {color: #66CD00;} +.u50 {color: #ED1C24;} +.u30 {color: #F37021;} +.u10 {color: #FAA61A;} +.u0 {color: #FFCB05;} +.d0 {color: #76B043;} +.d20 {color: #33A52E;} + +.checkboxes {margin-bottom: 10px;} +.checkboxes .checkbox-primary {margin-bottom: 5px;} +.fixed-header-copy thead tr th {color: #fff !important;} diff --git a/module/pivot/css/preview.css b/module/pivot/css/preview.css new file mode 100644 index 0000000000..f7a384c8e2 --- /dev/null +++ b/module/pivot/css/preview.css @@ -0,0 +1,4 @@ +.main-position {position: relative;} +.toolbar-padding {padding-right: 100px;} +.child-position {position: absolute; right: 0;} +#reportGroups .active {background-color: #e9f2fb; color: #006af1;} diff --git a/module/pivot/css/productsummary.css b/module/pivot/css/productsummary.css new file mode 100644 index 0000000000..d3aeb68419 --- /dev/null +++ b/module/pivot/css/productsummary.css @@ -0,0 +1,5 @@ +td.child {padding-left: 15px;} +.c-name {width: 200px;} +.c-count {width: 70px;} +#conditions {display: flex;} +#conditions .condition-options {margin-left: 16px;} diff --git a/module/pivot/css/projectdeviation.css b/module/pivot/css/projectdeviation.css new file mode 100644 index 0000000000..5ee6104e66 --- /dev/null +++ b/module/pivot/css/projectdeviation.css @@ -0,0 +1,2 @@ +.c-hours, .c-deviation, .c-deviation-rate {width: 100px;} +.c-id {width: 70px;} diff --git a/module/pivot/css/workload.css b/module/pivot/css/workload.css new file mode 100644 index 0000000000..04afc3d79f --- /dev/null +++ b/module/pivot/css/workload.css @@ -0,0 +1 @@ +.c-hours, .c-count, .c-workload {width: 100px;} diff --git a/module/pivot/js/bugassign.js b/module/pivot/js/bugassign.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/module/pivot/js/bugcreate.js b/module/pivot/js/bugcreate.js new file mode 100644 index 0000000000..b856ba4ead --- /dev/null +++ b/module/pivot/js/bugcreate.js @@ -0,0 +1,23 @@ +function changeParams(obj) +{ + var begin = $('#conditions').find('#begin').val(); + var end = $('#conditions').find('#end').val(); + var product = $('#conditions').find('#product').val(); + var execution = $('#conditions').find('#execution').val(); + if(begin.indexOf('-') != -1) + { + var beginarray = begin.split("-"); + var begin = ''; + for(i=0 ; i < beginarray.length ; i++) begin = begin + beginarray[i]; + } + if(end.indexOf('-') != -1) + { + var endarray = end.split("-"); + var end = ''; + for(i=0 ; i < endarray.length ; i++) end = end + endarray[i]; + } + + var params = window.btoa('begin=' + begin + '&end=' + end + '&product=' + product + '&execution=' + execution); + var link = createLink('pivot', 'preview', 'dimension=' + dimension + '&group=' + group + '&module=pivot&method=bugcreate¶ms=' + params); + location.href = link; +} diff --git a/module/pivot/js/productsummary.js b/module/pivot/js/productsummary.js new file mode 100644 index 0000000000..039a510eed --- /dev/null +++ b/module/pivot/js/productsummary.js @@ -0,0 +1,13 @@ +$('#conditions input:checkbox').change(function() +{ + var conditions = ''; + $('#conditions input:checkbox').each(function(i) + { + if($(this).prop('checked')) conditions += $(this).val() + ','; + }) + conditions = conditions.substring(0, conditions.length - 1); + + var params = window.btoa('conditions=' + conditions); + var link = createLink('pivot', 'preview', 'dimension=' + dimension + '&group=' + group + '&module=pivot&method=productSummary¶ms=' + params); + location.href = link; +}) diff --git a/module/pivot/js/projectdeviation.js b/module/pivot/js/projectdeviation.js new file mode 100644 index 0000000000..f4ff8d4be7 --- /dev/null +++ b/module/pivot/js/projectdeviation.js @@ -0,0 +1,36 @@ +$(document).ready(function() +{ + initChart(); + + $('.icon-exclamation-sign').hover(function(){ + $('#desc').removeClass('hidden'); + }, function(){ + $('#desc').addClass('hidden'); + }); +}); + +function changeDate(begin, end) +{ + if(begin.indexOf('-') != -1) + { + var beginarray = begin.split("-"); + var begin = ''; + for(i=0 ; i < beginarray.length ; i++) + { + begin = begin + beginarray[i]; + } + } + if(end.indexOf('-') != -1) + { + var endarray = end.split("-"); + var end = ''; + for(i=0 ; i < endarray.length ; i++) + { + end = end + endarray[i]; + } + } + + var params = window.btoa('begin=' + begin + '&end=' + end); + var link = createLink('pivot', 'preview', 'dimension=' + dimension + '&group=' + group + '&module=pivot&method=projectdeviation¶ms=' + params); + location.href = link; +} diff --git a/module/pivot/js/workload.js b/module/pivot/js/workload.js new file mode 100644 index 0000000000..350d3ea035 --- /dev/null +++ b/module/pivot/js/workload.js @@ -0,0 +1,85 @@ +function changeParams(obj) +{ + var begin = $('#conditions').find('#begin').val(); + var end = $('#conditions').find('#end').val(); + var workday = $('#conditions').find('#workday').val(); + var dept = $('#conditions').find('#dept').val(); + var assign = $('#conditions').find('#assign').val(); + var days = diffDate(begin, end); + + $('#days').val(days); + + if(begin.indexOf('-') != -1) + { + var beginarray = begin.split("-"); + var begin = ''; + for(i = 0; i < beginarray.length; i++) begin = begin + beginarray[i]; + } + if(end.indexOf('-') != -1) + { + var endarray = end.split("-"); + var end = ''; + for(i = 0 ; i < endarray.length ; i++) end = end + endarray[i]; + } + + var params = window.btoa('begin=' + begin + '&end=' + end + '&days=' + days + '&workday=' + workday + '&dept=' + dept + '&assign=' + assign); + var link = createLink('pivot', 'preview', 'dimension=' + dimension + '&group=' + group + '&module=pivot&method=workload¶ms=' + params); + location.href = link; +} + +/** + * Convert a date string to date object in js. + * + * @param string $date + * @access public + * @return date + */ +function convertStringToDate(dateString) +{ + dateString = dateString.split('-'); + return new Date(dateString[0], dateString[1] - 1, dateString[2]); +} + +/** + * Compute the diff days of two date. + * + * @param string $date1 + * @param string $date1 + * @access public + * @return int + */ +function diffDate(date1, date2) +{ + date1 = convertStringToDate(date1); + date2 = convertStringToDate(date2); + delta = (date2 - date1) / (1000 * 60 * 60 * 24) + 1; + + weekEnds = 0; + for(i = 0; i < delta; i++) + { + if((weekend == 2 && date1.getDay() == 6) || date1.getDay() == 0) weekEnds ++; + date1 = date1.valueOf(); + date1 += 1000 * 60 * 60 * 24; + date1 = new Date(date1); + } + return delta - weekEnds; +} + +$(function() +{ + var options = + { + language: config.clientLang, + weekStart: 1, + todayBtn: 1, + autoclose: 1, + todayHighlight: 1, + startView: 2, + forceParse: 0, + showMeridian: 1, + minView: 2, + format: 'yyyy-mm-dd', + startDate: new Date() + }; + $('input#begin,input#end').fixedDate().datetimepicker(options); +}); diff --git a/module/pivot/lang/de.php b/module/pivot/lang/de.php new file mode 100644 index 0000000000..abab8c3a56 --- /dev/null +++ b/module/pivot/lang/de.php @@ -0,0 +1,107 @@ + + * @package pivot + * @version $Id: en.php 5080 2013-07-10 00:46:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +$lang->pivot->index = 'Home'; +$lang->pivot->list = 'Liste'; +$lang->pivot->preview = 'View Pivot Table'; +$lang->pivot->item = 'Eintrag'; +$lang->pivot->value = 'Wert'; +$lang->pivot->percent = '%'; +$lang->pivot->undefined = 'Undefiniert'; +$lang->pivot->query = 'Abfrage'; +$lang->pivot->project = $lang->projectCommon; +$lang->pivot->PO = 'PO'; + +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; + +$lang->pivot->assign['noassign'] = 'Nicht zugeordnet'; +$lang->pivot->assign['assign'] = 'Zugeordnet'; + +$lang->pivot->singleColor[] = 'F6BD0F'; + +$lang->pivot->projectDeviation = "{$lang->execution->common}abweichungsbericht"; +$lang->pivot->productSummary = $lang->productCommon . ' Zusammenfassung'; +$lang->pivot->bugCreate = 'Bug gemeldet'; +$lang->pivot->bugAssign = 'Bug zugeordnet'; +$lang->pivot->workload = 'Team Arbeitslast '; +$lang->pivot->workloadAB = 'Arbeitslast'; +$lang->pivot->bugOpenedDate = 'Bug gemeldet am'; +$lang->pivot->beginAndEnd = ' : von'; +$lang->pivot->begin = 'Begin'; +$lang->pivot->end = 'End'; +$lang->pivot->dept = 'Abteilung'; +$lang->pivot->deviationChart = "{$lang->projectCommon} Deviation Chart"; + +$lang->pivotList = new stdclass(); +$lang->pivotList->product = new stdclass(); +$lang->pivotList->project = new stdclass(); +$lang->pivotList->test = new stdclass(); +$lang->pivotList->staff = new stdclass(); + +$lang->pivotList->product->lists[10] = $lang->productCommon . ' Zusammenfassung|pivot|productsummary'; +$lang->pivotList->project->lists[10] = "{$lang->execution->common} Abweichnung|pivot|projectdeviation"; +$lang->pivotList->test->lists[10] = 'Bugs gemeldet|pivot|bugcreate'; +$lang->pivotList->test->lists[13] = 'Bugs zugeordnet|pivot|bugassign'; +$lang->pivotList->staff->lists[10] = 'Team Arbeitslast|pivot|workload'; + +$lang->pivot->id = 'ID'; +$lang->pivot->execution = $lang->executionCommon; +$lang->pivot->product = $lang->productCommon; +$lang->pivot->user = 'Name'; +$lang->pivot->bugTotal = 'Bug'; +$lang->pivot->task = 'Aufgabe'; +$lang->pivot->estimate = 'Schätzung(h)'; +$lang->pivot->consumed = 'Verbraucht'; +$lang->pivot->remain = 'Rest'; +$lang->pivot->deviation = 'Abweichung'; +$lang->pivot->deviationRate = 'Abweichungsrate'; +$lang->pivot->total = 'Summe'; +$lang->pivot->to = 'bis'; +$lang->pivot->taskTotal = "Summe Aufgaben"; +$lang->pivot->manhourTotal = "Summe Stunden"; +$lang->pivot->validRate = "Gültigkeitsrate"; +$lang->pivot->validRateTips = "Lösung ist gelöst/verschoben oder der Status ist gelöst/geschlossen."; +$lang->pivot->unplanned = 'Ungeplant'; +$lang->pivot->workday = 'Stunden/Tag'; +$lang->pivot->diffDays = 'Manntage'; + +$lang->pivot->typeList['default'] = 'Standard'; +$lang->pivot->typeList['pie'] = 'Torte'; +$lang->pivot->typeList['bar'] = 'Balken'; +$lang->pivot->typeList['line'] = 'Linien'; + +$lang->pivot->conditions = 'Filter:'; +$lang->pivot->closedProduct = 'Geschlossen ' . $lang->productCommon; +$lang->pivot->overduePlan = 'Fälligkeit Plan'; + +$lang->pivot->idAB = 'ID'; +$lang->pivot->bugTitle = 'Bug-Name'; +$lang->pivot->taskName = 'Aufgabe-Name'; +$lang->pivot->todoName = 'Todo-Name'; +$lang->pivot->testTaskName = 'Testaufgabe-Name'; +$lang->pivot->deadline = 'Fällig'; + +$lang->pivot->deviationDesc = 'According to the Closed Execution Deviation Rate = ((Total Cost - Total Estimate) / Total Estimate), the Deviation Rate is n/a when the Total Estimate is 0.'; +$lang->pivot->proVersion = 'Testen Sie ZenTao Pro für mehr Informationen!'; +$lang->pivot->proVersionEn = 'Testen Sie ZenTao Pro für mehr Informationen!'; +$lang->pivot->workloadDesc = 'Workload = the total left hours of all tasks of the user / selected days * hours per day. +For example: the begin and end date is January 1st to January 7th, and the total work days is 5 days, 8 hours per day. The Work load is all unfinished tasks assigned to this user to be finished in 5 days, 8 hours per day.'; diff --git a/module/pivot/lang/en.php b/module/pivot/lang/en.php new file mode 100644 index 0000000000..93684b3862 --- /dev/null +++ b/module/pivot/lang/en.php @@ -0,0 +1,107 @@ + + * @package pivot + * @version $Id: en.php 5080 2013-07-10 00:46:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +$lang->pivot->index = 'Pivot Home'; +$lang->pivot->list = 'Pivot Table'; +$lang->pivot->preview = 'View Pivot Table'; +$lang->pivot->item = 'Item'; +$lang->pivot->value = 'Value'; +$lang->pivot->percent = '%'; +$lang->pivot->undefined = 'Undefined'; +$lang->pivot->query = 'Query'; +$lang->pivot->project = $lang->projectCommon; +$lang->pivot->PO = 'PO'; + +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'F6BD0F'; +$lang->pivot->colors[] = '8BBA00'; +$lang->pivot->colors[] = 'FF8E46'; +$lang->pivot->colors[] = '008E8E'; +$lang->pivot->colors[] = 'D64646'; +$lang->pivot->colors[] = '8E468E'; +$lang->pivot->colors[] = '588526'; +$lang->pivot->colors[] = 'B3AA00'; +$lang->pivot->colors[] = '008ED6'; +$lang->pivot->colors[] = '9D080D'; +$lang->pivot->colors[] = 'A186BE'; + +$lang->pivot->assign['noassign'] = 'Unassigned'; +$lang->pivot->assign['assign'] = 'Assigned'; + +$lang->pivot->singleColor[] = 'F6BD0F'; + +$lang->pivot->projectDeviation = "{$lang->execution->common} Deviation"; +$lang->pivot->productSummary = $lang->productCommon . ' Summary'; +$lang->pivot->bugCreate = 'Bug Reported Summary'; +$lang->pivot->bugAssign = 'Bug Assigned Summary'; +$lang->pivot->workload = 'Team Workload Summary'; +$lang->pivot->workloadAB = 'Workload'; +$lang->pivot->bugOpenedDate = 'Bug pivoted from'; +$lang->pivot->beginAndEnd = ' From'; +$lang->pivot->begin = ' Begin'; +$lang->pivot->end = ' End'; +$lang->pivot->dept = 'Department'; +$lang->pivot->deviationChart = "{$lang->projectCommon} Deviation Chart"; + +$lang->pivotList = new stdclass(); +$lang->pivotList->product = new stdclass(); +$lang->pivotList->project = new stdclass(); +$lang->pivotList->test = new stdclass(); +$lang->pivotList->staff = new stdclass(); + +$lang->pivotList->product->lists[10] = $lang->productCommon . ' Summary|pivot|productsummary'; +$lang->pivotList->project->lists[10] = "{$lang->execution->common} Deviation|pivot|projectdeviation"; +$lang->pivotList->test->lists[10] = 'Bug Reported Summary|pivot|bugcreate'; +$lang->pivotList->test->lists[13] = 'Bug Assigned Summary|pivot|bugassign'; +$lang->pivotList->staff->lists[10] = 'Team Workload Summary|pivot|workload'; + +$lang->pivot->id = 'ID'; +$lang->pivot->execution = $lang->execution->common; +$lang->pivot->product = $lang->productCommon; +$lang->pivot->user = 'User'; +$lang->pivot->bugTotal = 'Bug'; +$lang->pivot->task = 'Task'; +$lang->pivot->estimate = 'Estimates'; +$lang->pivot->consumed = 'Cost'; +$lang->pivot->remain = 'Left'; +$lang->pivot->deviation = 'Deviation'; +$lang->pivot->deviationRate = 'Deviation Rate'; +$lang->pivot->total = 'Total'; +$lang->pivot->to = 'to'; +$lang->pivot->taskTotal = "Total Tasks"; +$lang->pivot->manhourTotal = "Total Hours"; +$lang->pivot->validRate = "Valid Rate"; +$lang->pivot->validRateTips = "Resolution is Resolved/Postponed or status is Resolved/Closed."; +$lang->pivot->unplanned = 'Unplanned'; +$lang->pivot->workday = 'Hours/Day'; +$lang->pivot->diffDays = 'days'; + +$lang->pivot->typeList['default'] = 'Default'; +$lang->pivot->typeList['pie'] = 'Pie'; +$lang->pivot->typeList['bar'] = 'Bar'; +$lang->pivot->typeList['line'] = 'Line'; + +$lang->pivot->conditions = 'Filter by:'; +$lang->pivot->closedProduct = 'Closed ' . $lang->productCommon . 's'; +$lang->pivot->overduePlan = 'Expired Plans'; + +$lang->pivot->idAB = 'ID'; +$lang->pivot->bugTitle = 'Bug Name'; +$lang->pivot->taskName = 'Task Name'; +$lang->pivot->todoName = 'Todo Name'; +$lang->pivot->testTaskName = 'Request Name'; +$lang->pivot->deadline = 'Deadline'; + +$lang->pivot->deviationDesc = 'According to the Closed Execution Deviation Rate = ((Total Cost - Total Estimate) / Total Estimate), the Deviation Rate is n/a when the Total Estimate is 0.'; +$lang->pivot->proVersion = 'Try ZenTao Biz for more!'; +$lang->pivot->proVersionEn = 'Try ZenTao Biz for more!'; +$lang->pivot->workloadDesc = 'Workload = the total left hours of all tasks of the user / selected days * hours per day. +For example: the begin and end date is January 1st to January 7th, and the total work days is 5 days, 8 hours per day. The Work load is all unfinished tasks assigned to this user to be finished in 5 days, 8 hours per day.'; diff --git a/module/pivot/lang/fr.php b/module/pivot/lang/fr.php new file mode 100644 index 0000000000..e771c3d098 --- /dev/null +++ b/module/pivot/lang/fr.php @@ -0,0 +1,107 @@ + + * @package pivot + * @version $Id: en.php 5080 2013-07-10 00:46:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +$lang->pivot->index = 'Accueil Rapports'; +$lang->pivot->list = 'Rapports'; +$lang->pivot->preview = 'View Pivot Table'; +$lang->pivot->item = 'Item'; +$lang->pivot->value = 'Valeur'; +$lang->pivot->percent = '%'; +$lang->pivot->undefined = 'N/D'; +$lang->pivot->query = 'Requête'; +$lang->pivot->project = $lang->projectCommon; +$lang->pivot->PO = 'PO'; + +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'AFD8F8'; + +$lang->pivot->assign['noassign'] = 'Non affecté'; +$lang->pivot->assign['assign'] = 'Affecté'; + +$lang->pivot->singleColor[] = 'F6BD0F'; + +$lang->pivot->projectDeviation = "Rapport de déviation du{$lang->execution->common}"; +$lang->pivot->productSummary = 'Résumé ' . $lang->productCommon; +$lang->pivot->bugCreate = 'Résumé remontée Bugs'; +$lang->pivot->bugAssign = 'Résumé affectation Bugs'; +$lang->pivot->workload = 'Résumé charge travail'; +$lang->pivot->workloadAB = 'Charge Travail'; +$lang->pivot->bugOpenedDate = 'Bugs signalés de'; +$lang->pivot->beginAndEnd = ' de'; +$lang->pivot->begin = 'Begin'; +$lang->pivot->end = 'End'; +$lang->pivot->dept = 'Compartiment'; +$lang->pivot->deviationChart = "{$lang->projectCommon} Deviation Chart"; + +$lang->pivotList = new stdclass(); +$lang->pivotList->product = new stdclass(); +$lang->pivotList->project = new stdclass(); +$lang->pivotList->test = new stdclass(); +$lang->pivotList->staff = new stdclass(); + +$lang->pivotList->product->lists[10] = 'Résumé ' . $lang->productCommon . '|pivot|productsummary'; +$lang->pivotList->project->lists[10] = "Dérv {$lang->execution->common}|pivot|projectdeviation"; +$lang->pivotList->test->lists[10] = 'Résumé remontée Bugs|pivot|bugcreate'; +$lang->pivotList->test->lists[13] = 'Résumé affectation Bugs|pivot|bugassign'; +$lang->pivotList->staff->lists[10] = 'Résumé charge travail|pivot|workload'; + +$lang->pivot->id = 'ID'; +$lang->pivot->execution = $lang->executionCommon; +$lang->pivot->product = $lang->productCommon; +$lang->pivot->user = 'Utilisateur'; +$lang->pivot->bugTotal = 'Bugs'; +$lang->pivot->task = 'Tâches'; +$lang->pivot->estimate = 'Estimé'; +$lang->pivot->consumed = 'Coût'; +$lang->pivot->remain = 'Reste'; +$lang->pivot->deviation = 'Dérive'; +$lang->pivot->deviationRate = 'Taux Dérive'; +$lang->pivot->total = 'Total'; +$lang->pivot->to = 'à'; +$lang->pivot->taskTotal = "Tâches Totales"; +$lang->pivot->manhourTotal = "Heures Totales"; +$lang->pivot->validRate = "Taux Validation"; +$lang->pivot->validRateTips = "Résolution est Résolu/Reporté ou statut est Résolu/Fermé."; +$lang->pivot->unplanned = 'Non planifié'; +$lang->pivot->workday = 'Heures/Jour'; +$lang->pivot->diffDays = 'jours'; + +$lang->pivot->typeList['default'] = 'Défaut'; +$lang->pivot->typeList['pie'] = 'Camenbert'; +$lang->pivot->typeList['bar'] = 'Barres'; +$lang->pivot->typeList['line'] = 'Lignes'; + +$lang->pivot->conditions = 'Filtré par :'; +$lang->pivot->closedProduct = $lang->productCommon . 's Fermés'; +$lang->pivot->overduePlan = 'Plans Echus'; + +$lang->pivot->idAB = 'ID'; +$lang->pivot->bugTitle = 'Nom Bug'; +$lang->pivot->taskName = 'Nom Tâche'; +$lang->pivot->todoName = 'Nom Agenda'; +$lang->pivot->testTaskName = 'Nom Recette'; +$lang->pivot->deadline = 'Date Butoir'; + +$lang->pivot->deviationDesc = 'According to the Closed Execution Deviation Rate = ((Total Cost - Total Estimate) / Total Estimate), the Deviation Rate is n/a when the Total Estimate is 0.'; +$lang->pivot->proVersion = 'Essayez ZenTao Pro pour en savoir plus !'; +$lang->pivot->proVersionEn = 'Try ZenTao Pro for more!'; +$lang->pivot->workloadDesc = 'Workload = the total left hours of all tasks of the user / selected days * hours per day. +For example: the begin and end date is January 1st to January 7th, and the total work days is 5 days, 8 hours per day. The Work load is all unfinished tasks assigned to this user to be finished in 5 days, 8 hours per day.'; diff --git a/module/pivot/lang/vi.php b/module/pivot/lang/vi.php new file mode 100644 index 0000000000..b4bb92a201 --- /dev/null +++ b/module/pivot/lang/vi.php @@ -0,0 +1,108 @@ + + * @package pivot + * @version $Id: vi.php 5080 2013-07-10 00:46:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +$lang->pivot->index = 'Trang báo cáo'; +$lang->pivot->list = 'Báo cáo'; +$lang->pivot->preview = 'View Pivot Table'; +$lang->pivot->item = 'Hạng mục'; +$lang->pivot->value = 'Giá trị'; +$lang->pivot->percent = '%'; +$lang->pivot->undefined = 'Chưa định nghĩa'; +$lang->pivot->query = 'Truy vấn'; +$lang->pivot->project = 'Project'; +$lang->pivot->PO = 'PO'; + +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'F6BD0F'; +$lang->pivot->colors[] = '8BBA00'; +$lang->pivot->colors[] = 'FF8E46'; +$lang->pivot->colors[] = '008E8E'; +$lang->pivot->colors[] = 'D64646'; +$lang->pivot->colors[] = '8E468E'; +$lang->pivot->colors[] = '588526'; +$lang->pivot->colors[] = 'B3AA00'; +$lang->pivot->colors[] = '008ED6'; +$lang->pivot->colors[] = '9D080D'; +$lang->pivot->colors[] = 'A186BE'; + +$lang->pivot->assign['noassign'] = 'Chưa giao'; +$lang->pivot->assign['assign'] = 'Đã giao'; + +$lang->pivot->singleColor[] = 'F6BD0F'; + +$lang->pivot->projectDeviation = 'Độ lệch thực hiện'; +$lang->pivot->productSummary = 'Tóm tắt '.$lang->productCommon; +$lang->pivot->bugCreate = 'Báo cáo Bug'; +$lang->pivot->bugAssign = 'Bàn giao Bug'; +$lang->pivot->workload = 'Lượng công việc đội nhóm'; +$lang->pivot->workloadAB = 'Lượng công việc'; +$lang->pivot->bugOpenedDate = 'Bug được báo cáo từ'; +$lang->pivot->beginAndEnd = ' từ'; +$lang->pivot->begin = 'Begin'; +$lang->pivot->end = 'End'; +$lang->pivot->dept = 'Phòng/Ban'; +$lang->pivot->deviationChart = 'Biểu đồ chênh lệcthực hiệnh'; + +$lang->pivotList = new stdclass(); +$lang->pivotList->product = new stdclass(); +$lang->pivotList->project = new stdclass(); +$lang->pivotList->test = new stdclass(); +$lang->pivotList->staff = new stdclass(); + +$lang->pivotList->product->lists[10] = 'Tóm tắt '.$lang->productCommon . '|pivot|productsummary'; +$lang->pivotList->project->lists[10] = 'Chênh lệchthực hiện|pivotprojectdeviation'; +$lang->pivotList->test->lists[10] = 'Báo cáo Bug|pivot|bugcreate'; +$lang->pivotList->test->lists[13] = 'Bàn giao Bug|pivot|bugassign'; +$lang->pivotList->staff->lists[10] = 'Lượng công việc đội nhóm|pivot|workload'; + +$lang->pivot->id = 'ID'; +$lang->pivot->execution = $lang->executionCommon; +$lang->pivot->product = $lang->productCommon; +$lang->pivot->user = 'Người dùng'; +$lang->pivot->bugTotal = 'Bug'; +$lang->pivot->task = 'Nhiệm vụ'; +$lang->pivot->estimate = 'Dự tính'; +$lang->pivot->consumed = 'Đã làm'; +$lang->pivot->remain = 'Còn'; +$lang->pivot->deviation = 'Chênh lệch'; +$lang->pivot->deviationRate = 'Tỷ lệ lệch'; +$lang->pivot->total = 'Tổng'; +$lang->pivot->to = 'to'; +$lang->pivot->taskTotal = "Tổng nhiệm vụ"; +$lang->pivot->manhourTotal = "Tổng số giờ"; +$lang->pivot->validRate = "Tỷ lệ hợp lý"; +$lang->pivot->validRateTips = "Giải pháp được Giải quyết/Hoãn lại hoặc Giải quyết/Đã đóng."; +$lang->pivot->unplanned = 'Chưa kế hoạch'; +$lang->pivot->workday = 'Giờ/ngày'; +$lang->pivot->diffDays = 'ngày'; + +$lang->pivot->typeList['default'] = 'Mặc định'; +$lang->pivot->typeList['pie'] = 'Pie'; +$lang->pivot->typeList['bar'] = 'Bar'; +$lang->pivot->typeList['line'] = 'Line'; + +$lang->pivot->conditions = 'Lọc theo:'; +$lang->pivot->closedProduct = $lang->productCommon . ' đã đóng'; +$lang->pivot->overduePlan = 'Kế hoạch quá hạn'; + +/* daily reminder. */ +$lang->pivot->idAB = 'ID'; +$lang->pivot->bugTitle = 'Tên Bug'; +$lang->pivot->taskName = 'Tên nhiệm vụ'; +$lang->pivot->todoName = 'Tên việc'; +$lang->pivot->testTaskName = 'Tên yêu cầu'; +$lang->pivot->deadline = 'Hạn chót'; + +$lang->pivot->deviationDesc = 'According to the Closed Execution Deviation Rate = ((Total Cost - Total Estimate) / Total Estimate), the Deviation Rate is n/a when the Total Estimate is 0.'; +$lang->pivot->proVersion = 'Hãy thử ZenTao Pro để biết thêm!'; +$lang->pivot->proVersionEn = 'Hãy thử ZenTao Pro để biết thêm!'; +$lang->pivot->workloadDesc = 'Workload = the total left hours of all tasks of the user / selected days * hours per day. +For example: the begin and end date is January 1st to January 7th, and the total work days is 5 days, 8 hours per day. The Work load is all unfinished tasks assigned to this user to be finished in 5 days, 8 hours per day.'; diff --git a/module/pivot/lang/zh-cn.php b/module/pivot/lang/zh-cn.php new file mode 100644 index 0000000000..a391761bfa --- /dev/null +++ b/module/pivot/lang/zh-cn.php @@ -0,0 +1,106 @@ + + * @package pivot + * @version $Id: zh-cn.php 5080 2013-07-10 00:46:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +$lang->pivot->index = '透视表首页'; +$lang->pivot->list = '透视表'; +$lang->pivot->preview = '查看透视表'; +$lang->pivot->item = '条目'; +$lang->pivot->value = '值'; +$lang->pivot->percent = '百分比'; +$lang->pivot->undefined = '未设定'; +$lang->pivot->query = '查询'; +$lang->pivot->project = $lang->projectCommon; +$lang->pivot->PO = 'PO'; + +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'F6BD0F'; +$lang->pivot->colors[] = '8BBA00'; +$lang->pivot->colors[] = 'FF8E46'; +$lang->pivot->colors[] = '008E8E'; +$lang->pivot->colors[] = 'D64646'; +$lang->pivot->colors[] = '8E468E'; +$lang->pivot->colors[] = '588526'; +$lang->pivot->colors[] = 'B3AA00'; +$lang->pivot->colors[] = '008ED6'; +$lang->pivot->colors[] = '9D080D'; +$lang->pivot->colors[] = 'A186BE'; + +$lang->pivot->assign['noassign'] = '未指派'; +$lang->pivot->assign['assign'] = '已指派'; + +$lang->pivot->singleColor[] = 'F6BD0F'; + +$lang->pivot->projectDeviation = "{$lang->execution->common}偏差报表"; +$lang->pivot->productSummary = $lang->productCommon . '汇总表'; +$lang->pivot->bugCreate = 'Bug创建表'; +$lang->pivot->bugAssign = 'Bug指派表'; +$lang->pivot->workload = '员工负载表'; +$lang->pivot->workloadAB = '工作负载'; +$lang->pivot->bugOpenedDate = 'Bug创建时间'; +$lang->pivot->beginAndEnd = '起止时间'; +$lang->pivot->begin = '起始日期'; +$lang->pivot->end = '结束日期'; +$lang->pivot->dept = '部门'; +$lang->pivot->deviationChart = "{$lang->execution->common}偏差曲线"; + +$lang->pivotList = new stdclass(); +$lang->pivotList->product = new stdclass(); +$lang->pivotList->project = new stdclass(); +$lang->pivotList->test = new stdclass(); +$lang->pivotList->staff = new stdclass(); + +$lang->pivotList->product->lists[10] = $lang->productCommon . '汇总表|pivot|productsummary'; +$lang->pivotList->project->lists[10] = "{$lang->execution->common}偏差报表|pivot|projectdeviation"; +$lang->pivotList->test->lists[10] = 'Bug创建表|pivot|bugcreate'; +$lang->pivotList->test->lists[13] = 'Bug指派表|pivot|bugassign'; +$lang->pivotList->staff->lists[10] = '员工负载表|pivot|workload'; + +$lang->pivot->id = '编号'; +$lang->pivot->execution = $lang->execution->common; +$lang->pivot->product = $lang->productCommon; +$lang->pivot->user = '姓名'; +$lang->pivot->bugTotal = 'Bug'; +$lang->pivot->task = '任务数'; +$lang->pivot->estimate = '总预计'; +$lang->pivot->consumed = '总消耗'; +$lang->pivot->remain = '剩余工时'; +$lang->pivot->deviation = '偏差'; +$lang->pivot->deviationRate = '偏差率'; +$lang->pivot->total = '总计'; +$lang->pivot->to = '至'; +$lang->pivot->taskTotal = "总任务数"; +$lang->pivot->manhourTotal = "总工时"; +$lang->pivot->validRate = "有效率"; +$lang->pivot->validRateTips = "方案为已解决或延期/状态为已解决或已关闭"; +$lang->pivot->unplanned = "未计划"; +$lang->pivot->workday = '每天工时'; +$lang->pivot->diffDays = '工作日天数'; + +$lang->pivot->typeList['default'] = '默认'; +$lang->pivot->typeList['pie'] = '饼图'; +$lang->pivot->typeList['bar'] = '柱状图'; +$lang->pivot->typeList['line'] = '折线图'; + +$lang->pivot->conditions = '筛选条件:'; +$lang->pivot->closedProduct = '关闭' . $lang->productCommon; +$lang->pivot->overduePlan = "过期计划"; + +$lang->pivot->idAB = 'ID'; +$lang->pivot->bugTitle = 'Bug标题'; +$lang->pivot->taskName = '任务名称'; +$lang->pivot->todoName = '待办名称'; +$lang->pivot->testTaskName = '版本名称'; +$lang->pivot->deadline = '截止日期'; + +$lang->pivot->deviationDesc = '按照已关闭执行统计偏差率(偏差率 = (总消耗 - 总预计) / 总预计),总预计为0时偏差率为n/a。'; +$lang->pivot->proVersion = '更多精彩,尽在企业版!'; +$lang->pivot->proVersionEn = 'Try ZenTao Biz for more!'; +$lang->pivot->workloadDesc = '工作负载=用户所有任务剩余工时之和/选择的时间天数*每天的工时。例如:起止时间设为1月1日~1月7日、工作日天数5天、每天工时8h,统计的是所有指派给该人员的未完成的任务,在5天内,每天8h的情况下的工作负载。'; diff --git a/module/pivot/lang/zh-tw.php b/module/pivot/lang/zh-tw.php new file mode 100644 index 0000000000..cb09354bf9 --- /dev/null +++ b/module/pivot/lang/zh-tw.php @@ -0,0 +1,106 @@ + + * @package pivot + * @version $Id: zh-tw.php 5080 2013-07-10 00:46:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +$lang->pivot->index = '統計首頁'; +$lang->pivot->list = '透视表'; +$lang->pivot->preview = '查看透视表'; +$lang->pivot->item = '條目'; +$lang->pivot->value = '值'; +$lang->pivot->percent = '百分比'; +$lang->pivot->undefined = '未設定'; +$lang->pivot->query = '查詢'; +$lang->pivot->project = '項目'; +$lang->pivot->PO = 'PO'; + +$lang->pivot->colors[] = 'AFD8F8'; +$lang->pivot->colors[] = 'F6BD0F'; +$lang->pivot->colors[] = '8BBA00'; +$lang->pivot->colors[] = 'FF8E46'; +$lang->pivot->colors[] = '008E8E'; +$lang->pivot->colors[] = 'D64646'; +$lang->pivot->colors[] = '8E468E'; +$lang->pivot->colors[] = '588526'; +$lang->pivot->colors[] = 'B3AA00'; +$lang->pivot->colors[] = '008ED6'; +$lang->pivot->colors[] = '9D080D'; +$lang->pivot->colors[] = 'A186BE'; + +$lang->pivot->assign['noassign'] = '未指派'; +$lang->pivot->assign['assign'] = '已指派'; + +$lang->pivot->singleColor[] = 'F6BD0F'; + +$lang->pivot->projectDeviation = "{$lang->execution->common}偏差報表"; +$lang->pivot->productSummary = $lang->productCommon . '彙總表'; +$lang->pivot->bugCreate = 'Bug創建表'; +$lang->pivot->bugAssign = 'Bug指派表'; +$lang->pivot->workload = '員工負載表'; +$lang->pivot->workloadAB = '工作負載'; +$lang->pivot->bugOpenedDate = 'Bug創建時間'; +$lang->pivot->beginAndEnd = '起止時間'; +$lang->pivot->begin = '起始日期'; +$lang->pivot->end = '結束日期'; +$lang->pivot->dept = '部門'; +$lang->pivot->deviationChart = "{$lang->execution->common}偏差曲綫"; + +$lang->pivotList = new stdclass(); +$lang->pivotList->product = new stdclass(); +$lang->pivotList->project = new stdclass(); +$lang->pivotList->test = new stdclass(); +$lang->pivotList->staff = new stdclass(); + +$lang->pivotList->product->lists[10] = $lang->productCommon . '彙總表|pivot|productsummary'; +$lang->pivotList->project->lists[10] = "{$lang->execution->common}偏差報表|pivot|projectdeviation"; +$lang->pivotList->test->lists[10] = 'Bug創建表|pivot|bugcreate'; +$lang->pivotList->test->lists[13] = 'Bug指派表|pivot|bugassign'; +$lang->pivotList->staff->lists[10] = '員工負載表|pivot|workload'; + +$lang->pivot->id = '編號'; +$lang->pivot->execution = $lang->execution->common; +$lang->pivot->product = $lang->productCommon; +$lang->pivot->user = '姓名'; +$lang->pivot->bugTotal = 'Bug'; +$lang->pivot->task = '任務數'; +$lang->pivot->estimate = '總預計'; +$lang->pivot->consumed = '總消耗'; +$lang->pivot->remain = '剩餘工時'; +$lang->pivot->deviation = '偏差'; +$lang->pivot->deviationRate = '偏差率'; +$lang->pivot->total = '總計'; +$lang->pivot->to = '至'; +$lang->pivot->taskTotal = "總任務數"; +$lang->pivot->manhourTotal = "總工時"; +$lang->pivot->validRate = "有效率"; +$lang->pivot->validRateTips = "方案為已解決或延期/狀態為已解決或已關閉"; +$lang->pivot->unplanned = "未計劃"; +$lang->pivot->workday = '每天工時'; +$lang->pivot->diffDays = '工作日天數'; + +$lang->pivot->typeList['default'] = '預設'; +$lang->pivot->typeList['pie'] = '餅圖'; +$lang->pivot->typeList['bar'] = '柱狀圖'; +$lang->pivot->typeList['line'] = '折線圖'; + +$lang->pivot->conditions = '篩選條件:'; +$lang->pivot->closedProduct = '關閉' . $lang->productCommon; +$lang->pivot->overduePlan = "過期計劃"; + +$lang->pivot->idAB = 'ID'; +$lang->pivot->bugTitle = 'Bug標題'; +$lang->pivot->taskName = '任務名稱'; +$lang->pivot->todoName = '待辦名稱'; +$lang->pivot->testTaskName = '版本名稱'; +$lang->pivot->deadline = '截止日期'; + +$lang->pivot->deviationDesc = '按照已關閉執行統計偏差率(偏差率 = (總消耗 - 總預計) / 總預計),總預計為0時偏差率為n/a。'; +$lang->pivot->proVersion = '更多精彩,盡在專業版!'; +$lang->pivot->proVersionEn = 'Try ZenTao Pro for more!'; +$lang->pivot->workloadDesc = '工作負載=用戶所有任務剩餘工時之和/選擇的時間天數*每天的工時。例如:起止時間設為1月1日~1月7日、工作日天數5天、每天工時8h,統計的是所有指派給該人員的未完成的任務,在5天內,每天8h的情況下的工作負載。'; diff --git a/module/pivot/model.php b/module/pivot/model.php new file mode 100644 index 0000000000..6d0487cd4e --- /dev/null +++ b/module/pivot/model.php @@ -0,0 +1,1105 @@ + + * @package pivot + * @version $Id: model.php 4726 2013-05-03 05:51:27Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +?> +value; + + $totalPercent = 0; + foreach($datas as $i => $data) + { + $data->percent = round($data->value / $sum, 4); + $totalPercent += $data->percent; + } + if(isset($i)) $datas[$i]->percent = round(1 - $totalPercent + $datas[$i]->percent, 4); + return $datas; + } + + /** + * Create json data of single charts + * @param array $sets + * @param array $dateList + * @return string the json string + */ + public function createSingleJSON($sets, $dateList) + { + $data = '['; + $now = date('Y-m-d'); + $preValue = 0; + $setsDate = array_keys($sets); + foreach($dateList as $i => $date) + { + $date = date('Y-m-d', strtotime($date)); + if($date > $now) break; + if(!isset($sets[$date]) and $sets) + { + $tmpDate = $setsDate; + $tmpDate[] = $date; + sort($tmpDate); + $tmpDateStr = ',' . join(',', $tmpDate); + $preDate = rtrim(substr($tmpDateStr, 0, strpos($tmpDateStr, $date)), ','); + $preDate = substr($preDate, strrpos($preDate, ',') + 1); + + if($preDate) + { + $preValue = $sets[$preDate]; + $preValue = $preValue->value; + } + } + + $data .= isset($sets[$date]) ? "{$sets[$date]->value}," : "{$preValue},"; + } + $data = rtrim($data, ','); + $data .= ']'; + return $data; + } + + /** + * Convert date format. + * + * @param array $dateList + * @param string $format + * @access public + * @return array + */ + public function convertFormat($dateList, $format = 'Y-m-d') + { + foreach($dateList as $i => $date) $dateList[$i] = date($format, strtotime($date)); + return $dateList; + } + + /** + * Get executions. + * + * @param string $begin + * @param string $end + * @access public + * @return array + */ + public function getExecutions($begin = 0, $end = 0) + { + $permission = common::hasPriv('pivot', 'showProject') or $this->app->user->admin; + $tasks = $this->dao->select('t1.*, IF(t3.multiple = "1", t2.name, "") as executionName, t3.name as projectName, t2.multiple')->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id') + ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t1.project = t3.id') + ->where('t1.status')->ne('cancel') + ->andWhere('t1.deleted')->eq(0) + ->beginIF(!$permission)->andWhere('t2.id')->in($this->app->user->view->sprints)->fi() + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t1.parent')->lt(1) + ->andWhere('t2.status')->eq('closed') + ->beginIF($begin)->andWhere('t2.begin')->ge($begin)->fi() + ->beginIF($end)->andWhere('t2.end')->le($end)->fi() + ->orderBy('t2.end_desc') + ->fetchAll(); + + $executions = array(); + foreach($tasks as $task) + { + $executionID = $task->execution; + if(!isset($executions[$executionID])) + { + $executions[$executionID] = new stdclass(); + $executions[$executionID]->estimate = 0; + $executions[$executionID]->consumed = 0; + } + + $executions[$executionID]->projectID = $task->project; + $executions[$executionID]->projectName = $task->projectName; + $executions[$executionID]->multiple = $task->multiple; + $executions[$executionID]->name = $task->executionName; + $executions[$executionID]->estimate += $task->estimate; + $executions[$executionID]->consumed += $task->consumed; + } + + return $executions; + } + + /** + * Get products. + * + * @access public + * @return array + */ + public function getProducts($conditions, $storyType = 'story') + { + $permission = common::hasPriv('pivot', 'showProduct') or $this->app->user->admin; + $products = $this->dao->select('t1.id as id, t1.code, t1.name, t1.PO')->from(TABLE_PRODUCT)->alias('t1') + ->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id') + ->where('t1.deleted')->eq(0) + ->andWhere('t1.shadow')->eq(0) + ->beginIF(strpos($conditions, 'closedProduct') === false)->andWhere('t1.status')->ne('closed')->fi() + ->beginIF(!$permission)->andWhere('t1.id')->in($this->app->user->view->products)->fi() + ->orderBy('t2.order_asc, t1.line_desc, t1.order_asc') + ->fetchAll('id'); + + $plans = $this->dao->select('id, product, branch, parent, title, begin, end')->from(TABLE_PRODUCTPLAN)->where('deleted')->eq(0)->andWhere('product')->in(array_keys($products)) + ->beginIF(strpos($conditions, 'overduePlan') === false)->andWhere('end')->gt(date('Y-m-d'))->fi() + ->orderBy('product,parent_desc,begin') + ->fetchAll('id'); + foreach($plans as $plan) + { + if($plan->parent > 0) + { + $parentPlan = zget($plans, $plan->parent, null); + if($parentPlan) + { + $products[$plan->product]->plans[$parentPlan->id] = $parentPlan; + unset($plans[$parentPlan->id]); + } + $plan->title = '>>' . $plan->title; + } + $products[$plan->product]->plans[$plan->id] = $plan; + } + + $planStories = array(); + $unplannedStories = array(); + $stmt = $this->dao->select('id,plan,product,status') + ->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('parent')->ge(0) + ->beginIF($storyType)->andWhere('type')->eq($storyType)->fi() + ->query(); + while($story = $stmt->fetch()) + { + if(empty($story->plan)) + { + $unplannedStories[$story->id] = $story; + continue; + } + + $storyPlans = array(); + $storyPlans[] = $story->plan; + if(strpos($story->plan, ',') !== false) $storyPlans = explode(',', trim($story->plan, ',')); + foreach($storyPlans as $planID) + { + if(isset($plans[$planID])) + { + $planStories[$story->id] = $story; + break; + } + } + } + + foreach($planStories as $story) + { + $storyPlans = array(); + $storyPlans[] = $story->plan; + if(strpos($story->plan, ',') !== false) $storyPlans = explode(',', trim($story->plan, ',')); + foreach($storyPlans as $planID) + { + if(!isset($plans[$planID])) continue; + $plan = $plans[$planID]; + $products[$plan->product]->plans[$planID]->status[$story->status] = isset($products[$plan->product]->plans[$planID]->status[$story->status]) ? $products[$plan->product]->plans[$planID]->status[$story->status] + 1 : 1; + } + } + + foreach($unplannedStories as $story) + { + $product = $story->product; + if(isset($products[$product])) + { + if(!isset($products[$product]->plans[0])) + { + $products[$product]->plans[0] = new stdClass(); + $products[$product]->plans[0]->title = $this->lang->pivot->unplanned; + $products[$product]->plans[0]->begin = ''; + $products[$product]->plans[0]->end = ''; + } + $products[$product]->plans[0]->status[$story->status] = isset($products[$product]->plans[0]->status[$story->status]) ? $products[$product]->plans[0]->status[$story->status] + 1 : 1; + } + } + + unset($products['']); + return $products; + } + + /** + * Get bugs + * + * @param int $begin + * @param int $end + * @param int $product + * @param int $execution + * @access public + * @return array + */ + public function getBugs($begin, $end, $product, $execution) + { + $end = date('Ymd', strtotime("$end +1 day")); + $bugs = $this->dao->select('id, resolution, openedBy, status')->from(TABLE_BUG) + ->where('deleted')->eq(0) + ->andWhere('openedDate')->ge($begin) + ->andWhere('openedDate')->le($end) + ->beginIF($product)->andWhere('product')->eq($product)->fi() + ->beginIF($execution)->andWhere('execution')->eq($execution)->fi() + ->fetchAll(); + + $bugCreate = array(); + foreach($bugs as $bug) + { + $bugCreate[$bug->openedBy][$bug->resolution] = empty($bugCreate[$bug->openedBy][$bug->resolution]) ? 1 : $bugCreate[$bug->openedBy][$bug->resolution] + 1; + $bugCreate[$bug->openedBy]['all'] = empty($bugCreate[$bug->openedBy]['all']) ? 1 : $bugCreate[$bug->openedBy]['all'] + 1; + if($bug->status == 'resolved' or $bug->status == 'closed') + { + $bugCreate[$bug->openedBy]['resolved'] = empty($bugCreate[$bug->openedBy]['resolved']) ? 1 : $bugCreate[$bug->openedBy]['resolved'] + 1; + } + } + + foreach($bugCreate as $account => $bug) + { + $validRate = 0; + if(isset($bug['fixed'])) $validRate += $bug['fixed']; + if(isset($bug['postponed'])) $validRate += $bug['postponed']; + $bugCreate[$account]['validRate'] = (isset($bug['resolved']) and $bug['resolved']) ? ($validRate / $bug['resolved']) : "0"; + } + uasort($bugCreate, 'sortSummary'); + return $bugCreate; + } + + /** + * Get workload. + * + * @param int $dept + * @param string $assign + * + * @access public + * @return array + */ + public function getWorkload($dept = 0, $assign = 'assign') + { + $deptUsers = array(); + if($dept) $deptUsers = $this->loadModel('dept')->getDeptUserPairs($dept); + + if($assign == 'noassign') + { + $members = $this->dao->select('t1.account,t2.name,t2.multiple,t1.root,t3.id as project,t3.name as projectname')->from(TABLE_TEAM)->alias('t1') + ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t2.id = t1.root') + ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t3.id = t2.project') + ->where('t2.status')->notin('cancel, closed, done, suspended') + ->beginIF($dept)->andWhere('t1.account')->in(array_keys($deptUsers))->fi() + ->andWhere('t1.type')->eq('execution') + ->andWhere("t1.account NOT IN(SELECT `assignedTo` FROM " . TABLE_TASK . " WHERE `execution` = t1.`root` AND `status` NOT IN('cancel, closed, done, pause') AND assignedTo != '' GROUP BY assignedTo)") + ->andWhere('t2.deleted')->eq('0') + ->fetchGroup('account', 'name'); + + $workload = array(); + if(!empty($members)) + { + foreach($members as $member => $executions) + { + $project = array(); + if(!empty($executions)) + { + foreach($executions as $name => $execution) + { + $project[$execution->projectname]['projectID'] = $execution->project; + $project[$execution->projectname]['execution'][$name]['executionID'] = $execution->root; + $project[$execution->projectname]['execution'][$name]['multiple'] = $execution->multiple; + $project[$execution->projectname]['execution'][$name]['count'] = 0; + $project[$execution->projectname]['execution'][$name]['manhour'] = 0; + + $workload[$member]['total']['count'] = 0; + $workload[$member]['total']['manhour'] = 0; + } + } + $workload[$member]['task']['project'] = $project; + } + } + return $workload; + } + + $stmt = $this->dao->select('t1.*, t2.name as executionName, t3.name as projectname, t2.multiple')->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id') + ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t3.id = t2.project') + ->where('t1.deleted')->eq(0) + ->andWhere('t1.status')->in('wait,pause,doing') + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t2.status')->in('wait,suspended,doing') + ->andWhere('assignedTo')->ne(''); + + $allTasks = $stmt->fetchAll('id'); + if(empty($allTasks)) return array(); + + $tasks = array(); + if(empty($dept)) + { + $tasks = $allTasks; + } + else + { + foreach($allTasks as $taskID => $task) + { + if(isset($deptUsers[$task->assignedTo])) $tasks[$taskID] = $task; + } + } + + /* Fix bug for children. */ + $parents = array(); + $taskIdList = array(); + $taskGroups = array(); + foreach($tasks as $task) + { + if($task->parent > 0) $parents[$task->parent] = $task->parent; + $taskGroups[$task->assignedTo][$task->id] = $task; + } + + $stmt = $this->dao->select('*')->from(TABLE_TASKTEAM)->where('task')->in(array_keys($allTasks)) + ->beginIF($dept)->andWhere('account')->in(array_keys($deptUsers))->fi() + ->query(); + $multiTaskTeams = array(); + while($taskTeam = $stmt->fetch()) + { + $account = $taskTeam->account; + if(!isset($multiTaskTeams[$account][$taskTeam->task])) + { + $multiTaskTeams[$account][$taskTeam->task] = $taskTeam; + } + else + { + $multiTaskTeams[$account][$taskTeam->task]->estimate += $taskTeam->estimate; + $multiTaskTeams[$account][$taskTeam->task]->consumed += $taskTeam->consumed; + $multiTaskTeams[$account][$taskTeam->task]->left += $taskTeam->left; + } + } + foreach($multiTaskTeams as $assignedTo => $taskTeams) + { + foreach($taskTeams as $taskTeam) + { + $userTask = clone $allTasks[$taskTeam->task]; + $userTask->estimate = $taskTeam->estimate; + $userTask->consumed = $taskTeam->consumed; + $userTask->left = $taskTeam->left; + $taskGroups[$assignedTo][$taskTeam->task] = $userTask; + } + } + + $workload = array(); + foreach($taskGroups as $user => $userTasks) + { + if($user) + { + $project = array(); + foreach($userTasks as $task) + { + if(isset($parents[$task->id])) continue; + + $project[$task->projectname]['projectID'] = isset($project[$task->projectname]['projectID']) ? $project[$task->projectname]['projectID'] : $task->project; + $project[$task->projectname]['execution'][$task->executionName]['executionID'] = isset($project[$task->projectname]['execution'][$task->executionName]['executionID']) ? $project[$task->projectname]['execution'][$task->executionName]['executionID'] : $task->execution; + $project[$task->projectname]['execution'][$task->executionName]['multiple'] = isset($project[$task->projectname]['execution'][$task->executionName]['multiple']) ? $project[$task->projectname]['execution'][$task->executionName]['multiple'] : $task->multiple; + $project[$task->projectname]['execution'][$task->executionName]['count'] = isset($project[$task->projectname]['execution'][$task->executionName]['count']) ? $project[$task->projectname]['execution'][$task->executionName]['count'] + 1 : 1; + $project[$task->projectname]['execution'][$task->executionName]['manhour'] = isset($project[$task->projectname]['execution'][$task->executionName]['manhour']) ? $project[$task->projectname]['execution'][$task->executionName]['manhour'] + $task->left : $task->left; + + $workload[$user]['total']['count'] = isset($workload[$user]['total']['count']) ? $workload[$user]['total']['count'] + 1 : 1; + $workload[$user]['total']['manhour'] = isset($workload[$user]['total']['manhour']) ? $workload[$user]['total']['manhour'] + $task->left : $task->left; + } + + if(empty($project)) continue; + $workload[$user]['task']['project'] = $project; + } + } + unset($workload['closed']); + return $workload; + } + + /** + * Get bug assign. + * + * @access public + * @return array + */ + public function getBugAssign() + { + $bugs = $this->dao->select('t1.*, t2.name AS productName')->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') + ->where('t1.deleted')->eq(0) + ->andWhere('t1.status')->eq('active') + ->andWhere('t2.deleted')->eq(0) + ->fetchGroup('assignedTo'); + $productProjects = $this->dao->select('t2.product, t2.project')->from(TABLE_PROJECT)->alias('t1') + ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id = t2.project') + ->where('t1.type')->eq('project') + ->andWhere('t1.hasProduct')->eq(0) + ->fetchPairs(); + $assign = array(); + foreach($bugs as $user => $userBugs) + { + if($user) + { + foreach($userBugs as $bug) + { + $assign[$user]['bug'][$bug->productName]['count'] = isset($assign[$user]['bug'][$bug->productName]['count']) ? $assign[$user]['bug'][$bug->productName]['count'] + 1 : 1; + $assign[$user]['bug'][$bug->productName]['productID'] = $bug->product; + $assign[$user]['bug'][$bug->productName]['projectID'] = zget($productProjects, $bug->product, 0); + $assign[$user]['total']['count'] = isset($assign[$user]['total']['count']) ? $assign[$user]['total']['count'] + 1 : 1; + } + } + } + unset($assign['closed']); + return $assign; + } + + /** + * Get System URL. + * + * @access public + * @return void + */ + public function getSysURL() + { + if(isset($this->config->mail->domain)) return $this->config->mail->domain; + + /* Ger URL when run in shell. */ + if(PHP_SAPI == 'cli') + { + $url = parse_url(trim($this->server->argv[1])); + $port = (empty($url['port']) or $url['port'] == 80) ? '' : $url['port']; + $host = empty($port) ? $url['host'] : $url['host'] . ':' . $port; + return $url['scheme'] . '://' . $host; + } + else + { + return common::getSysURL(); + } + } + + /** + * Get user bugs. + * + * @access public + * @return void + */ + public function getUserBugs() + { + return $this->dao->select('t1.id, t1.title, t2.account as user, t1.deadline') + ->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2') + ->on('t1.assignedTo = t2.account') + ->where('t1.assignedTo')->ne('') + ->andWhere('t1.assignedTo')->ne('closed') + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t1.deadline', true)->eq('0000-00-00') + ->orWhere('t1.deadline')->lt(date(DT_DATE1, strtotime('+4 day'))) + ->markRight(1) + ->fetchGroup('user'); + } + + /** + * Get user tasks. + * + * @access public + * @return void + */ + public function getUserTasks() + { + return $this->dao->select('t1.id, t1.name, t2.account as user, t1.deadline')->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t1.assignedTo = t2.account') + ->leftJoin(TABLE_EXECUTION)->alias('t3')->on('t1.execution = t3.id') + ->leftJoin(TABLE_PROJECT)->alias('t4')->on('t1.project = t4.id') + ->where('t1.assignedTo')->ne('') + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t3.deleted')->eq(0) + ->andWhere('t4.deleted')->eq(0) + ->andWhere('t1.status')->in('wait,doing') + ->andWhere('t3.status')->ne('suspended') + ->andWhere('t1.deadline', true)->eq('0000-00-00') + ->orWhere('t1.deadline')->lt(date(DT_DATE1, strtotime('+4 day'))) + ->markRight(1) + ->fetchGroup('user'); + } + + /** + * Get user todos. + * + * @access public + * @return array + */ + public function getUserTodos() + { + $stmt = $this->dao->select('t1.*, t2.account as user') + ->from(TABLE_TODO)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2') + ->on('t1.account = t2.account') + ->where('t1.cycle')->eq(0) + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t1.status')->in('wait,doing') + ->query(); + + $todos = array(); + while($todo = $stmt->fetch()) + { + if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name'); + if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title'); + $todos[$todo->user][] = $todo; + } + return $todos; + } + + /** + * Get user testTasks. + * + * @access public + * @return array + */ + public function getUserTestTasks() + { + return $this->dao->select('t1.*, t2.account as user')->from(TABLE_TESTTASK)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t1.owner = t2.account') + ->where('t1.deleted')->eq('0') + ->andWhere('t2.deleted')->eq('0') + ->andWhere("(t1.status='wait' OR t1.status='doing')") + ->fetchGroup('user'); + } + + /** + * Get user login count in this year. + * + * @param array $accounts + * @param int $year + * @access public + * @return int + */ + public function getUserYearLogins($accounts, $year) + { + return $this->dao->select('count(*) as count')->from(TABLE_ACTION)->where('actor')->in($accounts)->andWhere('LEFT(date, 4)')->eq($year)->andWhere('action')->eq('login')->fetch('count'); + } + + /** + * Get user action count in this year. + * + * @param array $accounts + * @param int $year + * @access public + * @return int + */ + public function getUserYearActions($accounts, $year) + { + return $this->dao->select('count(*) as count')->from(TABLE_ACTION) + ->where('LEFT(date, 4)')->eq($year) + ->beginIF($accounts)->andWhere('actor')->in($accounts)->fi() + ->fetch('count'); + } + + /** + * Get user contributions in this year. + * + * @param array $accounts + * @param int $year + * @access public + * @return array + */ + public function getUserYearContributions($accounts, $year) + { + $stmt = $this->dao->select('*')->from(TABLE_ACTION) + ->where('LEFT(date, 4)')->eq($year) + ->andWhere('objectType')->in(array_keys($this->config->pivot->annualData['contributions'])) + ->beginIF($accounts)->andWhere('actor')->in($accounts)->fi() + ->orderBy('objectType,objectID,id') + ->query(); + + $filterActions = array(); + $objectIdList = array(); + while($action = $stmt->fetch()) + { + $objectType = $action->objectType; + $objectID = $action->objectID; + $lowerAction = strtolower($action->action); + if(!isset($this->config->pivot->annualData['contributions'][$objectType][$lowerAction])) continue; + + $objectIdList[$objectType][$objectID] = $objectID; + $filterActions[$objectType][$objectID][$action->id] = $action; + } + + foreach($objectIdList as $objectType => $idList) + { + $deletedIdList = $this->dao->select('id')->from($this->config->objectTables[$objectType])->where('deleted')->eq(1)->andWhere('id')->in($idList)->fetchPairs('id', 'id'); + foreach($deletedIdList as $id) unset($filterActions[$objectType][$id]); + } + + $actionGroups = array(); + foreach($filterActions as $objectType => $objectActions) + { + foreach($objectActions as $objectID => $actions) + { + foreach($actions as $action) $actionGroups[$objectType][$action->id] = $action; + } + } + + $contributions = array(); + foreach($actionGroups as $objectType => $actions) + { + foreach($actions as $action) + { + $lowerAction = strtolower($action->action); + $actionName = $this->config->pivot->annualData['contributions'][$objectType][$lowerAction]; + + $type = ($actionName == 'svnCommit' or $actionName == 'gitCommit') ? 'repo' : $objectType; + if(!isset($contributions[$type][$actionName])) $contributions[$type][$actionName] = 0; + $contributions[$type][$actionName] += 1; + } + } + + $contributions['case']['run'] = $this->dao->select('count(*) as count')->from(TABLE_TESTRESULT)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id') + ->where('LEFT(t1.date, 4)')->eq($year) + ->andWhere('t2.deleted')->eq(0) + ->beginIF($accounts)->andWhere('t1.lastRunner')->in($accounts)->fi() + ->fetch('count'); + + return $contributions; + } + + /** + * Get user todo stat in this year. + * + * @param array $accounts + * @param int $year + * @access public + * @return object + */ + public function getUserYearTodos($accounts, $year) + { + return $this->dao->select("count(*) as count, sum(if((`status` != 'done'), 1, 0)) AS `undone`, sum(if((`status` = 'done'), 1, 0)) AS `done`")->from(TABLE_TODO) + ->where('LEFT(date, 4)')->eq($year) + ->andWhere('deleted')->eq('0') + ->andWhere('vision')->eq($this->config->vision) + ->beginIF($accounts)->andWhere('account')->in($accounts)->fi() + ->fetch(); + } + + /** + * Get user effort stat in this error. + * + * @param array $accounts + * @param int $year + * @access public + * @return object + */ + public function getUserYearEfforts($accounts, $year) + { + $effort = $this->dao->select('count(*) as count, sum(consumed) as consumed')->from(TABLE_EFFORT) + ->where('LEFT(date, 4)')->eq($year) + ->andWhere('deleted')->eq(0) + ->beginIF($accounts)->andWhere('account')->in($accounts)->fi() + ->fetch(); + + $effort->consumed = !empty($effort->consumed) ? round($effort->consumed, 2) : 0; + return $effort; + } + + /** + * Get count of created story,plan and closed story by accounts every product in this year. + * + * @param array $accounts + * @param int $year + * @access public + * @return array + */ + public function getUserYearProducts($accounts, $year) + { + /* Get changed products in this year. */ + $products = $this->dao->select('id,name')->from(TABLE_PRODUCT) + ->where('deleted')->eq(0) + ->andWhere('LEFT(createdDate, 4)')->eq($year) + ->beginIF($accounts) + ->andWhere('createdBy', true)->in($accounts) + ->orWhere('PO')->in($accounts) + ->orWhere('QD')->in($accounts) + ->orWhere('RD')->in($accounts) + ->markRight(1) + ->fi() + ->andWhere('shadow')->eq(0) + ->fetchAll('id'); + + /* Get created plans in this year. */ + $plans = $this->dao->select('t1.id,t1.product')->from(TABLE_PRODUCTPLAN)->alias('t1') + ->leftJoin(TABLE_ACTION)->alias('t2')->on("t1.id=t2.objectID and t2.objectType='productplan'") + ->where('LEFT(t2.date, 4)')->eq($year) + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t1.product')->in(array_keys($products)) + ->beginIF($accounts) + ->andWhere('t2.actor')->in($accounts) + ->fi() + ->andWhere('t2.action')->eq('opened') + ->fetchAll(); + + $planProducts = array(); + $planGroups = array(); + foreach($plans as $plan) + { + $planProducts[$plan->product] = $plan->product; + $planGroups[$plan->product][$plan->id] = $plan->id; + } + + $createStoryProducts = $this->dao->select('DISTINCT product')->from(TABLE_STORY) + ->where('LEFT(openedDate, 4)')->eq($year) + ->andWhere('deleted')->eq(0) + ->andWhere('product')->in(array_keys($products)) + ->beginIF($accounts)->andWhere('openedBy')->in($accounts)->fi() + ->fetchPairs('product', 'product'); + $closeStoryProducts = $this->dao->select('DISTINCT product')->from(TABLE_STORY) + ->where('LEFT(closedDate, 4)')->eq($year) + ->andWhere('deleted')->eq(0) + ->andWhere('product')->in(array_keys($products)) + ->beginIF($accounts)->andWhere('closedBy')->in($accounts)->fi() + ->fetchPairs('product', 'product'); + if($createStoryProducts or $closeStoryProducts) + { + $products += $this->dao->select('id,name')->from(TABLE_PRODUCT) + ->where('id')->in($createStoryProducts + $closeStoryProducts + $planProducts) + ->andWhere('deleted')->eq(0) + ->fetchAll('id'); + } + + $createdStoryStats = $this->dao->select("product,sum(if((type = 'requirement'), 1, 0)) as requirement, sum(if((type = 'story'), 1, 0)) as story")->from(TABLE_STORY) + ->where('product')->in(array_keys($products)) + ->andWhere('deleted')->eq(0) + ->andWhere('LEFT(openedDate, 4)')->eq($year) + ->beginIF($accounts)->andWhere('openedBy')->in($accounts)->fi() + ->groupBy('product') + ->fetchAll('product'); + + $closedStoryStats = $this->dao->select("product,sum(if((status = 'closed'), 1, 0)) as closed")->from(TABLE_STORY) + ->where('product')->in(array_keys($products)) + ->andWhere('deleted')->eq(0) + ->andWhere('LEFT(closedDate, 4)')->eq($year) + ->beginIF($accounts)->andWhere('closedBy')->in($accounts)->fi() + ->groupBy('product') + ->fetchAll('product'); + + /* Merge created plan, created story and closed story in every product. */ + foreach($products as $productID => $product) + { + $product->plan = 0; + $product->requirement = 0; + $product->story = 0; + $product->closed = 0; + + $plans = zget($planGroups, $productID, array()); + if($plans) $product->plan = count($plans); + + $createdStoryStat = zget($createdStoryStats, $productID, ''); + if($createdStoryStat) + { + $product->requirement = $createdStoryStat->requirement; + $product->story = $createdStoryStat->story; + } + + $closedStoryStat = zget($closedStoryStats, $productID, ''); + if($closedStoryStat) $product->closed = $closedStoryStat->closed; + } + + return $products; + } + + /** + * Get count of finished task, story and resolved bug by accounts every executions in this year. + * + * @param array $accounts + * @param int $year + * @access public + * @return array + */ + public function getUserYearExecutions($accounts, $year) + { + /* Get changed executions in this year. */ + $executions = $this->dao->select('id,name')->from(TABLE_EXECUTION)->where('deleted')->eq(0) + ->andwhere('type')->eq('sprint') + ->andwhere('multiple')->eq('1') + ->andWhere('LEFT(begin, 4)', true)->eq($year) + ->orWhere('LEFT(end, 4)')->eq($year) + ->markRight(1) + ->beginIF($accounts) + ->andWhere('openedBy', true)->in($accounts) + ->orWhere('PO')->in($accounts) + ->orWhere('PM')->in($accounts) + ->orWhere('QD')->in($accounts) + ->orWhere('RD')->in($accounts) + ->markRight(1) + ->fi() + ->orderBy('`order` desc') + ->fetchAll('id'); + + $teamExecutions = $this->dao->select('t1.root')->from(TABLE_TEAM)->alias('t1') + ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.root=t2.id') + ->where('t1.type')->eq('execution') + ->beginIF($accounts)->andWhere('account')->in($accounts)->fi() + ->andWhere('t2.multiple')->eq('1') + ->andWhere('LEFT(`join`, 4)')->eq($year) + ->fetchPairs('root', 'root'); + + $taskExecutions = $this->dao->select('t1.execution')->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution=t2.id') + ->where('LEFT(t1.finishedDate, 4)')->eq($year) + ->beginIF($accounts)->andWhere('finishedBy')->in($accounts)->fi() + ->andWhere('t2.multiple')->eq('1') + ->andWhere('t1.deleted')->eq(0) + ->fetchPairs('execution', 'execution'); + + if($teamExecutions or $taskExecutions) + { + $executions += $this->dao->select('id,name')->from(TABLE_EXECUTION) + ->where('id')->in($teamExecutions + $taskExecutions) + ->andWhere('deleted')->eq(0) + ->andWhere('type')->eq('sprint') + ->orderBy('`order` desc') + ->fetchAll('id'); + } + + /* Get count of finished task, story and resolved bug in this year. */ + $taskStats = $this->dao->select('execution, count(*) as finishedTask, sum(if((story != 0), 1, 0)) as finishedStory')->from(TABLE_TASK) + ->where('execution')->in(array_keys($executions)) + ->andWhere('finishedBy')->ne('') + ->andWhere('LEFT(finishedDate, 4)')->eq($year) + ->andWhere('deleted')->eq(0) + ->beginIF($accounts)->andWhere('finishedBy')->in($accounts)->fi() + ->groupBy('execution') + ->fetchAll('execution'); + $resolvedBugs = $this->dao->select('t2.execution, count(*) as count')->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.resolvedBuild=t2.id') + ->where('t2.execution')->in(array_keys($executions)) + ->andWhere('t1.resolvedBy')->ne('') + ->andWhere('t1.deleted')->eq(0) + ->andWhere('LEFT(t1.resolvedDate, 4)')->eq($year) + ->beginIF($accounts)->andWhere('t1.resolvedBy')->in($accounts)->fi() + ->groupBy('t2.execution') + ->fetchAll('execution'); + + foreach($executions as $executionID => $execution) + { + $execution->task = 0; + $execution->story = 0; + $execution->bug = 0; + + $taskStat = zget($taskStats, $executionID, ''); + if($taskStat) + { + $execution->task = $taskStat->finishedTask; + $execution->story = $taskStat->finishedStory; + } + + $resolvedBug = zget($resolvedBugs, $executionID, ''); + if($resolvedBug) $execution->bug = $resolvedBug->count; + } + + return $executions; + } + + /** + * Get status stat that is all time, include story, task and bug. + * + * @access public + * @return array + */ + public function getAllTimeStatusStat() + { + $statusStat = array(); + $statusStat['story'] = $this->dao->select('status, count(status) as count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('type')->eq('story')->groupBy('status')->fetchPairs('status', 'count'); + $statusStat['task'] = $this->dao->select('status, count(status) as count')->from(TABLE_TASK)->where('deleted')->eq(0)->groupBy('status')->fetchPairs('status', 'count'); + $statusStat['bug'] = $this->dao->select('status, count(status) as count')->from(TABLE_BUG)->where('deleted')->eq(0)->groupBy('status')->fetchPairs('status', 'count'); + + return $statusStat; + } + + /** + * Get year object stat, include status and action stat + * + * @param array $accounts + * @param string $year + * @param string $objectType story|task|bug + * @access public + * @return array + */ + public function getYearObjectStat($accounts, $year, $objectType) + { + $table = ''; + if($objectType == 'story') $table = TABLE_STORY; + if($objectType == 'task') $table = TABLE_TASK; + if($objectType == 'bug') $table = TABLE_BUG; + if(empty($table)) return array(); + + $months = $this->getYearMonths($year); + $stmt = $this->dao->select('t1.*, t2.status')->from(TABLE_ACTION)->alias('t1') + ->leftJoin($table)->alias('t2')->on('t1.objectID=t2.id') + ->where('t1.objectType')->eq($objectType) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('LEFT(t1.date, 4)')->eq($year) + ->andWhere('t1.action')->in($this->config->pivot->annualData['monthAction'][$objectType]) + ->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi() + ->query(); + + /* Build object action stat and get status group. */ + $statuses = array(); + $actionStat = array(); + while($action = $stmt->fetch()) + { + $statuses[$action->objectID] = $action->status; + + $lowerAction = strtolower($action->action); + /* Story,bug can from feedback and ticket, task can from feedback, boil this action down to opened. */ + if(in_array($lowerAction, array('fromfeedback', 'fromticket'))) $lowerAction = 'opened'; + if(!isset($actionStat[$lowerAction])) + { + foreach($months as $month) $actionStat[$lowerAction][$month] = 0; + } + + $month = substr($action->date, 0, 7); + $actionStat[$lowerAction][$month] += 1; + } + + /* Build status stat. */ + $statusStat = array(); + foreach($statuses as $storyID => $status) + { + if(!isset($statusStat[$status])) $statusStat[$status] = 0; + $statusStat[$status] += 1; + } + + return array('statusStat' => $statusStat, 'actionStat' => $actionStat); + } + + /** + * Get year case stat, include result and action stat. + * + * @param array $accounts + * @param string $year + * @access public + * @return array + */ + public function getYearCaseStat($accounts, $year) + { + $months = $this->getYearMonths($year); + $stmt = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.objectID=t2.id') + ->where('t1.objectType')->eq('case') + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t1.action')->eq('opened') + ->andWhere('LEFT(t1.date, 4)')->eq($year) + ->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi() + ->query(); + + /* Build create case stat. */ + $resultStat = array(); + $actionStat = array(); + foreach($months as $month) + { + $actionStat['opened'][$month] = 0; + $actionStat['run'][$month] = 0; + $actionStat['createBug'][$month] = 0; + } + + while($action = $stmt->fetch()) + { + $month = substr($action->date, 0, 7); + $actionStat['opened'][$month] += 1; + } + + /* Build testcase result stat and run case stat. */ + $stmt = $this->dao->select('t1.*')->from(TABLE_TESTRESULT)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id') + ->where('LEFT(t1.date, 4)')->eq($year) + ->andWhere('t2.deleted')->eq(0) + ->beginIF($accounts)->andWhere('t1.lastRunner')->in($accounts)->fi() + ->query(); + while($testResult = $stmt->fetch()) + { + if(!isset($resultStat[$testResult->caseResult])) $resultStat[$testResult->caseResult] = 0; + $resultStat[$testResult->caseResult] += 1; + + $month = substr($testResult->date, 0, 7); + $actionStat['run'][$month] += 1; + } + + /* Build testcase create bug stat. */ + $stmt = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1') + ->leftJoin(TABLE_BUG)->alias('t2')->on('t1.objectID=t2.id') + ->where('t1.objectType')->eq('bug') + ->andWhere('t2.deleted')->eq(0) + ->andWhere('LEFT(t1.date, 4)')->eq($year) + ->andWhere('t1.action')->eq('opened') + ->andWhere('t2.case')->ne('0') + ->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi() + ->query(); + while($action = $stmt->fetch()) + { + $month = substr($action->date, 0, 7); + $actionStat['createBug'][$month] += 1; + } + + return array('resultStat' => $resultStat, 'actionStat' => $actionStat); + } + + /** + * Get year months. + * + * @param string $year + * @access public + * @return array + */ + public function getYearMonths($year) + { + $months = array(); + for($i = 1; $i <= 12; $i ++) $months[] = $year . '-' . sprintf('%02d', $i); + + return $months; + } + + /** + * Get project and execution name. + * + * @access public + * @return array + */ + public function getProjectExecutions() + { + $executions = $this->dao->select('t1.id, t1.name, t2.name as projectname, t1.status, t1.multiple') + ->from(TABLE_EXECUTION)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id') + ->where('t1.deleted')->eq(0) + ->andWhere('t1.type')->in('stage,sprint') + ->fetchAll(); + + $pairs = array(); + foreach($executions as $execution) + { + if($execution->multiple) $pairs[$execution->id] = $execution->projectname . '/' . $execution->name; + if(!$execution->multiple) $pairs[$execution->id] = $execution->projectname; + } + + return $pairs; + } +} + +/** + * @param $pre + * @param $next + * + * @return int + */ +function sortSummary($pre, $next) +{ + if($pre['validRate'] == $next['validRate']) return 0; + return $pre['validRate'] > $next['validRate'] ? -1 : 1; +} diff --git a/module/pivot/view/bugassign.html.php b/module/pivot/view/bugassign.html.php new file mode 100644 index 0000000000..715c1462ff --- /dev/null +++ b/module/pivot/view/bugassign.html.php @@ -0,0 +1,56 @@ +config->edition != 'open'):?> + + + + +
+
+

error->noData;?>

+
+
+ +
+
+
+
+ +
+
+ + + + + + + + + + + $assign):?> + + + + + $count):?> + ';?> + + + + + + '; $id ++;?> + + + + +
pivot->user;?>pivot->product;?>pivot->bugTotal;?>pivot->total;?>
+ createLink('product', 'view', "product={$count['productID']}") : $this->createLink('project', 'view', "projectID={$count['projectID']}");?> + + + +
+
+
+
+ + diff --git a/module/pivot/view/bugcreate.html.php b/module/pivot/view/bugcreate.html.php new file mode 100644 index 0000000000..1c97908732 --- /dev/null +++ b/module/pivot/view/bugcreate.html.php @@ -0,0 +1,79 @@ + +
+
+
+
+ pivot->bugOpenedDate;?> +
+ pivot->to;?> +
+
+
+
+
+ pivot->product;?> + +
+
+
+
+ execution->common;?> + +
+
+
+
+ +
+
+

error->noData;?>

+
+
+ +
+
+
+
+ +
+
+ + + + + + bug->resolutionList as $resolutionType => $resolution):?> + + + + + + + + + $bug):?> + + + + + bug->resolutionList as $resolutionType => $resolution):?> + + + + + + + + +
bug->openedBy;?>bug->unResolved;?>pivot->validRate;?>pivot->total;?>
+
+
+
+ + diff --git a/module/pivot/view/preview.html.php b/module/pivot/view/preview.html.php new file mode 100644 index 0000000000..a8f6fdeb99 --- /dev/null +++ b/module/pivot/view/preview.html.php @@ -0,0 +1,46 @@ + + +config->edition != 'open'):?> + + + + + +
+ +
+ +
+

error->noData;?>

+
+ + fetch($module, $method, $params);?> + +
+
+ diff --git a/module/pivot/view/productsummary.html.php b/module/pivot/view/productsummary.html.php new file mode 100644 index 0000000000..532d0a5a20 --- /dev/null +++ b/module/pivot/view/productsummary.html.php @@ -0,0 +1,113 @@ + +
+
+
+
+
+
+
+
+ /> + +
+
+ /> + +
+
+
+
+ +
+
+
+ +
+
+

error->noData;?>

+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + plans) ? count($product->plans) : 1;?> + + + plans)):?> + + plans as $plan):?> + + "?> + parent) and $plan->parent > 0 and isset($product->plans[$plan->parent])) ? ' child' : '';?> + + + + status['draft']) ? $plan->status['draft'] : 0; + $reviewingCount = isset($plan->status['reviewing']) ? $plan->status['reviewing'] : 0; + $activeCount = isset($plan->status['active']) ? $plan->status['active'] : 0; + $changedCount = isset($plan->status['changing']) ? $plan->status['changing'] : 0; + $closedCount = isset($plan->status['closed']) ? $plan->status['closed'] : 0; + ?> + + + + + + + "?> + + + + + + + + + + + + + + + + + + + +
product->name;?>pivot->PO;?>productplan->common;?>productplan->begin;?>productplan->end;?>story->statusList['draft'];?>story->statusList['reviewing'];?>story->statusList['active'];?>story->statusList['changing'];?>story->statusList['closed'];?>pivot->total;?>
" . html::a($this->createLink('product', 'view', "product=$product->id"), $product->name) . "

";?>
" . zget($users, $product->PO) . '

';?>
title;?>begin == '2030-01-01' ? $lang->productplan->future : $plan->begin;?>end == '2030-01-01' ? $lang->productplan->future : $plan->end;?>000000
+
+
+
+ + diff --git a/module/pivot/view/projectdeviation.html.php b/module/pivot/view/projectdeviation.html.php new file mode 100644 index 0000000000..24d990e088 --- /dev/null +++ b/module/pivot/view/projectdeviation.html.php @@ -0,0 +1,184 @@ + + +
+
+
+
+ pivot->execution . $lang->pivot->begin;?> +
+
+
+
+
+ pivot->execution . $lang->pivot->end;?> +
+
+
+
+
+ +
+
+

error->noData;?>

+
+
+ + array(), 'data' => array());?> +
+
+
+
+ + + +
+ +
+
+ + + + + + + + + + + + + + $execution):?> + + + + + + + consumed - $execution->estimate, 2);?> + + + + + +
pivot->id;?>pivot->project;?>pivot->execution;?>pivot->estimate;?>pivot->consumed;?>pivot->deviation;?>pivot->deviationRate;?>
+ name ? $execution->projectName : html::a($this->createLink('project', 'index', "projectID=$execution->projectID"), $execution->projectName);?> + + multiple):?> + name ? html::a($this->createLink('execution', 'view', "executionID=$id"), $execution->name) : '';?> + + null;?> + + estimate, 2);?>consumed, 2);?> + 0) + { + echo '↑' . $deviation; + } + else if($deviation < 0) + { + echo '↓' . abs($deviation); + } + else + { + echo '0'; + } + ?> + + estimate ? round($deviation / $execution->estimate * 100, 2) : 'n/a'; + if($num >= 50) + { + echo '' . $num . '%'; + } + elseif($num >= 30) + { + echo '' . $num . '%'; + } + elseif($num >= 10) + { + echo '' . $num . '%'; + } + elseif($num > 0) + { + echo '' . abs($num) . '%'; + } + elseif($num <= -20) + { + echo '' . abs($num) . '%'; + } + elseif($num < 0) + { + echo '' . abs($num) . '%'; + } + elseif($num == 'n/a') + { + echo '' . $num . ''; + } + else + { + echo '' . abs($num) . '%'; + } + + $chartData['labels'][] = $execution->name; + $chartData['data'][] = $deviation; + ?> +
+
+
+
+ + +
+ 30) + { + $chartData['labels'] = array_slice($chartData['labels'], 0, 30); + $chartData['data'] = array_slice($chartData['data'], 0, 30); + } + ?> +
+
+
pivot->deviationChart;?>
+
+
+ +
+
+
+ + + diff --git a/module/pivot/view/workload.html.php b/module/pivot/view/workload.html.php new file mode 100644 index 0000000000..2b125f064b --- /dev/null +++ b/module/pivot/view/workload.html.php @@ -0,0 +1,121 @@ + +execution->weekend);?> +
+
+
+
+
+ pivot->dept;?> + +
+
+
+
+ pivot->beginAndEnd;?> +
+ pivot->to;?> +
+
+
+
+
+ pivot->diffDays;?> + +
+
+
+
+
+
+ pivot->workday;?> + +
+
+
+ pivot->assign, $assign, "class='form-control' onchange='changeParams(this)'");?> +
+
+ pivot->query, '', 'btn btn-primary btn-block');?> +
+
+
+
+
+
+ +
+
+

error->noData;?>

+
+
+ +
+
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + $load):?> + + + + $info) foreach($info['execution'] as $executionName => $executionInfo) $userCount ++;?> + + $info):?> + + $executionInfo) $projectCount ++ ;?> + $executionInfo):?> + ";?> + + + + + + + + + + + + + + + + ";?> + + + + + + + +
pivot->user;?>pivot->project ;?> + pivot->execution;?>pivot->task;?>pivot->remain;?>pivot->taskTotal;?>pivot->manhourTotal;?>pivot->workloadAB;?>
createLink('project', 'view', "projectID={$info['projectID']}"), $projectName);?>createLink('execution', 'view', "executionID={$executionInfo['executionID']}"), $executionName);?>null;?>
+
+
+
+ + diff --git a/module/pivot/zen.php b/module/pivot/zen.php new file mode 100644 index 0000000000..ce870eb2aa --- /dev/null +++ b/module/pivot/zen.php @@ -0,0 +1,139 @@ +getDefaultDimension(); + if(!$group) $group = $this->getDefaultGroup($dimension); + if(!$module || !$method) list($module, $method, $params) = $this->getDefaultMethod($dimension, $group); + + if(!empty($module) && !empty($method) && !common::hasPriv($module, $method)) common::deny('pivot', $method); + + $this->view->sidebar = $this->getSidebar($dimension, $group, $module, $method, $params); + $this->view->dimension = $dimension; + $this->view->group = $group; + $this->view->module = $module; + $this->view->method = $method; + $this->view->params = $params; + + if(empty($this->view->title)) $this->view->title = $this->lang->pivot->list; + } + + /** + * Get default dimension of pivot. + * + * @access public + * @return int + */ + public function getDefaultDimension() + { + return 1; + } + + /** + * Get default group of a dimension. + * + * @param int $dimension + * @access public + * @return string + */ + public function getDefaultGroup($dimension) + { + foreach($this->lang->pivotList as $group => $list) + { + if(empty($list->lists)) continue; + + foreach($list->lists as $item) + { + $items = explode('|', $item); + if(count($items) < 3) continue; + + list($label, $module, $method) = $items; + + if(common::hasPriv($module, $method)) return $group; + } + } + + return ''; + } + + /** + * Get default module name and method name and params of pivot in a group. + * + * @param int $dimension + * @param string $group + * @access public + * @return array + */ + public function getDefaultMethod($dimension, $group) + { + if(empty($this->lang->pivotList->$group->lists)) return array('', '', ''); + + foreach($this->lang->pivotList->$group->lists as $item) + { + $items = explode('|', $item . '|'); + if(count($items) < 4) continue; + + list($label, $module, $method, $params) = $items; + + if(common::hasPriv($module, $method)) return array($module, $method, $params); + } + + return array('', '', ''); + } + + /** + * Get sidebar of pivot. + * + * @param int $dimension + * @param string $group + * @param string $module + * @param string $method + * @param string $params + * @access public + * @return string + */ + public function getSidebar($dimension, $group, $module, $method, $params) + { + if(empty($this->lang->pivotList->$group->lists)) return ''; + + $sidebar = ''; + $module = strtolower($module); + $method = strtolower($method); + + ksort($this->lang->pivotList->$group->lists); + foreach($this->lang->pivotList->$group->lists as $item) + { + $items = explode('|', $item . '|'); + if(count($items) < 4) continue; + + list($label, $moduleName, $methodName, $params) = $items; + + $class = ''; + if($module == strtolower($moduleName) && $method == strtolower($methodName)) + { + $class = 'selected'; + + $this->view->title = $label; + } + + $params = helper::safe64Encode($params); + if(common::hasPriv($moduleName, $methodName)) $sidebar .= html::a(helper::createLink('pivot', 'preview', "dimension=$dimension&group=$group&module=$moduleName&method=$methodName¶ms=$params"), ' ' . $label, '', "class='$class' title='$label'"); + } + + return $sidebar; + } +}