<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[CRM 4 - Alexander Development]]></title><description><![CDATA[CRM 4 - Alexander Development]]></description><link>https://alexanderdevelopment.net/</link><image><url>https://alexanderdevelopment.net/favicon.png</url><title>CRM 4 - Alexander Development</title><link>https://alexanderdevelopment.net/</link></image><generator>Ghost 1.20</generator><lastBuildDate>Thu, 23 Apr 2026 03:05:49 GMT</lastBuildDate><atom:link href="https://alexanderdevelopment.net/tag/crm-4/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Unit testing Microsoft Dynamics CRM code]]></title><description><![CDATA[<div class="kg-card-markdown"><p>If you're developing code that runs against Dynamics CRM, you know you should be testing it, right? As a developer first and foremost, I always believed that tests and documentation got in the way of the important - and more fun - stuff, but as I transitioned into a management</p></div>]]></description><link>https://alexanderdevelopment.net/post/2011/03/31/unit-testing-microsoft-dynamics-crm-code/</link><guid isPermaLink="false">5a5837216636a30001b976a5</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[unit testing]]></category><category><![CDATA[CRM 4]]></category><category><![CDATA[continuous integration]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Fri, 01 Apr 2011 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>If you're developing code that runs against Dynamics CRM, you know you should be testing it, right? As a developer first and foremost, I always believed that tests and documentation got in the way of the important - and more fun - stuff, but as I transitioned into a management role with responsibility for my company's Dynamics CRM system, I began to appreciate the value of the less-fun stuff.In this post I'll give you an overview of our continuous integration environment and offer a conceptual example of how to unit test your CRM code without having to execute tests against a running CRM system.Our full build and unit testing process used the following:</p>
<ol>
<li>
<p><a href="http://nant.sourceforge.net/">NAnt</a> for builds</p>
</li>
<li>
<p><a href="http://nunit.org/">NUnit</a> for unit tests</p>
</li>
<li>
<p><a href="http://subversion.apache.org/">Subversion</a> (SVN) for version control</p>
</li>
<li>
<p><a href="http://confluence.public.thoughtworks.org/display/CCNET/Welcome+to+CruiseControl.NET">CruiseControl.NET</a> (CC.NET) for continuous integration</p>
</li>
<li>
<p><a href="http://ayende.com/projects/rhino-mocks.aspx">Rhino.Mocks</a> for mock object framework</p>
</li>
</ol>
<p>Whenever a developer made a commit to SVN, CC.NET would execute the correct NAnt build target (different ones for production, testing, etc.), then it would run the NUnit tests. The results of the build (broken/successful) and the results of the NUnit tests were all reported through the CC.NET web interface so you could see a historical view. CC.NET also has a desktop notification app that is green when all builds are good or red when all builds are bad that you can use to easily check up on your development team.</p>
<p>Originally our NUnit tests ran against our CRM staging server and staging database, but we found that it was a problem keeping the staging system populated with &quot;real&quot; data, and our staging system was underpowered, so unit tests took a long time to execute. We solved this by using Rhino.Mocks to setup a mock CRM framework to verify that our code would send the correct calls to CRM without actually having to make the calls against an actual system.</p>
<p>Here's a conceptual example from version 4, but it will work similarly in 2011. Let's say we want to test code that deactivates an account. First, the test method sets up a mock object to represent the CRM service. Second, we set up an object to retrieve the setstate request object that the production code will pass to CRM. Third, the test method runs the production code against the mocked CRM service and captures the request object. Finally, we test the properties of the request object using an Assert.AreEqual call.</p>
<p>If you're ready to dig into the technical details of Rhino.Mocks + CRM, take a look at this excellent blog post with code samples: <a href="http://www.develop1.net/public/post/Unit-Testing-Dynamics-CRM2011-Pipeline-Plugins-using-Rhino-Mocks.aspx">http://www.develop1.net/public/post/Unit-Testing-Dynamics-CRM2011-Pipeline-Plugins-using-Rhino-Mocks.aspx</a>.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Dynamically setting field requirement levels in Microsoft Dynamics CRM]]></title><description><![CDATA[<div class="kg-card-markdown"><p>In Dynamics CRM you may have a field you want to be required some of the time, but not required, or maybe not even enabled, the rest of the time. In this post I'll show you how to dynamically enable/disable and set/unset the required attribute of CRM form</p></div>]]></description><link>https://alexanderdevelopment.net/post/2011/03/20/dynamically-setting-field-requirement-levels-in-microsoft-dynamics-crm/</link><guid isPermaLink="false">5a5837216636a30001b97691</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[programming]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[CRM 4]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 21 Mar 2011 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>In Dynamics CRM you may have a field you want to be required some of the time, but not required, or maybe not even enabled, the rest of the time. In this post I'll show you how to dynamically enable/disable and set/unset the required attribute of CRM form fields using JavaScript.</p>
<p>Let's say you have a delivery restaurant that sells pizza and wings. You could store the order attributes in CRM on a custom DeliveryOrder entity. You could have a picklist to represent the order type, pizza or wings, and you could store the pizza toppings in a text field. If the order type is pizza, you want to require something be entered in the toppings field. If the order type is wings, you don't want to even allow an entry in the toppings field.</p>
<p>First, create the entity attributes. We'll call the picklist lucas_ordertype, and we'll call the text field lucas_toppings. The picklist values for lucas_ordertype are Pizza and Wings, and it is a business required field. When you create the lucas_toppings field, don't change the default requirement attribute.</p>
<p>Once you've added the fields to your CRM form, you'll need to add some JavaScript to enable or disable the toppings field and set its requirement level appropriately. Here's script that does it:</p>
<pre><code>//get a references to our picklist object  
var oOrderType = crmForm.all.lucas_ordertype;  
  
//default toppings field as disabled, not required  
crmForm.all.lucas_toppings.Disabled = true;  
crmForm.SetFieldReqLevel(&quot;lucas_toppings&quot;, false);  
  
//if order type is pizza, enable and require toppings field  
if(oOrderType.SelectedText==&quot;Pizza&quot;)  
{  
crmForm.all.lucas_toppings.Disabled = false;  
crmForm.SetFieldReqLevel(&quot;lucas_toppings&quot;, true);  
}
</code></pre>
<p>Add this script to the form's onLoad event and the lucas_ordertype field's onChange event, and you're set. Now you'll get the information you need without unduly inconveniencing your users.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Activity coding in Dynamics CRM]]></title><description><![CDATA[<div class="kg-card-markdown"><p>At a previous job, we had used GoldMine (version 6.7 was where we parted ways) as our CRM system before moving to Dynamics CRM. At the time - maybe it's still done this way - GoldMine allowed you to code activities with a hierarchy of references, codes and results.</p></div>]]></description><link>https://alexanderdevelopment.net/post/2011/03/14/activity-coding-in-dynamics-crm/</link><guid isPermaLink="false">5a5837216636a30001b976be</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[CRM 4]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Tue, 15 Mar 2011 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>At a previous job, we had used GoldMine (version 6.7 was where we parted ways) as our CRM system before moving to Dynamics CRM. At the time - maybe it's still done this way - GoldMine allowed you to code activities with a hierarchy of references, codes and results. We used reference to separate activities either by department or broad functional grouping (e.g. &quot;service&quot; was a separate reference although there was no separate &quot;service&quot; department). Codes were the specific kinds of activities or client touch points grouped under a reference, and the results indicated how the activity concluded.</p>
<p>The reference/code/result structure allowed us an incredible level of granularity for tracking all the times we either interacted with an external stakeholder (client, prospect, partner, external service provider) or did something on its behalf. We were able to compile detailed &quot;production&quot; reports for our call center reps, and the activities' structure gave them a framework for approaching their routine daily responsibilities.</p>
<p>Here's a simple reference/code/result example:</p>
<ul>
<li>Reference - Sales</li>
<li>Code - 1PC//Prospecting call_ (In GoldMine everything before the // was treated as the picklist entry's primary key, so the 1PC would be stored in the database. We would then speak of 1PC calls as a shorthand.)_</li>
<li>Result - 1LM//Left message</li>
</ul>
<p>We tracked everything this way. Despite us still using GoldMine 6.7 in some parts of our business all the way into 2008, activity tracking was great except for two problems. First, although the codes existed in our processes as a logical hierarchy, GoldMine didn't understand that. If you picked the &quot;sales&quot; reference, you still had to weed through all the codes and results that corresponded to all the other references. Second, adding new reference/code/result entries in a supported manner took a lot of time.When we started considering the move to CRM 3 in 2005, I found the default activity entity structure to be something of a letdown, so I brought the reference/code/result framework over when we actually did move. Here's how I did it.</p>
<p>First, I created three separate picklist attributes in CRM on the six main activity entities we used - appointment, e-mail, fax, letter, phone call and task. Let's call them lucas_reference, lucas_code and lucas_result. I then populated them with the existing references, codes and results from GoldMine. The following are not the actual codes, but they'll give you a decent idea of how things were structured.</p>
<p><em>References (lucas_reference)</em><br>
Sales<br>
Service</p>
<p><em>Codes (lucas_code)</em><br>
1CD//Contract discussion<br>
1PC//Prospecting call<br>
1PE//Prospecting e-mail<br>
1FC//Follow-up call<br>
1FE//Follow-up e-mail<br>
1SC//Suspect call<br>
2CI//Service call inbound<br>
2EI//Service e-mail inbound<br>
2FU//Service follow-up</p>
<p><em>Results (lucas_result)</em><br>
1CF//Contract finalized<br>
1UP//Understands product<br>
2CS//Customer satisfied<br>
2CU//Customer unsatisfied<br>
2IE//Issue escalated<br>
2IR//Issue resolved<br>
CRS//Call rescheduled<br>
CMP//Completed<br>
EMI//E-mail in<br>
EMO//E-mail out<br>
PCI//Phone call in<br>
PCO//Phone call out<br>
LVM//Left message</p>
<p>In this example, codes and results starting with 1 are children of the &quot;sales&quot; reference. Codes and results starting with 2 are children of the &quot;service&quot; reference. Codes and results starting with letters are general options available to any reference.</p>
<p>At this point, allow me to point out a few things. First, we didn't use the existing CRM service activity, and we rarely (practically never) used the fax or letter entities. Why we didn't is beyond the scope of this blog post.Second, the reference/code/result picklist entries were duplicated across all six activity entities even if they didn't make sense. That is, you could have a task with a result of &quot;PCO//Phone call out.&quot; Because we had several hundred options, it was easier to make sure every activity had everything than to weed out the ones that didn't fit. Also it made report writing simpler.Third, the general options were handy for when we didn't have a firm process that applied to the activity. For example, sometimes on the service side, all we could do was note that a call came in.Fourth, reference and code were business required. Result was not because you obviously wouldn't know a scheduled activity's result at the point in time when you created it.</p>
<p>Once I created and populated the picklist attributes, I added them to the entities' forms, which was simple enough, but you'd still have the GoldMine problem of every code and result being available for any reference. I took care of that with a bit of JavaScript.The following example is based on something I picked up from <a href="http://www.amazon.com/Working-Microsoft-Dynamics-CRM-3-0/dp/0735622590/ref=sr_1_11?ie=UTF8&amp;qid=1300215967&amp;sr=8-11">&quot;Working with Microsoft Dynamics CRM 3.0&quot;</a> by Mike Snyder and Jim Steger.</p>
<pre><code>var objRef = crmForm.all.lucas_reference;  
var objCode = crmForm.all.lucas_code;  
var objRes = crmForm.all.lucas_result;  
  
//get the currently selected code and result values so we don't lose data if we're editing an activity instead of creating a new one  
var curcode = objCode.DataValue;  
var curresult = objRes.DataValue;  
  
//set the lucas_code and lucas_result picklist options to empy arrays for now  
var oTempArray = new Array();  
objCode.Options = oTempArray;  
var oTempArrayRes = new Array();  
objRes.Options = oTempArrayRes;  
  
//if a reference is selected  
if(objRef.SelectedText!=&quot;&quot;)  
{  
//get prefix of codes we're going to enable  
var codePrefix = &quot;&quot;;  
var resPrefix = &quot;&quot;;  
switch(objRef.SelectedText)  
{  
case &quot;Sales&quot;:  
codePrefix = &quot;1&quot;;  
resPrefix = &quot;1&quot;;  
break;  
case &quot;Service&quot;:  
codePrefix = &quot;2&quot;;  
resPrefix = &quot;2&quot;;  
break;  
}  
  
//enable the correct code codes  
if(codePrefix != &quot;&quot;)  
{  
//loop through the original lucas_code options  
for (var i = 1; i &lt; objCode.originalPicklistOptions.length; i++)  
{  
//if the lucas_code option begins with the codePrefix, add it to the holding array  
if(objCode.originalPicklistOptions[i].Text.indexOf(codePrefix)==0)  
{  
objCode.AddOption(objCode.originalPicklistOptions[i].Text, objCode.originalPicklistOptions[i].DataValue);  
}  
}  
  
//make sure the picklist is enabled  
objCode.Disabled = false;  
  
//set the picklist's selected value to what we stored earlier  
objCode.DataValue = curcode;  
}  
else  
{  
//disable the field  
objCode.Disabled = true;  
}  
  
//enable the correct result codes  
if(resPrefix != &quot;&quot;)  
{  
//loop through the original lucas_result options  
for (var j = 1; j &lt; objRes.originalPicklistOptions.length; j++)  
{  
//if the lucas_result option begins with the resPrefix, add it to the holding array  
if(objRes.originalPicklistOptions[j].Text.indexOf(resPrefix)==0)  
{  
objRes.AddOption(objRes.originalPicklistOptions[j].Text, objRes.originalPicklistOptions[j].DataValue);  
}  
//handle some general cases  
if(objRes.originalPicklistOptions[j].Text.indexOf(&quot;CRS&quot;)==0)  
{  
objRes.AddOption(objRes.originalPicklistOptions[j].Text, objRes.originalPicklistOptions[j].DataValue);  
}  
if(objRes.originalPicklistOptions[j].Text.indexOf(&quot;CMP&quot;)==0)  
{  
objRes.AddOption(objRes.originalPicklistOptions[j].Text, objRes.originalPicklistOptions[j].DataValue);  
}  
}  
  
//make sure the picklist is enabled  
objRes.Disabled = false;  
  
//set the picklist's selected value to what we stored earlier  
objRes.DataValue = curresult;  
}  
else  
{  
//disable the field  
objRes.Disabled = true;  
}  
}  
else  
{  
//no selected reference, no displayed codes or results  
objCode.Options = oTempArray();  
objRes.Options = oTempArrayRes();  
  
//disable the fields for good measure  
objRes.Disabled = true;  
objCode.Disabled = true;  
)
</code></pre>
<p>Add that to the onLoad event for each activity form and the onChange event for the reference field on each activity form, and you're good to go.</p>
<p>Happy activity documenting!</p>
</div>]]></content:encoded></item></channel></rss>