Merge branch 'master' into zenops_44
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
**/
|
||||
class bugResolveEntry extends Entry
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $bugID
|
||||
@@ -19,7 +19,7 @@ class bugResolveEntry extends Entry
|
||||
* @return void
|
||||
*/
|
||||
public function post($bugID)
|
||||
{
|
||||
{
|
||||
$fields = 'resolution,resolvedBuild,resolvedDate,duplicateBug,assignedTo,uid,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
@@ -33,6 +33,6 @@ class bugResolveEntry extends Entry
|
||||
$bug = $this->loadModel('bug')->getByID($bugID);
|
||||
|
||||
$this->send(200, $this->format($bug, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,resolvedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class feedbacksEntry extends entry
|
||||
if(strpos(strtolower($this->param('fields')), 'moduleandproduct') !== false) return $this->getModuleAndProduct();
|
||||
|
||||
$control = $this->loadController('feedback', 'admin');
|
||||
$control->admin($this->param('solution', 'unclosed'), 0, $this->param('orderBy', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$control->admin($this->param('status', 'unclosed'), 0, $this->param('orderBy', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
|
||||
@@ -176,7 +176,7 @@ class reportsEntry extends entry
|
||||
foreach(array_keys($statusList) as $status)
|
||||
{
|
||||
$statusName = zget($this->lang->project->statusList, $status);
|
||||
if($status == 'all') $statusName = $this->lang->project->featureBar['all'];
|
||||
if($status == 'all') $statusName = $this->lang->project->featureBar['browse']['all'];
|
||||
|
||||
$statusList[$status]['code'] = $status;
|
||||
$statusList[$status]['name'] = $statusName;
|
||||
@@ -193,8 +193,7 @@ class reportsEntry extends entry
|
||||
*/
|
||||
public function executionProgress()
|
||||
{
|
||||
$executions = $this->loadModel('project')->getStats(0, 'all', 0, 0, 30, 'id_desc');
|
||||
$this->app->loadLang('execution');
|
||||
$executions = $this->loadModel('execution')->getStatData(0, 'all', 0, 0, false, '', 'id_desc');
|
||||
|
||||
$processedExecutions = array();
|
||||
$statusList['all']['total'] = 0;
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
|
||||
if(!function_exists('getWebRoot')){function getWebRoot(){}}
|
||||
|
||||
/* 基本设置。Basic settings. */
|
||||
$config->version = '17.6'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->version = '17.6.1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->liteVersion = '1.2'; // 迅捷版版本。 The version of Lite.
|
||||
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
|
||||
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -11,5 +11,7 @@ CREATE TABLE `zt_taskteam` (
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `task` (`task`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
ALTER TABLE `zt_taskestimate` ADD `order` tinyint unsigned NULL DEFAULT '0';
|
||||
ALTER TABLE `zt_taskestimate` ADD `order` tinyint unsigned NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `zt_effort` ADD `order` tinyint unsigned NOT NULL DEFAULT '0' AFTER `end`;
|
||||
ALTER TABLE `zt_storyspec` ADD `files` text NOT NULL AFTER `verify`;
|
||||
ALTER TABLE `zt_block` CHANGE `block` `block` varchar(30) COLLATE 'utf8_general_ci' NOT NULL AFTER `source`;
|
||||
|
||||
+2
-1
@@ -218,7 +218,7 @@ CREATE TABLE IF NOT EXISTS `zt_block` (
|
||||
`type` char(30) NOT NULL,
|
||||
`title` varchar(100) NOT NULL,
|
||||
`source` varchar(20) NOT NULL,
|
||||
`block` varchar(20) NOT NULL,
|
||||
`block` varchar(30) NOT NULL,
|
||||
`params` text NOT NULL,
|
||||
`order` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`grid` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
@@ -1504,6 +1504,7 @@ CREATE TABLE IF NOT EXISTS `zt_storyspec` (
|
||||
`title` varchar(255) NOT NULL,
|
||||
`spec` mediumtext NOT NULL,
|
||||
`verify` mediumtext NOT NULL,
|
||||
`files` text NOT NULL,
|
||||
UNIQUE KEY `story` (`story`,`version`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
-- DROP TABLE IF EXISTS `zt_storystage`;
|
||||
|
||||
+127
@@ -1,3 +1,130 @@
|
||||
2022-09-08 17.6.1
|
||||
完成的需求
|
||||
开源版:
|
||||
31896 Scrum看板列中动态加载卡片数据
|
||||
34361 需求编辑页面增加附件信息的显示
|
||||
35317 禅道可以支持腾讯云和阿里云数据库
|
||||
35436 批量创建和编辑页面保存时,增加名称必填项校验
|
||||
35475 并行多人任务完成后重新激活无法再完成
|
||||
35909 通用看板增加区域的检索标签
|
||||
36259 需求详情中的附件去掉删除操作
|
||||
36444 多人串行任务,状态为“未开始”时,可以维护自己的工时日志
|
||||
36445 多人串行任务,只有指派人可以开始任务或完成任务
|
||||
36448 多人串行任务,状态为“进行中”时,可以新增工序和成员
|
||||
36451 多人串行任务,状态为“进行中”时,可以修改工序和成员
|
||||
36452 多人串行任务,状态为“进行中”时,可以删除工序和成员
|
||||
36453 多人串行任务,状态为“已完成”时,不可以编辑工序和团队成员
|
||||
36454 多人任务,只有编辑人可以修改自己的日志
|
||||
36455 多人串行任务的状态为“进行中”,且指派人为自己时,可以编辑当前工序的工时日志
|
||||
36457 多人串行任务的状态为“已完成”,可以修改自己已经填写的工时
|
||||
36458 多人串行任务状态为已关闭或已完成时,可以激活
|
||||
36459 多人串行任务,状态为“未开始”时,可以维护工序和团队成员
|
||||
36460 多人并行任务,状态为“未开始”时,可以维护团队成员
|
||||
36461 创建和编辑多人任务团队时,预计剩余不为0
|
||||
36462 多人并行任务,状态为“进行中”时,可以修改团队成员
|
||||
36463 多人并行任务,状态为“进行中”时,可以添加团队成员
|
||||
36464 多人并行任务,状态为“进行中”时,可以删除团队成员
|
||||
36465 多人并行任务,状态为“已完成”时,不能维护团队成员
|
||||
36466 多人并行任务中,自己可以维护自己创建的日志
|
||||
36467 多人串行任务状态为“已取消”时,激活后选择继续或重新开始
|
||||
36468 多人串行任务状态为已关闭、已暂停、已取消时不能维护团队和日志
|
||||
36469 多人并行任务状态为已关闭、已暂停、已取消时不能维护团队
|
||||
36470 多人并行任务状态为已关闭、已暂停、已取消时可以维护日志
|
||||
36471 多人并行任务状态为已关闭或已完成时,可以激活
|
||||
36663 任务日志列表展示”最初预计“和”累积耗时“
|
||||
36664 多人串行任务的日志,根据团队成员的状态展示我的日志和所有日志
|
||||
36666 维护多人串行任务日志时,根据团队成员的状态判断是新增日志还是追加日志
|
||||
36678 单人任务和多人并行任务,日志页展示历史的日志和新增日志入口
|
||||
36720 通过面板二维码下载移动端时,可以自动判断当前版本匹配的移动端版本
|
||||
36723 测试单列表增加搜索功能
|
||||
36730 需求变更评审时,系统根据需求不同评审结果进行后续处理
|
||||
36783 变更需求时,附件删除操作记录版本号
|
||||
36784 需求的附件跟随版本变化
|
||||
36785 变更需求时,附件删除操作保存后再生效
|
||||
36795 权限分组的视野维护中,项目集下拉菜单支持按树状结构进行显示和选择
|
||||
36998 执行概况的燃尽图中增加延期状态的标签
|
||||
企业版:
|
||||
30912 地盘日志列表新建日志时对象与执行的展示顺序修改
|
||||
旗舰版:
|
||||
36984 实现瀑布项目总体进展统计区块
|
||||
36989 项目周报中将进度调整为本周进度
|
||||
34731 瀑布项目里评审下的基线评审列表增加删除功能
|
||||
36744 复制项目的执行的时间填写后,自动计算可用工作日
|
||||
36813 瀑布项目评审下的问题列表增加删除权限
|
||||
36839 QA质量保证计划可以在地盘待处理显示
|
||||
禅道客户端:
|
||||
35987 群成员管理列表点击成员头像或名称显示成员名片的功能
|
||||
35878 实现群成员管理列表的搜索功能
|
||||
35875 实现群管理列表的搜索功能
|
||||
35873 实现群成员管理列表中设置群主功能
|
||||
35853 实现群成员管理列表中单个移除成员的功能
|
||||
35852 实现群成员管理列表中添加成员功能
|
||||
35976 实现讨论组成员管理列表的右键菜单及功能
|
||||
35850 实现群成员管理列表
|
||||
35974 实现群管理列表的右键菜单及功能
|
||||
35848 实现群管理列表
|
||||
35986 客户端应用中增加讨论组管理的应用入口
|
||||
36496 系统默认讨论组分组不支持重命名
|
||||
36447 扩展API应用分组、排序功能优化
|
||||
36446 扩展API应用搜索功能优化
|
||||
36443 扩展API应用界面优化
|
||||
36425 扩展API应用增加介绍模块
|
||||
36090 重新规划扩展API应用分组维度
|
||||
36426 新建讨论组时可以将其增加到分组
|
||||
21476 讨论组的分组功能可以有明确的添加入口
|
||||
36030 实现在线编辑喧喧文件的功能(word文件/excel文件)
|
||||
36037 实现群管理列表按表头排序的功能
|
||||
36039 实现群成员管理列表按表头排序的功能
|
||||
修复的Bug
|
||||
23401 经典模式项目树状图下点击模块后导航错乱,点击报错
|
||||
23957 批量创建用例超过10条相关需求不显示
|
||||
24830 创建Bug页面进入维护模块页面再关闭维护模块页面后所属产品变了
|
||||
24894 待办名称过长时会将整个页面撑开
|
||||
25409 在“待处理”中添加待办后“我的待办”的保存按钮置灰
|
||||
25515 组织日志页面数据较多下滑到最下时出现2个滚动条
|
||||
25695 英文下,复选框文案没有根据个性化设置动态变化
|
||||
25904 代号关闭后,已保存的搜索条件代号被填充到了第一个搜索框中
|
||||
25942 创建项目集页面预算右侧边框样式问题
|
||||
26122 日志信息在任务列表和日志详情中不一致
|
||||
26181 产品发布下关联需求页面点击返回后二级导航缺失
|
||||
26193 输入两次不同密码后强度校验了md5值
|
||||
26235 展开收起模块树会导致Bug标题显示不出来
|
||||
26298 项目集日期超出父项目集起止日期时提示信息优化
|
||||
26412 选择某个研发需求点击移除已选项数量仍然是一项
|
||||
26466 经典模式升级全新模式弱密码设置仍跳转重置密码界面
|
||||
26469 项目下的执行列表没有显示已延期
|
||||
26551 产品下未完成的项目列表表统计错误
|
||||
26619 创建测试任务时第2条软件需求的日程规划未显示“同上”
|
||||
26622 创建任务选择日期后,同上没有隐藏掉
|
||||
26632 专业研发看板/scrum看板下创建测试任务页面样式问题
|
||||
26646 删除附件时页面全局刷新了
|
||||
26648 发布时选了项目团队成员,不在这个项目的人也能收到通知
|
||||
26659 点击动态中的设计名称,在设计详情页返回后提示无项目权限
|
||||
26660 项目列表中人数统计与团队人数不一致
|
||||
26670 编辑项目页面选择计划起止日期时页面抖动
|
||||
26681 批量编辑用户页面密码输入位置问题
|
||||
26687 创建测试任务时,删除需求列表的第一行仍显示同上复选框
|
||||
26715 新建项目时切换顶级项目集预算未刷新
|
||||
26724 未关闭标签下无数据
|
||||
26725 编辑任务时仍能选到已关闭的迭代
|
||||
26758 编辑任务中相关研发需求下拉框显示不友好
|
||||
26842 测试单再关联新的用例后,已生成的测试报告中的统计信息被影响
|
||||
26936 项目列表无法根据状态搜索
|
||||
26963 执行看板中的需求无法拖动
|
||||
26971 权限分组视野中维护可访问项目集后不生效
|
||||
26994 多分支产品,在列表批量修改计划,数据库存储有逗号,导致按计划排序有问题
|
||||
27007 年度统计没有所有用户选项
|
||||
27020 在选择项目集创建项目时“关联产品”项没有添加必填项标识
|
||||
27034 点击执行树状图下的相关用例后,二级导航不显示了
|
||||
27068 编辑用例时,所属模块和相关研发需求的判断问题
|
||||
27135 点击卡片更多操作已归档卡片展示未收起
|
||||
27186 研发需求或者用户需求中点击取消相关用户需求或相关研发需求后页面显示“删除中”
|
||||
27192 创建测试类型任务页面截止时间小于预计开始时没有校验
|
||||
27258 编辑模块点击保存时希望不要弹出新窗口提醒
|
||||
26082 勾选设置的初始化会议状态账号一直处于会议状态
|
||||
26085 LDAP配置不对时,提示需要优化
|
||||
26207 修复了会话新建分组时无法输入中文的问题
|
||||
|
||||
2022-08-25 17.6
|
||||
完成的需求
|
||||
开源版:
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<div class='detail-title'><?php echo $lang->attatch;?></div>
|
||||
<div class='form-group'>
|
||||
<?php $canChangeFile = strpos('draft,changing', $story->status) !== false ? true : false;?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $files, 'fieldset' => 'false', 'object' => $story, 'method' => 'edit', 'showDelete' => $canChangeFile));?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'false', 'object' => $story, 'method' => 'edit', 'showDelete' => $canChangeFile));?>
|
||||
<?php echo $canChangeFile ? $this->fetch('file', 'buildform') : '';?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<div class="detail-title"><?php echo $lang->story->legendSpec;?></div>
|
||||
<div class="detail-content article-content"><?php echo $story->spec;?></div>
|
||||
</div>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'true', 'object' => $story));?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'true', 'object' => $story, 'method' => 'view', 'showDelete' => false));?>
|
||||
<?php
|
||||
$canBeChanged = common::canBeChanged('story', $story);
|
||||
if($canBeChanged) $actionFormLink = $this->createLink('action', 'comment', "objectType=story&objectID=$story->id");
|
||||
|
||||
+10
-1
@@ -332,12 +332,20 @@ class actionModel extends model
|
||||
->where("objectType IN('project', 'testtask', 'build')")
|
||||
->andWhere('project')->eq((int)$objectID)
|
||||
->fi()
|
||||
->beginIF($objectType == 'story')
|
||||
->where('objectType')->in('story,requirement')
|
||||
->andWhere('objectID')->eq((int)$objectID)
|
||||
->fi()
|
||||
->beginIF($objectType == 'case')
|
||||
->where('objectType')->in('case,testcase')
|
||||
->andWhere('objectID')->eq((int)$objectID)
|
||||
->fi()
|
||||
->beginIF($objectType == 'module')
|
||||
->where('objectType')->eq($objectType)
|
||||
->andWhere('((action')->ne('deleted')->andWhere('objectID')->eq((int)$objectID)->markRight(1)
|
||||
->orWhere('(action')->eq('deleted')->andWhere('objectID')->in($modules)->markRight(1)->markRight(1)
|
||||
->fi()
|
||||
->beginIF($objectType != 'project' and $objectType != 'module')
|
||||
->beginIF(strpos('project,case,story,module', $objectType) === false)
|
||||
->where('objectType')->eq($objectType)
|
||||
->andWhere('objectID')->eq((int)$objectID)
|
||||
->fi()
|
||||
@@ -1698,6 +1706,7 @@ class actionModel extends model
|
||||
$fieldName = $history->field;
|
||||
$history->fieldLabel = (isset($this->lang->$objectType) && isset($this->lang->$objectType->$fieldName)) ? $this->lang->$objectType->$fieldName : $fieldName;
|
||||
if($objectType == 'module') $history->fieldLabel = $this->lang->tree->$fieldName;
|
||||
if($fieldName == 'fileName') $history->fieldLabel = $this->lang->file->$fieldName;
|
||||
if(($length = strlen($history->fieldLabel)) > $maxLength) $maxLength = $length;
|
||||
$history->diff ? $historiesWithDiff[] = $history : $historiesWithoutDiff[] = $history;
|
||||
}
|
||||
|
||||
@@ -935,8 +935,9 @@ class block extends control
|
||||
$current = zget($weeks, $monday, '');
|
||||
$current = substr($current, 0, -11) . substr($current, -6);
|
||||
|
||||
$project->pv = $this->weekly->getPV($projectID, $today);
|
||||
$project->ev = $this->weekly->getEV($projectID, $today);
|
||||
$PVEV = $this->weekly->getPVEV($projectID, $today);
|
||||
$project->pv = $PVEV['PV'];
|
||||
$project->ev = $PVEV['EV'];
|
||||
$project->ac = $this->weekly->getAC($projectID, $today);
|
||||
$project->sv = $this->weekly->getSV($project->ev, $project->pv);
|
||||
$project->cv = $this->weekly->getCV($project->ev, $project->ac);
|
||||
@@ -1200,14 +1201,39 @@ class block extends control
|
||||
|
||||
$this->weekly->save($this->session->project, $date);
|
||||
|
||||
$this->view->pv = (float)$this->weekly->getPV($this->session->project, $today);
|
||||
$this->view->ev = (float)$this->weekly->getEV($this->session->project, $today);
|
||||
$PVEV = $this->weekly->getPVEV($this->session->project, $today);
|
||||
$this->view->pv = (float)$PVEV['PV'];
|
||||
$this->view->ev = (float)$PVEV['EV'];
|
||||
$this->view->ac = (float)$this->weekly->getAC($this->session->project, $today);
|
||||
$this->view->sv = $this->weekly->getSV($this->view->ev, $this->view->pv);
|
||||
$this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac);
|
||||
|
||||
$progress = !empty($this->view->pv) ? floor($this->view->ac / $this->view->pv * 1000) / 1000 * 100 : 0;
|
||||
$this->view->progress = $progress > 100 ? 100 : $progress;
|
||||
$this->view->current = $current;
|
||||
$this->view->progress = !empty($this->view->pv) ? floor($this->view->ac / $this->view->pv * 1000) / 1000 * 100 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print waterfall general report block.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function printWaterfallGeneralReportBlock()
|
||||
{
|
||||
$this->app->loadLang('programplan');
|
||||
$this->loadModel('project');
|
||||
$this->loadModel('weekly');
|
||||
|
||||
$data = $this->project->getWaterfallPVEVAC($this->session->project);
|
||||
$this->view->pv = (float)$data['PV'];
|
||||
$this->view->ev = (float)$data['EV'];
|
||||
$this->view->ac = (float)$data['AC'];
|
||||
$this->view->sv = $this->weekly->getSV($this->view->ev, $this->view->pv);
|
||||
$this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac);
|
||||
|
||||
$progress = !empty($this->view->pv) ? floor($this->view->ac / $this->view->pv * 1000) / 1000 * 100 : 0;
|
||||
$this->view->progress = $progress > 100 ? 100 : $progress;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-2
@@ -656,18 +656,29 @@ class blockModel extends model
|
||||
* Get waterfall project report pararms.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
* @return bool
|
||||
*/
|
||||
public function getWaterfallReportParams()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get waterfall general report params.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function getWaterfallGeneralReportParams()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project estimate pararms.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
* @return bool
|
||||
*/
|
||||
public function getWaterfallEstimateParams()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<style>
|
||||
.block-waterfallgeneralreport .col-left {width: 25%; text-align: center;}
|
||||
.block-waterfallgeneralreport .col-right {width: 87%;}
|
||||
.block-waterfallgeneralreport .panel-body {padding-top: 0;}
|
||||
.block-waterfallgeneralreport .table-row {margin-bottom: 20px;}
|
||||
<?php if(common::checkNotCN()):?>
|
||||
.block-waterfallgeneralreport .stage {position: absolute; top: 14px; left: 140px;}
|
||||
<?php else:?>
|
||||
.block-waterfallgeneralreport .stage {position: absolute; top: 14px; left: 90px;}
|
||||
<?php endif;?>
|
||||
.block-waterfallgeneralreport .col-right .tiles {padding: 10px 0 0 16px;}
|
||||
.block-waterfallgeneralreport .col-right .tile {width: 20%;}
|
||||
.block-waterfallgeneralreport .col-right .tile .tile-title {font-weight: 700;}
|
||||
.block-waterfallgeneralreport .progress {position: absolute; left: 45px; top: 90px; right: 40px;}
|
||||
.block-waterfallgeneralreport .progress-num {font-size: 20px; font-weight: 700;}
|
||||
.block-waterfallgeneralreport .col-right .tile-amount {font-size: 20px;}
|
||||
</style>
|
||||
|
||||
<div class="panel-body conatiner-fluid">
|
||||
<div class='table-row'>
|
||||
<div class="col col-left hide-in-sm">
|
||||
<h4><?php echo $lang->project->progress;?></h4>
|
||||
<span class='progress-num'><?php echo $progress . '%';?></span>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="<?php echo $progress;?>" aria-valuemin="0" aria-valuemax="100" style="width: <?php echo $progress;?>%">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-right'>
|
||||
<div class='row tiles'>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'PV(' . $lang->programplan->end . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $pv == 0 ? 0 : $pv;?></div>
|
||||
</div>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'EV(' . $lang->programplan->realEnd . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $ev == 0 ? 0 : $ev;?></div>
|
||||
</div>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'AC(' . $lang->programplan->ac . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $ac == 0 ? 0 : $ac;?></div>
|
||||
</div>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'SV(' . $lang->programplan->sv . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $sv . '%';?></div>
|
||||
</div>
|
||||
<div class="col tile">
|
||||
<div class="tile-title"><?php echo 'CV(' . $lang->programplan->cv . ')';?></div>
|
||||
<div class="tile-amount"><?php echo $cv . '%';?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -970,17 +970,15 @@ class bug extends control
|
||||
return print(js::error(dao::getError()));
|
||||
}
|
||||
}
|
||||
$files = $this->loadModel('file')->saveUpload('bug', $bugID);
|
||||
if(empty($files) and $this->post->uid != '' and isset($_SESSION['album']['used'][$this->post->uid])) $files = $this->file->getPairs($_SESSION['album']['used'][$this->post->uid]);
|
||||
}
|
||||
if($this->post->comment != '' or !empty($changes) or !empty($files))
|
||||
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
$action = (!empty($changes) or !empty($files)) ? 'Edited' : 'Commented';
|
||||
$fileAction = '';
|
||||
if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ;
|
||||
$actionID = $this->action->create('bug', $bugID, $action, $fileAction . $this->post->comment);
|
||||
$action = !empty($changes) ? 'Edited' : 'Commented';
|
||||
$actionID = $this->action->create('bug', $bugID, $action, $this->post->comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'data' => $bugID));
|
||||
$bug = $this->bug->getById($bugID);
|
||||
|
||||
|
||||
@@ -687,7 +687,7 @@ class bugModel extends model
|
||||
*/
|
||||
public function update($bugID)
|
||||
{
|
||||
$oldBug = $this->dao->select('*')->from(TABLE_BUG)->where('id')->eq((int)$bugID)->fetch();
|
||||
$oldBug = $this->getById($bugID);
|
||||
if(!empty($_POST['lastEditedDate']) and $oldBug->lastEditedDate != $this->post->lastEditedDate)
|
||||
{
|
||||
dao::$errors[] = $this->lang->error->editedByOther;
|
||||
@@ -707,6 +707,7 @@ class bugModel extends model
|
||||
->setDefault('resolvedDate', '0000-00-00 00:00:00')
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
->setDefault('mailto', '')
|
||||
->setDefault('deleteFiles', array())
|
||||
->add('lastEditedDate', $now)
|
||||
->setIF(strpos($this->config->bug->edit->requiredFields, 'deadline') !== false, 'deadline', $this->post->deadline)
|
||||
->join('openedBuild', ',')
|
||||
@@ -736,7 +737,7 @@ class bugModel extends model
|
||||
->get();
|
||||
|
||||
$bug = $this->loadModel('file')->processImgURL($bug, $this->config->bug->editor->edit['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_BUG)->data($bug)
|
||||
$this->dao->update(TABLE_BUG)->data($bug, 'deleteFiles')
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->bug->edit->requiredFields, 'notempty')
|
||||
->checkIF($bug->resolvedBy, 'resolution', 'notempty')
|
||||
@@ -783,12 +784,12 @@ class bugModel extends model
|
||||
}
|
||||
|
||||
if(!empty($bug->resolvedBy)) $this->loadModel('score')->create('bug', 'resolve', $bugID);
|
||||
$this->file->updateObjectID($this->post->uid, $bugID, 'bug');
|
||||
|
||||
if($bug->execution and $bug->status != $oldBug->status) $this->loadModel('kanban')->updateLane($bug->execution, 'bug');
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $oldBug->feedback) $this->loadModel('feedback')->updateStatus('bug', $oldBug->feedback, $bug->status, $oldBug->status);
|
||||
|
||||
$this->file->processFile4Object('bug', $oldBug, $bug);
|
||||
return common::createChanges($oldBug, $bug);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,10 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
|
||||
<?php $this->printExtendFields($bug, 'div', 'position=left');?>
|
||||
<div class="detail">
|
||||
<div class="detail-title"><?php echo $lang->files;?></div>
|
||||
<div class='detail-content'><?php echo $this->fetch('file', 'buildform');?></div>
|
||||
<div class='detail-content'>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $bug->files, 'fieldset' => 'false', 'object' => $bug, 'method' => 'edit'));?>
|
||||
<?php echo $this->fetch('file', 'buildform');?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='actions form-actions text-center'>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $bug->files, 'fieldset' => 'true', 'object' => $bug));?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $bug->files, 'fieldset' => 'true', 'object' => $bug, 'method' => 'view', 'showDelete' => false));?>
|
||||
<?php
|
||||
$canBeChanged = common::canBeChanged('bug', $bug);
|
||||
if($canBeChanged) $actionFormLink = $this->createLink('action', 'comment', "objectType=bug&objectID=$bug->id");
|
||||
|
||||
@@ -100,7 +100,6 @@ $lang->saveSuccess = 'Gespeichert';
|
||||
$lang->importSuccess = 'Gespeichert';
|
||||
$lang->fail = 'Fehlgeschlagen';
|
||||
$lang->addFiles = 'Hinzufügen ';
|
||||
$lang->deleteFiles = 'Anhang gelöscht ';
|
||||
$lang->files = 'Datei ';
|
||||
$lang->pasteText = 'Einfügen';
|
||||
$lang->uploadImages = 'Hochladen';
|
||||
|
||||
@@ -100,7 +100,6 @@ $lang->saveSuccess = 'Saved';
|
||||
$lang->importSuccess = 'Saved';
|
||||
$lang->fail = 'Fail';
|
||||
$lang->addFiles = 'Added Files ';
|
||||
$lang->deleteFiles = 'Deleted Files ';
|
||||
$lang->files = 'Files ';
|
||||
$lang->pasteText = 'Multi-line Paste';
|
||||
$lang->uploadImages = 'Multi-image Upload';
|
||||
|
||||
@@ -100,7 +100,6 @@ $lang->saveSuccess = 'Sauvegardé';
|
||||
$lang->importSuccess = 'Sauvé';
|
||||
$lang->fail = 'Echec';
|
||||
$lang->addFiles = 'Fichiers ajoutés ';
|
||||
$lang->deleteFiles = 'Pièce jointe supprimée ';
|
||||
$lang->files = 'Fichiers ';
|
||||
$lang->pasteText = 'Collage Multi-lignes';
|
||||
$lang->uploadImages = 'Upload Multi-images';
|
||||
|
||||
@@ -79,7 +79,6 @@ $lang->saveSuccess = 'Đã lưu';
|
||||
$lang->importSuccess = 'Đã lưu';
|
||||
$lang->fail = 'Thất bại';
|
||||
$lang->addFiles = 'Tập tin đã thêm ';
|
||||
$lang->deleteFiles = 'Tháo ảnh ';
|
||||
$lang->files = 'Files ';
|
||||
$lang->pasteText = 'Dán nhiều dòng';
|
||||
$lang->uploadImages = 'Tải lên nhiều ảnh';
|
||||
|
||||
@@ -100,7 +100,6 @@ $lang->saveSuccess = '保存成功';
|
||||
$lang->importSuccess = '导入成功';
|
||||
$lang->fail = '失败';
|
||||
$lang->addFiles = '上传了附件 ';
|
||||
$lang->deleteFiles = '删除了附件 ';
|
||||
$lang->files = '附件 ';
|
||||
$lang->pasteText = '多项录入';
|
||||
$lang->uploadImages = '多图上传 ';
|
||||
|
||||
+62
-72
@@ -46,25 +46,23 @@ class fileModel extends model
|
||||
->where('objectType')->eq($objectType)
|
||||
->andWhere('objectID')->eq((int)$objectID)
|
||||
->andWhere('extra')->ne('editor')
|
||||
->beginIF(strpos('story,requirement', $objectType) !== false and $extra)->andWhere('extra')->like("%,$extra,%")->fi()
|
||||
->beginIF(strpos('story,requirement', $objectType) === false and $extra)->andWhere('extra')->eq($extra)->fi()
|
||||
->beginIF($extra)->andWhere('extra')->eq($extra)
|
||||
->andWhere('deleted')->eq('0')
|
||||
->orderBy('id')
|
||||
->fetchAll('id');
|
||||
|
||||
foreach($files as $file)
|
||||
{
|
||||
if($objectType != 'traincourse' and $objectType != 'traincontents')
|
||||
{
|
||||
$realPathName = $this->getRealPathName($file->pathname);
|
||||
$file->realPath = $this->savePath . $realPathName;
|
||||
$file->webPath = $this->webPath . $realPathName;
|
||||
}
|
||||
else
|
||||
if($objectType == 'traincourse' or $objectType == 'traincontents')
|
||||
{
|
||||
$file->realPath = $this->app->getWwwRoot() . 'data/course/' . $file->pathname;
|
||||
$file->webPath = 'data/course/' . $file->pathname;
|
||||
continue;
|
||||
}
|
||||
|
||||
$realPathName = $this->getRealPathName($file->pathname);
|
||||
$file->realPath = $this->savePath . $realPathName;
|
||||
$file->webPath = $this->webPath . $realPathName;
|
||||
}
|
||||
|
||||
return $files;
|
||||
@@ -81,33 +79,52 @@ class fileModel extends model
|
||||
{
|
||||
$file = $this->dao->findById($fileID)->from(TABLE_FILE)->fetch();
|
||||
if(empty($file)) return false;
|
||||
if($file->objectType != 'traincourse' and $file->objectType != 'traincontents')
|
||||
{
|
||||
$realPathName = $this->getRealPathName($file->pathname);
|
||||
$file->realPath = $this->savePath . $realPathName;
|
||||
$file->webPath = $this->webPath . $realPathName;
|
||||
}
|
||||
else
|
||||
{
|
||||
$file->realPath = $this->app->getWwwRoot() . 'data/course/' . $file->pathname;
|
||||
$file->webPath = $this->app->getWebRoot() . 'data/course/' . $file->pathname;
|
||||
}
|
||||
|
||||
if($file->objectType != 'traincourse' and $file->objectType != 'traincontents')
|
||||
{
|
||||
$realPathName = $this->getRealPathName($file->pathname);
|
||||
$file->realPath = $this->savePath . $realPathName;
|
||||
$file->webPath = $this->webPath . $realPathName;
|
||||
}
|
||||
else
|
||||
if($file->objectType == 'traincourse' or $file->objectType == 'traincontents')
|
||||
{
|
||||
$file->realPath = $this->app->getWwwRoot() . 'data/course/' . $file->pathname;
|
||||
$file->webPath = 'data/course/' . $file->pathname;
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
$realPathName = $this->getRealPathName($file->pathname);
|
||||
$file->realPath = $this->savePath . $realPathName;
|
||||
$file->webPath = $this->webPath . $realPathName;
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get files by ID list.
|
||||
*
|
||||
* @param int $fileIdList
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getByIdList($fileIdList)
|
||||
{
|
||||
if(empty($fileIdList)) return array();
|
||||
|
||||
$files = $this->dao->select('*')->from(TABLE_FILE)->where('id')->in($fileIdList)->orderBy('id')->fetchAll('id');
|
||||
|
||||
foreach($files as $file)
|
||||
{
|
||||
if($file->objectType == 'traincourse' or $file->objectType == 'traincontents')
|
||||
{
|
||||
$file->realPath = $this->app->getWwwRoot() . 'data/course/' . $file->pathname;
|
||||
$file->webPath = 'data/course/' . $file->pathname;
|
||||
continue;
|
||||
}
|
||||
|
||||
$realPathName = $this->getRealPathName($file->pathname);
|
||||
$file->realPath = $this->savePath . $realPathName;
|
||||
$file->webPath = $this->webPath . $realPathName;
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save upload.
|
||||
*
|
||||
@@ -1121,60 +1138,33 @@ class fileModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Update version of story files.
|
||||
* Process file info for object.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param int $storyVersion
|
||||
* @param array $deleteFiles
|
||||
* @param string $objectType
|
||||
* @param object $oldObject
|
||||
* @param object $newObject
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function updateStoryFileVersion($storyID, $storyVersion, $deleteFiles = array())
|
||||
public function processFile4Object($objectType, $oldObject, $newObject)
|
||||
{
|
||||
$oldStoryVersion = $storyVersion - 1;
|
||||
$this->dao->update(TABLE_FILE)->set("extra = CONCAT(extra, '$storyVersion,')")
|
||||
->where('objectType')->in('story,requirement')
|
||||
->andWhere('objectID')->eq($storyID)
|
||||
->andWhere('extra')->like("%,$oldStoryVersion,%")
|
||||
->beginIF(!empty($deleteFiles))->andWhere('id')->notin($deleteFiles)->fi()
|
||||
->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete story file.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param int $storyVersion
|
||||
* @param array $deleteFiles
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function deleteStoryFile($storyID, $storyVersion, $deleteFiles = array())
|
||||
{
|
||||
$deleteFileList = $this->dao->select('*')->from(TABLE_FILE)
|
||||
->where('objectType')->in('story,requirement')
|
||||
->andWhere('objectID')->eq($storyID)
|
||||
->andWhere('extra')->eq(",$storyVersion,")
|
||||
->beginIF(!empty($deleteFiles))->andWhere('id')->in($deleteFiles)->fi()
|
||||
->fetchAll('id');
|
||||
|
||||
if(!empty($deleteFileList))
|
||||
$oldFiles = empty($oldObject->files) ? '' : join(',', array_keys($oldObject->files));
|
||||
$deleteFiles = $newObject->deleteFiles;
|
||||
if(!empty($deleteFiles))
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_FILE)->where('id')->in(array_keys($deleteFileList))->exec();
|
||||
|
||||
foreach($deleteFileList as $file)
|
||||
$this->dao->delete()->from(TABLE_FILE)->where('id')->in($deleteFiles)->exec();
|
||||
foreach($deleteFiles as $fileID)
|
||||
{
|
||||
$realPathName = $this->getRealPathName($file->pathname);
|
||||
@unlink($realPathName);
|
||||
@unlink($oldObject->files[$fileID]->realPath);
|
||||
$oldFiles = empty($oldFiles) ? '' : trim(str_replace(",$fileID,", ',', ",$oldFiles,"), ',');
|
||||
}
|
||||
}
|
||||
|
||||
/* When the file is in multiple story versions, 'extra' need delete the version to be deleted. */
|
||||
$this->dao->update(TABLE_FILE)->set("extra = REPLACE(extra, '$storyVersion,', '')")
|
||||
->where('objectType')->in('story,requirement')
|
||||
->andWhere('objectID')->eq($storyID)
|
||||
->andWhere('extra')->like("%,$storyVersion,%")
|
||||
->beginIF(!empty($deleteFiles))->andWhere('id')->in($deleteFiles)->fi()
|
||||
->exec();
|
||||
$this->updateObjectID($this->post->uid, $oldObject->id, $objectType);
|
||||
$addedFiles = $this->saveUpload($objectType, $oldObject->id);
|
||||
$addedFiles = empty($addedFiles) ? '' : ',' . join(',', array_keys($addedFiles));
|
||||
|
||||
$newObject->files = trim($oldFiles . $addedFiles, ',');
|
||||
$oldObject->files = join(',', array_keys($oldObject->files));
|
||||
}
|
||||
}
|
||||
|
||||
+19
-24
@@ -205,21 +205,19 @@ class holidayModel extends model
|
||||
$workingDays = $this->getWorkingDays($begin, $end);
|
||||
$weekend = isset($this->config->project->weekend) ? $this->config->project->weekend : 2;
|
||||
|
||||
$holidaysFlip = array_flip($holidays);
|
||||
$workingDaysFlip = array_flip($workingDays);
|
||||
|
||||
/* When the start date and end date are the same. */
|
||||
$beginTimestamp = strtotime($begin);
|
||||
if($begin == $end)
|
||||
{
|
||||
if(in_array($begin, $workingDays)) return $actualDays[] = $begin;
|
||||
if(in_array($begin, $holidays)) return $actualDays;
|
||||
if(isset($workingDaysFlip[$begin])) return $actualDays[] = $begin;
|
||||
if(isset($holidaysFlip[$begin])) return $actualDays;
|
||||
|
||||
$w = date('w', strtotime($begin));
|
||||
if($weekend == 2)
|
||||
{
|
||||
if($w == 0 or $w == 6) return $actualDays;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($w == 0) return $actualDays;
|
||||
}
|
||||
$w = date('w', $beginTimestamp);
|
||||
if($weekend == 2 and ($w == 0 or $w == 6)) return $actualDays;
|
||||
if($weekend != 2 and $w == 0) return $actualDays;
|
||||
|
||||
$actualDays[] = $begin;
|
||||
return $actualDays;
|
||||
@@ -227,24 +225,21 @@ class holidayModel extends model
|
||||
|
||||
for($i = 0; $currentDay < $end; $i ++)
|
||||
{
|
||||
$currentDay = date('Y-m-d', strtotime("$begin + $i days"));
|
||||
$w = date('w', strtotime($currentDay));
|
||||
$currentTimestamp = $beginTimestamp + ($i * 24 * 3600);
|
||||
$currentDay = date('Y-m-d', $currentTimestamp);
|
||||
|
||||
if(in_array($currentDay, $workingDays))
|
||||
if(isset($workingDaysFlip[$currentDay]))
|
||||
{
|
||||
$actualDays[] = $currentDay;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(in_array($currentDay, $holidays)) continue;
|
||||
if($weekend == 2)
|
||||
{
|
||||
if($w == 0 or $w == 6) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($w == 0) continue;
|
||||
}
|
||||
if(isset($holidaysFlip[$currentDay])) continue;
|
||||
|
||||
$w = date('w', $currentTimestamp);
|
||||
if($weekend == 2 and ($w == 0 or $w == 6)) continue;
|
||||
if($weekend != 2 and $w == 0) continue;
|
||||
|
||||
$actualDays[] = $currentDay;
|
||||
}
|
||||
|
||||
@@ -266,7 +261,7 @@ class holidayModel extends model
|
||||
$days = ($endTime - $beginTime) / 86400;
|
||||
|
||||
$dateList = array();
|
||||
for($i = 0; $i <= $days; $i ++) $dateList[] = date('Y-m-d', strtotime("+$i days", $beginTime));
|
||||
for($i = 0; $i <= $days; $i ++) $dateList[] = date('Y-m-d', $beginTime + ($i *24 *3600));
|
||||
|
||||
return $dateList;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme
|
||||
$lang->misc->feature->visionsDesc = "<p>The concept of interface has been added since 16.5. Users can deal with R & D affairs in <span style='color: #0c60e1'>[R&D]</span> and daily office affairs in <span style='color: #0c60e1'>[Lite]</span>.</p><p>You can view the current interface on the avatar, and click the name of the interface to view and switch other interfaces.</p>";
|
||||
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions_en.png';
|
||||
|
||||
$lang->misc->releaseDate['17.6.1'] = '2022-09-08';
|
||||
$lang->misc->releaseDate['17.6'] = '2022-08-26';
|
||||
$lang->misc->releaseDate['17.5'] = '2022-08-11';
|
||||
$lang->misc->releaseDate['17.4'] = '2022-07-27';
|
||||
@@ -188,6 +189,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['17.6.1'][] = array('title' => "Optimized the processing logic of multi-member tasks. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.6'][] = array('title' => "The processing logic of requirements is optimized, and the permissions of user requirements and soft requirements are split. Gantt chart supports manual drag and drop to manage task relationship. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.5'][] = array('title' => "Provide efficient visual statistical tools. Optimize ZenTao performance, the database engine is adjusted from MyISAM to InnoDB. Gantt chart is optimized and upgraded, and the Copy items of the Max version can replicate more information. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.4'][] = array('title' => "Optimization of details Page visualization and jumping page logic. Improvement of Kanban function. Optimization of document creating and editing pages. Fix bugs.", 'desc' => '');
|
||||
|
||||
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme
|
||||
$lang->misc->feature->visionsDesc = "<p>The concept of interface has been added since 16.5. Users can deal with R & D affairs in <span style='color: #0c60e1'>[R&D]</span> and daily office affairs in <span style='color: #0c60e1'>[Lite]</span>.</p><p>You can view the current interface on the avatar, and click the name of the interface to view and switch other interfaces.</p>";
|
||||
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions_en.png';
|
||||
|
||||
$lang->misc->releaseDate['17.6.1'] = '2022-09-08';
|
||||
$lang->misc->releaseDate['17.6'] = '2022-08-26';
|
||||
$lang->misc->releaseDate['17.5'] = '2022-08-11';
|
||||
$lang->misc->releaseDate['17.4'] = '2022-07-27';
|
||||
@@ -188,6 +189,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['17.6.1'][] = array('title' => "Optimized the processing logic of multi-member tasks. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.6'][] = array('title' => "The processing logic of requirements is optimized, and the permissions of user requirements and soft requirements are split. Gantt chart supports manual drag and drop to manage task relationship. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.5'][] = array('title' => "Provide efficient visual statistical tools. Optimize ZenTao performance, the database engine is adjusted from MyISAM to InnoDB. Gantt chart is optimized and upgraded, and the Copy items of the Max version can replicate more information. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.4'][] = array('title' => "Optimization of details Page visualization and jumping page logic. Improvement of Kanban function. Optimization of document creating and editing pages. Fix bugs.", 'desc' => '');
|
||||
|
||||
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme
|
||||
$lang->misc->feature->visionsDesc = "<p>The concept of interface has been added since 16.5. Users can deal with R & D affairs in <span style='color: #0c60e1'>[R&D]</span> and daily office affairs in <span style='color: #0c60e1'>[Lite]</span>.</p><p>You can view the current interface on the avatar, and click the name of the interface to view and switch other interfaces.</p>";
|
||||
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions_en.png';
|
||||
|
||||
$lang->misc->releaseDate['17.6.1'] = '2022-09-08';
|
||||
$lang->misc->releaseDate['17.6'] = '2022-08-26';
|
||||
$lang->misc->releaseDate['17.5'] = '2022-08-11';
|
||||
$lang->misc->releaseDate['17.4'] = '2022-07-27';
|
||||
@@ -188,6 +189,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['17.6.1'][] = array('title' => "Optimized the processing logic of multi-member tasks. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.6'][] = array('title' => "The processing logic of requirements is optimized, and the permissions of user requirements and soft requirements are split. Gantt chart supports manual drag and drop to manage task relationship. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.5'][] = array('title' => "Provide efficient visual statistical tools. Optimize ZenTao performance, the database engine is adjusted from MyISAM to InnoDB. Gantt chart is optimized and upgraded, and the Copy items of the Max version can replicate more information. Fix bugs.", 'desc' => '');
|
||||
$lang->misc->feature->all['17.4'][] = array('title' => "Optimization of details Page visualization and jumping page logic. Improvement of Kanban function. Optimization of document creating and editing pages. Fix bugs.", 'desc' => '');
|
||||
|
||||
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = "<p>禅道15系列上线了全新的“
|
||||
$lang->misc->feature->visionsDesc = "<p>从16.5开始增加了界面概念,用户可以在<span style='color:#0c60e1'>[研发综合界面]</span>中处理研发事务、在<span style='color:#0c60e1'>[迅捷界面]</span>处理日常办公事务。</p><p>在头像右侧即可查看当前所处界面,点击当前界面名称可查看和切换其他的界面。</p>";
|
||||
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions.png';
|
||||
|
||||
$lang->misc->releaseDate['17.6.1'] = '2022-09-08';
|
||||
$lang->misc->releaseDate['17.6'] = '2022-08-26';
|
||||
$lang->misc->releaseDate['17.5'] = '2022-08-11';
|
||||
$lang->misc->releaseDate['17.4'] = '2022-07-27';
|
||||
@@ -188,6 +189,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['17.6.1'][] = array('title' => '优化了多人任务的处理逻辑,修复Bug。', 'desc' => '');
|
||||
$lang->misc->feature->all['17.6'][] = array('title' => '优化了需求的处理逻辑,拆分了用需和软需的权限。甘特图支持手动拖拽维护任务关系。修复Bug。', 'desc' => '');
|
||||
$lang->misc->feature->all['17.5'][] = array('title' => '提供高效的可视化统计工具。优化禅道性能,数据库引擎从MyISAM调整为InnoDB。甘特图优化升级,旗舰版的复制项目可以复制任务等更多信息。修复Bug。', 'desc' => '');
|
||||
$lang->misc->feature->all['17.4'][] = array('title' => '详情页面的视觉优化和部分页面跳转逻辑优化。看板功能完善。文档创建和编辑页面优化。修复Bug。', 'desc' => '');
|
||||
|
||||
@@ -153,6 +153,7 @@ class my extends control
|
||||
$riskCount = 0;
|
||||
$reviewCount = 0;
|
||||
$ncCount = 0;
|
||||
$qaCount = 0;
|
||||
$meetingCount = 0;
|
||||
$isMax = $this->config->edition == 'max' ? 1 : 0;
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ $config->product->all->search['fields']['createdDate'] = $lang->product->created
|
||||
$config->product->all->search['fields']['createdBy'] = $lang->product->createdBy;
|
||||
|
||||
$config->product->all->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
$config->product->all->search['params']['code'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
if(!isset($config->setCode) or $config->setCode == 1) $config->product->all->search['params']['code'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
|
||||
$config->product->all->search['params']['id'] = array('operator' => '=', 'control' => 'input', 'values' => '');
|
||||
if($config->systemMode == 'new') $config->product->all->search['params']['program'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
$config->product->all->search['params']['line'] = array('operator' => '=', 'control' => 'select', 'values' => '');
|
||||
|
||||
@@ -415,6 +415,42 @@ class projectModel extends model
|
||||
return is_numeric($projectIDList) ? (empty($progressList) ? 0 : $progressList[$projectIDList]) : $progressList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get waterfall general PV and EV.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getWaterfallPVEVAC($projectID)
|
||||
{
|
||||
$executions = $this->dao->select('id,begin,end,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($projectID)->fetchAll('id');
|
||||
$stmt = $this->dao->select('id,status,estimate,consumed,`left`,closedReason')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere("parent")->ge(0)->andWhere("deleted")->eq(0)->query();
|
||||
|
||||
$PV = 0;
|
||||
$EV = 0;
|
||||
$AC = 0;
|
||||
while($task = $stmt->fetch())
|
||||
{
|
||||
if(empty($task->estimate)) continue;
|
||||
|
||||
$PV += $task->estimate;
|
||||
$AC += $task->consumed;
|
||||
if($task->status == 'done' or $task->closedReason == 'done')
|
||||
{
|
||||
$EV += $task->estimate;
|
||||
}
|
||||
else
|
||||
{
|
||||
$task->progress = 0;
|
||||
if(($task->consumed + $task->left) > 0) $task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100;
|
||||
$EV += round($task->estimate * $task->progress / 100, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return array('PV' => sprintf("%.2f", $PV), 'EV' => sprintf("%.2f", $EV), 'AC' => sprintf("%.2f", $AC));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project workhour info.
|
||||
*
|
||||
|
||||
@@ -119,12 +119,10 @@ class release extends control
|
||||
{
|
||||
$changes = $this->release->update($releaseID);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$files = $this->loadModel('file')->saveUpload('release', $releaseID);
|
||||
if($changes or $files)
|
||||
|
||||
if($changes)
|
||||
{
|
||||
$fileAction = '';
|
||||
if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ;
|
||||
$actionID = $this->loadModel('action')->create('release', $releaseID, 'Edited', $fileAction);
|
||||
$actionID = $this->loadModel('action')->create('release', $releaseID, 'Edited');
|
||||
if(!empty($changes)) $this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ $lang->release->name = 'Name';
|
||||
$lang->release->marker = 'Meilensteine';
|
||||
$lang->release->date = 'Datum';
|
||||
$lang->release->desc = 'Beschreibung';
|
||||
$lang->release->files = 'Gehäuse';
|
||||
$lang->release->status = 'Status';
|
||||
$lang->release->subStatus = 'Sub Status';
|
||||
$lang->release->last = 'Letztes Release';
|
||||
|
||||
@@ -42,6 +42,7 @@ $lang->release->name = 'Name';
|
||||
$lang->release->marker = 'Milestone';
|
||||
$lang->release->date = 'Release Date';
|
||||
$lang->release->desc = 'Description';
|
||||
$lang->release->files = 'Files';
|
||||
$lang->release->status = 'Status';
|
||||
$lang->release->subStatus = 'Sub Status';
|
||||
$lang->release->last = 'Last Release';
|
||||
|
||||
@@ -42,6 +42,7 @@ $lang->release->name = 'Nom';
|
||||
$lang->release->marker = 'Etape Importante';
|
||||
$lang->release->date = 'Date Release';
|
||||
$lang->release->desc = 'Description';
|
||||
$lang->release->files = 'Files';
|
||||
$lang->release->status = 'Statut';
|
||||
$lang->release->subStatus = 'Sous-statut';
|
||||
$lang->release->last = 'Dernière Release';
|
||||
|
||||
@@ -41,6 +41,7 @@ $lang->release->name = 'Tên';
|
||||
$lang->release->marker = 'Cột mốc';
|
||||
$lang->release->date = 'Ngày';
|
||||
$lang->release->desc = 'Mô tả';
|
||||
$lang->release->files = 'Chung';
|
||||
$lang->release->status = 'Tình trạng';
|
||||
$lang->release->subStatus = 'Tình trạng con';
|
||||
$lang->release->last = 'Phát hành gần nhất';
|
||||
|
||||
@@ -42,6 +42,7 @@ $lang->release->name = '发布名称';
|
||||
$lang->release->marker = '里程碑';
|
||||
$lang->release->date = '发布日期';
|
||||
$lang->release->desc = '描述';
|
||||
$lang->release->files = '附件';
|
||||
$lang->release->status = '状态';
|
||||
$lang->release->subStatus = '子状态';
|
||||
$lang->release->last = '上次发布';
|
||||
|
||||
@@ -42,6 +42,7 @@ $lang->release->name = '發佈名稱';
|
||||
$lang->release->marker = '里程碑';
|
||||
$lang->release->date = '發佈日期';
|
||||
$lang->release->desc = '描述';
|
||||
$lang->release->files = '附件';
|
||||
$lang->release->status = '狀態';
|
||||
$lang->release->subStatus = '子狀態';
|
||||
$lang->release->last = '上次發佈';
|
||||
|
||||
@@ -263,13 +263,14 @@ class releaseModel extends model
|
||||
{
|
||||
/* Init vars. */
|
||||
$releaseID = (int)$releaseID;
|
||||
$oldRelease = $this->dao->select('*')->from(TABLE_RELEASE)->where('id')->eq($releaseID)->fetch();
|
||||
$oldRelease = $this->getById($releaseID);
|
||||
$branch = $this->dao->select('branch')->from(TABLE_BUILD)->where('id')->eq((int)$this->post->build)->fetch('branch');
|
||||
|
||||
$release = fixer::input('post')->stripTags($this->config->release->editor->edit['id'], $this->config->allowedTags)
|
||||
->add('id', $releaseID)
|
||||
->add('branch', (int)$branch)
|
||||
->setDefault('mailto', '')
|
||||
->setDefault('deleteFiles', array())
|
||||
->join('mailto', ',')
|
||||
->setIF(!$this->post->marker, 'marker', 0)
|
||||
->cleanInt('product')
|
||||
@@ -286,7 +287,7 @@ class releaseModel extends model
|
||||
$release->project = $buildInfo->project;
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_RELEASE)->data($release)
|
||||
$this->dao->update(TABLE_RELEASE)->data($release, 'deleteFiles')
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->release->edit->requiredFields, 'notempty')
|
||||
->check('name', 'unique', "id != '$releaseID' AND product = '{$release->product}' AND branch = '$branch' AND deleted = '0'")
|
||||
@@ -295,7 +296,7 @@ class releaseModel extends model
|
||||
->exec();
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->file->updateObjectID($this->post->uid, $releaseID, 'release');
|
||||
$this->file->processFile4Object('release', $oldRelease, $release);
|
||||
return common::createChanges($oldRelease, $release);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,10 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->files;?></th>
|
||||
<td colspan='2'><?php echo $this->fetch('file', 'buildform');?></td>
|
||||
<td colspan='2'>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $release->files, 'fieldset' => 'false', 'object' => $release, 'method' => 'edit'));?>
|
||||
<?php echo $this->fetch('file', 'buildform');?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='3' class='text-center form-actions'>
|
||||
|
||||
@@ -373,11 +373,11 @@
|
||||
</div>
|
||||
<div class='detail'>
|
||||
<div class='detail-title'><?php echo $lang->files?></div>
|
||||
<div class='detail-content article-content'>
|
||||
<div class='detail-content'>
|
||||
<?php
|
||||
if($release->files)
|
||||
{
|
||||
echo $this->fetch('file', 'printFiles', array('files' => $release->files, 'fieldset' => 'false'));
|
||||
echo $this->fetch('file', 'printFiles', array('files' => $release->files, 'fieldset' => 'false', 'object' => $release, 'method' => 'view', 'showDelete' => false));
|
||||
}
|
||||
elseif($release->filePath)
|
||||
{
|
||||
|
||||
@@ -863,7 +863,6 @@ class story extends control
|
||||
$this->view->reviewers = array_keys($reviewerList);
|
||||
$this->view->reviewedReviewer = $reviewedReviewer;
|
||||
$this->view->productReviewers = $this->user->getPairs('noclosed|nodeleted', array_keys($reviewerList), 0, $productReviewers);
|
||||
$this->view->files = $this->file->getByObject($story->type, $storyID, $story->version);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -1080,25 +1079,17 @@ class story extends control
|
||||
$this->loadModel('file');
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$deleteFiles = isset($_POST['deleteFiles']) ? $this->file->getPairs($_POST['deleteFiles'], 'title') : array();
|
||||
$changes = $this->story->change($storyID);
|
||||
$changes = $this->story->change($storyID);
|
||||
if(dao::isError())
|
||||
{
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'fail', 'message' => dao::getError()));
|
||||
return print(js::error(dao::getError()));
|
||||
}
|
||||
|
||||
$story = $this->story->getByID($storyID);
|
||||
$version = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch('version');
|
||||
$files = $this->file->saveUpload($story->type, $storyID, ",$version,");
|
||||
if(empty($files) and $this->post->uid != '' and isset($_SESSION['album']['used'][$this->post->uid])) $files = $this->file->getPairs($_SESSION['album']['used'][$this->post->uid]);
|
||||
|
||||
if($this->post->comment != '' or !empty($changes) or !empty($files) or !empty($deleteFiles))
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
$action = (!empty($changes) or !empty($files)) ? 'Changed' : 'Commented';
|
||||
$fileAction = empty($files) ? '' : $this->lang->addFiles . join(',', $files) . "\n" ;
|
||||
$fileAction .= empty($deleteFiles) ? '' : $this->lang->deleteFiles . join(',', $deleteFiles) . "\n";
|
||||
$actionID = $this->action->create('story', $storyID, $action, $fileAction . $this->post->comment);
|
||||
$action = !empty($changes) ? 'Changed' : 'Commented';
|
||||
$actionID = $this->action->create('story', $storyID, $action, $this->post->comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
@@ -1148,7 +1139,7 @@ class story extends control
|
||||
$this->app->loadLang('testcase');
|
||||
$this->app->loadLang('execution');
|
||||
|
||||
$story = $this->story->getById($storyID);
|
||||
$story = $this->view->story;
|
||||
$reviewer = $this->story->getReviewerPairs($storyID, $story->version);
|
||||
$product = $this->loadModel('product')->getByID($story->product);
|
||||
|
||||
@@ -1163,7 +1154,6 @@ class story extends control
|
||||
$this->view->needReview = (($this->app->user->account == $this->view->product->PO or $this->config->story->needReview == 0) and empty($reviewer)) ? "checked='checked'" : "";
|
||||
$this->view->reviewer = implode(',', array_keys($reviewer));
|
||||
$this->view->productReviewers = $this->user->getPairs('noclosed|nodeleted', $reviewer, 0, $productReviewers);
|
||||
$this->view->files = $this->file->getByObject($story->type, $storyID, $story->version);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -1250,7 +1240,6 @@ class story extends control
|
||||
|
||||
$this->story->replaceURLang($story->type);
|
||||
|
||||
$story->files = $this->loadModel('file')->getByObject($story->type, $storyID, $version);
|
||||
$product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id, type, status')->fetch();
|
||||
$plan = $this->dao->findById($story->plan)->from(TABLE_PRODUCTPLAN)->fetch('title');
|
||||
$bugs = $this->dao->select('id,title,status,pri,severity')->from(TABLE_BUG)->where('story')->eq($storyID)->andWhere('deleted')->eq(0)->fetchAll();
|
||||
|
||||
+59
-65
@@ -30,18 +30,20 @@ class storyModel extends model
|
||||
->fetch();
|
||||
if(!$story) return false;
|
||||
|
||||
$this->loadModel('file');
|
||||
if(helper::isZeroDate($story->closedDate)) $story->closedDate = '';
|
||||
if($version == 0) $version = $story->version;
|
||||
$spec = $this->dao->select('title,spec,verify')->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWhere('version')->eq($version)->fetch();
|
||||
$spec = $this->dao->select('title,spec,verify,files')->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWhere('version')->eq($version)->fetch();
|
||||
$story->title = isset($spec->title) ? $spec->title : '';
|
||||
$story->spec = isset($spec->spec) ? $spec->spec : '';
|
||||
$story->verify = isset($spec->verify) ? $spec->verify : '';
|
||||
$story->files = isset($spec->files) ? $this->file->getByIdList($spec->files) : '';
|
||||
if(!empty($story->fromStory)) $story->sourceName = $this->dao->select('title')->from(TABLE_STORY)->where('id')->eq($story->fromStory)->fetch('title');
|
||||
|
||||
/* Check parent story. */
|
||||
if($story->parent > 0) $story->parentName = $this->dao->findById($story->parent)->from(TABLE_STORY)->fetch('title');
|
||||
|
||||
$story = $this->loadModel('file')->replaceImgURL($story, 'spec,verify');
|
||||
$story = $this->file->replaceImgURL($story, 'spec,verify');
|
||||
if($setImgSize) $story->spec = $this->file->setImgSize($story->spec);
|
||||
if($setImgSize) $story->verify = $this->file->setImgSize($story->verify);
|
||||
|
||||
@@ -264,21 +266,22 @@ class storyModel extends model
|
||||
$this->subdivide($story->parent, $stories);
|
||||
}
|
||||
|
||||
$this->file->updateObjectID($this->post->uid, $storyID, $story->type);
|
||||
$this->file->saveUpload($story->type, $storyID, ',1,');
|
||||
|
||||
if(!empty($story->plan))
|
||||
{
|
||||
$this->updateStoryOrderOfPlan($storyID, $story->plan); // Set story order in this plan.
|
||||
$this->loadModel('action')->create('productplan', $story->plan, 'linkstory', '', $storyID);
|
||||
}
|
||||
|
||||
$this->file->updateObjectID($this->post->uid, $storyID, $story->type);
|
||||
$files = $this->file->saveUpload($story->type, $storyID, 1);
|
||||
|
||||
$data = new stdclass();
|
||||
$data->story = $storyID;
|
||||
$data->version = 1;
|
||||
$data->title = $story->title;
|
||||
$data->spec = $story->spec;
|
||||
$data->verify = $story->verify;
|
||||
$data->files = join(',', array_keys($files));
|
||||
$this->dao->insert(TABLE_STORYSPEC)->data($data)->exec();
|
||||
|
||||
/* Save the story reviewer to storyreview table. */
|
||||
@@ -658,11 +661,7 @@ class storyModel extends model
|
||||
public function change($storyID)
|
||||
{
|
||||
$specChanged = false;
|
||||
$oldStory = $this->dao->findById((int)$storyID)->from(TABLE_STORY)->fetch();
|
||||
$oldSpec = $this->dao->select('title,spec,verify')->from(TABLE_STORYSPEC)->where('story')->eq((int)$storyID)->andWhere('version')->eq($oldStory->version)->fetch();
|
||||
$oldStory->title = isset($oldSpec->title) ? $oldSpec->title : '';
|
||||
$oldStory->spec = isset($oldSpec->spec) ? $oldSpec->spec : '';
|
||||
$oldStory->verify = isset($oldSpec->verify) ? $oldSpec->verify : '';
|
||||
$oldStory = $this->getById($storyID);
|
||||
|
||||
if(!empty($_POST['lastEditedDate']) and $oldStory->lastEditedDate != $this->post->lastEditedDate)
|
||||
{
|
||||
@@ -688,12 +687,13 @@ class storyModel extends model
|
||||
$oldStoryReviewers = $this->getReviewerPairs($storyID, $oldStory->version);
|
||||
$_POST['reviewer'] = isset($_POST['reviewer']) ? $_POST['reviewer'] : array();
|
||||
$reviewerHasChanged = (array_diff(array_keys($oldStoryReviewers), $_POST['reviewer']) or array_diff($_POST['reviewer'], array_keys($oldStoryReviewers)));
|
||||
if($story->spec != $oldStory->spec or $story->verify != $oldStory->verify or $story->title != $oldStory->title or $this->loadModel('file')->getCount() or $reviewerHasChanged or isset($_POST['deleteFiles'])) $specChanged = true;
|
||||
if($story->spec != $oldStory->spec or $story->verify != $oldStory->verify or $story->title != $oldStory->title or $this->loadModel('file')->getCount() or $reviewerHasChanged or isset($story->deleteFiles)) $specChanged = true;
|
||||
|
||||
$now = helper::now();
|
||||
$story = fixer::input('post')
|
||||
->callFunc('title', 'trim')
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
->setDefault('deleteFiles', array())
|
||||
->add('id', $storyID)
|
||||
->add('lastEditedDate', $now)
|
||||
->setIF($specChanged, 'version', $oldStory->version + 1)
|
||||
@@ -706,11 +706,11 @@ class storyModel extends model
|
||||
->setIF($specChanged and $oldStory->closedBy, 'closedDate', '0000-00-00')
|
||||
->setIF(!$specChanged, 'status', $oldStory->status)
|
||||
->stripTags($this->config->story->editor->change['id'], $this->config->allowedTags)
|
||||
->remove('files,labels,reviewer,comment,needNotReview,uid,deleteFiles')
|
||||
->remove('files,labels,reviewer,comment,needNotReview,uid')
|
||||
->get();
|
||||
|
||||
$story = $this->loadModel('file')->processImgURL($story, $this->config->story->editor->change['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_STORY)->data($story, 'spec,verify')
|
||||
$this->dao->update(TABLE_STORY)->data($story, 'spec,verify,deleteFiles')
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->story->change->requiredFields, 'notempty')
|
||||
->checkFlow()
|
||||
@@ -720,20 +720,27 @@ class storyModel extends model
|
||||
{
|
||||
if($specChanged)
|
||||
{
|
||||
$this->file->updateObjectID($this->post->uid, $storyID, 'story');
|
||||
$addedFiles = $this->file->saveUpload($oldStory->type, $storyID, $story->version);
|
||||
$addedFiles = empty($addedFiles) ? '' : join(',', array_keys($addedFiles)) . ',';
|
||||
$storyFiles = $oldStory->files = join(',', array_keys($oldStory->files));
|
||||
foreach($story->deleteFiles as $fileID) $storyFiles = str_replace(",$fileID,", ',', ",$storyFiles,");
|
||||
|
||||
$data = new stdclass();
|
||||
$data->story = $storyID;
|
||||
$data->version = $oldStory->version + 1;
|
||||
$data->version = $story->version;
|
||||
$data->title = $story->title;
|
||||
$data->spec = $story->spec;
|
||||
$data->verify = $story->verify;
|
||||
$data->files = $story->files = $addedFiles . trim($storyFiles, ',');
|
||||
$this->dao->insert(TABLE_STORYSPEC)->data($data)->exec();
|
||||
|
||||
$story = $this->getById($storyID);
|
||||
/* IF is story and has changed, update its relation version to new. */
|
||||
if($oldStory->type == 'story')
|
||||
{
|
||||
$newStory = $this->getById($storyID);
|
||||
$this->dao->update(TABLE_STORY)->set('URChanged')->eq(0)->where('id')->eq($oldStory->id)->exec();
|
||||
$this->updateStoryVersion($story);
|
||||
$this->updateStoryVersion($newStory);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -742,7 +749,7 @@ class storyModel extends model
|
||||
->where('AType')->eq('requirement')
|
||||
->andWhere('BType')->eq('story')
|
||||
->andWhere('relation')->eq('subdivideinto')
|
||||
->andWhere('AID')->eq($story->id)
|
||||
->andWhere('AID')->eq($storyID)
|
||||
->fetchPairs();
|
||||
|
||||
foreach($relations as $relationID) $this->dao->update(TABLE_STORY)->set('URChanged')->eq(1)->where('id')->eq($relationID)->exec();
|
||||
@@ -763,13 +770,8 @@ class storyModel extends model
|
||||
$oldStory->reviewers = implode(',', array_keys($oldStoryReviewers));
|
||||
$story->reviewers = implode(',', $_POST['reviewer']);
|
||||
}
|
||||
|
||||
$deleteFiles = isset($_POST['deleteFiles']) ? $_POST['deleteFiles'] : array();
|
||||
if(!empty($deleteFiles)) $this->file->deleteStoryFile($story->id, $story->version, $deleteFiles);
|
||||
$this->file->updateStoryFileVersion($story->id, $story->version, $deleteFiles);
|
||||
}
|
||||
|
||||
$this->file->updateObjectID($this->post->uid, $storyID, 'story');
|
||||
return common::createChanges($oldStory, $story);
|
||||
}
|
||||
}
|
||||
@@ -784,7 +786,7 @@ class storyModel extends model
|
||||
public function update($storyID)
|
||||
{
|
||||
$now = helper::now();
|
||||
$oldStory = $this->dao->select('*')->from(TABLE_STORY)->where('id')->eq($storyID)->fetch();
|
||||
$oldStory = $this->getById($storyID);
|
||||
if(!empty($_POST['lastEditedDate']) and $oldStory->lastEditedDate != $this->post->lastEditedDate)
|
||||
{
|
||||
dao::$errors[] = $this->lang->error->editedByOther;
|
||||
@@ -797,11 +799,6 @@ class storyModel extends model
|
||||
return false;
|
||||
}
|
||||
|
||||
$oldSpec = $this->dao->select('title,spec,verify')->from(TABLE_STORYSPEC)->where('story')->eq((int)$storyID)->andWhere('version')->eq($oldStory->version)->fetch();
|
||||
$oldStory->title = isset($oldSpec->title) ? $oldSpec->title : '';
|
||||
$oldStory->spec = isset($oldSpec->spec) ? $oldSpec->spec : '';
|
||||
$oldStory->verify = isset($oldSpec->verify) ? $oldSpec->verify : '';
|
||||
|
||||
$story = fixer::input('post')
|
||||
->cleanInt('product,module,pri,duplicateStory')
|
||||
->cleanFloat('estimate')
|
||||
@@ -812,6 +809,7 @@ class storyModel extends model
|
||||
->setDefault('spec', $oldStory->spec)
|
||||
->setDefault('verify', $oldStory->verify)
|
||||
->setDefault('mailto', '')
|
||||
->setDefault('deleteFiles', array())
|
||||
->add('id', $storyID)
|
||||
->add('lastEditedDate', $now)
|
||||
->setDefault('plan,notifyEmail', '')
|
||||
@@ -831,7 +829,7 @@ class storyModel extends model
|
||||
->join('linkStories', ',')
|
||||
->join('linkRequirements', ',')
|
||||
->join('childStories', ',')
|
||||
->remove('files,labels,comment,contactListMenu,stages,reviewer,needNotReview,deleteFiles')
|
||||
->remove('files,labels,comment,contactListMenu,stages,reviewer,needNotReview')
|
||||
->get();
|
||||
|
||||
if($oldStory->type == 'story' and !isset($story->linkStories)) $story->linkStories = '';
|
||||
@@ -877,34 +875,34 @@ class storyModel extends model
|
||||
{
|
||||
$_POST['reviewer'] = isset($_POST['needNotReview']) ? array() : array_filter($_POST['reviewer']);
|
||||
$oldReviewer = $this->getReviewerPairs($storyID, $oldStory->version);
|
||||
if(array_diff($_POST['reviewer'], array_keys($oldReviewer)) or array_diff(array_keys($oldReviewer), $_POST['reviewer']))
|
||||
|
||||
/* Update story reviewer. */
|
||||
$this->dao->delete()->from(TABLE_STORYREVIEW)
|
||||
->where('story')->eq($storyID)
|
||||
->andWhere('version')->eq($oldStory->version)
|
||||
->beginIF($oldStory->status == 'reviewing')->andWhere('reviewer')->notin(implode(',', $_POST['reviewer']))
|
||||
->exec();
|
||||
|
||||
foreach($_POST['reviewer'] as $reviewer)
|
||||
{
|
||||
/* Update story reviewer. */
|
||||
$this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->andWhere('reviewer')->notin(implode(',', $_POST['reviewer']))->exec();
|
||||
foreach($_POST['reviewer'] as $reviewer)
|
||||
{
|
||||
if(in_array($reviewer, array_keys($oldReviewer))) continue;
|
||||
if($oldStory->status == 'reviewing' and in_array($reviewer, array_keys($oldReviewer))) continue;
|
||||
|
||||
$reviewData = new stdclass();
|
||||
$reviewData->story = $storyID;
|
||||
$reviewData->version = $oldStory->version;
|
||||
$reviewData->reviewer = $reviewer;
|
||||
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
|
||||
}
|
||||
|
||||
if($story->status == 'reviewing')
|
||||
{
|
||||
$story->reviewedBy = $oldStory->reviewedBy;
|
||||
$story = $this->updateStoryByReview($storyID, $oldStory, $story);
|
||||
}
|
||||
$reviewData = new stdclass();
|
||||
$reviewData->story = $storyID;
|
||||
$reviewData->version = $oldStory->version;
|
||||
$reviewData->reviewer = $reviewer;
|
||||
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
|
||||
}
|
||||
|
||||
if($oldStory->status == 'reviewing') $story = $this->updateStoryByReview($storyID, $oldStory, $story);
|
||||
if(strpos('draft,changing', $oldStory->status) != false) $story->reviewedBy = '';
|
||||
|
||||
$oldStory->reviewers = implode(',', array_keys($oldReviewer));
|
||||
$story->reviewers = implode(',', array_keys($this->getReviewerPairs($storyID, $oldStory->version)));
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_STORY)
|
||||
->data($story, 'reviewers,spec,verify,finalResult')
|
||||
->data($story, 'reviewers,spec,verify,finalResult,deleteFiles')
|
||||
->autoCheck()
|
||||
->checkIF(isset($story->closedBy), 'closedReason', 'notempty')
|
||||
->checkIF(isset($story->closedReason) and $story->closedReason == 'done', 'stage', 'notempty')
|
||||
@@ -916,12 +914,20 @@ class storyModel extends model
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
if($story->spec != $oldStory->spec or $story->verify != $oldStory->verify or $story->title != $oldStory->title)
|
||||
$this->file->updateObjectID($this->post->uid, $storyID, 'story');
|
||||
$addedFiles = $this->file->saveUpload($oldStory->type, $storyID, $oldStory->version);
|
||||
|
||||
if($story->spec != $oldStory->spec or $story->verify != $oldStory->verify or $story->title != $oldStory->title or !empty($story->deleteFiles) or !empty($addedFiles))
|
||||
{
|
||||
$addedFiles = empty($addedFiles) ? '' : join(',', array_keys($addedFiles)) . ',';
|
||||
$storyFiles = $oldStory->files = join(',', array_keys($oldStory->files));
|
||||
foreach($story->deleteFiles as $fileID) $storyFiles = str_replace(",$fileID,", ',', ",$storyFiles,");
|
||||
|
||||
$data = new stdclass();
|
||||
$data->title = $story->title;
|
||||
$data->spec = $story->spec;
|
||||
$data->verify = $story->verify;
|
||||
$data->files = $story->files = $addedFiles . trim($storyFiles, ',');
|
||||
$this->dao->update(TABLE_STORYSPEC)->data($data)->where('story')->eq((int)$storyID)->andWhere('version')->eq($oldStory->version)->exec();
|
||||
}
|
||||
|
||||
@@ -1040,21 +1046,13 @@ class storyModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
$changes = common::createChanges($oldStory, $story);
|
||||
$deleteFiles = isset($_POST['deleteFiles']) ? $this->file->getPairs($_POST['deleteFiles'], 'title') : array();
|
||||
|
||||
if(isset($_POST['deleteFiles'])) $this->file->deleteStoryFile($storyID, $oldStory->version, $_POST['deleteFiles']);
|
||||
$this->file->updateObjectID($this->post->uid, $storyID, 'story');
|
||||
|
||||
$files = $this->file->saveUpload($oldStory->type, $storyID, ",$oldStory->version,");
|
||||
$changes = common::createChanges($oldStory, $story);
|
||||
if(empty($files) and $this->post->uid != '' and isset($_SESSION['album']['used'][$this->post->uid])) $files = $this->file->getPairs($_SESSION['album']['used'][$this->post->uid]);
|
||||
|
||||
if($this->post->comment != '' or !empty($changes) or !empty($files) or !empty($deleteFiles))
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
$action = (!empty($changes) or !empty($files)) ? 'Edited' : 'Commented';
|
||||
$fileAction = empty($files) ? '' : $this->lang->addFiles . join(',', $files) . "\n" ;
|
||||
$fileAction .= empty($deleteFiles) ? '' : $this->lang->deleteFiles . join(',', $deleteFiles) . "\n";
|
||||
$actionID = $this->action->create('story', $storyID, $action, $fileAction . $this->post->comment);
|
||||
$action = !empty($changes) ? 'Edited' : 'Commented';
|
||||
$actionID = $this->action->create('story', $storyID, $action, $this->post->comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
if(isset($story->finalResult)) $this->recordReviewAction($story);
|
||||
@@ -1609,8 +1607,6 @@ class storyModel extends model
|
||||
/* Delete versions that is after this version. */
|
||||
$this->dao->delete()->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWHere('version')->eq($story->version)->exec();
|
||||
$this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($story->version)->exec();
|
||||
|
||||
$this->loadModel('file')->deleteStoryFile($storyID, $story->version);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5620,8 +5616,6 @@ class storyModel extends model
|
||||
/* Delete versions that is after this version. */
|
||||
$this->dao->delete()->from(TABLE_STORYSPEC)->where('story')->eq($story->id)->andWHere('version')->in($oldStory->version)->exec();
|
||||
$this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->in($oldStory->version)->exec();
|
||||
|
||||
$this->file->deleteStoryFile($story->id, $oldStory->version);
|
||||
}
|
||||
|
||||
if($result == 'reject')
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<tr>
|
||||
<th><?php echo $lang->attatch;?></th>
|
||||
<td>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $files, 'fieldset' => 'false', 'object' => $story, 'method' => 'edit'));?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'false', 'object' => $story, 'method' => 'edit'));?>
|
||||
<?php echo $this->fetch('file', 'buildform');?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -85,13 +85,13 @@
|
||||
<?php echo strpos('draft,changing', $story->status) !== false ? html::textarea('verify', htmlSpecialString($story->verify), "rows='5' class='form-control'") : $story->verify;?>
|
||||
</div>
|
||||
</div>
|
||||
<?php $showFile = (strpos('draft,changing', $story->status) === false and empty($files)) ? false : true;?>
|
||||
<?php $showFile = (strpos('draft,changing', $story->status) === false and empty($story->files)) ? false : true;?>
|
||||
<?php if($showFile):?>
|
||||
<div class='detail'>
|
||||
<div class='detail-title'><?php echo $lang->attatch;?></div>
|
||||
<div class='form-group'>
|
||||
<?php $canChangeFile = strpos('draft,changing', $story->status) !== false ? true : false;?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $files, 'fieldset' => 'false', 'object' => $story, 'method' => 'edit', 'showDelete' => $canChangeFile));?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'false', 'object' => $story, 'method' => 'edit', 'showDelete' => $canChangeFile));?>
|
||||
<?php echo $canChangeFile ? $this->fetch('file', 'buildform') : '';?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -537,20 +537,16 @@ class task extends control
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = array();
|
||||
$files = array();
|
||||
if($comment == false)
|
||||
{
|
||||
$changes = $this->task->update($taskID);
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
$files = $this->loadModel('file')->saveUpload('task', $taskID);
|
||||
if(empty($files) and $this->post->uid != '' and isset($_SESSION['album']['used'][$this->post->uid])) $files = $this->file->getPairs($_SESSION['album']['used'][$this->post->uid]);
|
||||
}
|
||||
|
||||
if($this->post->comment != '' or !empty($changes) or !empty($files))
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
$action = (!empty($changes) or !empty($files)) ? 'Edited' : 'Commented';
|
||||
$fileAction = !empty($files) ? $this->lang->addFiles . join(',', $files) . "\n" : '';
|
||||
$actionID = $this->action->create('task', $taskID, $action, $fileAction . $this->post->comment);
|
||||
$action = !empty($changes) ? 'Edited' : 'Commented';
|
||||
$actionID = $this->action->create('task', $taskID, $action, $this->post->comment);
|
||||
if(!empty($changes)) $this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,3 +13,4 @@
|
||||
.icon-calendar {color: rgb(22, 168, 248)}
|
||||
#recordForm .table>thead>tr>th{ border: none}
|
||||
.main-header {border-bottom: none !important}
|
||||
.body-modal .main-header>h2 { max-width: 70% !important;}
|
||||
|
||||
@@ -19,3 +19,6 @@
|
||||
.c-actions {width: 175px;}
|
||||
|
||||
[lang^='de'] #mainContent .main-actions .btn-toolbar .btn {padding-left: 3px; padding-right: 3px;}
|
||||
|
||||
#childrenTable .c-id {width: 60px;}
|
||||
#childrenTable .c-lblPri {width: 50px;}
|
||||
|
||||
@@ -14,7 +14,7 @@ $('#confirmButton').click(function()
|
||||
var $tr = $(this).closest('tr');
|
||||
var account = $(this).find('option:selected').text();
|
||||
|
||||
estimate = parseFloat($tr.find('[name^=teamEstimate]').val());
|
||||
var estimate = parseFloat($tr.find('[name^=teamEstimate]').val());
|
||||
if(!isNaN(estimate)) totalEstimate += estimate;
|
||||
if(isNaN(estimate) || estimate == 0)
|
||||
{
|
||||
@@ -23,12 +23,13 @@ $('#confirmButton').click(function()
|
||||
return false;
|
||||
}
|
||||
|
||||
consumed = parseFloat($tr.find('[name^=teamConsumed]').val());
|
||||
var consumed = parseFloat($tr.find('[name^=teamConsumed]').val());
|
||||
if(!isNaN(consumed)) totalConsumed += consumed;
|
||||
|
||||
left = parseFloat($tr.find('[name^=teamLeft]').val());
|
||||
var $left = $tr.find('[name^=teamLeft]');
|
||||
var left = parseFloat($left.val());
|
||||
if(!isNaN(left)) totalLeft += left;
|
||||
if(!$tr.hasClass('member-done') && (isNaN(left) || left == 0))
|
||||
if(!$left.prop('readonly') && (isNaN(left) || left == 0))
|
||||
{
|
||||
bootbox.alert(account + ' ' + leftNotEmpty);
|
||||
error = true;
|
||||
|
||||
@@ -97,7 +97,7 @@ $('#confirmButton').click(function()
|
||||
var $tr = $(this).closest('tr');
|
||||
var account = $(this).find('option:selected').text();
|
||||
|
||||
estimate = parseFloat($tr.find('[name^=teamEstimate]').val());
|
||||
var estimate = parseFloat($tr.find('[name^=teamEstimate]').val());
|
||||
if(!isNaN(estimate)) totalEstimate += estimate;
|
||||
if(isNaN(estimate) || estimate == 0)
|
||||
{
|
||||
@@ -106,12 +106,13 @@ $('#confirmButton').click(function()
|
||||
return false;
|
||||
}
|
||||
|
||||
consumed = parseFloat($tr.find('[name^=teamConsumed]').val());
|
||||
var consumed = parseFloat($tr.find('[name^=teamConsumed]').val());
|
||||
if(!isNaN(consumed)) totalConsumed += consumed;
|
||||
|
||||
left = parseFloat($tr.find('[name^=teamLeft]').val());
|
||||
var $left = $tr.find('[name^=teamLeft]');
|
||||
var left = parseFloat($left.val());
|
||||
if(!isNaN(left)) totalLeft += left;
|
||||
if(!$tr.hasClass('member-done') && (isNaN(left) || left == 0))
|
||||
if(!$left.prop('readonly') && (isNaN(left) || left == 0))
|
||||
{
|
||||
bootbox.alert(account + ' ' + leftNotEmpty);
|
||||
error = true;
|
||||
|
||||
@@ -47,6 +47,7 @@ $lang->task->exportAction = "Export Task";
|
||||
$lang->task->reportChart = "Bericht Chart";
|
||||
$lang->task->fromBug = 'Von Bug';
|
||||
$lang->task->case = 'Fall';
|
||||
$lang->task->process = 'Process Task';
|
||||
$lang->task->confirmStoryChange = "Storyäanderung bestätigen";
|
||||
$lang->task->storyChange = "Story Changed";
|
||||
$lang->task->progress = 'Fortschritt';
|
||||
@@ -57,7 +58,7 @@ $lang->task->waitTask = 'Waiting Task';
|
||||
$lang->task->allModule = 'All Module';
|
||||
$lang->task->replace = 'Replace';
|
||||
$lang->task->myEffort = 'My Effort';
|
||||
$lang->task->allEffort = 'All Effort';
|
||||
$lang->task->allEffort = 'Team Effort';
|
||||
$lang->task->teamOrder = 'Order';
|
||||
|
||||
$lang->task->common = 'Aufgabe';
|
||||
|
||||
@@ -47,6 +47,7 @@ $lang->task->exportAction = "Export Task";
|
||||
$lang->task->reportChart = "Report Chart";
|
||||
$lang->task->fromBug = 'From Bug';
|
||||
$lang->task->case = 'Linked Case';
|
||||
$lang->task->process = 'Process Task';
|
||||
$lang->task->confirmStoryChange = "Confirm Change";
|
||||
$lang->task->storyChange = "Story Changed";
|
||||
$lang->task->progress = 'Progress';
|
||||
@@ -57,7 +58,7 @@ $lang->task->waitTask = 'Waiting Task';
|
||||
$lang->task->allModule = 'All Module';
|
||||
$lang->task->replace = 'Replace';
|
||||
$lang->task->myEffort = 'My Effort';
|
||||
$lang->task->allEffort = 'All Effort';
|
||||
$lang->task->allEffort = 'Team Effort';
|
||||
$lang->task->teamOrder = 'Order';
|
||||
|
||||
$lang->task->common = 'Task';
|
||||
|
||||
@@ -47,6 +47,7 @@ $lang->task->exportAction = "Exporter Tâche";
|
||||
$lang->task->reportChart = "Rapport Graphique";
|
||||
$lang->task->fromBug = 'à partir Bug';
|
||||
$lang->task->case = 'Associée CasTest';
|
||||
$lang->task->process = 'Process Task';
|
||||
$lang->task->confirmStoryChange = "Confirmer Changement";
|
||||
$lang->task->storyChange = "Story Changée";
|
||||
$lang->task->progress = 'Progression';
|
||||
@@ -57,7 +58,7 @@ $lang->task->waitTask = 'Tâche en attente';
|
||||
$lang->task->allModule = 'Tous Modules';
|
||||
$lang->task->replace = 'Replace';
|
||||
$lang->task->myEffort = 'My Effort';
|
||||
$lang->task->allEffort = 'All Effort';
|
||||
$lang->task->allEffort = 'Team Effort';
|
||||
$lang->task->teamOrder = 'Order';
|
||||
|
||||
$lang->task->common = 'Tâche';
|
||||
|
||||
@@ -47,6 +47,7 @@ $lang->task->exportAction = "导出任务";
|
||||
$lang->task->reportChart = "报表统计";
|
||||
$lang->task->fromBug = '来源Bug';
|
||||
$lang->task->case = '相关用例';
|
||||
$lang->task->process = '处理任务';
|
||||
$lang->task->confirmStoryChange = "确认{$lang->SRCommon}变动";
|
||||
$lang->task->storyChange = "{$lang->SRCommon}变更";
|
||||
$lang->task->progress = '进度';
|
||||
@@ -57,7 +58,7 @@ $lang->task->waitTask = '未开始的任务';
|
||||
$lang->task->allModule = '所有模块';
|
||||
$lang->task->replace = '替换';
|
||||
$lang->task->myEffort = '我的日志';
|
||||
$lang->task->allEffort = '所有日志';
|
||||
$lang->task->allEffort = '团队日志';
|
||||
$lang->task->teamOrder = '工序';
|
||||
|
||||
$lang->task->common = '任务';
|
||||
@@ -166,7 +167,7 @@ $lang->task->recordEstimateAction = '添加工时';
|
||||
|
||||
$lang->task->ditto = '同上';
|
||||
$lang->task->dittoNotice = "该任务与上一任务不属于同一%s!";
|
||||
$lang->task->selectTestStory = "选择测试{$lang->SRCommon}";
|
||||
$lang->task->selectTestStory = "选择{$lang->SRCommon}";
|
||||
$lang->task->selectAllUser = '全部';
|
||||
$lang->task->noStory = "无{$lang->SRCommon}";
|
||||
$lang->task->noAssigned = '未指派';
|
||||
|
||||
@@ -152,7 +152,7 @@ $lang->task->recordEstimateAction = '添加工時';
|
||||
|
||||
$lang->task->ditto = '同上';
|
||||
$lang->task->dittoNotice = "該任務與上一任務不屬於同一%s!";
|
||||
$lang->task->selectTestStory = "選擇測試需求";
|
||||
$lang->task->selectTestStory = "選擇{$lang->SRCommon}";
|
||||
$lang->task->selectAllUser = '全部';
|
||||
$lang->task->noStory = "無{$lang->SRCommon}";
|
||||
$lang->task->noAssigned = '未指派';
|
||||
|
||||
@@ -1075,6 +1075,7 @@ class taskModel extends model
|
||||
->setDefault('story, estimate, left, consumed', 0)
|
||||
->setDefault('realStarted', '0000-00-00 00:00:00')
|
||||
->setDefault('mailto', '')
|
||||
->setDefault('deleteFiles', array())
|
||||
->setIF(is_numeric($this->post->estimate), 'estimate', (float)$this->post->estimate)
|
||||
->setIF(is_numeric($this->post->consumed), 'consumed', (float)$this->post->consumed)
|
||||
->setIF(is_numeric($this->post->left), 'left', (float)$this->post->left)
|
||||
@@ -1158,7 +1159,7 @@ class taskModel extends model
|
||||
|
||||
$requiredFields = trim($requiredFields, ',');
|
||||
|
||||
$this->dao->update(TABLE_TASK)->data($task)
|
||||
$this->dao->update(TABLE_TASK)->data($task, 'deleteFiles')
|
||||
->autoCheck()
|
||||
->batchCheckIF($task->status != 'cancel', $requiredFields, 'notempty')
|
||||
->checkIF(!helper::isZeroDate($task->deadline), 'deadline', 'ge', $task->estStarted)
|
||||
@@ -1247,12 +1248,10 @@ class taskModel extends model
|
||||
if(!empty($changes)) $this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
}
|
||||
$this->file->updateObjectID($this->post->uid, $taskID, 'task');
|
||||
|
||||
unset($oldTask->parent);
|
||||
unset($task->parent);
|
||||
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $oldTask->feedback) $this->loadModel('feedback')->updateStatus('task', $oldTask->feedback, $task->status, $oldTask->status);
|
||||
|
||||
if(isset($oldTask->team))
|
||||
@@ -1269,6 +1268,7 @@ class taskModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
$this->file->processFile4Object('task', $oldTask, $task);
|
||||
return common::createChanges($oldTask, $task);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,10 @@ foreach(explode(',', $config->task->edit->requiredFields) as $field)
|
||||
<?php $this->printExtendFields($task, 'div', 'position=left');?>
|
||||
<div class='detail'>
|
||||
<div class='detail-title'><?php echo $lang->files;?></div>
|
||||
<div class='detail-content'><?php echo $this->fetch('file', 'buildform');?></div>
|
||||
<div class='detail-content'>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $task->files, 'fieldset' => 'false', 'object' => $task, 'method' => 'edit'));?>
|
||||
<?php echo $this->fetch('file', 'buildform');?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='detail text-center form-actions'>
|
||||
<?php echo html::hidden('lastEditedDate', $task->lastEditedDate);?>
|
||||
|
||||
@@ -18,7 +18,11 @@ foreach($efforts as $effort)
|
||||
$account = $effort->account;
|
||||
$allEfforts[$order][] = $effort;
|
||||
$recorders[$order][$account] = $account;
|
||||
if($app->user->account == $account) $myOrders[$order] = $order;
|
||||
if($app->user->account == $account)
|
||||
{
|
||||
if(!isset($myOrders[$order])) $myOrders[$order] = 0;
|
||||
$myOrders[$order] += 1;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div id='linearefforts'>
|
||||
@@ -30,25 +34,28 @@ foreach($efforts as $effort)
|
||||
</ul>
|
||||
<div class='tab-content'>
|
||||
<div class='tab-pane active' id='legendMyEffort'>
|
||||
<?php foreach($myOrders as $order):?>
|
||||
<div class='caption'>
|
||||
<span class='label label-badge'><?php echo $order + 1;?></span>
|
||||
<span class='account'><?php echo zget($users, $app->user->account);?></span>
|
||||
</div>
|
||||
<table class='table table-bordered table-fixed table-recorded'>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th class="w-60px"> <?php echo $lang->task->teamOrder;?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->date;?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->recordedBy;?></th>
|
||||
<th><?php echo $lang->comment;?></th>
|
||||
<th><?php echo $lang->task->work;?></th>
|
||||
<th class="thWidth"><?php echo $lang->task->consumed;?></th>
|
||||
<th class="thWidth"><?php echo $lang->task->left;?></th>
|
||||
<th class='c-actions-2'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($myOrders as $order => $count):?>
|
||||
<?php $showOrder = false;?>
|
||||
<?php foreach($allEfforts[$order] as $effort):?>
|
||||
<?php if($effort->account != $this->app->user->account) continue;?>
|
||||
<tr class="text-center">
|
||||
<?php if(!$showOrder):?>
|
||||
<td rowspan='<?php echo $count;?>'><?php echo $order + 1;?></td>
|
||||
<?php $showOrder = true;?>
|
||||
<?php endif;?>
|
||||
<td><?php echo $effort->date;?></td>
|
||||
<td><?php echo zget($users, $effort->account);?></td>
|
||||
<td class="text-left" title="<?php echo $effort->work;?>"><?php echo $effort->work;?></td>
|
||||
@@ -63,31 +70,33 @@ foreach($efforts as $effort)
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
<div class='tab-pane' id='legendAllEffort'>
|
||||
<?php endif;?>
|
||||
<?php foreach($recorders as $order => $accounts):?>
|
||||
<div class='caption'>
|
||||
<span class='label label-badge'><?php echo $order + 1;?></span>
|
||||
<span class='account'><?php foreach($accounts as $account) echo zget($users, $account) . ' ';?></span>
|
||||
</div>
|
||||
<table class='table table-bordered table-fixed table-recorded'>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th class="w-60px"> <?php echo $lang->task->teamOrder;?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->date;?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->recordedBy;?></th>
|
||||
<th><?php echo $lang->comment;?></th>
|
||||
<th><?php echo $lang->task->work;?></th>
|
||||
<th class="thWidth"><?php echo $lang->task->consumed;?></th>
|
||||
<th class="thWidth"><?php echo $lang->task->left;?></th>
|
||||
<th class='c-actions-2'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($recorders as $order => $accounts):?>
|
||||
<?php $showOrder = false;?>
|
||||
<?php foreach($allEfforts[$order] as $effort):?>
|
||||
<tr class="text-center">
|
||||
<?php if(!$showOrder):?>
|
||||
<td rowspan='<?php echo count($allEfforts[$order]);?>'><?php echo $order + 1;?></td>
|
||||
<?php $showOrder = true;?>
|
||||
<?php endif;?>
|
||||
<td><?php echo $effort->date;?></td>
|
||||
<td><?php echo zget($users, $effort->account);?></td>
|
||||
<td class="text-left" title="<?php echo $effort->work;?>"><?php echo $effort->work;?></td>
|
||||
@@ -102,9 +111,9 @@ foreach($efforts as $effort)
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endforeach;?>
|
||||
<?php if($myOrders):?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -74,10 +74,10 @@
|
||||
<div class="alert with-icon">
|
||||
<i class="icon-exclamation-sign"></i>
|
||||
<div class="content">
|
||||
<?php if($task->assignedTo != $app->user->account and $task->mode == 'linear'):?>
|
||||
<p><?php echo sprintf($lang->task->deniedNotice, '<strong>' . $task->assignedToRealName . '</strong>', $lang->task->logEfforts);?></p>
|
||||
<?php elseif(!isset($task->members[$app->user->account])):?>
|
||||
<?php if(!isset($task->members[$app->user->account])):?>
|
||||
<p><?php echo sprintf($lang->task->deniedNotice, '<strong>' . $lang->task->teamMember . '</strong>', $lang->task->logEfforts);?></p>
|
||||
<?php elseif($task->assignedTo != $app->user->account and $task->mode == 'linear'):?>
|
||||
<p><?php echo sprintf($lang->task->deniedNotice, '<strong>' . $task->assignedToRealName . '</strong>', $lang->task->logEfforts);?></p>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,7 +91,7 @@
|
||||
$readonly = ' readonly';
|
||||
$left = 0;
|
||||
$reverseOrders = array_reverse($myOrders, true);
|
||||
foreach($reverseOrders as $order) $reverseOrders[$order] = $order + 1;
|
||||
foreach($reverseOrders as $order => $count) $reverseOrders[$order] = $order + 1;
|
||||
}
|
||||
?>
|
||||
<table class='table table-form table-fixed table-record'>
|
||||
@@ -107,7 +107,8 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php for($i = 1; $i <= 3; $i++):?>
|
||||
<?php $initNum = !empty($efforts) ? 3 : 5;?>
|
||||
<?php for($i = 1; $i <= $initNum; $i++):?>
|
||||
<tr class="text-center">
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php
|
||||
echo $this->fetch('file', 'printFiles', array('files' => $task->files, 'fieldset' => 'true', 'object' => $task));
|
||||
echo $this->fetch('file', 'printFiles', array('files' => $task->files, 'fieldset' => 'true', 'object' => $task, 'method' => 'view', 'showDelete' => false));
|
||||
|
||||
$canBeChanged = common::canBeChanged('task', $task);
|
||||
if($canBeChanged) $actionFormLink = $this->createLink('action', 'comment', "objectType=task&objectID=$task->id");
|
||||
|
||||
@@ -860,20 +860,16 @@ class testcase extends control
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$changes = array();
|
||||
$files = array();
|
||||
if($comment == false or $comment == 'false')
|
||||
{
|
||||
$changes = $this->testcase->update($caseID, $testtasks);
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
$files = $this->loadModel('file')->saveUpload('testcase', $caseID);
|
||||
}
|
||||
if($this->post->comment != '' or !empty($changes) or !empty($files))
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$action = (!empty($changes) or !empty($files)) ? 'Edited' : 'Commented';
|
||||
$fileAction = '';
|
||||
if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n";
|
||||
$actionID = $this->action->create('case', $caseID, $action, $fileAction . $this->post->comment);
|
||||
$action = !empty($changes) ? 'Edited' : 'Commented';
|
||||
$actionID = $this->action->create('case', $caseID, $action, $this->post->comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
|
||||
@@ -802,6 +802,7 @@ class testcaseModel extends model
|
||||
->add('lastEditedDate', $now)
|
||||
->setDefault('story,branch', 0)
|
||||
->setDefault('stage', '')
|
||||
->setDefault('deleteFiles', array())
|
||||
->join('stage', ',')
|
||||
->join('linkCase', ',')
|
||||
->setForce('status', $status)
|
||||
@@ -820,7 +821,7 @@ class testcaseModel extends model
|
||||
$requiredFields = implode(',', $requiredFieldsArr);
|
||||
}
|
||||
$case = $this->loadModel('file')->processImgURL($case, $this->config->testcase->editor->edit['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_CASE)->data($case)->autoCheck()->batchCheck($requiredFields, 'notempty')->checkFlow()->where('id')->eq((int)$caseID)->exec();
|
||||
$this->dao->update(TABLE_CASE)->data($case, 'deleteFiles')->autoCheck()->batchCheck($requiredFields, 'notempty')->checkFlow()->where('id')->eq((int)$caseID)->exec();
|
||||
if(!$this->dao->isError())
|
||||
{
|
||||
$this->updateCase2Project($oldCase, $case, $caseID);
|
||||
@@ -927,6 +928,8 @@ class testcaseModel extends model
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->file->processFile4Object('testcase', $oldCase, $case);
|
||||
return common::createChanges($oldCase, $case);
|
||||
}
|
||||
}
|
||||
@@ -2390,7 +2393,6 @@ class testcaseModel extends model
|
||||
|
||||
if(!empty($_POST['title']) and $case->title != $this->post->title) $stepChanged = true;
|
||||
if(!empty($_POST['precondition']) and $case->precondition != $this->post->precondition) $stepChanged = true;
|
||||
if(!empty($_POST['labels'][0])) $stepChanged = true;
|
||||
|
||||
return array($stepChanged, $status);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,10 @@
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="detail-title"><?php echo $lang->files;?></div>
|
||||
<div class='detail-content'><?php echo $this->fetch('file', 'buildform');?></div>
|
||||
<div class='detail-content'>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $case->files, 'fieldset' => 'false', 'object' => $case, 'method' => 'edit'));?>
|
||||
<?php echo $this->fetch('file', 'buildform');?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='text-center detail form-actions'>
|
||||
<?php echo html::hidden('lastEditedDate', $case->lastEditedDate);?>
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
<div class="detail-content article-content"><?php echo nl2br(htmlSpecialString($case->xml));?></div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $case->files, 'fieldset' => 'true', 'object' => $case));?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $case->files, 'fieldset' => 'true', 'object' => $case, 'method' => 'view', 'showDelete' => false));?>
|
||||
</div>
|
||||
<?php $this->printExtendFields($case, 'div', "position=left&inForm=0&inCell=1");?>
|
||||
<div class='main-actions'>
|
||||
|
||||
@@ -49,7 +49,7 @@ $lang->testreport->legendCase = 'CasTests associés';
|
||||
$lang->testreport->legendLegacyBugs = 'Bugs Restants';
|
||||
$lang->testreport->legendReport = 'Rapport';
|
||||
$lang->testreport->legendComment = 'Résumé';
|
||||
$lang->testreport->legendMore = 'Plus...';
|
||||
$lang->testreport->legendMore = 'Plus';
|
||||
$lang->testreport->date = 'Date';
|
||||
|
||||
$lang->testreport->bugSeverityGroups = 'Distribution Sévérité de Bug';
|
||||
|
||||
@@ -750,11 +750,12 @@ class testtaskModel extends model
|
||||
*/
|
||||
public function update($taskID)
|
||||
{
|
||||
$oldTask = $this->dao->select("*")->from(TABLE_TESTTASK)->where('id')->eq((int)$taskID)->fetch();
|
||||
$oldTask = $this->getById($taskID);
|
||||
$task = fixer::input('post')
|
||||
->add('id', $taskID)
|
||||
->setDefault('type', '')
|
||||
->setDefault('mailto', '')
|
||||
->setDefault('deleteFiles', array())
|
||||
->stripTags($this->config->testtask->editor->edit['id'], $this->config->allowedTags)
|
||||
->join('mailto', ',')
|
||||
->join('type', ',')
|
||||
@@ -762,7 +763,7 @@ class testtaskModel extends model
|
||||
->get();
|
||||
$task = $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->edit['id'], $this->post->uid);
|
||||
|
||||
$this->dao->update(TABLE_TESTTASK)->data($task)
|
||||
$this->dao->update(TABLE_TESTTASK)->data($task, 'deleteFiles')
|
||||
->autoCheck()
|
||||
->batchcheck($this->config->testtask->edit->requiredFields, 'notempty')
|
||||
->checkIF($task->end != '', 'end', 'ge', $task->begin)
|
||||
@@ -772,8 +773,7 @@ class testtaskModel extends model
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->file->updateObjectID($this->post->uid, $taskID, 'testtask');
|
||||
$this->file->saveUpload('testtask', $taskID);
|
||||
$this->file->processFile4Object('testtask', $oldTask, $task);
|
||||
return common::createChanges($oldTask, $task);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,10 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->files;?></th>
|
||||
<td colspan='3'><?php echo $this->fetch('file', 'buildform');?></td>
|
||||
<td colspan='3'>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $task->files, 'fieldset' => 'false', 'object' => $task, 'method' => 'edit'));?>
|
||||
<?php echo $this->fetch('file', 'buildform');?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->testtask->mailto;?></th>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<div class="detail-title"><?php echo $lang->testtask->desc;?></div>
|
||||
<div class="detail-content article-content"><?php echo !empty($task->desc) ? $task->desc : $lang->noData;?></div>
|
||||
</div>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $task->files, 'fieldset' => 'true', 'object' => $task));?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $task->files, 'fieldset' => 'true', 'object' => $task, 'method' => 'view', 'showDelete' => false));?>
|
||||
<?php if($task->report):?>
|
||||
<div class="detail">
|
||||
<div class="detail-title"><?php echo $lang->testtask->report;?></div>
|
||||
|
||||
@@ -24,6 +24,7 @@ $config->upgrade->maxVersion['max3_4'] = '17_3';
|
||||
$config->upgrade->maxVersion['max3_5'] = '17_4';
|
||||
$config->upgrade->maxVersion['max3_6'] = '17_5';
|
||||
$config->upgrade->maxVersion['max3_6_1'] = '17_6';
|
||||
$config->upgrade->maxVersion['max3_6_2'] = '17_6_1';
|
||||
|
||||
$config->upgrade->bizVersion = array();
|
||||
$config->upgrade->bizVersion['biz1_0'] = '9_5_1';
|
||||
@@ -86,6 +87,7 @@ $config->upgrade->bizVersion['biz7_3'] = '17_3';
|
||||
$config->upgrade->bizVersion['biz7_4'] = '17_4';
|
||||
$config->upgrade->bizVersion['biz7_5'] = '17_5';
|
||||
$config->upgrade->bizVersion['biz7_6'] = '17_6';
|
||||
$config->upgrade->bizVersion['biz7_6_1'] = '17_6_1';
|
||||
|
||||
$config->upgrade->proVersion = array();
|
||||
$config->upgrade->proVersion['pro1_0'] = '3_1';
|
||||
|
||||
@@ -165,6 +165,7 @@ $lang->upgrade->fromVersions['17_3'] = '17.3';
|
||||
$lang->upgrade->fromVersions['17_4'] = '17.4';
|
||||
$lang->upgrade->fromVersions['17_5'] = '17.5';
|
||||
$lang->upgrade->fromVersions['17_6'] = '17.6';
|
||||
$lang->upgrade->fromVersions['17_6_1'] = '17.6.1';
|
||||
|
||||
global $config;
|
||||
/* Lite. */
|
||||
@@ -334,6 +335,7 @@ $lang->upgrade->fromVersions['biz7_3'] = 'Biz7.3';
|
||||
$lang->upgrade->fromVersions['biz7_4'] = 'Biz7.4';
|
||||
$lang->upgrade->fromVersions['biz7_5'] = 'Biz7.5';
|
||||
$lang->upgrade->fromVersions['biz7_6'] = 'Biz7.6';
|
||||
$lang->upgrade->fromVersions['biz7_6_1'] = 'Biz7.6.1';
|
||||
|
||||
/* Max. */
|
||||
$lang->upgrade->fromVersions['max2_0_beta4'] = 'Max2.0.beta4';
|
||||
@@ -359,3 +361,4 @@ $lang->upgrade->fromVersions['max3_3'] = 'Max3.3';
|
||||
$lang->upgrade->fromVersions['max3_4'] = 'Max3.4';
|
||||
$lang->upgrade->fromVersions['max3_5'] = 'Max3.5';
|
||||
$lang->upgrade->fromVersions['max3_6'] = 'Max3.6';
|
||||
$lang->upgrade->fromVersions['max3_6_1'] = 'Max3.6.1';
|
||||
|
||||
+185
-17
@@ -552,6 +552,10 @@ class upgradeModel extends model
|
||||
$this->updateStoryFile();
|
||||
$this->convertTaskteam();
|
||||
$this->convertEstToEffort();
|
||||
$this->fixWeeklyReport();
|
||||
$this->xuanSetOwnedByForGroups();
|
||||
$this->xuanRecoverCreatedDates();
|
||||
$this->xuanSetPartitionedMessageIndex();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1018,6 +1022,8 @@ class upgradeModel extends model
|
||||
$confirmContent .= file_get_contents($this->getUpgradeFile('17.4'));
|
||||
case '17_5':
|
||||
$confirmContent .= file_get_contents($this->getUpgradeFile('17.5'));
|
||||
case '17_6':
|
||||
$confirmContent .= file_get_contents($this->getUpgradeFile('17.6'));
|
||||
}
|
||||
|
||||
return $confirmContent;
|
||||
@@ -7220,27 +7226,18 @@ class upgradeModel extends model
|
||||
{
|
||||
$storyFileList = $this->dao->select('*')->from(TABLE_FILE)->where('objectType')->in('story,requirement')->andWhere('extra')->ne('editor')->fetchAll('id');
|
||||
|
||||
/* Get story version. */
|
||||
$storyIDList = array();
|
||||
foreach($storyFileList as $file) $storyIDList[$file->objectID] = $file->objectID;
|
||||
$storyVersionList = $this->dao->select('id,version')->from(TABLE_STORY)->where('id')->in($storyIDList)->fetchPairs();
|
||||
|
||||
$storyFiles = array();
|
||||
foreach($storyFileList as $file)
|
||||
{
|
||||
if(!is_numeric($file->extra)) continue;
|
||||
|
||||
$fileExtra = '';
|
||||
$storyVersion = $storyVersionList[$file->objectID];
|
||||
if($file->extra != $storyVersion)
|
||||
{
|
||||
for($i = $file->extra; $i <= $storyVersion; $i ++) $fileExtra .= ",$i";
|
||||
$fileExtra .= ',';
|
||||
}
|
||||
if(empty($fileExtra)) $fileExtra = ",$file->extra,";
|
||||
if(!isset($storyFiles[$file->objectID])) $storyFiles[$file->objectID] = '';
|
||||
|
||||
$this->dao->update(TABLE_FILE)->set('extra')->eq($fileExtra)->where('id')->eq($file->id)->exec();
|
||||
$storyFiles[$file->objectID] .= "$file->id,";
|
||||
}
|
||||
|
||||
foreach($storyFiles as $storyID => $files) $this->dao->update(TABLE_STORYSPEC)->set('files')->eq($files)->where('story')->eq($storyID)->exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7252,7 +7249,6 @@ class upgradeModel extends model
|
||||
*/
|
||||
public function processFeedbackModule()
|
||||
{
|
||||
|
||||
$products = $this->dao->select('id, name')->from(TABLE_PRODUCT)->fetchAll();
|
||||
$modules = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('feedback')->andWhere('root')->eq(0)->fetchAll('id');
|
||||
$feedbacks = $this->dao->select('*')->from(TABLE_FEEDBACK)->fetchAll();
|
||||
@@ -7318,7 +7314,7 @@ class upgradeModel extends model
|
||||
|
||||
$this->dao->insert(TABLE_TASKTEAM)->data($oldTeam)->exec();
|
||||
|
||||
$this->dao->update(TABLE_TASKESTIMATE)->set('`order`')->eq($order)->where('task')->($oldTeam->task)->andWhere('account')->eq($oldTeam->account)->exec();
|
||||
$this->dao->update(TABLE_TASKESTIMATE)->set('`order`')->eq($order)->where('task')->eq($oldTeam->task)->andWhere('account')->eq($oldTeam->account)->exec();
|
||||
$this->dao->update(TABLE_EFFORT)->set('`order`')->eq($order)->where('objectType')->eq('task')->andWhere('objectID')->eq($oldTeam->task)->andWhere('account')->eq($oldTeam->account)->exec();
|
||||
$order ++;
|
||||
}
|
||||
@@ -7337,6 +7333,7 @@ class upgradeModel extends model
|
||||
{
|
||||
$estimates = $this->dao->select('*')->from(TABLE_TASKESTIMATE)->orderBy('id')->fetchAll();
|
||||
|
||||
$this->app->loadLang('task');
|
||||
$this->loadModel('action');
|
||||
foreach($estimates as $estimate)
|
||||
{
|
||||
@@ -7348,7 +7345,7 @@ class upgradeModel extends model
|
||||
$effort->product = $relation['product'];
|
||||
$effort->project = (int)$relation['project'];
|
||||
$effort->account = $estimate->account;
|
||||
$effort->work = empty($estimate->work) ? $this->lang->effort->handleTask : $estimate->work;
|
||||
$effort->work = empty($estimate->work) ? $this->lang->task->process : $estimate->work;
|
||||
$effort->date = $estimate->date;
|
||||
$effort->left = $estimate->left;
|
||||
$effort->consumed = $estimate->consumed;
|
||||
@@ -7360,4 +7357,175 @@ class upgradeModel extends model
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Xuan: Set ownedBy for group chats without it.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function xuanSetOwnedByForGroups()
|
||||
{
|
||||
$this->dao->update(TABLE_IM_CHAT)->set('ownedBy = createdBy')->where('ownedBy')->eq('')->exec();
|
||||
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Xuan: Recover created date for chats.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function xuanRecoverCreatedDates()
|
||||
{
|
||||
$chats = $this->dao->select('gid, id')->from(TABLE_IM_CHAT)
|
||||
->where('createdDate')->eq('0000-00-00 00:00:00')
|
||||
->fetchPairs('gid');
|
||||
if(empty($chats)) return true;
|
||||
|
||||
$createdDateData = array();
|
||||
|
||||
/* Try query earliest message date indexed. */
|
||||
$indexedMinDates = $this->dao->select('gid, MIN(startDate)')->from(TABLE_IM_CHAT_MESSAGE_INDEX)
|
||||
->where('gid')->in(array_keys($chats))
|
||||
->groupBy('gid')
|
||||
->fetchPairs('gid');
|
||||
|
||||
/* Then try query earliest message date non-indexed from master table. */
|
||||
$queryChats = array_diff(array_keys($chats), array_keys($indexedMinDates));
|
||||
$minDates = $this->dao->select('cgid, MIN(date)')->from(TABLE_IM_MESSAGE)
|
||||
->where('cgid')->in($queryChats)
|
||||
->groupBy('cgid')
|
||||
->fetchPairs('cgid');
|
||||
|
||||
$knownMinDates = array_merge($indexedMinDates, $minDates);
|
||||
|
||||
$remainingChats = $chats;
|
||||
foreach($chats as $cgid => $cid)
|
||||
{
|
||||
if(isset($knownMinDates[$cgid]))
|
||||
{
|
||||
$createdDateData[$cid] = $knownMinDates[$cgid];
|
||||
unset($remainingChats[$cgid]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Use other dates for chats without messages. */
|
||||
$chatDates = $this->dao->select('id, gid, editedDate, lastActiveTime, dismissDate')->from(TABLE_IM_CHAT)
|
||||
->where('gid')->in(array_keys($remainingChats))
|
||||
->fetchAll('gid');
|
||||
$chatDates = array_map(function($chatDate)
|
||||
{
|
||||
$dates = array_filter(array($chatDate->editedDate, $chatDate->lastActiveTime, $chatDate->dismissDate), function($date)
|
||||
{
|
||||
return $date != '0000-00-00 00:00:00';
|
||||
});
|
||||
$minDate = min($dates);
|
||||
return $minDate;
|
||||
}, $chatDates);
|
||||
|
||||
$knownMinDates = array_merge($knownMinDates, $chatDates);
|
||||
if(empty($knownMinDates)) return true;
|
||||
|
||||
$queryData = array();
|
||||
foreach($knownMinDates as $gid => $date) $queryData[] = "WHEN {$chats[$gid]} THEN '{$date}'";
|
||||
|
||||
if(empty($queryData)) return true;
|
||||
|
||||
$query = "UPDATE " . TABLE_IM_CHAT . " SET `createdDate` = (CASE `id` " . join(' ', $queryData) . " END) WHERE `id` IN(" . join(",", array_values($chats)) . ");";
|
||||
$this->dao->query($query);
|
||||
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Xuan: Set index range for chats in chat partition index table.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function xuanSetPartitionedMessageIndex()
|
||||
{
|
||||
ini_set('memory_limit', '1024M');
|
||||
set_time_limit(0);
|
||||
|
||||
/* Fetch chat and message partition table associations with message range. */
|
||||
$chatTableData = $this->dao->select('gid, tableName, start, end')->from(TABLE_IM_CHAT_MESSAGE_INDEX)
|
||||
->where('startIndex')->eq(0)
|
||||
->orWhere('endIndex')->eq(0)
|
||||
->orderBy('id_asc')
|
||||
->fetchAll();
|
||||
if(empty($chatTableData)) return true;
|
||||
|
||||
/* Sort ranges by table. */
|
||||
$tableRanges = array();
|
||||
foreach($chatTableData as $chatTable)
|
||||
{
|
||||
if(isset($tableRanges[$chatTable->tableName]))
|
||||
{
|
||||
$tableRanges[$chatTable->tableName]->start[] = $chatTable->start;
|
||||
$tableRanges[$chatTable->tableName]->end[] = $chatTable->end;
|
||||
continue;
|
||||
}
|
||||
$tableRanges[$chatTable->tableName] = (object)array('start' => array($chatTable->start), 'end' => array($chatTable->end));
|
||||
}
|
||||
|
||||
/* Query corresponding message indice. */
|
||||
foreach($tableRanges as $tableName => $tableRange)
|
||||
{
|
||||
$ids = array_merge($tableRange->start, $tableRange->end);
|
||||
$ids = array_unique($ids);
|
||||
$indexPairs = $this->dao->select('id, `index`')->from("`$tableName`")
|
||||
->where('id')->in($ids)
|
||||
->fetchPairs('id');
|
||||
$tableRanges[$tableName]->indexPairs = $indexPairs;
|
||||
}
|
||||
|
||||
/* Set startIndice and endIndice. */
|
||||
foreach($tableRanges as $tableRange)
|
||||
{
|
||||
$queryData = array();
|
||||
foreach($tableRange->start as $id) $queryData[] = "WHEN $id THEN {$tableRange->indexPairs[$id]}";
|
||||
$query = "UPDATE " . TABLE_IM_CHAT_MESSAGE_INDEX . " SET `startIndex` = (CASE `start` " . join(' ', $queryData) . " END) WHERE `start` IN(" . join(',', $tableRange->start) . ");";
|
||||
$this->dao->query($query);
|
||||
|
||||
$queryData = array();
|
||||
foreach($tableRange->end as $id) $queryData[] = "WHEN $id THEN {$tableRange->indexPairs[$id]}";
|
||||
$query = "UPDATE " . TABLE_IM_CHAT_MESSAGE_INDEX . " SET `endIndex` = (CASE `end` " . join(' ', $queryData) . " END) WHERE `end` IN(" . join(',', $tableRange->end) . ");";
|
||||
$this->dao->query($query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix weekly report.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function fixWeeklyReport()
|
||||
{
|
||||
$this->loadModel('weekly');
|
||||
$projects = $this->dao->select('id,begin,end')->from(TABLE_PROJECT)->where('deleted')->eq('0')->andWhere('model')->eq('waterfall')->fetchAll('id');
|
||||
|
||||
$today = helper::today();
|
||||
foreach($projects as $projectID => $project)
|
||||
{
|
||||
if(helper::isZeroDate($project->begin) or helper::isZeroDate($project->end)) continue;
|
||||
|
||||
$begin = $project->begin;
|
||||
$end = $today > $project->end ? $project->end : $today;
|
||||
|
||||
$beginTimestame = strtotime($begin);
|
||||
$endTimestame = strtotime($end);
|
||||
while($beginTimestame <= $endTimestame)
|
||||
{
|
||||
$this->weekly->save($projectID, $begin);
|
||||
|
||||
$beginTimestame += 7 * 24 * 3600;
|
||||
$begin = date('Y-m-d', $beginTimestame);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +54,9 @@ class weekly extends control
|
||||
|
||||
$this->view->title = $this->lang->weekly->common;
|
||||
|
||||
$this->view->pv = $this->weekly->getPV($projectID, $date);
|
||||
$this->view->ev = $this->weekly->getEV($projectID, $date);
|
||||
$PVEV = $this->weekly->getPVEV($projectID, $date);
|
||||
$this->view->pv = $PVEV['PV'];
|
||||
$this->view->ev = $PVEV['EV'];
|
||||
$this->view->ac = $this->weekly->getAC($projectID, $date);
|
||||
$this->view->sv = $this->weekly->getSV($this->view->ev, $this->view->pv);
|
||||
$this->view->cv = $this->weekly->getCV($this->view->ev, $this->view->ac);
|
||||
|
||||
+25
-64
@@ -121,8 +121,9 @@ class weeklyModel extends model
|
||||
->exec();
|
||||
|
||||
$report = new stdclass;
|
||||
$report->pv = $this->getPV($project, $date);
|
||||
$report->ev = $this->getEV($project, $date);
|
||||
$PVEV = $this->getPVEV($project, $date);
|
||||
$report->pv = $PVEV['PV'];
|
||||
$report->ev = $PVEV['EV'];
|
||||
$report->ac = $this->getAC($project, $date);
|
||||
$report->sv = $this->getSV($report->ev, $report->pv);
|
||||
$report->cv = $this->getCV($report->ev, $report->ac);
|
||||
@@ -369,17 +370,17 @@ class weeklyModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* GetPV
|
||||
* Get PV and EV
|
||||
*
|
||||
* @param int $project
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return int
|
||||
* @return array
|
||||
*/
|
||||
public function getPV($projectID, $date = '')
|
||||
public function getPVEV($projectID, $date = '')
|
||||
{
|
||||
$report = $this->getFromDB($projectID, $date);
|
||||
if(!empty($report)) return $report->pv;
|
||||
if(!empty($report)) return array('PV' => $report->pv, 'EV' => $report->ev);
|
||||
|
||||
if(!$date) $date = date('Y-m-d');
|
||||
$monday = $this->getThisMonday($date);
|
||||
@@ -397,84 +398,49 @@ class weeklyModel extends model
|
||||
->fetchAll('id');
|
||||
|
||||
$PV = 0;
|
||||
$EV = 0;
|
||||
$this->loadModel('holiday');
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if(helper::isZeroDate($task->estStarted)) $task->estStarted = date('Y-m-d', strtotime($task->openedDate));
|
||||
$execution = $executions[$task->execution];
|
||||
if(helper::isZeroDate($task->estStarted)) $task->estStarted = helper::isZeroDate($task->openedDate) ? $execution->begin : date('Y-m-d', strtotime($task->openedDate));
|
||||
if(helper::isZeroDate($task->deadline))
|
||||
{
|
||||
$execution = $executions[$task->execution];
|
||||
$task->deadline = helper::isZeroDate($execution->realEnd) ? $execution->end : $execution->realEnd;
|
||||
if(helper::isZeroDate($task->finishedDate)) $task->deadline = date('Y-m-d', strtotime($task->finishedDate));
|
||||
}
|
||||
|
||||
$fullDays = $this->loadModel('holiday')->getActualWorkingDays($task->estStarted, $task->deadline);
|
||||
$fullDays = $this->holiday->getActualWorkingDays($task->estStarted, $task->deadline);
|
||||
if($task->estStarted < $monday and $task->deadline >= $nextMonday)
|
||||
{
|
||||
$weekActualDays = $workdays;
|
||||
}
|
||||
elseif($task->estStarted >= $monday and $task->estStarted < $nextMonday)
|
||||
{
|
||||
$weekActualDays = $this->loadModel('holiday')->getActualWorkingDays($task->estStarted, $task->deadline >= $nextMonday ? $sunday : $task->deadline);
|
||||
$weekActualDays = $this->holiday->getActualWorkingDays($task->estStarted, $task->deadline >= $nextMonday ? $sunday : $task->deadline);
|
||||
}
|
||||
elseif($task->deadline >= $monday and $task->deadline < $nextMonday)
|
||||
{
|
||||
$weekActualDays = $this->loadModel('holiday')->getActualWorkingDays($monday, $task->deadline);
|
||||
$weekActualDays = $this->holiday->getActualWorkingDays($monday, $task->deadline);
|
||||
}
|
||||
|
||||
if(empty($fullDays) or empty($weekActualDays) or empty($task->estimate)) continue;
|
||||
$PV += round(count($weekActualDays) / count($fullDays) * $task->estimate, 2);
|
||||
}
|
||||
$thisPV = round(count($weekActualDays) / count($fullDays) * $task->estimate, 2);
|
||||
|
||||
return sprintf("%.2f",$PV);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get EV data.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getEV($projectID, $date = '')
|
||||
{
|
||||
$report = $this->getFromDB($projectID, $date);
|
||||
if(!empty($report)) return $report->ev;
|
||||
|
||||
$executions = $this->loadModel('execution')->getList($projectID);
|
||||
$executionIdList = array_keys($executions);
|
||||
|
||||
if(!$date) $date = date('Y-m-d');
|
||||
$monday = $this->getThisMonday($date);
|
||||
$sunday = $this->getThisSunday($date);
|
||||
$lastDay = $this->getLastDay($date);
|
||||
$nextMonday = date('Y-m-d', strtotime($sunday) + 24 * 3600);
|
||||
|
||||
$tasks = $this->dao->select('*')
|
||||
->from(TABLE_TASK)
|
||||
->where('execution')->in($executionIdList)
|
||||
->andWhere('consumed')->gt(0)
|
||||
->andWhere("((estStarted >= '$monday' AND estStarted < '$nextMonday') OR (deadline >= '$monday' AND deadline < '$nextMonday') OR (estStarted < '$monday' AND deadline > '$nextMonday'))")
|
||||
->andWhere("parent")->ge(0)
|
||||
->andWhere("deleted")->eq(0)
|
||||
->andWhere('status')->ne('cancel')
|
||||
->query();
|
||||
|
||||
$EV = 0;
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->status == 'done' or $task->closedReason == 'done')
|
||||
{
|
||||
$EV += $task->estimate;
|
||||
$EV += $thisPV;
|
||||
}
|
||||
else
|
||||
{
|
||||
$task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100;
|
||||
$EV += $task->estimate * $task->progress / 100;
|
||||
$task->progress = 0;
|
||||
if(($task->consumed + $task->left) > 0) $task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100;
|
||||
$EV += round($thisPV * $task->progress / 100, 2);
|
||||
}
|
||||
$PV += $thisPV;
|
||||
}
|
||||
|
||||
return sprintf("%.2f", $EV);
|
||||
return array('PV' => sprintf("%.2f", $PV), 'EV' => sprintf("%.2f", $EV));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,15 +458,10 @@ class weeklyModel extends model
|
||||
|
||||
if(!$date) $date = date('Y-m-d');
|
||||
|
||||
$monday = $this->getThisMonday($date);
|
||||
$nextMonday = date('Y-m-d', strtotime($monday) + (7 * 24 * 3600));
|
||||
$executions = $this->dao->select('id,begin,end,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($project)->fetchAll('id');
|
||||
$executionIdList = array_keys($executions);
|
||||
$taskIdList = $this->dao->select('id')->from(TABLE_TASK)
|
||||
->where('execution')->in($executionIdList)
|
||||
->andWhere("parent")->ge(0)
|
||||
->andWhere("deleted")->eq(0)
|
||||
->fetchPairs();
|
||||
$monday = $this->getThisMonday($date);
|
||||
$nextMonday = date('Y-m-d', strtotime($monday) + (7 * 24 * 3600));
|
||||
$executions = $this->dao->select('id,begin,end,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($project)->fetchAll('id');
|
||||
$taskIdList = $this->dao->select('id')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere("parent")->ge(0)->andWhere("deleted")->eq(0)->fetchPairs();
|
||||
|
||||
$AC = $this->dao->select('sum(consumed) as consumed')
|
||||
->from(TABLE_EFFORT)
|
||||
|
||||
@@ -290,37 +290,20 @@ class weeklyTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getPV
|
||||
* Test getPVEV
|
||||
*
|
||||
* @param int $project
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getPVTest($projectID, $date = '')
|
||||
public function getPVEVTest($projectID, $date = '')
|
||||
{
|
||||
$objects = $this->objectModel->getPV($projectID, $date);
|
||||
$objects = $this->objectModel->getPVEV($projectID, $date);
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
|
||||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get EV data.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getEVTest($projectID, $date = '')
|
||||
{
|
||||
$objects = $this->objectModel->getEV($projectID, $date);
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
|
||||
return $objects;
|
||||
return $objects['PV'] . ',' . $objects['EV'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
|
||||
$db->switchDB();
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 projectModel->getWaterfallPVEVAC();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试projectID值为0 >> 0.00,0.00,0.00
|
||||
测试projectID值为11 >> 97.00,53.94,108.00
|
||||
测试projectID值为41 >> 52.00,19.87,33.00
|
||||
|
||||
*/
|
||||
|
||||
$projectIDList = array(0, 11, 41);
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('project');
|
||||
|
||||
r($tester->project->getWaterfallPVEVAC($projectIDList[0])) && p('PV,EV,AC') && e('0.00,0.00,0.00'); //测试projectID值为0
|
||||
r($tester->project->getWaterfallPVEVAC($projectIDList[1])) && p('PV,EV,AC') && e('97.00,53.94,108.00'); //测试projectID值为11
|
||||
r($tester->project->getWaterfallPVEVAC($projectIDList[2])) && p('PV,EV,AC') && e('52.00,19.87,33.00'); //测试projectID值为41
|
||||
|
||||
$db->restoreDB();
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
|
||||
include dirname(dirname(dirname(__FILE__))) . '/class/weekly.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 weeklyModel->getEV();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试projectID值为0,date值为2022-05-01 >> 768.75
|
||||
测试projectID值为0,date值为空 >> 2347.38
|
||||
测试projectID值为11,date值为2022-05-01 >> 12.5
|
||||
测试projectID值为11,date值为空 >> 53.63
|
||||
测试projectID值为41,date值为2022-05-01 >> 6.91
|
||||
测试projectID值为41,date值为空 >> 19.87
|
||||
|
||||
*/
|
||||
$projectIDList = array(0, 11, 41);
|
||||
$dateList = array('2022-05-01', '');
|
||||
|
||||
$weekly = new weeklyTest();
|
||||
|
||||
r($weekly->getEVTest($projectIDList[0], $dateList[0])) && p() && e('768.75'); //测试projectID值为0,date值为2022-05-01
|
||||
r($weekly->getEVTest($projectIDList[0], $dateList[1])) && p() && e('2347.38'); //测试projectID值为0,date值为空
|
||||
r($weekly->getEVTest($projectIDList[1], $dateList[0])) && p() && e('12.5'); //测试projectID值为11,date值为2022-05-01
|
||||
r($weekly->getEVTest($projectIDList[1], $dateList[1])) && p() && e('53.63'); //测试projectID值为11,date值为空
|
||||
r($weekly->getEVTest($projectIDList[2], $dateList[0])) && p() && e('6.91'); //测试projectID值为41,date值为2022-05-01
|
||||
r($weekly->getEVTest($projectIDList[2], $dateList[1])) && p() && e('19.87'); //测试projectID值为41,date值为空
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
|
||||
include dirname(dirname(dirname(__FILE__))) . '/class/weekly.class.php';
|
||||
$db->switchDB();
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 weeklyModel->getPVEV();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试projectID值为0,date值为2022-05-01 >> 0.00,0.00
|
||||
测试projectID值为0,date值为空 >> 0.00,0.00
|
||||
测试projectID值为11,date值为2022-05-01 >> 0.00,0.00
|
||||
测试projectID值为11,date值为空 >> 6.00,1.98
|
||||
测试projectID值为41,date值为2022-05-01 >> 0.00,0.00
|
||||
测试projectID值为41,date值为空 >> 14.50,3.43
|
||||
|
||||
*/
|
||||
|
||||
$projectIDList = array(0, 11, 41);
|
||||
$dateList = array('2022-05-01', '');
|
||||
|
||||
$weekly = new weeklyTest();
|
||||
|
||||
r($weekly->getPVEVTest($projectIDList[0], $dateList[0])) && p() && e('0.00,0.00'); //测试projectID值为0,date值为2022-05-01
|
||||
r($weekly->getPVEVTest($projectIDList[0], $dateList[1])) && p() && e('0.00,0.00'); //测试projectID值为0,date值为空
|
||||
r($weekly->getPVEVTest($projectIDList[1], $dateList[0])) && p() && e('0.00,0.00'); //测试projectID值为11,date值为2022-05-01
|
||||
r($weekly->getPVEVTest($projectIDList[1], $dateList[1])) && p() && e('6.00,1.98'); //测试projectID值为11,date值为空
|
||||
r($weekly->getPVEVTest($projectIDList[2], $dateList[0])) && p() && e('0.00,0.00'); //测试projectID值为41,date值为2022-05-01
|
||||
r($weekly->getPVEVTest($projectIDList[2], $dateList[1])) && p() && e('14.50,3.43'); //测试projectID值为41,date值为空
|
||||
$db->restoreDB();
|
||||
@@ -1 +1 @@
|
||||
v6.3.0
|
||||
v6.4.0
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
6.3
|
||||
6.4
|
||||
|
||||
Reference in New Issue
Block a user