在Dynamis CRM中打造一键保存关闭刷新案例的功能
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复172或者20151114可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me!
我们知道在Dynamics CRM中,点击命令栏的 解决案例 的话会弹出一个解决案例对话框,解决字段的内容必须输入,然后再点击 解决 按钮才能解决案例。有的客户嫌这个麻烦,要求改造成一个一键解决方案,就是点击解决案例按钮后,先保存记录,再解决案例,最后刷新案例让用户看到新的状态。困难总比想象的多,但是请相信,方法比困难更多,本篇博文就提供一个方法,并且顺便介绍了如何加快Ribbon Workbench的发布的方法,自创的。
点击 解决案例 弹出的对话框如下,输入解决字段的值,还可以选择下记账时间,填入备注,再点击解决按钮。
就可以看到一些比较明显的变化,状态变成了已解析,右下角有个只读的文字,记录当然也是只读了,命令栏看不到 解决案例 按钮,新增加显示了一个 重新激活案例 按钮。
我们还是先准备用到的JavaScript文件中的函数吧,我这里使用的函数如下,放在唯一名称为new_/common/js/RibbonScript.js 的Web资源中。当中涉及到通过JavaScript执行实体消息,也就是通过JavaScript执行案例实体(Incident)的CloseIncident消息,这个请参考我的博文: 通过JavaScript调用SOAP终结点执行实体消息
function CloseCaseAsResolved(CaseId, FormOrList) { if (FormOrList == "Form" && Xrm.Page.data.entity.getIsDirty()) { Xrm.Page.data.save(true).then(function () { ExecuteCloseIncidentRequestRequest(CaseId, FormOrList, true); }, function (errorCode, message) { Xrm.Utility.alertDialog("Save record error." + message); }); } else { ExecuteCloseIncidentRequestRequest(CaseId, FormOrList, false); } } function ExecuteCloseIncidentRequestRequest(CaseId, FormOrList, IsDirty) { var requestMain = "" requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">"; requestMain += " <s:Body>"; requestMain += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">"; requestMain += " <request i:type=\"b:CloseIncidentRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">"; requestMain += " <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">"; requestMain += " <a:KeyValuePairOfstringanyType>"; requestMain += " <c:key>IncidentResolution</c:key>"; requestMain += " <c:value i:type=\"a:Entity\">"; requestMain += " <a:Attributes>"; requestMain += " <a:KeyValuePairOfstringanyType>"; requestMain += " <c:key>subject</c:key>"; requestMain += " <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">"; requestMain += "已解决"; requestMain += " </c:value>"; requestMain += " </a:KeyValuePairOfstringanyType>"; requestMain += " <a:KeyValuePairOfstringanyType>"; requestMain += " <c:key>incidentid</c:key>"; requestMain += " <c:value i:type=\"a:EntityReference\">"; requestMain += " <a:Id>"; requestMain += CaseId; requestMain += " </a:Id>"; requestMain += " <a:LogicalName>incident</a:LogicalName>"; requestMain += " <a:Name i:nil=\"true\" />"; requestMain += " </c:value>"; requestMain += " </a:KeyValuePairOfstringanyType>"; requestMain += " </a:Attributes>"; requestMain += " <a:EntityState i:nil=\"true\" />"; requestMain += " <a:FormattedValues />"; requestMain += " <a:Id>00000000-0000-0000-0000-000000000000</a:Id>"; requestMain += " <a:LogicalName>incidentresolution</a:LogicalName>"; requestMain += " <a:RelatedEntities />"; requestMain += " </c:value>"; requestMain += " </a:KeyValuePairOfstringanyType>"; requestMain += " <a:KeyValuePairOfstringanyType>"; requestMain += " <c:key>Status</c:key>"; requestMain += " <c:value i:type=\"a:OptionSetValue\">"; requestMain += " <a:Value>5</a:Value>"; requestMain += " </c:value>"; requestMain += " </a:KeyValuePairOfstringanyType>"; requestMain += " </a:Parameters>"; requestMain += " <a:RequestId i:nil=\"true\" />"; requestMain += " <a:RequestName>CloseIncident</a:RequestName>"; requestMain += " </request>"; requestMain += " </Execute>"; requestMain += " </s:Body>"; requestMain += "</s:Envelope>"; var req = new XMLHttpRequest(); req.open("POST", Xrm.Page.context.getClientUrl() + "/XRMServices/2011/Organization.svc/web", false); req.setRequestHeader("Accept", "application/xml, text/xml, */*"); req.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute"); req.send(requestMain); var strResponse = req.responseText; var reg = /\<faultstring[\s\S]*\<\/faultstring\>/im; var faultmsg = reg.exec(strResponse); if (faultmsg != null) { reg = /\>[\s\S]*\<\//im; faultmsg = reg.exec(faultmsg.toString()); if (faultmsg != null) { Xrm.Utility.alertDialog("解决案例出现错误. " + faultmsg.toString().substring(1, faultmsg.toString().length - 2), function () { }); } } else { if (FormOrList == "Form") { if (IsDirty) { Xrm.Page.data.entity.attributes.forEach( function (attribute, index) { if (attribute.getIsDirty()) { attribute.setSubmitMode("never"); } } ); } Xrm.Utility.openEntityForm("incident", CaseId); } else { location.reload(); } } }
然后参考我这篇博文 Dynamics CRM 客户端程序开发:自定义系统标准按钮的可用性 来定制下命令栏。将案例实体和要用到的JavaScript放到解决方案中,然后用Ribbon Workbench打开它,我先修改表单(Form)界面的解决案例按钮,右击FROM那栏的 Resolve Case 按钮,选择 Customise Command ,这是因为我们只是定义下他们执行的命令而已,所以不用 Customise Button这个菜单项。
然后我们就会看到Solution Elements > Commands 下面增加了一个元素,名称是 Mscrm.Form.incident.Resolve ,这个元素下面还有一个 Javascript Command的命令,从这个我们也可以知道这个按钮执行的是 /_static/_common/scripts/CommandBarActions.js 这个js文件中的 Mscrm.CommandBarActions.resolve 方法。
我这里的客制化就是改动他执行的类库和函数并增加参数,更改如下:
1. 将FunctionName 改成我前面撰写的函数CloseCaseAsResolved
2. 将Liabrary 改成我前面加入的专门用于命令栏的JavaScript文件:$webresource:new_/common/js/RibbonScript.js
3. 点击Parameters,增加两个参数,因为我要执行的函数需要两个参数:
第一个是 Crm Parameter 类型的参数,我使用了 FirstPrimaryItemId ,名称我命名为 CaseId. 这个用来传递要关闭的案例的主键。
第二个是String Parameter类型的参数,名称我命名为 FormOrList ,值我用 Form。用来说明用户是在表单界面还是在列表界面关闭案例的。
<?xml version="1.0" encoding="utf-16"?> <RibbonDiffXml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <CustomActions> <CustomAction Id="new.Mscrm.Form.incident.Reactivate.CustomAction" Location="Mscrm.Form.incident.MainTab.Save.Controls._children" Sequence="47"> <CommandUIDefinition> <Button Alt="$Resources:Ribbon.Form.incident.MainTab.Actions.Reactivate" Command="Mscrm.Form.incident.Reactivate" Id="Mscrm.Form.incident.Reactivate" Image32by32="/_imgs/ribbon/ReactivateCase_32.png" Image16by16="/_imgs/ribbon/ReactivateCase_16.png" LabelText="$Resources:Ribbon.Form.incident.MainTab.Actions.Reactivate" Sequence="47" TemplateAlias="o1" ToolTipTitle="$Resources:Mscrm_Form_incident_MainTab_Actions_Reactivate_ToolTipTitle" ToolTipDescription="$Resources:Mscrm_Form_incident_MainTab_Actions_Reactivate_ToolTipDescription" ModernImage="ReactivateCase" /> </CommandUIDefinition> </CustomAction> </CustomActions> <Templates> <RibbonTemplates Id="Mscrm.Templates" /> </Templates> <CommandDefinitions> <CommandDefinition Id="Mscrm.Form.incident.Reactivate"> <EnableRules> <EnableRule Id="Mscrm.CanChangeIncidentForm" /> <EnableRule Id="new.incident.EnableRule1.ReactivateEnableRule" /> </EnableRules> <DisplayRules> <DisplayRule Id="Mscrm.CanChangeIncidentForm" /> <DisplayRule Id="Mscrm.IncidentIsInactive" /> </DisplayRules> <Actions> <JavaScriptFunction FunctionName="Mscrm.CommandBarActions.reactivate" Library="/_static/_common/scripts/CommandBarActions.js" /> </Actions> </CommandDefinition> <CommandDefinition Id="Mscrm.Form.incident.Resolve"> <EnableRules> <EnableRule Id="Mscrm.CanChangeIncidentForm" /> <EnableRule Id="Mscrm.IncidentIsActive" /> </EnableRules> <DisplayRules> <DisplayRule Id="Mscrm.CanChangeIncidentForm" /> <DisplayRule Id="Mscrm.IncidentIsActive" /> </DisplayRules> <Actions> <JavaScriptFunction FunctionName="CloseCaseAsResolved" Library="$webresource:new_/common/js/RibbonScript.js"> <CrmParameter Value="FirstPrimaryItemId" /> <StringParameter Value="Form" /> </JavaScriptFunction> </Actions> </CommandDefinition> </CommandDefinitions> <RuleDefinitions> <TabDisplayRules /> <DisplayRules> <DisplayRule Id="Mscrm.CanChangeIncidentForm"> <EntityPrivilegeRule PrivilegeType="Write" PrivilegeDepth="Basic" EntityName="incident" /> <EntityPrivilegeRule PrivilegeType="AppendTo" PrivilegeDepth="Basic" EntityName="incident" /> <EntityPrivilegeRule PrivilegeType="Create" PrivilegeDepth="Basic" EntityName="activitypointer" /> <EntityPrivilegeRule PrivilegeType="Append" PrivilegeDepth="Basic" EntityName="activitypointer" /> </DisplayRule> <DisplayRule Id="Mscrm.IncidentIsInactive"> <FormStateRule State="Disabled" /> </DisplayRule> <DisplayRule Id="Mscrm.IncidentIsActive"> <FormStateRule State="Existing" /> </DisplayRule> </DisplayRules> <EnableRules> <EnableRule Id="Mscrm.CanChangeIncidentForm"> <FormStateRule State="Create" InvertResult="true" /> <RecordPrivilegeRule PrivilegeType="Write" AppliesTo="PrimaryEntity" /> <RecordPrivilegeRule PrivilegeType="AppendTo" AppliesTo="PrimaryEntity" /> </EnableRule> <EnableRule Id="new.incident.EnableRule1.ReactivateEnableRule"> <OrRule> <Or> <CustomRule FunctionName="CheckOwnerEqualsCurrentUser" Library="$webresource:new_/common/RibbonScript.js" /> </Or> <Or> <CustomRule FunctionName="CheckCurrentUserInTeam" Library="$webresource:new_/common/RibbonScript.js"> <StringParameter Value="MyTeam" /> </CustomRule> </Or> </OrRule> </EnableRule> <EnableRule Id="Mscrm.IncidentIsActive"> <FormStateRule State="Existing" /> </EnableRule> </EnableRules> </RuleDefinitions> <LocLabels /> </RibbonDiffXml>
然后参考我的这篇博客:Dynamics CRM命令栏定制基础知识及手动编辑customization.xml实例 ,将之前的Ribbon解决方案作为非托管解决方案导出,然后将复制好的内容去掉<?xml version="1.0" encoding="utf-16"?> 这行,还去掉 RibbonDiffXml 的所有属性及其值,然后替换掉 customizations.xml 文件中的第一个 RibbonDiffXml 的值,然后将这个解决方案导入CRM,发布它就可以测试了。我这里录入一个简单的案例如下:
测试发现关闭以后,我当时没有保存的说明字段的内容保存了,也刷新了页面告诉我新案例关闭了:
然后同样利用Ribbon Workbench来修改案例实体列表界面的解决案例按钮,主要设置如下:
然后也是获取修改的xml,替换掉第一个 RibbonDiffXml 的值 ,再导入系统进行测试,测试OK的,和标准功能基本一样,也会刷新当前页面。