细微的调整,巨大的收益:如何定制您的项目管理信息系统(PMIS)以实现更大的业务价值





5.00/5 (4投票s)
如何定制您的 PMIS 以获得更大的业务价值
引言
项目管理信息系统(PMIS)是许多事物的集合——强大、高效、可适应且用途广泛的软件产品。
但它们并非完美(至少开箱即用时并非如此)。
每家公司都有其内部的项目管理职能标准,而开箱即用的PMIS中提供的基础平台功能永远无法自动匹配这些偏好。
但通过一点点的定制,您可以将PMIS的体验调整为符合您组织的独特需求——解锁隐藏的业务价值,并调动一批强大但未被充分利用的平台功能。
默认设置的问题
在本论文中,我们将探讨Microsoft Project Server的定制。
尤其当与Microsoft SharePoint结合使用时,Project Server是企业PMIS最有效且应用最广泛的选择之一。但与任何PMIS一样,它开箱即用时远非完美。
总的来说,PMIS如Project Server肩负着诸多职责,包括
- 项目启动(包括项目验证以及范围、容量、资源和预算需求的分析)
- 网络进度计划
- 项目资源管理
- 维护运营信息和监控项目状态
- 项目文档流程和文档归档;
- 项目风险、问题和变更请求的管理
- 运营和统计报告
在处理某些任务时——例如网络进度计划和项目资源管理——MS Project Server“开箱即用”时的表现相当不错。但项目工作流功能则完全是另一回事。
为了说明工作流问题,让我们看一个真实的案例。
在此项目的启动和规划阶段,我们将要求MS Project Server协助完成两项主要任务
- 创建符合我们所有内部标准的项目——例如,确保项目代码符合内部预算和组合分类。
- 创建一个协作工作空间,其中包含我们所有的项目数据,包括
- 分类(目标、解决方案、结果、收益、可行性分析)
- 组织结构(管理和运营指导、工作组、技能集)
- 范围(功能、组织和技术要素,范围变更的程序)
- 实施方法(部署策略、假设和限制、影响分析)
- 预算(预算阶段、预算阶段内的工程量和成本项目、总体项目预算)
- 文档(所有项目报告的结构化存储)
- 项目章程(最终项目文档的自动生成)
此外,我们还需要这个协作工作空间拥有直观的用户界面。(这在项目的早期阶段尤其重要,因为您的许多团队成员可能仍然在熟悉MS Project Server。)
首先,让我们看看当我们在“开箱即用”的情况下尝试这些任务时会发生什么。
任务一——创建项目——完成得相当好。我们可以通过自定义字段机制选择我们的扩展项目属性,这意味着它们将自动包含在我们的报告数据库中,并且我们可以在此基础上构建分析。
“开箱即用”时遇到的唯一显著限制是,我们无法根据项目类型和其他分类属性自动生成项目代码。
任务二——创建工作空间——问题就大多了,因为我们只能创建一个包含文档、风险和问题的标准项目工作空间。
因此,我们初步的结论是,“开箱即用”的设置虽然与涉及网络进度计划、资源管理和风险的项目管理职能高度契合,但它们非常不适合自动生成项目章程、项目财务规划、合同工作以及一般的项目文档流程。
考虑到这些限制,让我们探讨一下如何通过对系统默认设置进行一些修改来改进功能。
定制实践
回到我们的项目示例,您会记得在任务一中,我们缺乏根据项目特征自动生成项目代码的功能。
在创建项目时,需要按照以下格式生成代码:PRJ [项目规格类型] [活动] [选定类型和方向内的编号]。
MS Project Server的事件处理程序机制非常适合这项任务。因此,我们需要实现一个处理程序,它将生成并保存我们所需项目代码。
为了直接处理字段,Project Server Web API(称为PSI)需要一个代理程序集,名为*ProjectServerServices.dll*。(请注意,使用PSI非常特殊,因为所有操作都是通过专门的DataSet
对象进行的,而这个对象缺乏连贯的文档)。
首先,您需要获取所需的字段ID,具体说明在此。
下一篇
//read project information
var projectDS = ProjectSvc.ReadProject(ProjectUID, SvcProject.DataStoreEnum.WorkingStore);
foreach (ProjectDataSet.ProjectCustomFieldsRow cfRow in projectDS.ProjectCustomFields)
{
//if field exists, just update it
if (cfRow.MD_PROP_UID.ToString() == id.ToString())
{
//update the value
cfRow.TEXT_VALUE = code;
customFieldFound = true;
}
}
之后,项目需要被返回
//create a new job id
jobId = Guid.NewGuid();
//checkin the updated project
bool force = false;
string sessionDescription = "updated custom fields";
ProjectSvc.QueueCheckInProject(jobId, ProjectUID,
force, sessionId, sessionDescription);
并发布
//create a new job id
jobId = Guid.NewGuid();
bool fullPublish = false;
ProjectSvc.QueuePublish(jobId, ProjectUID,
fullPublish, EndpointAddressProjectSvc.Uri.ToString())
一旦项目创建完成(任务一),我们就需要创建一个工作空间(任务二),该工作空间能够提供编译项目数据的功能——例如,我们的项目章程。
但正如您所记得的,一个标准的MS SharePoint工作空间只是一个包含文档库以及问题和风险列表的简单Web模板。
我们需要一个功能更丰富的Web模板。
总的来说,有两种方法可以创建可用作MS SharePoint工作空间模板的站点定义——创建基于标准PWS工作空间的沙盒解决方案(Sandboxed Solution),或创建场解决方案(Farm Solution)站点定义。
沙盒解决方案站点定义是对现有工作空间的调整。其优点是,我们创建的工作空间会立即出现在管理界面中。然而,沙盒解决方案有严格的限制。例如,不能访问数据库,而这正是我们为了显示各种MS Project和工作空间数据集所缺少的功能。
场解决方案有一个明显的优势——我们可以完全访问SharePoint对象模型,并可以从各种来源检索数据。但是,使用场解决方案,我们如何使我们的站点定义能够用作Project上的模板工作空间?当时Google帮不了我们——所以我们带着IL-Spy或Reflector踏上了征程。
最好从“企业项目类型详细信息”页面(\PWA\ADMIN\EnterpriseProjectTypeDetails.aspx)开始。
从那里,经过一系列调用,我们将进入*Microsoft.Office.Project.Server.dll*以及*Microsoft.Office.Project.Server.BusinessLayer.Admin*类中的ReadWssInstalledLanguagesAndWebTempalates(…)
方法。
这是我们将看到的内容
foreach (SPWebTemplate sPWebTemplate in sPWebTemplateCollection)
{
if (sPWebTemplate.ID >= 6000 && sPWebTemplate.ID <= 6220)
{
dataRow = webTemplatesTable.NewRow();
dataRow["LanguageId"] = sPLanguage.LCID;
dataRow["TemplateName"] = sPWebTemplate.Name;
dataRow["TemplateTitle"] = sPWebTemplate.Title;
dataRow["TemplateId"] = sPWebTemplate.ID;
webTemplatesTable.Rows.Add(dataRow);
}
}
此ID与*webtemp_***.xml*中定义的ID相同(它必须在6000到6220之间)。然而,如果我们创建一个具有正确ID的SiteDefinition
,它肯定会出现在“企业项目类型详细信息”页面上——但站点的创建将失败。
失败原因可以在*Microsoft.Office.Project.Server.BusinessLayer.Project*类中的AddOrChangeProjectWorkspaceAddress(…)
方法中找到。
如果您仔细查看代码,您会发现它依赖于PWSIssues
、PWSRisk
和PWSDocLibs
列表。我们可以将相关功能添加到我们的SiteDefinition
中,或者我们可以简单地将PWS功能添加到*onet.xml*中,这将添加所有必需的内容。
<!--Activate PWS Feature -->
<Feature ID="90014905-433F-4a06-8A61-FD153A27A2B5">
<Properties xmlns="http://schemas.microsoft.com/sharepoint/">
<Property Key="InheritGlobalNavigation" Value="false"/>
<Property Key="OnQuickLaunch" Value="false"/>
<Property Key="InheritCurrentNavigation" Value="false"/>
<Property Key="IncludeSubSites" Value="false"/>
<Property Key="IncludePages" Value="False"/>
</Properties>
</Feature>
这并不令人惊讶,因为标准的PWS站点定义只是一个启用了此功能的站点。(请注意,我们的工作空间的创建正在“Microsoft Project Server Queue Service 2010”中进行。因此,在对SiteDefinition
进行更改后,我们需要重新启动它。)
采用这种方法,我们的工作空间将成为一组具有特定数据的列表,以及一组反映不同列表切片——以及ProjectServer_Reporting
数据库的页面。但仍有两个问题
- 如何以最少的代码实现数据连接?
- 如何选择数据(特别是与当前项目相关而非其他项目相关的任务)?
关于第一个问题,DataFormWebPart
及其AggregateDataSource
非常适合连接。关键在于,我们将从所有源中选择数据,然后在*.xsl*级别实现连接。例如
<cc1:AggregateDataSource runat="server"
RowsName="" SeparateRoot="true" RootName="" IsSynchronous="">
<Sources>
<cc1:SPSqlDataSource runat="server" AllowIntegratedSecurity="False" ConnectionString="
<%$ connectionStrings:.._ConnectionString %>"
SelectCommand="SELECT TOP 1000 [Results] as WorkResults,
[TaskIndex], [TaskOutlineNumber], [TaskUID],cast(cast(TaskWork as decimal(9,2)) AS FLOAT)
as TaskWork,[TaskName] FROM [ProjectServer_Reporting].[dbo].[MSP_EpmTask_UserView]
TV INNER JOIN [ProjectServer_Reporting].[dbo].[MSP_EpmProject] PR ON
TV.ProjectUID = PR.ProjectUID WHERE PR.ProjectUID = @ProjUid " ID="SqlDataSource1">
<SelectParameters>
<asp:controlparameter name="ProjUid" controlid="PlaceHolderMain$wspp" propertyname="ProjUid"/>
</SelectParameters>
</cc1:SPSqlDataSource>
<cc1:SPDataSource runat="server" DataSourceMode="List" SelectCommand="..."/>
<cc1:SPDataSource runat="server" DataSourceMode="List" SelectCommand="..."/>
<cc1:SPDataSource runat="server" DataSourceMode="List" SelectCommand="..."/>
</Sources>
<Aggregate>
<concat name="data source">
<datasource name="TasksInfo" id="0" />
<datasource name="ProjectPhases" id="1" />
<datasource name="ProjectWorkSteps" id="2" />
<datasource name="Contracts" id="3" />
</concat>
</Aggregate>
</cc1:AggregateDataSource>
从上面的代码可以看出,有一组用于数据库查询的SPSqlDataSource
,以及用于列表查询的SPDataSource
。剩下的就是编写一个*.xsl*文件,将其以正确的顺序显示出来。
关于第二个问题——如何选择数据——我们有两种选择。一方面,我们可以关注工作空间的URL,然后使用请求中的MSP_EpmProject
表获取已配置的ProjUid。另一方面,MS SharePoint工作空间的ProjUid保存在SPWeb
属性的MSPWAPROJUID
字段中——所以我们可以编写一个简单的控件来获取它
public class WSProjectProperties : WebControl
{
public String ProjUid
{
get
{
if (SPContext.Current == null)
return null;
if (SPContext.Current.Web == null)
return null;
return SPContext.Current.Web.AllProperties[“MSPWAPROJUID”] as string;
}
}
}
然后,该值应传递给DataSource
,这正是前面示例所涵盖的内容。
定制的成果
通过这些微小的修改,我们赋予了标准工作空间全面的协作功能——符合我们自己内部的要求。
我们来看一下
注意:基于Microsoft Project 2010日历计划或财务系统的实际数据自动形成的参数以红色标出。
注意:关于项目阶段、工作范围和截止日期信息是根据Microsoft Project 2010日历计划数据实时收集的;项目里程碑达成信息是从项目库中存储的文档收集的。
简单而强大
在这个项目示例中,我们仅用很低的劳动成本就满足了所有必要的 yb要求。通过定制,我们实现了
- 全面的项目信息、分类和结构
- 预算管理,支持多阶段预算场景
- 风险/范围/变更/质量/时间/成本/采购管理
- 文档库
- 支持所有项目阶段
- 项目状态仪表板、报告和项目指标的自动计算
- 支持我们内部项目管理方法论中定义的多步骤流程
- Project Server和SharePoint之间的集成
此外,这个项目示例基于实际的Microsoft Project Server 2010的采用和定制工作——任何行业的任何项目管理团队都可以轻松复制。
事实上,基本的定制不仅能促进项目计划的协作。所有涉及操作数据工作的项目任务都可以通过这种方式进行简化,包括
- 采购管理
- 合同工作管理
- 处理项目问题和风险
- 处理项目相关文档,包括结构化文档存储和定制工作流
信息很明确:无论公司的内部标准如何,一点点的定制都可以为PMIS功能带来无数新的潜力——为您的企业带来无数新的价值。